1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

net: move unix socket code to net.unix and skip net/unix/unix_test.v … (#8681)

This commit is contained in:
bettafish04 2021-02-11 17:51:12 +01:00 committed by GitHub
parent f8db44bb15
commit 9b4f2edbfa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 561 additions and 425 deletions

View File

@ -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',
]

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,8 @@
module net
// needed for unix domain sockets support
#include <afunix.h>
// is not included in CI rn
// #include <afunix.h>
// 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
//
@ -864,7 +775,7 @@ mut:
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')
}

View File

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

127
vlib/net/unix/common.v Normal file
View File

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

288
vlib/net/unix/stream_nix.v Normal file
View File

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

View File

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