net: use mut and refs as receivers consistently (#8205)

pull/8221/head
Delyan Angelov 2021-01-20 12:11:01 +02:00 committed by GitHub
parent 158aefc37f
commit d92f5c55ba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 236 additions and 206 deletions

View File

@ -55,7 +55,7 @@ fn (mut dtp DTP) read() ?[]byte {
return data
}
fn (dtp DTP) close() {
fn (mut dtp DTP) close() {
dtp.conn.close()
}

View File

@ -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

View File

@ -12,14 +12,14 @@ import time
import io
const (
recv_size = 128
recv_size = 128
)
enum ReplyCode {
ready = 220
close = 221
auth_ok = 235
action_ok = 250
ready = 220
close = 221
auth_ok = 235
action_ok = 250
mail_start = 354
}
@ -39,7 +39,7 @@ pub:
password string
from string
pub mut:
is_open bool
is_open bool
}
pub struct Mail {
@ -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
c.reconnect()?
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,29 +80,34 @@ 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
pub fn (mut c Client) quit() ? {
c.send_str('QUIT\r\n')
c.expect_reply(.close)
c.conn.close()?
c.conn.close() ?
c.is_open = false
}
// expect_reply checks if the SMTP server replied with the expected reply code
fn (c Client) expect_reply(expected ReplyCode) ? {
bytes := io.read_all(reader: c.conn)?
fn (mut c Client) expect_reply(expected ReplyCode) ? {
bytes := io.read_all(reader: c.conn) ?
str := bytes.bytestr().trim_space()
$if smtp_debug? {
$if smtp_debug ? {
eprintln('\n\n[RECV]')
eprint(str)
}
@ -108,30 +117,32 @@ 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) ? {
$if smtp_debug? {
fn (mut c Client) send_str(s string) ? {
$if smtp_debug ? {
eprintln('\n\n[SEND START]')
eprint(s.trim_space())
eprintln('\n[SEND END]')
}
c.conn.write(s.bytes())?
c.conn.write(s.bytes()) ?
}
[inline]
fn (c Client) send_ehlo() ? {
c.send_str('EHLO $c.server\r\n')?
c.expect_reply(.action_ok)?
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
}
}
mut sb := strings.new_builder(100)
sb.write_b(0)
sb.write(c.username)
@ -139,26 +150,26 @@ fn (c Client) send_auth() ? {
sb.write(c.password)
a := sb.str()
auth := 'AUTH PLAIN ${base64.encode(a)}\r\n'
c.send_str(auth)?
c.expect_reply(.auth_ok)?
c.send_str(auth) ?
c.expect_reply(.auth_ok) ?
}
fn (c Client) send_mailfrom(from string) ? {
c.send_str('MAIL FROM: <$from>\r\n')?
c.expect_reply(.action_ok)?
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) ? {
c.send_str('RCPT TO: <$to>\r\n')?
c.expect_reply(.action_ok)?
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() ? {
c.send_str('DATA\r\n')?
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)
@ -174,6 +185,6 @@ fn (c Client) send_body(cfg Mail) ? {
sb.write('\r\n\r\n')
sb.write(cfg.body)
sb.write('\r\n.\r\n')
c.send_str(sb.str())?
c.expect_reply(.action_ok)?
c.send_str(sb.str()) ?
c.expect_reply(.action_ok) ?
}

View File

@ -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
}

View File

@ -8,8 +8,8 @@ const (
)
pub struct TcpConn {
pub:
sock TcpSocket
pub mut:
sock TcpSocket
mut:
write_deadline time.Time
read_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 {
sock TcpSocket
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

View File

@ -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 {

View File

@ -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)

View File

@ -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,25 +18,23 @@ 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
}
fn echo() ? {
mut c := net.dial_tcp('127.0.0.1:$test_port')?
mut c := net.dial_tcp('127.0.0.1:$test_port') ?
defer {
c.close() or { }
}
data := 'Hello from vlib/net!'
c.write_str(data)?
c.write_str(data) ?
mut buf := []byte{len: 4096}
read := c.read(mut buf)?
read := c.read(mut buf) ?
assert read == data.len
for i := 0; i < read; i++ {
assert buf[i] == data[i]
@ -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()
}

View File

@ -8,7 +8,8 @@ const (
)
pub struct UdpConn {
sock UdpSocket
pub mut:
sock UdpSocket
mut:
write_deadline time.Time
read_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)
}

View File

@ -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
}
mut buf := []byte{len: 100, init: 0}
read, addr := c.read(mut buf) or { continue }
c.write_to(addr, buf[..read]) or {
println('Server: connection dropped')
@ -16,14 +13,16 @@ 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 { } }
mut c := net.dial_udp('127.0.0.1:40003', '127.0.0.1:40001') ?
defer {
c.close() or { }
}
data := 'Hello from vlib/net!'
c.write_str(data)?
c.write_str(data) ?
mut buf := []byte{ len: 100, init: 0 }
read, addr := c.read(mut buf)?
mut buf := []byte{len: 100, init: 0}
read, addr := c.read(mut buf) ?
assert read == data.len
println('Got address $addr')
@ -35,21 +34,21 @@ fn echo() ? {
assert buf[i] == data[i]
}
println('Got "${buf.bytestr()}"')
println('Got "$buf.bytestr()"')
c.close()?
c.close() ?
return none
}
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

View File

@ -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++

View File

@ -44,10 +44,10 @@ mut:
content_type string = 'text/plain'
status string = '200 OK'
pub:
req http.Request
conn net.TcpConn
req http.Request
// 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()) ?
}

View File

@ -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)

View File

@ -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')

View File

@ -9,8 +9,8 @@ import rand
// Server represents a websocket server connection
pub struct Server {
mut:
logger &log.Log // logger used to log
ls net.TcpListener // listener used to get incoming connection to socket
logger &log.Log // logger used to log
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