net: use mut and refs as receivers consistently (#8205)
parent
158aefc37f
commit
d92f5c55ba
|
@ -55,7 +55,7 @@ fn (mut dtp DTP) read() ?[]byte {
|
|||
return data
|
||||
}
|
||||
|
||||
fn (dtp DTP) close() {
|
||||
fn (mut dtp DTP) close() {
|
||||
dtp.conn.close()
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ module net
|
|||
#include <netdb.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#flag solaris -lsocket
|
||||
fn error_code() int {
|
||||
return C.errno
|
||||
}
|
||||
|
@ -24,5 +24,3 @@ pub const (
|
|||
const (
|
||||
error_ewouldblock = C.EWOULDBLOCK
|
||||
)
|
||||
|
||||
#flag solaris -lsocket
|
||||
|
|
|
@ -54,15 +54,19 @@ pub struct Mail {
|
|||
}
|
||||
|
||||
// new_client returns a new SMTP client and connects to it
|
||||
pub fn new_client(config Client) ?Client {
|
||||
mut c := config
|
||||
pub fn new_client(config Client) ?&Client {
|
||||
mut c := &Client{
|
||||
...config
|
||||
}
|
||||
c.reconnect() ?
|
||||
return c
|
||||
}
|
||||
|
||||
// reconnect reconnects to the SMTP server if the connection was closed
|
||||
pub fn (mut c Client) reconnect() ? {
|
||||
if c.is_open { return error('Already connected to server') }
|
||||
if c.is_open {
|
||||
return error('Already connected to server')
|
||||
}
|
||||
|
||||
conn := net.dial_tcp('$c.server:$c.port') or { return error('Connecting to server failed') }
|
||||
c.conn = conn
|
||||
|
@ -76,13 +80,18 @@ pub fn (mut c Client) reconnect() ? {
|
|||
}
|
||||
|
||||
// send sends an email
|
||||
pub fn (c Client) send(config Mail) ? {
|
||||
if !c.is_open { return error('Disconnected from server') }
|
||||
pub fn (mut c Client) send(config Mail) ? {
|
||||
if !c.is_open {
|
||||
return error('Disconnected from server')
|
||||
}
|
||||
from := if config.from != '' { config.from } else { c.from }
|
||||
c.send_mailfrom(from) or { return error('Sending mailfrom failed') }
|
||||
c.send_mailto(config.to) or { return error('Sending mailto failed') }
|
||||
c.send_data() or { return error('Sending mail data failed') }
|
||||
c.send_body({ config | from: from }) or { return error('Sending mail body failed') }
|
||||
c.send_body({
|
||||
config |
|
||||
from: from
|
||||
}) or { return error('Sending mail body failed') }
|
||||
}
|
||||
|
||||
// quit closes the connection to the server
|
||||
|
@ -94,7 +103,7 @@ pub fn (mut c Client) quit() ? {
|
|||
}
|
||||
|
||||
// expect_reply checks if the SMTP server replied with the expected reply code
|
||||
fn (c Client) expect_reply(expected ReplyCode) ? {
|
||||
fn (mut c Client) expect_reply(expected ReplyCode) ? {
|
||||
bytes := io.read_all(reader: c.conn) ?
|
||||
|
||||
str := bytes.bytestr().trim_space()
|
||||
|
@ -108,11 +117,13 @@ fn (c Client) expect_reply(expected ReplyCode) ? {
|
|||
if ReplyCode(status) != expected {
|
||||
return error('Received unexpected status code $status, expecting $expected')
|
||||
}
|
||||
} else { return error('Recieved unexpected SMTP data: $str') }
|
||||
} else {
|
||||
return error('Recieved unexpected SMTP data: $str')
|
||||
}
|
||||
}
|
||||
|
||||
[inline]
|
||||
fn (c Client) send_str(s string) ? {
|
||||
fn (mut c Client) send_str(s string) ? {
|
||||
$if smtp_debug ? {
|
||||
eprintln('\n\n[SEND START]')
|
||||
eprint(s.trim_space())
|
||||
|
@ -122,13 +133,13 @@ fn (c Client) send_str(s string) ? {
|
|||
}
|
||||
|
||||
[inline]
|
||||
fn (c Client) send_ehlo() ? {
|
||||
fn (mut c Client) send_ehlo() ? {
|
||||
c.send_str('EHLO $c.server\r\n') ?
|
||||
c.expect_reply(.action_ok) ?
|
||||
}
|
||||
|
||||
[inline]
|
||||
fn (c Client) send_auth() ? {
|
||||
fn (mut c Client) send_auth() ? {
|
||||
if c.username.len == 0 {
|
||||
return
|
||||
}
|
||||
|
@ -143,22 +154,22 @@ fn (c Client) send_auth() ? {
|
|||
c.expect_reply(.auth_ok) ?
|
||||
}
|
||||
|
||||
fn (c Client) send_mailfrom(from string) ? {
|
||||
fn (mut c Client) send_mailfrom(from string) ? {
|
||||
c.send_str('MAIL FROM: <$from>\r\n') ?
|
||||
c.expect_reply(.action_ok) ?
|
||||
}
|
||||
|
||||
fn (c Client) send_mailto(to string) ? {
|
||||
fn (mut c Client) send_mailto(to string) ? {
|
||||
c.send_str('RCPT TO: <$to>\r\n') ?
|
||||
c.expect_reply(.action_ok) ?
|
||||
}
|
||||
|
||||
fn (c Client) send_data() ? {
|
||||
fn (mut c Client) send_data() ? {
|
||||
c.send_str('DATA\r\n') ?
|
||||
c.expect_reply(.mail_start)
|
||||
}
|
||||
|
||||
fn (c Client) send_body(cfg Mail) ? {
|
||||
fn (mut c Client) send_body(cfg Mail) ? {
|
||||
is_html := cfg.body_type == .html
|
||||
date := cfg.date.utc_string().trim_right(' UTC') // TODO
|
||||
mut sb := strings.new_builder(200)
|
||||
|
|
|
@ -3,7 +3,7 @@ import smtp
|
|||
import time
|
||||
|
||||
// Used to test that a function call returns an error
|
||||
fn fn_errors(c smtp.Client, m smtp.Mail) bool {
|
||||
fn fn_errors(mut c smtp.Client, m smtp.Mail) bool {
|
||||
c.send(m) or { return true }
|
||||
return false
|
||||
}
|
||||
|
@ -14,7 +14,9 @@ fn fn_errors(c smtp.Client, m smtp.Mail) bool {
|
|||
* Created by: nedimf (07/2020)
|
||||
*/
|
||||
fn test_smtp() {
|
||||
$if !network ? { return }
|
||||
$if !network ? {
|
||||
return
|
||||
}
|
||||
|
||||
client_cfg := smtp.Client{
|
||||
server: 'smtp.mailtrap.io'
|
||||
|
@ -32,20 +34,57 @@ fn test_smtp() {
|
|||
body: 'Plain text'
|
||||
}
|
||||
|
||||
mut client := smtp.new_client(client_cfg) or { assert false return }
|
||||
mut client := smtp.new_client(client_cfg) or {
|
||||
assert false
|
||||
return
|
||||
}
|
||||
assert true
|
||||
client.send(send_cfg) or { assert false return }
|
||||
client.send(send_cfg) or {
|
||||
assert false
|
||||
return
|
||||
}
|
||||
assert true
|
||||
// client.send({ send_cfg | body_type: .html, body: '<html><h1>HTML V email!</h1></html>' }) or { assert false return }
|
||||
client.send({ send_cfg | from: 'alexander@vlang.io' }) or { assert false return }
|
||||
client.send({ send_cfg | cc: 'alexander@vlang.io,joe@vlang.io', bcc: 'spytheman@vlang.io' }) or { assert false return }
|
||||
client.send({ send_cfg | date: time.now().add_days(1000) }) or { assert false return }
|
||||
client.send({
|
||||
send_cfg |
|
||||
from: 'alexander@vlang.io'
|
||||
}) or {
|
||||
assert false
|
||||
return
|
||||
}
|
||||
client.send({
|
||||
send_cfg |
|
||||
cc: 'alexander@vlang.io,joe@vlang.io'
|
||||
bcc: 'spytheman@vlang.io'
|
||||
}) or {
|
||||
assert false
|
||||
return
|
||||
}
|
||||
client.send({
|
||||
send_cfg |
|
||||
date: time.now().add_days(1000)
|
||||
}) or {
|
||||
assert false
|
||||
return
|
||||
}
|
||||
assert true
|
||||
client.quit() or { assert false return }
|
||||
client.quit() or {
|
||||
assert false
|
||||
return
|
||||
}
|
||||
assert true
|
||||
// This call should return an error, since the connection is closed
|
||||
if !fn_errors(client, send_cfg) { assert false return }
|
||||
client.reconnect() or { assert false return }
|
||||
client.send(send_cfg) or { assert false return }
|
||||
if !fn_errors(mut client, send_cfg) {
|
||||
assert false
|
||||
return
|
||||
}
|
||||
client.reconnect() or {
|
||||
assert false
|
||||
return
|
||||
}
|
||||
client.send(send_cfg) or {
|
||||
assert false
|
||||
return
|
||||
}
|
||||
assert true
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ const (
|
|||
)
|
||||
|
||||
pub struct TcpConn {
|
||||
pub:
|
||||
pub mut:
|
||||
sock TcpSocket
|
||||
mut:
|
||||
write_deadline time.Time
|
||||
|
@ -17,23 +17,23 @@ mut:
|
|||
write_timeout time.Duration
|
||||
}
|
||||
|
||||
pub fn dial_tcp(address string) ?TcpConn {
|
||||
s := new_tcp_socket() ?
|
||||
pub fn dial_tcp(address string) ?&TcpConn {
|
||||
mut s := new_tcp_socket() ?
|
||||
s.connect(address) ?
|
||||
return TcpConn{
|
||||
return &TcpConn{
|
||||
sock: s
|
||||
read_timeout: tcp_default_read_timeout
|
||||
write_timeout: tcp_default_write_timeout
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (c TcpConn) close() ? {
|
||||
pub fn (mut c TcpConn) close() ? {
|
||||
c.sock.close() ?
|
||||
return none
|
||||
}
|
||||
|
||||
// write_ptr blocks and attempts to write all data
|
||||
pub fn (c TcpConn) write_ptr(b byteptr, len int) ? {
|
||||
pub fn (mut c TcpConn) write_ptr(b byteptr, len int) ? {
|
||||
$if trace_tcp ? {
|
||||
eprintln('>>> TcpConn.write_ptr | c.sock.handle: $c.sock.handle | b: ${ptr_str(b)} len: $len |\n' +
|
||||
unsafe { b.vstring_with_len(len) })
|
||||
|
@ -61,16 +61,16 @@ pub fn (c TcpConn) write_ptr(b byteptr, len int) ? {
|
|||
}
|
||||
|
||||
// write blocks and attempts to write all data
|
||||
pub fn (c TcpConn) write(bytes []byte) ? {
|
||||
pub fn (mut c TcpConn) write(bytes []byte) ? {
|
||||
return c.write_ptr(bytes.data, bytes.len)
|
||||
}
|
||||
|
||||
// write_str blocks and attempts to write all data
|
||||
pub fn (c TcpConn) write_str(s string) ? {
|
||||
pub fn (mut c TcpConn) write_str(s string) ? {
|
||||
return c.write_ptr(s.str, s.len)
|
||||
}
|
||||
|
||||
pub fn (c TcpConn) read_ptr(buf_ptr byteptr, len int) ?int {
|
||||
pub fn (mut c TcpConn) read_ptr(buf_ptr byteptr, len int) ?int {
|
||||
mut res := wrap_read_result(C.recv(c.sock.handle, buf_ptr, len, 0)) ?
|
||||
$if trace_tcp ? {
|
||||
eprintln('<<< TcpConn.read_ptr | c.sock.handle: $c.sock.handle | buf_ptr: ${ptr_str(buf_ptr)} len: $len | res: $res')
|
||||
|
@ -92,11 +92,11 @@ pub fn (c TcpConn) read_ptr(buf_ptr byteptr, len int) ?int {
|
|||
return none
|
||||
}
|
||||
|
||||
pub fn (c TcpConn) read(mut buf []byte) ?int {
|
||||
pub fn (mut c TcpConn) read(mut buf []byte) ?int {
|
||||
return c.read_ptr(buf.data, buf.len)
|
||||
}
|
||||
|
||||
pub fn (c TcpConn) read_deadline() ?time.Time {
|
||||
pub fn (mut c TcpConn) read_deadline() ?time.Time {
|
||||
if c.read_deadline.unix == 0 {
|
||||
return c.read_deadline
|
||||
}
|
||||
|
@ -107,7 +107,7 @@ pub fn (mut c TcpConn) set_read_deadline(deadline time.Time) {
|
|||
c.read_deadline = deadline
|
||||
}
|
||||
|
||||
pub fn (c TcpConn) write_deadline() ?time.Time {
|
||||
pub fn (mut c TcpConn) write_deadline() ?time.Time {
|
||||
if c.write_deadline.unix == 0 {
|
||||
return c.write_deadline
|
||||
}
|
||||
|
@ -118,7 +118,7 @@ pub fn (mut c TcpConn) set_write_deadline(deadline time.Time) {
|
|||
c.write_deadline = deadline
|
||||
}
|
||||
|
||||
pub fn (c TcpConn) read_timeout() time.Duration {
|
||||
pub fn (c &TcpConn) read_timeout() time.Duration {
|
||||
return c.read_timeout
|
||||
}
|
||||
|
||||
|
@ -126,7 +126,7 @@ pub fn (mut c TcpConn) set_read_timeout(t time.Duration) {
|
|||
c.read_timeout = t
|
||||
}
|
||||
|
||||
pub fn (c TcpConn) write_timeout() time.Duration {
|
||||
pub fn (c &TcpConn) write_timeout() time.Duration {
|
||||
return c.write_timeout
|
||||
}
|
||||
|
||||
|
@ -135,23 +135,23 @@ pub fn (mut c TcpConn) set_write_timeout(t time.Duration) {
|
|||
}
|
||||
|
||||
[inline]
|
||||
pub fn (c TcpConn) wait_for_read() ? {
|
||||
pub fn (mut c TcpConn) wait_for_read() ? {
|
||||
return wait_for_read(c.sock.handle, c.read_deadline, c.read_timeout)
|
||||
}
|
||||
|
||||
[inline]
|
||||
pub fn (c TcpConn) wait_for_write() ? {
|
||||
pub fn (mut c TcpConn) wait_for_write() ? {
|
||||
return wait_for_write(c.sock.handle, c.write_deadline, c.write_timeout)
|
||||
}
|
||||
|
||||
pub fn (c TcpConn) peer_addr() ?Addr {
|
||||
pub fn (c &TcpConn) peer_addr() ?Addr {
|
||||
mut addr := C.sockaddr{}
|
||||
len := sizeof(C.sockaddr)
|
||||
socket_error(C.getpeername(c.sock.handle, &addr, &len)) ?
|
||||
return new_addr(addr)
|
||||
}
|
||||
|
||||
pub fn (c TcpConn) peer_ip() ?string {
|
||||
pub fn (c &TcpConn) peer_ip() ?string {
|
||||
buf := [44]byte{}
|
||||
peeraddr := C.sockaddr_in{}
|
||||
speeraddr := sizeof(peeraddr)
|
||||
|
@ -164,19 +164,20 @@ pub fn (c TcpConn) peer_ip() ?string {
|
|||
return res
|
||||
}
|
||||
|
||||
pub fn (c TcpConn) str() string {
|
||||
pub fn (c &TcpConn) str() string {
|
||||
// TODO
|
||||
return 'TcpConn'
|
||||
return 'TcpConn {write_deadline: $c.write_deadline, read_deadline: $c.read_deadline, read_timeout: $c.read_timeout, write_timeout: $c.write_timeout, sock: $c.sock}'
|
||||
}
|
||||
|
||||
pub struct TcpListener {
|
||||
pub mut:
|
||||
sock TcpSocket
|
||||
mut:
|
||||
accept_timeout time.Duration
|
||||
accept_deadline time.Time
|
||||
}
|
||||
|
||||
pub fn listen_tcp(port int) ?TcpListener {
|
||||
pub fn listen_tcp(port int) ?&TcpListener {
|
||||
s := new_tcp_socket() ?
|
||||
validate_port(port) ?
|
||||
mut addr := C.sockaddr_in{}
|
||||
|
@ -188,14 +189,14 @@ pub fn listen_tcp(port int) ?TcpListener {
|
|||
sockaddr := unsafe { &C.sockaddr(&addr) }
|
||||
socket_error(C.bind(s.handle, sockaddr, size)) ?
|
||||
socket_error(C.listen(s.handle, 128)) ?
|
||||
return TcpListener{
|
||||
return &TcpListener{
|
||||
sock: s
|
||||
accept_deadline: no_deadline
|
||||
accept_timeout: infinite_timeout
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (l TcpListener) accept() ?TcpConn {
|
||||
pub fn (mut l TcpListener) accept() ?&TcpConn {
|
||||
addr := C.sockaddr_storage{}
|
||||
unsafe { C.memset(&addr, 0, sizeof(C.sockaddr_storage)) }
|
||||
size := sizeof(C.sockaddr_storage)
|
||||
|
@ -210,14 +211,14 @@ pub fn (l TcpListener) accept() ?TcpConn {
|
|||
}
|
||||
}
|
||||
new_sock := tcp_socket_from_handle(new_handle) ?
|
||||
return TcpConn{
|
||||
return &TcpConn{
|
||||
sock: new_sock
|
||||
read_timeout: tcp_default_read_timeout
|
||||
write_timeout: tcp_default_write_timeout
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (c TcpListener) accept_deadline() ?time.Time {
|
||||
pub fn (c &TcpListener) accept_deadline() ?time.Time {
|
||||
if c.accept_deadline.unix != 0 {
|
||||
return c.accept_deadline
|
||||
}
|
||||
|
@ -228,7 +229,7 @@ pub fn (mut c TcpListener) set_accept_deadline(deadline time.Time) {
|
|||
c.accept_deadline = deadline
|
||||
}
|
||||
|
||||
pub fn (c TcpListener) accept_timeout() time.Duration {
|
||||
pub fn (c &TcpListener) accept_timeout() time.Duration {
|
||||
return c.accept_timeout
|
||||
}
|
||||
|
||||
|
@ -236,16 +237,16 @@ pub fn (mut c TcpListener) set_accept_timeout(t time.Duration) {
|
|||
c.accept_timeout = t
|
||||
}
|
||||
|
||||
pub fn (c TcpListener) wait_for_accept() ? {
|
||||
pub fn (mut c TcpListener) wait_for_accept() ? {
|
||||
return wait_for_read(c.sock.handle, c.accept_deadline, c.accept_timeout)
|
||||
}
|
||||
|
||||
pub fn (c TcpListener) close() ? {
|
||||
pub fn (mut c TcpListener) close() ? {
|
||||
c.sock.close() ?
|
||||
return none
|
||||
}
|
||||
|
||||
pub fn (c TcpListener) address() ?Addr {
|
||||
pub fn (c &TcpListener) address() ?Addr {
|
||||
return c.sock.address()
|
||||
}
|
||||
|
||||
|
@ -256,7 +257,7 @@ pub:
|
|||
|
||||
fn new_tcp_socket() ?TcpSocket {
|
||||
sockfd := socket_error(C.socket(SocketFamily.inet, SocketType.tcp, 0)) ?
|
||||
s := TcpSocket{
|
||||
mut s := TcpSocket{
|
||||
handle: sockfd
|
||||
}
|
||||
// s.set_option_bool(.reuse_addr, true)?
|
||||
|
@ -271,7 +272,7 @@ fn new_tcp_socket() ?TcpSocket {
|
|||
}
|
||||
|
||||
fn tcp_socket_from_handle(sockfd int) ?TcpSocket {
|
||||
s := TcpSocket{
|
||||
mut s := TcpSocket{
|
||||
handle: sockfd
|
||||
}
|
||||
// s.set_option_bool(.reuse_addr, true)?
|
||||
|
@ -285,7 +286,7 @@ fn tcp_socket_from_handle(sockfd int) ?TcpSocket {
|
|||
return s
|
||||
}
|
||||
|
||||
pub fn (s TcpSocket) set_option_bool(opt SocketOption, value bool) ? {
|
||||
pub fn (mut s TcpSocket) set_option_bool(opt SocketOption, value bool) ? {
|
||||
// TODO reenable when this `in` operation works again
|
||||
// if opt !in opts_can_set {
|
||||
// return err_option_not_settable
|
||||
|
@ -297,16 +298,16 @@ pub fn (s TcpSocket) set_option_bool(opt SocketOption, value bool) ? {
|
|||
return none
|
||||
}
|
||||
|
||||
pub fn (s TcpSocket) set_option_int(opt SocketOption, value int) ? {
|
||||
pub fn (mut s TcpSocket) set_option_int(opt SocketOption, value int) ? {
|
||||
socket_error(C.setsockopt(s.handle, C.SOL_SOCKET, int(opt), &value, sizeof(int))) ?
|
||||
return none
|
||||
}
|
||||
|
||||
fn (s TcpSocket) close() ? {
|
||||
fn (mut s TcpSocket) close() ? {
|
||||
return shutdown(s.handle)
|
||||
}
|
||||
|
||||
fn (s TcpSocket) @select(test Select, timeout time.Duration) ?bool {
|
||||
fn (mut s TcpSocket) @select(test Select, timeout time.Duration) ?bool {
|
||||
return @select(s.handle, test, timeout)
|
||||
}
|
||||
|
||||
|
@ -314,7 +315,7 @@ const (
|
|||
connect_timeout = 5 * time.second
|
||||
)
|
||||
|
||||
fn (s TcpSocket) connect(a string) ? {
|
||||
fn (mut s TcpSocket) connect(a string) ? {
|
||||
addr := resolve_addr(a, .inet, .tcp) ?
|
||||
res := C.connect(s.handle, &addr.addr, addr.len)
|
||||
if res == 0 {
|
||||
|
@ -335,7 +336,7 @@ fn (s TcpSocket) connect(a string) ? {
|
|||
}
|
||||
|
||||
// address gets the address of a socket
|
||||
pub fn (s TcpSocket) address() ?Addr {
|
||||
pub fn (s &TcpSocket) address() ?Addr {
|
||||
mut addr := C.sockaddr_in{}
|
||||
size := sizeof(C.sockaddr_in)
|
||||
// cast to the correct type
|
||||
|
|
|
@ -10,7 +10,7 @@ const (
|
|||
// It will *always* return a line, ending with CRLF, or just '', on EOF.
|
||||
// NB: if you want more control over the buffer, please use a buffered IO
|
||||
// reader instead: `io.new_buffered_reader({reader: io.make_reader(con)})`
|
||||
pub fn (con TcpConn) read_line() string {
|
||||
pub fn (mut con TcpConn) read_line() string {
|
||||
mut buf := [max_read]byte{} // where C.recv will store the network data
|
||||
mut res := '' // The final result, including the ending \n.
|
||||
for {
|
||||
|
|
|
@ -6,36 +6,28 @@ const (
|
|||
server_port = 22334
|
||||
)
|
||||
|
||||
fn setup() (net.TcpListener, net.TcpConn, net.TcpConn) {
|
||||
server := net.listen_tcp(server_port) or {
|
||||
panic(err)
|
||||
}
|
||||
mut client := net.dial_tcp('127.0.0.1:$server_port') or {
|
||||
panic(err)
|
||||
}
|
||||
mut socket := server.accept() or {
|
||||
panic(err)
|
||||
}
|
||||
fn setup() (&net.TcpListener, &net.TcpConn, &net.TcpConn) {
|
||||
mut server := net.listen_tcp(server_port) or { panic(err) }
|
||||
mut client := net.dial_tcp('127.0.0.1:$server_port') or { panic(err) }
|
||||
mut socket := server.accept() or { panic(err) }
|
||||
$if debug_peer_ip ? {
|
||||
ip := con.peer_ip() or {
|
||||
'$err'
|
||||
}
|
||||
ip := con.peer_ip() or { '$err' }
|
||||
eprintln('connection peer_ip: $ip')
|
||||
}
|
||||
assert true
|
||||
return server, client, socket
|
||||
}
|
||||
|
||||
fn cleanup(server &net.TcpListener, client &net.TcpConn, socket &net.TcpConn) {
|
||||
fn cleanup(mut server net.TcpListener, mut client net.TcpConn, mut socket net.TcpConn) {
|
||||
server.close() or { }
|
||||
client.close() or { }
|
||||
socket.close() or { }
|
||||
}
|
||||
|
||||
fn test_socket() {
|
||||
server, client, socket := setup()
|
||||
mut server, mut client, mut socket := setup()
|
||||
defer {
|
||||
cleanup(server, client, socket)
|
||||
cleanup(mut server, mut client, mut socket)
|
||||
}
|
||||
message := 'Hello World'
|
||||
socket.write_str(message) or {
|
||||
|
@ -65,14 +57,12 @@ fn test_socket() {
|
|||
}
|
||||
|
||||
fn test_socket_write_and_read() {
|
||||
server, client, socket := setup()
|
||||
mut server, mut client, mut socket := setup()
|
||||
defer {
|
||||
cleanup(server, client, socket)
|
||||
cleanup(mut server, mut client, mut socket)
|
||||
}
|
||||
message1 := 'a message 1'
|
||||
socket.write_str(message1) or {
|
||||
assert false
|
||||
}
|
||||
socket.write_str(message1) or { assert false }
|
||||
mut rbuf := []byte{len: message1.len}
|
||||
client.read(mut rbuf)
|
||||
line := rbuf.bytestr()
|
||||
|
@ -80,18 +70,16 @@ fn test_socket_write_and_read() {
|
|||
}
|
||||
|
||||
fn test_socket_read_line() {
|
||||
server, client, socket := setup()
|
||||
mut reader := io.new_buffered_reader({
|
||||
mut server, mut client, mut socket := setup()
|
||||
mut reader := io.new_buffered_reader(
|
||||
reader: io.make_reader(client)
|
||||
})
|
||||
)
|
||||
defer {
|
||||
cleanup(server, client, socket)
|
||||
cleanup(mut server, mut client, mut socket)
|
||||
}
|
||||
message1, message2 := 'message1', 'message2'
|
||||
message := '$message1\n$message2\n'
|
||||
socket.write_str(message) or {
|
||||
assert false
|
||||
}
|
||||
socket.write_str(message) or { assert false }
|
||||
assert true
|
||||
//
|
||||
line1 := reader.read_line() or {
|
||||
|
@ -109,9 +97,9 @@ fn test_socket_read_line() {
|
|||
}
|
||||
|
||||
fn test_socket_write_fail_without_panic() {
|
||||
server, client, socket := setup()
|
||||
mut server, mut client, mut socket := setup()
|
||||
defer {
|
||||
cleanup(server, client, socket)
|
||||
cleanup(mut server, mut client, mut socket)
|
||||
}
|
||||
message2 := 'a message 2'
|
||||
// ensure that socket.write (i.e. done on the server side)
|
||||
|
@ -131,12 +119,12 @@ fn test_socket_write_fail_without_panic() {
|
|||
}
|
||||
|
||||
fn test_socket_read_line_long_line_without_eol() {
|
||||
server, client, socket := setup()
|
||||
mut reader := io.new_buffered_reader({
|
||||
mut server, mut client, mut socket := setup()
|
||||
mut reader := io.new_buffered_reader(
|
||||
reader: io.make_reader(client)
|
||||
})
|
||||
)
|
||||
defer {
|
||||
cleanup(server, client, socket)
|
||||
cleanup(mut server, mut client, mut socket)
|
||||
}
|
||||
message := strings.repeat_string('123', 400)
|
||||
socket.write_str(message)
|
||||
|
|
|
@ -4,8 +4,7 @@ const (
|
|||
test_port = 45123
|
||||
)
|
||||
|
||||
fn handle_conn(_c net.TcpConn) {
|
||||
mut c := _c
|
||||
fn handle_conn(mut c net.TcpConn) {
|
||||
for {
|
||||
mut buf := []byte{len: 100, init: 0}
|
||||
read := c.read(mut buf) or {
|
||||
|
@ -19,12 +18,10 @@ fn handle_conn(_c net.TcpConn) {
|
|||
}
|
||||
}
|
||||
|
||||
fn echo_server(l net.TcpListener) ? {
|
||||
fn echo_server(mut l net.TcpListener) ? {
|
||||
for {
|
||||
new_conn := l.accept() or {
|
||||
continue
|
||||
}
|
||||
go handle_conn(new_conn)
|
||||
mut new_conn := l.accept() or { continue }
|
||||
go handle_conn(mut new_conn)
|
||||
}
|
||||
return none
|
||||
}
|
||||
|
@ -47,16 +44,8 @@ fn echo() ? {
|
|||
}
|
||||
|
||||
fn test_tcp() {
|
||||
l := net.listen_tcp(test_port) or {
|
||||
panic(err)
|
||||
}
|
||||
go echo_server(l)
|
||||
echo() or {
|
||||
panic(err)
|
||||
}
|
||||
mut l := net.listen_tcp(test_port) or { panic(err) }
|
||||
go echo_server(mut l)
|
||||
echo() or { panic(err) }
|
||||
l.close() or { }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
test_tcp()
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ const (
|
|||
)
|
||||
|
||||
pub struct UdpConn {
|
||||
pub mut:
|
||||
sock UdpSocket
|
||||
mut:
|
||||
write_deadline time.Time
|
||||
|
@ -16,7 +17,7 @@ mut:
|
|||
write_timeout time.Duration
|
||||
}
|
||||
|
||||
pub fn dial_udp(laddr string, raddr string) ?UdpConn {
|
||||
pub fn dial_udp(laddr string, raddr string) ?&UdpConn {
|
||||
// Dont have to do this when its fixed
|
||||
// this just allows us to store this `none` optional in a struct
|
||||
resolve_wrapper := fn (raddr string) ?Addr {
|
||||
|
@ -30,27 +31,27 @@ pub fn dial_udp(laddr string, raddr string) ?UdpConn {
|
|||
l: local
|
||||
r: resolve_wrapper(raddr)
|
||||
}
|
||||
return UdpConn{
|
||||
return &UdpConn{
|
||||
sock: sock
|
||||
read_timeout: udp_default_read_timeout
|
||||
write_timeout: udp_default_write_timeout
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (c UdpConn) write_ptr(b byteptr, len int) ? {
|
||||
pub fn (mut c UdpConn) write_ptr(b byteptr, len int) ? {
|
||||
remote := c.sock.remote() or { return err_no_udp_remote }
|
||||
return c.write_to_ptr(remote, b, len)
|
||||
}
|
||||
|
||||
pub fn (c UdpConn) write(buf []byte) ? {
|
||||
pub fn (mut c UdpConn) write(buf []byte) ? {
|
||||
return c.write_ptr(buf.data, buf.len)
|
||||
}
|
||||
|
||||
pub fn (c UdpConn) write_str(s string) ? {
|
||||
pub fn (mut c UdpConn) write_str(s string) ? {
|
||||
return c.write_ptr(s.str, s.len)
|
||||
}
|
||||
|
||||
pub fn (c UdpConn) write_to_ptr(addr Addr, b byteptr, len int) ? {
|
||||
pub fn (mut c UdpConn) write_to_ptr(addr Addr, b byteptr, len int) ? {
|
||||
res := C.sendto(c.sock.handle, b, len, 0, &addr.addr, addr.len)
|
||||
if res >= 0 {
|
||||
return none
|
||||
|
@ -66,17 +67,17 @@ pub fn (c UdpConn) write_to_ptr(addr Addr, b byteptr, len int) ? {
|
|||
}
|
||||
|
||||
// write_to blocks and writes the buf to the remote addr specified
|
||||
pub fn (c UdpConn) write_to(addr Addr, buf []byte) ? {
|
||||
pub fn (mut c UdpConn) write_to(addr Addr, buf []byte) ? {
|
||||
return c.write_to_ptr(addr, buf.data, buf.len)
|
||||
}
|
||||
|
||||
// write_to_string blocks and writes the buf to the remote addr specified
|
||||
pub fn (c UdpConn) write_to_string(addr Addr, s string) ? {
|
||||
pub fn (mut c UdpConn) write_to_string(addr Addr, s string) ? {
|
||||
return c.write_to_ptr(addr, s.str, s.len)
|
||||
}
|
||||
|
||||
// read reads from the socket into buf up to buf.len returning the number of bytes read
|
||||
pub fn (c UdpConn) read(mut buf []byte) ?(int, Addr) {
|
||||
pub fn (mut c UdpConn) read(mut buf []byte) ?(int, Addr) {
|
||||
mut addr_from := C.sockaddr{}
|
||||
len := sizeof(C.sockaddr)
|
||||
mut res := wrap_read_result(C.recvfrom(c.sock.handle, buf.data, buf.len, 0, &addr_from,
|
||||
|
@ -100,7 +101,7 @@ pub fn (c UdpConn) read(mut buf []byte) ?(int, Addr) {
|
|||
return none
|
||||
}
|
||||
|
||||
pub fn (c UdpConn) read_deadline() ?time.Time {
|
||||
pub fn (c &UdpConn) read_deadline() ?time.Time {
|
||||
if c.read_deadline.unix == 0 {
|
||||
return c.read_deadline
|
||||
}
|
||||
|
@ -111,7 +112,7 @@ pub fn (mut c UdpConn) set_read_deadline(deadline time.Time) {
|
|||
c.read_deadline = deadline
|
||||
}
|
||||
|
||||
pub fn (c UdpConn) write_deadline() ?time.Time {
|
||||
pub fn (c &UdpConn) write_deadline() ?time.Time {
|
||||
if c.write_deadline.unix == 0 {
|
||||
return c.write_deadline
|
||||
}
|
||||
|
@ -122,7 +123,7 @@ pub fn (mut c UdpConn) set_write_deadline(deadline time.Time) {
|
|||
c.write_deadline = deadline
|
||||
}
|
||||
|
||||
pub fn (c UdpConn) read_timeout() time.Duration {
|
||||
pub fn (c &UdpConn) read_timeout() time.Duration {
|
||||
return c.read_timeout
|
||||
}
|
||||
|
||||
|
@ -130,7 +131,7 @@ pub fn (mut c UdpConn) set_read_timeout(t time.Duration) {
|
|||
c.read_timeout = t
|
||||
}
|
||||
|
||||
pub fn (c UdpConn) write_timeout() time.Duration {
|
||||
pub fn (c &UdpConn) write_timeout() time.Duration {
|
||||
return c.write_timeout
|
||||
}
|
||||
|
||||
|
@ -139,27 +140,27 @@ pub fn (mut c UdpConn) set_write_timeout(t time.Duration) {
|
|||
}
|
||||
|
||||
[inline]
|
||||
pub fn (c UdpConn) wait_for_read() ? {
|
||||
pub fn (mut c UdpConn) wait_for_read() ? {
|
||||
return wait_for_read(c.sock.handle, c.read_deadline, c.read_timeout)
|
||||
}
|
||||
|
||||
[inline]
|
||||
pub fn (c UdpConn) wait_for_write() ? {
|
||||
pub fn (mut c UdpConn) wait_for_write() ? {
|
||||
return wait_for_write(c.sock.handle, c.write_deadline, c.write_timeout)
|
||||
}
|
||||
|
||||
pub fn (c UdpConn) str() string {
|
||||
pub fn (c &UdpConn) str() string {
|
||||
// TODO
|
||||
return 'UdpConn'
|
||||
}
|
||||
|
||||
pub fn (c UdpConn) close() ? {
|
||||
pub fn (mut c UdpConn) close() ? {
|
||||
return c.sock.close()
|
||||
}
|
||||
|
||||
pub fn listen_udp(port int) ?UdpConn {
|
||||
pub fn listen_udp(port int) ?&UdpConn {
|
||||
s := new_udp_socket(port) ?
|
||||
return UdpConn{
|
||||
return &UdpConn{
|
||||
sock: s
|
||||
read_timeout: udp_default_read_timeout
|
||||
write_timeout: udp_default_write_timeout
|
||||
|
@ -172,9 +173,9 @@ struct UdpSocket {
|
|||
r ?Addr
|
||||
}
|
||||
|
||||
fn new_udp_socket(local_port int) ?UdpSocket {
|
||||
fn new_udp_socket(local_port int) ?&UdpSocket {
|
||||
sockfd := socket_error(C.socket(SocketFamily.inet, SocketType.udp, 0)) ?
|
||||
s := UdpSocket{
|
||||
mut s := &UdpSocket{
|
||||
handle: sockfd
|
||||
}
|
||||
s.set_option_bool(.reuse_addr, true) ?
|
||||
|
@ -197,11 +198,11 @@ fn new_udp_socket(local_port int) ?UdpSocket {
|
|||
return s
|
||||
}
|
||||
|
||||
pub fn (s UdpSocket) remote() ?Addr {
|
||||
pub fn (s &UdpSocket) remote() ?Addr {
|
||||
return s.r
|
||||
}
|
||||
|
||||
pub fn (s UdpSocket) set_option_bool(opt SocketOption, value bool) ? {
|
||||
pub fn (mut s UdpSocket) set_option_bool(opt SocketOption, value bool) ? {
|
||||
// TODO reenable when this `in` operation works again
|
||||
// if opt !in opts_can_set {
|
||||
// return err_option_not_settable
|
||||
|
@ -213,10 +214,10 @@ pub fn (s UdpSocket) set_option_bool(opt SocketOption, value bool) ? {
|
|||
return none
|
||||
}
|
||||
|
||||
fn (s UdpSocket) close() ? {
|
||||
fn (mut s UdpSocket) close() ? {
|
||||
return shutdown(s.handle)
|
||||
}
|
||||
|
||||
fn (s UdpSocket) @select(test Select, timeout time.Duration) ?bool {
|
||||
fn (mut s UdpSocket) @select(test Select, timeout time.Duration) ?bool {
|
||||
return @select(s.handle, test, timeout)
|
||||
}
|
||||
|
|
|
@ -1,12 +1,9 @@
|
|||
import net
|
||||
|
||||
fn echo_server(_c net.UdpConn) {
|
||||
mut c := _c
|
||||
fn echo_server(mut c net.UdpConn) {
|
||||
for {
|
||||
mut buf := []byte{len: 100, init: 0}
|
||||
read, addr := c.read(mut buf) or {
|
||||
continue
|
||||
}
|
||||
read, addr := c.read(mut buf) or { continue }
|
||||
|
||||
c.write_to(addr, buf[..read]) or {
|
||||
println('Server: connection dropped')
|
||||
|
@ -17,7 +14,9 @@ fn echo_server(_c net.UdpConn) {
|
|||
|
||||
fn echo() ? {
|
||||
mut c := net.dial_udp('127.0.0.1:40003', '127.0.0.1:40001') ?
|
||||
defer { c.close() or { } }
|
||||
defer {
|
||||
c.close() or { }
|
||||
}
|
||||
data := 'Hello from vlib/net!'
|
||||
|
||||
c.write_str(data) ?
|
||||
|
@ -35,7 +34,7 @@ fn echo() ? {
|
|||
assert buf[i] == data[i]
|
||||
}
|
||||
|
||||
println('Got "${buf.bytestr()}"')
|
||||
println('Got "$buf.bytestr()"')
|
||||
|
||||
c.close() ?
|
||||
|
||||
|
@ -43,13 +42,13 @@ fn echo() ? {
|
|||
}
|
||||
|
||||
fn test_udp() {
|
||||
l := net.listen_udp(40001) or {
|
||||
mut l := net.listen_udp(40001) or {
|
||||
println(err)
|
||||
assert false
|
||||
panic('')
|
||||
}
|
||||
|
||||
go echo_server(l)
|
||||
go echo_server(mut l)
|
||||
echo() or {
|
||||
println(err)
|
||||
assert false
|
||||
|
|
|
@ -230,7 +230,7 @@ struct SimpleTcpClientConfig {
|
|||
}
|
||||
|
||||
fn simple_tcp_client(config SimpleTcpClientConfig) ?string {
|
||||
mut client := net.TcpConn{}
|
||||
mut client := &net.TcpConn(0)
|
||||
mut tries := 0
|
||||
for tries < config.retries {
|
||||
tries++
|
||||
|
|
|
@ -45,9 +45,9 @@ mut:
|
|||
status string = '200 OK'
|
||||
pub:
|
||||
req http.Request
|
||||
conn net.TcpConn
|
||||
// TODO Response
|
||||
pub mut:
|
||||
conn &net.TcpConn
|
||||
static_files map[string]string
|
||||
static_mime_types map[string]string
|
||||
form map[string]string
|
||||
|
@ -123,7 +123,7 @@ pub fn (mut ctx Context) send_response_to_client(mimetype string, res string) bo
|
|||
defer {
|
||||
s.free()
|
||||
}
|
||||
send_string(ctx.conn, s) or { return false }
|
||||
send_string(mut ctx.conn, s) or { return false }
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -152,7 +152,7 @@ pub fn (mut ctx Context) redirect(url string) Result {
|
|||
return Result{}
|
||||
}
|
||||
ctx.done = true
|
||||
send_string(ctx.conn, 'HTTP/1.1 302 Found\r\nLocation: $url$ctx.headers\r\n$headers_close') or {
|
||||
send_string(mut ctx.conn, 'HTTP/1.1 302 Found\r\nLocation: $url$ctx.headers\r\n$headers_close') or {
|
||||
return Result{}
|
||||
}
|
||||
return Result{}
|
||||
|
@ -163,7 +163,7 @@ pub fn (mut ctx Context) not_found() Result {
|
|||
return Result{}
|
||||
}
|
||||
ctx.done = true
|
||||
send_string(ctx.conn, http_404) or { }
|
||||
send_string(mut ctx.conn, http_404) or { }
|
||||
return Result{}
|
||||
}
|
||||
|
||||
|
@ -242,8 +242,10 @@ pub fn run<T>(port int) {
|
|||
|
||||
pub fn run_app<T>(mut app T, port int) {
|
||||
println('Running a Vweb app on http://localhost:$port')
|
||||
l := net.listen_tcp(port) or { panic('failed to listen') }
|
||||
app.Context = Context{}
|
||||
mut l := net.listen_tcp(port) or { panic('failed to listen') }
|
||||
app.Context = Context{
|
||||
conn: 0
|
||||
}
|
||||
app.init_once()
|
||||
$for method in T.methods {
|
||||
$if method.return_type is Result {
|
||||
|
@ -301,7 +303,7 @@ fn handle_conn<T>(mut conn net.TcpConn, mut app T) {
|
|||
vals := first_line.split(' ')
|
||||
if vals.len < 2 {
|
||||
println('no vals for http')
|
||||
send_string(conn, http_500) or { }
|
||||
send_string(mut conn, http_500) or { }
|
||||
return
|
||||
}
|
||||
mut headers := []string{}
|
||||
|
@ -383,7 +385,7 @@ fn handle_conn<T>(mut conn net.TcpConn, mut app T) {
|
|||
mime_type := app.static_mime_types[static_file_name]
|
||||
if static_file != '' && mime_type != '' {
|
||||
data := os.read_file(static_file) or {
|
||||
send_string(conn, http_404) or { }
|
||||
send_string(mut conn, http_404) or { }
|
||||
return
|
||||
}
|
||||
app.send_response_to_client(mime_type, data)
|
||||
|
@ -544,7 +546,7 @@ fn handle_conn<T>(mut conn net.TcpConn, mut app T) {
|
|||
}
|
||||
if action == '' {
|
||||
// site not found
|
||||
send_string(conn, http_404) or { }
|
||||
send_string(mut conn, http_404) or { }
|
||||
return
|
||||
}
|
||||
$for method in T.methods {
|
||||
|
@ -685,6 +687,6 @@ fn filter(s string) string {
|
|||
|
||||
pub type RawHtml = string
|
||||
|
||||
fn send_string(conn net.TcpConn, s string) ? {
|
||||
fn send_string(mut conn net.TcpConn, s string) ? {
|
||||
conn.write(s.bytes()) ?
|
||||
}
|
||||
|
|
|
@ -86,7 +86,7 @@ fn (mut ws Client) shutdown_socket() ? {
|
|||
}
|
||||
|
||||
// dial_socket connects tcp socket and initializes default configurations
|
||||
fn (mut ws Client) dial_socket() ?net.TcpConn {
|
||||
fn (mut ws Client) dial_socket() ?&net.TcpConn {
|
||||
tcp_address := '$ws.uri.hostname:$ws.uri.port'
|
||||
mut t := net.dial_tcp(tcp_address) ?
|
||||
optval := int(1)
|
||||
|
|
|
@ -30,7 +30,7 @@ pub:
|
|||
uri Uri // uri of current connection
|
||||
id string // unique id of client
|
||||
pub mut:
|
||||
conn net.TcpConn // underlying TCP socket connection
|
||||
conn &net.TcpConn // underlying TCP socket connection
|
||||
nonce_size int = 16 // size of nounce used for masking
|
||||
panic_on_callback bool // set to true of callbacks can panic
|
||||
state State // current state of connection
|
||||
|
@ -75,6 +75,7 @@ pub enum OPCode {
|
|||
pub fn new_client(address string) ?&Client {
|
||||
uri := parse_uri(address) ?
|
||||
return &Client{
|
||||
conn: 0
|
||||
is_server: false
|
||||
ssl_conn: openssl.new_ssl_conn()
|
||||
is_ssl: address.starts_with('wss')
|
||||
|
|
|
@ -10,7 +10,7 @@ import rand
|
|||
pub struct Server {
|
||||
mut:
|
||||
logger &log.Log // logger used to log
|
||||
ls net.TcpListener // listener used to get incoming connection to socket
|
||||
ls &net.TcpListener // listener used to get incoming connection to socket
|
||||
accept_client_callbacks []AcceptClientFn // accept client callback functions
|
||||
message_callbacks []MessageEventHandler // new message callback functions
|
||||
close_callbacks []CloseEventHandler // close message callback functions
|
||||
|
@ -36,6 +36,7 @@ pub mut:
|
|||
// new_server instance a new websocket server on provided port and route
|
||||
pub fn new_server(port int, route string) &Server {
|
||||
return &Server{
|
||||
ls: 0
|
||||
port: port
|
||||
logger: &log.Log{
|
||||
level: .info
|
||||
|
|
Loading…
Reference in New Issue