diff --git a/cmd/tools/vtest-self.v b/cmd/tools/vtest-self.v index ea1823aca3..150abd9e39 100644 --- a/cmd/tools/vtest-self.v +++ b/cmd/tools/vtest-self.v @@ -52,7 +52,7 @@ const ( 'vlib/net/tcp_simple_client_server_test.v', 'vlib/net/tcp_test.v', 'vlib/net/udp_test.v', - 'vlib/net/unix_test.v', + 'vlib/net/unix/unix_test.v', 'vlib/orm/orm_test.v', 'vlib/os/os_test.v', 'vlib/dl/dl_test.v', @@ -189,6 +189,7 @@ const ( 'vlib/orm/orm_test.v', 'vlib/v/tests/orm_sub_struct_test.v', 'vlib/net/websocket/ws_test.v', + 'vlib/net/unix/unix_test.v', 'vlib/x/websocket/websocket_test.v', 'vlib/vweb/tests/vweb_test.v', ] diff --git a/vlib/net/aasocket.c.v b/vlib/net/aasocket.c.v index f054bbb1dc..15344a87d9 100644 --- a/vlib/net/aasocket.c.v +++ b/vlib/net/aasocket.c.v @@ -16,7 +16,6 @@ pub enum SocketType { // SocketFamily are the available address families pub enum SocketFamily { inet = C.AF_INET - unix = C.AF_UNIX } struct C.in_addr { diff --git a/vlib/net/common.v b/vlib/net/common.v index 3d25ec41ca..41486a5389 100644 --- a/vlib/net/common.v +++ b/vlib/net/common.v @@ -6,10 +6,10 @@ import time fn shutdown(handle int) ? { $if windows { C.shutdown(handle, C.SD_BOTH) - socket_error(C.closesocket(handle))? + socket_error(C.closesocket(handle)) ? } $else { C.shutdown(handle, C.SHUT_RDWR) - socket_error(C.close(handle))? + socket_error(C.close(handle)) ? } return none @@ -34,19 +34,19 @@ fn @select(handle int, test Select, timeout time.Duration) ?bool { // infinite timeout is signaled by passing null as the timeout to // select - if timeout == infinite_timeout { + if timeout == net.infinite_timeout { timeval_timeout = &C.timeval(0) } match test { .read { - socket_error(C.@select(handle+1, &set, C.NULL, C.NULL, timeval_timeout))? + socket_error(C.@select(handle + 1, &set, C.NULL, C.NULL, timeval_timeout)) ? } .write { - socket_error(C.@select(handle+1, C.NULL, &set, C.NULL, timeval_timeout))? + socket_error(C.@select(handle + 1, C.NULL, &set, C.NULL, timeval_timeout)) ? } .except { - socket_error(C.@select(handle+1, C.NULL, C.NULL, &set, timeval_timeout))? + socket_error(C.@select(handle + 1, C.NULL, C.NULL, &set, timeval_timeout)) ? } } @@ -54,18 +54,14 @@ fn @select(handle int, test Select, timeout time.Duration) ?bool { } // wait_for_common wraps the common wait code -fn wait_for_common( - handle int, - deadline time.Time, - timeout time.Duration, - test Select) ? { +fn wait_for_common(handle int, deadline time.Time, timeout time.Duration, test Select) ? { if deadline.unix == 0 { // only accept infinite_timeout as a valid // negative timeout - it is handled in @select however - if timeout < 0 && timeout != infinite_timeout { + if timeout < 0 && timeout != net.infinite_timeout { return err_timed_out } - ready := @select(handle, test, timeout)? + ready := @select(handle, test, timeout) ? if ready { return none } @@ -80,7 +76,7 @@ fn wait_for_common( return err_timed_out } - ready := @select(handle, test, d_timeout)? + ready := @select(handle, test, d_timeout) ? if ready { return none } @@ -88,25 +84,21 @@ fn wait_for_common( } // wait_for_write waits for a write io operation to be available -fn wait_for_write( - handle int, - deadline time.Time, - timeout time.Duration) ? { +fn wait_for_write(handle int, deadline time.Time, timeout time.Duration) ? { return wait_for_common(handle, deadline, timeout, .write) } // wait_for_read waits for a read io operation to be available -fn wait_for_read( - handle int, - deadline time.Time, - timeout time.Duration) ? { +fn wait_for_read(handle int, deadline time.Time, timeout time.Duration) ? { return wait_for_common(handle, deadline, timeout, .read) } // no_deadline should be given to functions when no deadline is wanted (i.e. all functions // return instantly) const ( - no_deadline = time.Time{unix: 0} + no_deadline = time.Time{ + unix: 0 + } ) // no_timeout should be given to functions when no timeout is wanted (i.e. all functions diff --git a/vlib/net/errors.v b/vlib/net/errors.v index 6187abe6bd..596887abe2 100644 --- a/vlib/net/errors.v +++ b/vlib/net/errors.v @@ -6,16 +6,18 @@ const ( // Well defined errors that are returned from socket functions pub const ( - err_new_socket_failed = error_with_code('net: new_socket failed to create socket', errors_base+1) - err_option_not_settable = error_with_code('net: set_option_xxx option not settable', errors_base+2) - err_option_wrong_type = error_with_code('net: set_option_xxx option wrong type', errors_base+3) - err_port_out_of_range = error_with_code('', errors_base+5) - err_no_udp_remote = error_with_code('', errors_base+6) - err_connect_failed = error_with_code('net: connect failed', errors_base+7) - err_connect_timed_out = error_with_code('net: connect timed out', errors_base+8) - - err_timed_out = error_with_code('net: op timed out', errors_base+9) - err_timed_out_code = errors_base+9 + err_new_socket_failed = error_with_code('net: new_socket failed to create socket', + errors_base + 1) + err_option_not_settable = error_with_code('net: set_option_xxx option not settable', + errors_base + 2) + err_option_wrong_type = error_with_code('net: set_option_xxx option wrong type', + errors_base + 3) + err_port_out_of_range = error_with_code('', errors_base + 5) + err_no_udp_remote = error_with_code('', errors_base + 6) + err_connect_failed = error_with_code('net: connect failed', errors_base + 7) + err_connect_timed_out = error_with_code('net: connect timed out', errors_base + 8) + err_timed_out = error_with_code('net: op timed out', errors_base + 9) + err_timed_out_code = errors_base + 9 ) pub fn socket_error(potential_code int) ?int { @@ -23,10 +25,10 @@ pub fn socket_error(potential_code int) ?int { if potential_code < 0 { last_error_int := C.WSAGetLastError() last_error := wsa_error(last_error_int) - return error_with_code('net: socket error: ($last_error_int) $last_error', int(last_error)) + return error_with_code('net: socket error: ($last_error_int) $last_error', + int(last_error)) } - } - $else { + } $else { if potential_code < 0 { last_error := error_code() return error_with_code('net: socket error: $last_error', last_error) @@ -40,8 +42,7 @@ pub fn wrap_error(error_code int) ? { $if windows { enum_error := wsa_error(error_code) return error_with_code('net: socket error: $enum_error', error_code) - } - $else { + } $else { if error_code == 0 { return } diff --git a/vlib/net/net_nix.v b/vlib/net/net_nix.v deleted file mode 100644 index 76c57cd6aa..0000000000 --- a/vlib/net/net_nix.v +++ /dev/null @@ -1,280 +0,0 @@ -module net - -import time -import os - -fn C.SUN_LEN(C.sockaddr_un) int - -fn C.strncpy(charptr, charptr, int) - -struct UnixSocket { -pub: - handle int -mut: - path string -} - -struct UnixConn { -pub mut: - sock UnixSocket -mut: - write_deadline time.Time - read_deadline time.Time - read_timeout time.Duration - write_timeout time.Duration -} - -struct UnixListener { -pub mut: - sock UnixSocket -mut: - accept_timeout time.Duration - accept_deadline time.Time -} - -fn new_unix_socket() ?UnixSocket { - sockfd := socket_error(C.socket(SocketFamily.unix, SocketType.tcp, 0)) ? - mut s := UnixSocket{ - handle: sockfd - } - return s -} - -fn (mut s UnixSocket) close() ? { - os.rm(s.path) ? - return shutdown(s.handle) -} - -fn (mut s UnixSocket) @select(test Select, timeout time.Duration) ?bool { - return @select(s.handle, test, timeout) -} - -fn (mut s UnixSocket) connect(a string) ? { - if a.len >= 108 { - return error('Socket path too long! Max length: 107 chars.') - } - mut addr := C.sockaddr_un{} - unsafe { C.memset(&addr, 0, sizeof(C.sockaddr_un)) } - addr.sun_family = int(SocketFamily.unix) - C.strncpy(addr.sun_path, a.str, 108) - size := C.SUN_LEN(&addr) - sockaddr := unsafe { &C.sockaddr(&addr) } - res := C.connect(s.handle, sockaddr, size) - // if res != 1 { - // return none - //} - if res == 0 { - return none - } - _ := error_code() - write_result := s.@select(.write, connect_timeout) ? - if write_result { - // succeeded - return none - } - except_result := s.@select(.except, connect_timeout) ? - if except_result { - return err_connect_failed - } - // otherwise we timed out - return err_connect_timed_out -} - -pub fn listen_unix(sock string) ?&UnixListener { - if sock.len >= 108 { - return error('Socket path too long! Max length: 107 chars.') - } - mut s := new_unix_socket() ? - s.path = sock - mut addr := C.sockaddr_un{} - unsafe { C.memset(&addr, 0, sizeof(C.sockaddr_un)) } - addr.sun_family = int(SocketFamily.unix) - C.strncpy(addr.sun_path, sock.str, 108) - size := C.SUN_LEN(&addr) - sockaddr := unsafe { &C.sockaddr(&addr) } - socket_error(C.bind(s.handle, sockaddr, size)) ? - socket_error(C.listen(s.handle, 128)) ? - return &UnixListener{ - sock: s - } -} - -pub fn connect_unix(path string) ?&UnixConn { - mut s := new_unix_socket() ? - s.connect(path) ? - return &UnixConn{ - sock: s - read_timeout: tcp_default_read_timeout - write_timeout: tcp_default_write_timeout - } -} - -pub fn (mut l UnixListener) accept() ?&UnixConn { - mut new_handle := C.accept(l.sock.handle, 0, 0) - if new_handle <= 0 { - l.wait_for_accept() ? - new_handle = C.accept(l.sock.handle, 0, 0) - if new_handle == -1 || new_handle == 0 { - return none - } - } - new_sock := UnixSocket{ - handle: new_handle - } - return &UnixConn{ - sock: new_sock - read_timeout: tcp_default_read_timeout - write_timeout: tcp_default_write_timeout - } -} - -pub fn (c &UnixListener) accept_deadline() ?time.Time { - if c.accept_deadline.unix != 0 { - return c.accept_deadline - } - return none -} - -pub fn (mut c UnixListener) set_accept_deadline(deadline time.Time) { - c.accept_deadline = deadline -} - -pub fn (c &UnixListener) accept_timeout() time.Duration { - return c.accept_timeout -} - -pub fn (mut c UnixListener) set_accept_timeout(t time.Duration) { - c.accept_timeout = t -} - -pub fn (mut c UnixListener) wait_for_accept() ? { - return wait_for_read(c.sock.handle, c.accept_deadline, c.accept_timeout) -} - -pub fn (mut c UnixListener) close() ? { - c.sock.close() ? - return none -} - -pub fn (mut c UnixConn) close() ? { - c.sock.close() ? - return none -} - -// write_ptr blocks and attempts to write all data -pub fn (mut c UnixConn) write_ptr(b byteptr, len int) ? { - $if trace_tcp ? { - eprintln( - '>>> UnixConn.write_ptr | c.sock.handle: $c.sock.handle | b: ${ptr_str(b)} len: $len |\n' + - unsafe { b.vstring_with_len(len) }) - } - unsafe { - mut ptr_base := byteptr(b) - mut total_sent := 0 - for total_sent < len { - ptr := ptr_base + total_sent - remaining := len - total_sent - mut sent := C.send(c.sock.handle, ptr, remaining, msg_nosignal) - if sent < 0 { - code := error_code() - if code == int(error_ewouldblock) { - c.wait_for_write() ? - continue - } else { - wrap_error(code) ? - } - } - total_sent += sent - } - } - return none -} - -// write blocks and attempts to write all data -pub fn (mut c UnixConn) write(bytes []byte) ? { - return c.write_ptr(bytes.data, bytes.len) -} - -// write_str blocks and attempts to write all data -pub fn (mut c UnixConn) write_str(s string) ? { - return c.write_ptr(s.str, s.len) -} - -pub fn (mut c UnixConn) 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('<<< UnixConn.read_ptr | c.sock.handle: $c.sock.handle | buf_ptr: ${ptr_str(buf_ptr)} len: $len | res: $res') - } - if res > 0 { - return res - } - code := error_code() - if code == int(error_ewouldblock) { - c.wait_for_read() ? - res = wrap_read_result(C.recv(c.sock.handle, buf_ptr, len, 0)) ? - $if trace_tcp ? { - eprintln('<<< UnixConn.read_ptr | c.sock.handle: $c.sock.handle | buf_ptr: ${ptr_str(buf_ptr)} len: $len | res: $res') - } - return socket_error(res) - } else { - wrap_error(code) ? - } - return none -} - -pub fn (mut c UnixConn) read(mut buf []byte) ?int { - return c.read_ptr(buf.data, buf.len) -} - -pub fn (mut c UnixConn) read_deadline() ?time.Time { - if c.read_deadline.unix == 0 { - return c.read_deadline - } - return none -} - -pub fn (mut c UnixConn) set_read_deadline(deadline time.Time) { - c.read_deadline = deadline -} - -pub fn (mut c UnixConn) write_deadline() ?time.Time { - if c.write_deadline.unix == 0 { - return c.write_deadline - } - return none -} - -pub fn (mut c UnixConn) set_write_deadline(deadline time.Time) { - c.write_deadline = deadline -} - -pub fn (c &UnixConn) read_timeout() time.Duration { - return c.read_timeout -} - -pub fn (mut c UnixConn) set_read_timeout(t time.Duration) { - c.read_timeout = t -} - -pub fn (c &UnixConn) write_timeout() time.Duration { - return c.write_timeout -} - -pub fn (mut c UnixConn) set_write_timeout(t time.Duration) { - c.write_timeout = t -} - -[inline] -pub fn (mut c UnixConn) wait_for_read() ? { - return wait_for_read(c.sock.handle, c.read_deadline, c.read_timeout) -} - -[inline] -pub fn (mut c UnixConn) wait_for_write() ? { - return wait_for_write(c.sock.handle, c.write_deadline, c.write_timeout) -} - -pub fn (c UnixConn) str() string { - s := c.sock.str().replace('\n', ' ').replace(' ', ' ') - return 'UnixConn{ write_deadline: $c.write_deadline, read_deadline: $c.read_deadline, read_timeout: $c.read_timeout, write_timeout: $c.write_timeout, sock: $s }' -} diff --git a/vlib/net/net_windows.c.v b/vlib/net/net_windows.c.v index 64cca39866..ac48f6be7c 100644 --- a/vlib/net/net_windows.c.v +++ b/vlib/net/net_windows.c.v @@ -1,7 +1,8 @@ module net // needed for unix domain sockets support -#include +// is not included in CI rn +// #include // WsaError is all of the socket errors that WSA provides from WSAGetLastError pub enum WsaError { @@ -13,7 +14,6 @@ pub enum WsaError { // A blocking operation was interrupted by a call to WSACancelBlockingCall. // wsaeintr = 10004 - // // MessageId: WSAEBADF // @@ -22,7 +22,6 @@ pub enum WsaError { // The file handle supplied is not valid. // wsaebadf = 10009 - // // MessageId: WSAEACCES // @@ -31,7 +30,6 @@ pub enum WsaError { // An attempt was made to access a socket in a way forbidden by its access permissions. // wsaeacces = 10013 - // // MessageId: WSAEFAULT // @@ -40,7 +38,6 @@ pub enum WsaError { // The system detected an invalid pointer address in attempting to use a pointer argument in a call. // wsaefault = 10014 - // // MessageId: WSAEINVAL // @@ -49,7 +46,6 @@ pub enum WsaError { // An invalid argument was supplied. // wsaeinval = 10022 - // // MessageId: WSAEMFILE // @@ -58,7 +54,6 @@ pub enum WsaError { // Too many open sockets. // wsaemfile = 10024 - // // MessageId: WSAEWOULDBLOCK // @@ -67,7 +62,6 @@ pub enum WsaError { // A non-blocking socket operation could not be completed immediately. // wsaewouldblock = 10035 - // // MessageId: WSAEINPROGRESS // @@ -76,7 +70,6 @@ pub enum WsaError { // A blocking operation is currently executing. // wsaeinprogress = 10036 - // // MessageId: WSAEALREADY // @@ -85,7 +78,6 @@ pub enum WsaError { // An operation was attempted on a non-blocking socket that already had an operation in progress. // wsaealready = 10037 - // // MessageId: WSAENOTSOCK // @@ -94,7 +86,6 @@ pub enum WsaError { // An operation was attempted on something that is not a socket. // wsaenotsock = 10038 - // // MessageId: WSAEDESTADDRREQ // @@ -103,7 +94,6 @@ pub enum WsaError { // A required address was omitted from an operation on a socket. // wsaedestaddrreq = 10039 - // // MessageId: WSAEMSGSIZE // @@ -112,7 +102,6 @@ pub enum WsaError { // A message sent on a datagram socket was larger than the internal message buffer or some other network limit, or the buffer used to receive a datagram into was smaller than the datagram itself. // wsaemsgsize = 10040 - // // MessageId: WSAEPROTOTYPE // @@ -121,7 +110,6 @@ pub enum WsaError { // A protocol was specified in the socket function call that does not support the semantics of the socket type requested. // wsaeprototype = 10041 - // // MessageId: WSAENOPROTOOPT // @@ -130,7 +118,6 @@ pub enum WsaError { // An unknown, invalid, or unsupported option or level was specified in a getsockopt or setsockopt call. // wsaenoprotoopt = 10042 - // // MessageId: WSAEPROTONOSUPPORT // @@ -139,7 +126,6 @@ pub enum WsaError { // The requested protocol has not been configured into the system, or no implementation for it exists. // wsaeprotonosupport = 10043 - // // MessageId: WSAESOCKTNOSUPPORT // @@ -148,7 +134,6 @@ pub enum WsaError { // The support for the specified socket type does not exist in this address family. // wsaesocktnosupport = 10044 - // // MessageId: WSAEOPNOTSUPP // @@ -157,7 +142,6 @@ pub enum WsaError { // The attempted operation is not supported for the type of object referenced. // wsaeopnotsupp = 10045 - // // MessageId: WSAEPFNOSUPPORT // @@ -166,7 +150,6 @@ pub enum WsaError { // The protocol family has not been configured into the system or no implementation for it exists. // wsaepfnosupport = 10046 - // // MessageId: WSAEAFNOSUPPORT // @@ -175,7 +158,6 @@ pub enum WsaError { // An address incompatible with the requested protocol was used. // wsaeafnosupport = 10047 - // // MessageId: WSAEADDRINUSE // @@ -184,7 +166,6 @@ pub enum WsaError { // Only one usage of each socket address (protocol/network address/port) is normally permitted. // wsaeaddrinuse = 10048 - // // MessageId: WSAEADDRNOTAVAIL // @@ -193,7 +174,6 @@ pub enum WsaError { // The requested address is not valid in its context. // wsaeaddrnotavail = 10049 - // // MessageId: WSAENETDOWN // @@ -202,7 +182,6 @@ pub enum WsaError { // A socket operation encountered a dead network. // wsaenetdown = 10050 - // // MessageId: WSAENETUNREACH // @@ -211,7 +190,6 @@ pub enum WsaError { // A socket operation was attempted to an unreachable network. // wsaenetunreach = 10051 - // // MessageId: WSAENETRESET // @@ -220,7 +198,6 @@ pub enum WsaError { // The connection has been broken due to keep-alive activity detecting a failure while the operation was in progress. // wsaenetreset = 10052 - // // MessageId: WSAECONNABORTED // @@ -229,7 +206,6 @@ pub enum WsaError { // An established connection was aborted by the software in your host machine. // wsaeconnaborted = 10053 - // // MessageId: WSAECONNRESET // @@ -238,7 +214,6 @@ pub enum WsaError { // An existing connection was forcibly closed by the remote host. // wsaeconnreset = 10054 - // // MessageId: WSAENOBUFS // @@ -247,7 +222,6 @@ pub enum WsaError { // An operation on a socket could not be performed because the system lacked sufficient buffer space or because a queue was full. // wsaenobufs = 10055 - // // MessageId: WSAEISCONN // @@ -256,7 +230,6 @@ pub enum WsaError { // A connect request was made on an already connected socket. // wsaeisconn = 10056 - // // MessageId: WSAENOTCONN // @@ -265,7 +238,6 @@ pub enum WsaError { // A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied. // wsaenotconn = 10057 - // // MessageId: WSAESHUTDOWN // @@ -274,7 +246,6 @@ pub enum WsaError { // A request to send or receive data was disallowed because the socket had already been shut down in that direction with a previous shutdown call. // wsaeshutdown = 10058 - // // MessageId: WSAETOOMANYREFS // @@ -283,7 +254,6 @@ pub enum WsaError { // Too many references to some kernel object. // wsaetoomanyrefs = 10059 - // // MessageId: WSAETIMEDOUT // @@ -292,7 +262,6 @@ pub enum WsaError { // A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond. // wsaetimedout = 10060 - // // MessageId: WSAECONNREFUSED // @@ -301,7 +270,6 @@ pub enum WsaError { // No connection could be made because the target machine actively refused it. // wsaeconnrefused = 10061 - // // MessageId: WSAELOOP // @@ -310,7 +278,6 @@ pub enum WsaError { // Cannot translate name. // wsaeloop = 10062 - // // MessageId: WSAENAMETOOLONG // @@ -319,7 +286,6 @@ pub enum WsaError { // Name component or name was too long. // wsaenametoolong = 10063 - // // MessageId: WSAEHOSTDOWN // @@ -328,7 +294,6 @@ pub enum WsaError { // A socket operation failed because the destination host was down. // wsaehostdown = 10064 - // // MessageId: WSAEHOSTUNREACH // @@ -337,7 +302,6 @@ pub enum WsaError { // A socket operation was attempted to an unreachable host. // wsaehostunreach = 10065 - // // MessageId: WSAENOTEMPTY // @@ -346,7 +310,6 @@ pub enum WsaError { // Cannot remove a directory that is not empty. // wsaenotempty = 10066 - // // MessageId: WSAEPROCLIM // @@ -355,7 +318,6 @@ pub enum WsaError { // A Windows Sockets implementation may have a limit on the number of applications that may use it simultaneously. // wsaeproclim = 10067 - // // MessageId: WSAEUSERS // @@ -364,7 +326,6 @@ pub enum WsaError { // Ran out of quota. // wsaeusers = 10068 - // // MessageId: WSAEDQUOT // @@ -373,7 +334,6 @@ pub enum WsaError { // Ran out of disk quota. // wsaedquot = 10069 - // // MessageId: WSAESTALE // @@ -382,7 +342,6 @@ pub enum WsaError { // File handle reference is no longer available. // wsaestale = 10070 - // // MessageId: WSAEREMOTE // @@ -391,7 +350,6 @@ pub enum WsaError { // Item is not available locally. // wsaeremote = 10071 - // // MessageId: WSASYSNOTREADY // @@ -400,7 +358,6 @@ pub enum WsaError { // WSAStartup cannot function at this time because the underlying system it uses to provide network services is currently unavailable. // wsasysnotready = 10091 - // // MessageId: WSAVERNOTSUPPORTED // @@ -409,7 +366,6 @@ pub enum WsaError { // The Windows Sockets version requested is not supported. // wsavernotsupported = 10092 - // // MessageId: WSANOTINITIALISED // @@ -418,7 +374,6 @@ pub enum WsaError { // Either the application has not called WSAStartup, or WSAStartup failed. // wsanotinitialised = 10093 - // // MessageId: WSAEDISCON // @@ -427,7 +382,6 @@ pub enum WsaError { // Returned by WSARecv or WSARecvFrom to indicate the remote party has initiated a graceful shutdown sequence. // wsaediscon = 10101 - // // MessageId: WSAENOMORE // @@ -436,7 +390,6 @@ pub enum WsaError { // No more results can be returned by WSALookupServiceNext. // wsaenomore = 10102 - // // MessageId: WSAECANCELLED // @@ -445,7 +398,6 @@ pub enum WsaError { // A call to WSALookupServiceEnd was made while this call was still processing. The call has been canceled. // wsaecancelled = 10103 - // // MessageId: WSAEINVALIDPROCTABLE // @@ -454,7 +406,6 @@ pub enum WsaError { // The procedure call table is invalid. // wsaeinvalidproctable = 10104 - // // MessageId: WSAEINVALIDPROVIDER // @@ -463,7 +414,6 @@ pub enum WsaError { // The requested service provider is invalid. // wsaeinvalidprovider = 10105 - // // MessageId: WSAEPROVIDERFAILEDINIT // @@ -472,7 +422,6 @@ pub enum WsaError { // The requested service provider could not be loaded or initialized. // wsaeproviderfailedinit = 10106 - // // MessageId: WSASYSCALLFAILURE // @@ -481,7 +430,6 @@ pub enum WsaError { // A system call has failed. // wsasyscallfailure = 10107 - // // MessageId: WSASERVICE_NOT_FOUND // @@ -490,7 +438,6 @@ pub enum WsaError { // No such service is known. The service cannot be found in the specified name space. // wsaservice_not_found = 10108 - // // MessageId: WSATYPE_NOT_FOUND // @@ -499,7 +446,6 @@ pub enum WsaError { // The specified class was not found. // wsatype_not_found = 10109 - // // MessageId: WSA_E_NO_MORE // @@ -508,7 +454,6 @@ pub enum WsaError { // No more results can be returned by WSALookupServiceNext. // wsa_e_no_more = 10110 - // // MessageId: WSA_E_CANCELLED // @@ -517,7 +462,6 @@ pub enum WsaError { // A call to WSALookupServiceEnd was made while this call was still processing. The call has been canceled. // wsa_e_cancelled = 10111 - // // MessageId: WSAEREFUSED // @@ -526,7 +470,6 @@ pub enum WsaError { // A database query failed because it was actively refused. // wsaerefused = 10112 - // // MessageId: WSAHOST_NOT_FOUND // @@ -535,7 +478,6 @@ pub enum WsaError { // No such host is known. // wsahost_not_found = 11001 - // // MessageId: WSATRY_AGAIN // @@ -544,7 +486,6 @@ pub enum WsaError { // This is usually a temporary error during hostname resolution and means that the local server did not receive a response from an authoritative server. // wsatry_again = 11002 - // // MessageId: WSANO_RECOVERY // @@ -553,7 +494,6 @@ pub enum WsaError { // A non-recoverable error occurred during a database lookup. // wsano_recovery = 11003 - // // MessageId: WSANO_DATA // @@ -562,7 +502,6 @@ pub enum WsaError { // The requested name is valid, but no data of the requested type was found. // wsano_data = 11004 - // // MessageId: WSA_QOS_RECEIVERS // @@ -571,7 +510,6 @@ pub enum WsaError { // At least one reserve has arrived. // wsa_qos_receivers = 11005 - // // MessageId: WSA_QOS_SENDERS // @@ -580,7 +518,6 @@ pub enum WsaError { // At least one path has arrived. // wsa_qos_senders = 11006 - // // MessageId: WSA_QOS_NO_SENDERS // @@ -589,7 +526,6 @@ pub enum WsaError { // There are no senders. // wsa_qos_no_senders = 11007 - // // MessageId: WSA_QOS_NO_RECEIVERS // @@ -598,7 +534,6 @@ pub enum WsaError { // There are no receivers. // wsa_qos_no_receivers = 11008 - // // MessageId: WSA_QOS_REQUEST_CONFIRMED // @@ -607,7 +542,6 @@ pub enum WsaError { // Reserve has been confirmed. // wsa_qos_request_confirmed = 11009 - // // MessageId: WSA_QOS_ADMISSION_FAILURE // @@ -616,7 +550,6 @@ pub enum WsaError { // Error due to lack of resources. // wsa_qos_admission_failure = 11010 - // // MessageId: WSA_QOS_POLICY_FAILURE // @@ -625,7 +558,6 @@ pub enum WsaError { // Rejected for administrative reasons - bad credentials. // wsa_qos_policy_failure = 11011 - // // MessageId: WSA_QOS_BAD_STYLE // @@ -634,7 +566,6 @@ pub enum WsaError { // Unknown or conflicting style. // wsa_qos_bad_style = 11012 - // // MessageId: WSA_QOS_BAD_OBJECT // @@ -643,7 +574,6 @@ pub enum WsaError { // Problem with some part of the filterspec or providerspecific buffer in general. // wsa_qos_bad_object = 11013 - // // MessageId: WSA_QOS_TRAFFIC_CTRL_ERROR // @@ -652,7 +582,6 @@ pub enum WsaError { // Problem with some part of the flowspec. // wsa_qos_traffic_ctrl_error = 11014 - // // MessageId: WSA_QOS_GENERIC_ERROR // @@ -661,7 +590,6 @@ pub enum WsaError { // General QOS error. // wsa_qos_generic_error = 11015 - // // MessageId: WSA_QOS_ESERVICETYPE // @@ -670,7 +598,6 @@ pub enum WsaError { // An invalid or unrecognized service type was found in the flowspec. // wsa_qos_eservicetype = 11016 - // // MessageId: WSA_QOS_EFLOWSPEC // @@ -679,7 +606,6 @@ pub enum WsaError { // An invalid or inconsistent flowspec was found in the QOS structure. // wsa_qos_eflowspec = 11017 - // // MessageId: WSA_QOS_EPROVSPECBUF // @@ -688,7 +614,6 @@ pub enum WsaError { // Invalid QOS provider-specific buffer. // wsa_qos_eprovspecbuf = 11018 - // // MessageId: WSA_QOS_EFILTERSTYLE // @@ -697,7 +622,6 @@ pub enum WsaError { // An invalid QOS filter style was used. // wsa_qos_efilterstyle = 11019 - // // MessageId: WSA_QOS_EFILTERTYPE // @@ -706,7 +630,6 @@ pub enum WsaError { // An invalid QOS filter type was used. // wsa_qos_efiltertype = 11020 - // // MessageId: WSA_QOS_EFILTERCOUNT // @@ -715,7 +638,6 @@ pub enum WsaError { // An incorrect number of QOS FILTERSPECs were specified in the FLOWDESCRIPTOR. // wsa_qos_efiltercount = 11021 - // // MessageId: WSA_QOS_EOBJLENGTH // @@ -724,7 +646,6 @@ pub enum WsaError { // An object with an invalid ObjectLength field was specified in the QOS provider-specific buffer. // wsa_qos_eobjlength = 11022 - // // MessageId: WSA_QOS_EFLOWCOUNT // @@ -733,7 +654,6 @@ pub enum WsaError { // An incorrect number of flow descriptors was specified in the QOS structure. // wsa_qos_eflowcount = 11023 - // // MessageId: WSA_QOS_EUNKOWNPSOBJ // @@ -742,7 +662,6 @@ pub enum WsaError { // An unrecognized object was found in the QOS provider-specific buffer. // wsa_qos_eunkownpsobj = 11024 - // // MessageId: WSA_QOS_EPOLICYOBJ // @@ -751,7 +670,6 @@ pub enum WsaError { // An invalid policy object was found in the QOS provider-specific buffer. // wsa_qos_epolicyobj = 11025 - // // MessageId: WSA_QOS_EFLOWDESC // @@ -760,7 +678,6 @@ pub enum WsaError { // An invalid QOS flow descriptor was found in the flow descriptor list. // wsa_qos_eflowdesc = 11026 - // // MessageId: WSA_QOS_EPSFLOWSPEC // @@ -769,7 +686,6 @@ pub enum WsaError { // An invalid or inconsistent flowspec was found in the QOS provider specific buffer. // wsa_qos_epsflowspec = 11027 - // // MessageId: WSA_QOS_EPSFILTERSPEC // @@ -778,7 +694,6 @@ pub enum WsaError { // An invalid FILTERSPEC was found in the QOS provider-specific buffer. // wsa_qos_epsfilterspec = 11028 - // // MessageId: WSA_QOS_ESDMODEOBJ // @@ -787,7 +702,6 @@ pub enum WsaError { // An invalid shape discard mode object was found in the QOS provider specific buffer. // wsa_qos_esdmodeobj = 11029 - // // MessageId: WSA_QOS_ESHAPERATEOBJ // @@ -796,7 +710,6 @@ pub enum WsaError { // An invalid shaping rate object was found in the QOS provider-specific buffer. // wsa_qos_eshaperateobj = 11030 - // // MessageId: WSA_QOS_RESERVED_PETYPE // @@ -805,7 +718,6 @@ pub enum WsaError { // A reserved policy element was found in the QOS provider-specific buffer. // wsa_qos_reserved_petype = 11031 - // // MessageId: WSA_SECURE_HOST_NOT_FOUND // @@ -814,7 +726,6 @@ pub enum WsaError { // No such host is known securely. // wsa_secure_host_not_found = 11032 - // // MessageId: WSA_IPSEC_NAME_POLICY_ERROR // @@ -841,9 +752,9 @@ const ( // Constants that windows needs const ( - fionbio = C.FIONBIO + fionbio = C.FIONBIO msg_nosignal = 0 - wsa_v22 = 0x202 // C.MAKEWORD(2, 2) + wsa_v22 = 0x202 // C.MAKEWORD(2, 2) ) // Error code returns the last socket error @@ -853,18 +764,18 @@ fn error_code() int { struct C.WSAData { mut: - wVersion u16 - wHighVersion u16 - szDescription [257]byte + wVersion u16 + wHighVersion u16 + szDescription [257]byte szSystemStatus [129]byte - iMaxSockets u16 - iMaxUdpDg u16 - lpVendorInfo byteptr + iMaxSockets u16 + iMaxUdpDg u16 + lpVendorInfo byteptr } fn init() { mut wsadata := C.WSAData{} - res := C.WSAStartup(wsa_v22, &wsadata) + res := C.WSAStartup(net.wsa_v22, &wsadata) if res != 0 { panic('socket: WSAStartup failed') } diff --git a/vlib/net/unix/aasocket.c.v b/vlib/net/unix/aasocket.c.v new file mode 100644 index 0000000000..813ab8d5df --- /dev/null +++ b/vlib/net/unix/aasocket.c.v @@ -0,0 +1,97 @@ +module unix + +// Select represents a select operation +enum Select { + read + write + except +} + +// SocketType are the available sockets +enum SocketType { + dgram = C.SOCK_DGRAM + stream = C.SOCK_STREAM + seqpacket = C.SOCK_SEQPACKET +} + +struct C.sockaddr { + sa_family u16 +} + +struct C.sockaddr_un { +mut: + sun_family int + sun_path charptr +} + +struct C.addrinfo { +mut: + ai_family int + ai_socktype int + ai_flags int + ai_protocol int + ai_addrlen int + ai_addr voidptr + ai_canonname voidptr + ai_next voidptr +} + +struct C.sockaddr_storage { +} + +fn C.socket() int + +fn C.setsockopt() int + +fn C.htonl() int + +fn C.htons() int + +fn C.bind() int + +fn C.listen() int + +fn C.accept() int + +fn C.getaddrinfo() int + +fn C.connect() int + +fn C.send() int + +fn C.sendto() int + +fn C.recv() int + +fn C.recvfrom() int + +fn C.shutdown() int + +fn C.ntohs() int + +fn C.getpeername() int + +fn C.inet_ntop(af int, src voidptr, dst charptr, dst_size int) charptr + +fn C.WSAAddressToStringA() int + +fn C.getsockname() int + +// defined in builtin +// fn C.read() int +// fn C.close() int + +fn C.ioctlsocket() int + +fn C.fcntl() int + +fn C.@select() int + +fn C.FD_ZERO() + +fn C.FD_SET() + +fn C.FD_ISSET() bool + +[typedef] +struct C.fd_set {} diff --git a/vlib/net/unix/common.v b/vlib/net/unix/common.v new file mode 100644 index 0000000000..f9c5904697 --- /dev/null +++ b/vlib/net/unix/common.v @@ -0,0 +1,127 @@ +module unix + +import time +import net + +fn C.SUN_LEN(C.sockaddr_un) int + +fn C.strncpy(charptr, charptr, int) + +// Shutdown shutsdown a socket and closes it +fn shutdown(handle int) ? { + $if windows { + C.shutdown(handle, C.SD_BOTH) + net.socket_error(C.closesocket(handle)) ? + } $else { + C.shutdown(handle, C.SHUT_RDWR) + net.socket_error(C.close(handle)) ? + } + + return none +} + +// Select waits for an io operation (specified by parameter `test`) to be available +fn @select(handle int, test Select, timeout time.Duration) ?bool { + set := C.fd_set{} + + C.FD_ZERO(&set) + C.FD_SET(handle, &set) + + seconds := timeout.milliseconds() / 1000 + microseconds := timeout - (seconds * time.second) + + mut tt := C.timeval{ + tv_sec: u64(seconds) + tv_usec: u64(microseconds) + } + + mut timeval_timeout := &tt + + // infinite timeout is signaled by passing null as the timeout to + // select + if timeout == unix.infinite_timeout { + timeval_timeout = &C.timeval(0) + } + + match test { + .read { + net.socket_error(C.@select(handle + 1, &set, C.NULL, C.NULL, timeval_timeout)) ? + } + .write { + net.socket_error(C.@select(handle + 1, C.NULL, &set, C.NULL, timeval_timeout)) ? + } + .except { + net.socket_error(C.@select(handle + 1, C.NULL, C.NULL, &set, timeval_timeout)) ? + } + } + + return C.FD_ISSET(handle, &set) +} + +// wait_for_common wraps the common wait code +fn wait_for_common(handle int, deadline time.Time, timeout time.Duration, test Select) ? { + if deadline.unix == 0 { + // only accept infinite_timeout as a valid + // negative timeout - it is handled in @select however + if timeout < 0 && timeout != unix.infinite_timeout { + return net.err_timed_out + } + ready := @select(handle, test, timeout) ? + if ready { + return none + } + return net.err_timed_out + } + // Convert the deadline into a timeout + // and use that + d_timeout := deadline.unix - time.now().unix + if d_timeout < 0 { + // deadline is in the past so this has already + // timed out + return net.err_timed_out + } + + ready := @select(handle, test, d_timeout) ? + if ready { + return none + } + return net.err_timed_out +} + +// wait_for_write waits for a write io operation to be available +fn wait_for_write(handle int, deadline time.Time, timeout time.Duration) ? { + return wait_for_common(handle, deadline, timeout, .write) +} + +// wait_for_read waits for a read io operation to be available +fn wait_for_read(handle int, deadline time.Time, timeout time.Duration) ? { + return wait_for_common(handle, deadline, timeout, .read) +} + +// no_deadline should be given to functions when no deadline is wanted (i.e. all functions +// return instantly) +const ( + no_deadline = time.Time{ + unix: 0 + } +) + +// no_timeout should be given to functions when no timeout is wanted (i.e. all functions +// return instantly) +const ( + no_timeout = time.Duration(0) +) + +// infinite_timeout should be given to functions when an infinite_timeout is wanted (i.e. functions +// only ever return with data) +const ( + infinite_timeout = time.Duration(-1) +) + +[inline] +fn wrap_read_result(result int) ?int { + if result != 0 { + return result + } + return none +} diff --git a/vlib/net/unix/stream_nix.v b/vlib/net/unix/stream_nix.v new file mode 100644 index 0000000000..7c67c92bb7 --- /dev/null +++ b/vlib/net/unix/stream_nix.v @@ -0,0 +1,288 @@ +module unix + +import time +import os +import net + +const ( + unix_default_read_timeout = 30 * time.second + unix_default_write_timeout = 30 * time.second + connect_timeout = 5 * time.second + msg_nosignal = 0x4000 +) + +struct StreamSocket { +pub: + handle int +mut: + path string +} + +struct StreamConn { +pub mut: + sock StreamSocket +mut: + write_deadline time.Time + read_deadline time.Time + read_timeout time.Duration + write_timeout time.Duration +} + +struct StreamListener { +pub mut: + sock StreamSocket +mut: + accept_timeout time.Duration + accept_deadline time.Time +} + +fn error_code() int { + return C.errno +} + +fn new_stream_socket() ?StreamSocket { + sockfd := net.socket_error(C.socket(C.AF_UNIX, SocketType.stream, 0)) ? + mut s := StreamSocket{ + handle: sockfd + } + return s +} + +fn (mut s StreamSocket) close() ? { + os.rm(s.path) ? + return shutdown(s.handle) +} + +fn (mut s StreamSocket) @select(test Select, timeout time.Duration) ?bool { + return @select(s.handle, test, timeout) +} + +fn (mut s StreamSocket) connect(a string) ? { + if a.len >= 108 { + return error('Socket path too long! Max length: 107 chars.') + } + mut addr := C.sockaddr_un{} + unsafe { C.memset(&addr, 0, sizeof(C.sockaddr_un)) } + addr.sun_family = C.AF_UNIX + C.strncpy(addr.sun_path, a.str, 108) + size := C.SUN_LEN(&addr) + sockaddr := unsafe { &C.sockaddr(&addr) } + res := C.connect(s.handle, sockaddr, size) + // if res != 1 { + // return none + //} + if res == 0 { + return none + } + _ := error_code() + write_result := s.@select(.write, unix.connect_timeout) ? + if write_result { + // succeeded + return none + } + except_result := s.@select(.except, unix.connect_timeout) ? + if except_result { + return net.err_connect_failed + } + // otherwise we timed out + return net.err_connect_timed_out +} + +pub fn listen_stream(sock string) ?&StreamListener { + if sock.len >= 108 { + return error('Socket path too long! Max length: 107 chars.') + } + mut s := new_stream_socket() ? + s.path = sock + mut addr := C.sockaddr_un{} + unsafe { C.memset(&addr, 0, sizeof(C.sockaddr_un)) } + addr.sun_family = C.AF_UNIX + C.strncpy(addr.sun_path, sock.str, 108) + size := C.SUN_LEN(&addr) + sockaddr := unsafe { &C.sockaddr(&addr) } + net.socket_error(C.bind(s.handle, sockaddr, size)) ? + net.socket_error(C.listen(s.handle, 128)) ? + return &StreamListener{ + sock: s + } +} + +pub fn connect_stream(path string) ?&StreamConn { + mut s := new_stream_socket() ? + s.connect(path) ? + return &StreamConn{ + sock: s + read_timeout: unix.unix_default_read_timeout + write_timeout: unix.unix_default_write_timeout + } +} + +pub fn (mut l StreamListener) accept() ?&StreamConn { + mut new_handle := C.accept(l.sock.handle, 0, 0) + if new_handle <= 0 { + l.wait_for_accept() ? + new_handle = C.accept(l.sock.handle, 0, 0) + if new_handle == -1 || new_handle == 0 { + return none + } + } + new_sock := StreamSocket{ + handle: new_handle + } + return &StreamConn{ + sock: new_sock + read_timeout: unix.unix_default_read_timeout + write_timeout: unix.unix_default_write_timeout + } +} + +pub fn (c &StreamListener) accept_deadline() ?time.Time { + if c.accept_deadline.unix != 0 { + return c.accept_deadline + } + return none +} + +pub fn (mut c StreamListener) set_accept_deadline(deadline time.Time) { + c.accept_deadline = deadline +} + +pub fn (c &StreamListener) accept_timeout() time.Duration { + return c.accept_timeout +} + +pub fn (mut c StreamListener) set_accept_timeout(t time.Duration) { + c.accept_timeout = t +} + +pub fn (mut c StreamListener) wait_for_accept() ? { + return wait_for_read(c.sock.handle, c.accept_deadline, c.accept_timeout) +} + +pub fn (mut c StreamListener) close() ? { + c.sock.close() ? + return none +} + +pub fn (mut c StreamConn) close() ? { + c.sock.close() ? + return none +} + +// write_ptr blocks and attempts to write all data +pub fn (mut c StreamConn) write_ptr(b byteptr, len int) ? { + $if trace_unix ? { + eprintln( + '>>> StreamConn.write_ptr | c.sock.handle: $c.sock.handle | b: ${ptr_str(b)} len: $len |\n' + + unsafe { b.vstring_with_len(len) }) + } + unsafe { + mut ptr_base := byteptr(b) + mut total_sent := 0 + for total_sent < len { + ptr := ptr_base + total_sent + remaining := len - total_sent + mut sent := C.send(c.sock.handle, ptr, remaining, unix.msg_nosignal) + if sent < 0 { + code := error_code() + if code == int(net.error_ewouldblock) { + c.wait_for_write() ? + continue + } else { + net.wrap_error(code) ? + } + } + total_sent += sent + } + } + return none +} + +// write blocks and attempts to write all data +pub fn (mut c StreamConn) write(bytes []byte) ? { + return c.write_ptr(bytes.data, bytes.len) +} + +// write_str blocks and attempts to write all data +pub fn (mut c StreamConn) write_str(s string) ? { + return c.write_ptr(s.str, s.len) +} + +pub fn (mut c StreamConn) read_ptr(buf_ptr byteptr, len int) ?int { + mut res := wrap_read_result(C.recv(c.sock.handle, buf_ptr, len, 0)) ? + $if trace_unix ? { + eprintln('<<< StreamConn.read_ptr | c.sock.handle: $c.sock.handle | buf_ptr: ${ptr_str(buf_ptr)} len: $len | res: $res') + } + if res > 0 { + return res + } + code := error_code() + if code == int(net.error_ewouldblock) { + c.wait_for_read() ? + res = wrap_read_result(C.recv(c.sock.handle, buf_ptr, len, 0)) ? + $if trace_unix ? { + eprintln('<<< StreamConn.read_ptr | c.sock.handle: $c.sock.handle | buf_ptr: ${ptr_str(buf_ptr)} len: $len | res: $res') + } + return net.socket_error(res) + } else { + net.wrap_error(code) ? + } + return none +} + +pub fn (mut c StreamConn) read(mut buf []byte) ?int { + return c.read_ptr(buf.data, buf.len) +} + +pub fn (mut c StreamConn) read_deadline() ?time.Time { + if c.read_deadline.unix == 0 { + return c.read_deadline + } + return none +} + +pub fn (mut c StreamConn) set_read_deadline(deadline time.Time) { + c.read_deadline = deadline +} + +pub fn (mut c StreamConn) write_deadline() ?time.Time { + if c.write_deadline.unix == 0 { + return c.write_deadline + } + return none +} + +pub fn (mut c StreamConn) set_write_deadline(deadline time.Time) { + c.write_deadline = deadline +} + +pub fn (c &StreamConn) read_timeout() time.Duration { + return c.read_timeout +} + +pub fn (mut c StreamConn) set_read_timeout(t time.Duration) { + c.read_timeout = t +} + +pub fn (c &StreamConn) write_timeout() time.Duration { + return c.write_timeout +} + +pub fn (mut c StreamConn) set_write_timeout(t time.Duration) { + c.write_timeout = t +} + +[inline] +pub fn (mut c StreamConn) wait_for_read() ? { + return wait_for_read(c.sock.handle, c.read_deadline, c.read_timeout) +} + +[inline] +pub fn (mut c StreamConn) wait_for_write() ? { + return wait_for_write(c.sock.handle, c.write_deadline, c.write_timeout) +} + +pub fn (c StreamConn) str() string { + s := c.sock.str().replace('\n', ' ').replace(' ', ' ') + return 'StreamConn{ write_deadline: $c.write_deadline, read_deadline: $c.read_deadline, read_timeout: $c.read_timeout, write_timeout: $c.write_timeout, sock: $s }' +} diff --git a/vlib/net/unix_test.v b/vlib/net/unix/unix_test.v similarity index 78% rename from vlib/net/unix_test.v rename to vlib/net/unix/unix_test.v index 26d9ba64b2..6dee7e4ec8 100644 --- a/vlib/net/unix_test.v +++ b/vlib/net/unix/unix_test.v @@ -1,10 +1,10 @@ -import net +import net.unix const ( test_port = 'test' ) -fn handle_conn(mut c net.UnixConn) { +fn handle_conn(mut c unix.StreamConn) { for { mut buf := []byte{len: 100, init: 0} read := c.read(mut buf) or { @@ -18,7 +18,7 @@ fn handle_conn(mut c net.UnixConn) { } } -fn echo_server(mut l net.UnixListener) ? { +fn echo_server(mut l unix.StreamListener) ? { for { mut new_conn := l.accept() or { continue } go handle_conn(mut new_conn) @@ -27,7 +27,7 @@ fn echo_server(mut l net.UnixListener) ? { } fn echo() ? { - mut c := net.connect_unix('test') ? + mut c := unix.connect_stream('test') ? defer { c.close() or { } } @@ -44,7 +44,7 @@ fn echo() ? { } fn test_tcp() { - mut l := net.listen_unix(test_port) or { panic(err) } + mut l := unix.listen_stream(test_port) or { panic(err) } go echo_server(mut l) echo() or { panic(err) } l.close() or { }