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