diff --git a/lib/std/net/ipproto.c3 b/lib/std/net/ipproto.c3 deleted file mode 100644 index 370274bc2..000000000 --- a/lib/std/net/ipproto.c3 +++ /dev/null @@ -1,104 +0,0 @@ -module std::net; - -const IPPPOTO_IP = 0; -const IPPROTO_ICMP = 1; -const IPPROTO_IGMP = 2; -const IPPROTO_IPV4 = 4; -const IPPROTO_TCP = 6; -const IPPROTO_ST = 7; -const IPPROTO_EGP = 8; -const IPPROTO_PIGP = 9; -const IPPROTO_RCCMON = 10; -const IPPROTO_NVPII = 11; -const IPPROTO_PUP = 12; -const IPPROTO_ARGUS = 13; -const IPPROTO_EMCON = 14; -const IPPROTO_XNET = 15; -const IPPROTO_CHAOS = 16; -const IPPROTO_UDP = 17; -const IPPROTO_MUX = 18; -const IPPROTO_MEAS = 19; -const IPPROTO_HMP = 20; -const IPPROTO_PRM = 21; -const IPPROTO_IDP = 22; -const IPPROTO_TRUNK1 = 23; -const IPPROTO_TRUNK2 = 24; -const IPPROTO_LEAF1 = 25; -const IPPROTO_LEAF2 = 26; -const IPPROTO_RDP = 27; -const IPPROTO_IRTP = 28; -const IPPROTO_TP = 29; -const IPPROTO_BLT = 30; -const IPPROTO_NSP = 31; -const IPPROTO_INP = 32; -const IPPROTO_SEP = 33; -const IPPROTO_3PC = 34; -const IPPROTO_IDPR = 35; -const IPPROTO_XTP = 36; -const IPPROTO_DDP = 37; -const IPPROTO_CMTP = 38; -const IPPROTO_TPXX = 39; -const IPPROTO_IL = 40; -const IPPROTO_IPV6 = 41; -const IPPROTO_SDRP = 42; -const IPPROTO_ROUTING = 43; -const IPPROTO_FRAGMENT = 44; -const IPPROTO_IDRP = 45; -const IPPROTO_RSVP = 46; -const IPPROTO_GRE = 47; -const IPPROTO_MHRP = 48; -const IPPROTO_BHA = 49; -const IPPROTO_ESP = 50; -const IPPROTO_AH = 51; -const IPPROTO_INLSP = 52; -const IPPROTO_SWIPE = 53; -const IPPROTO_NHRP = 54; -const IPPROTO_ICMPV6 = 58; -const IPPROTO_NONE = 59; -const IPPROTO_DSTOPTS = 60; -const IPPROTO_AHIP = 61; -const IPPROTO_CFTP = 62; -const IPPROTO_HELLO = 63; -const IPPROTO_SATEXPAK = 64; -const IPPROTO_KRYPTOLAN = 65; -const IPPROTO_RVD = 66; -const IPPROTO_IPPC = 67; -const IPPROTO_ADFS = 68; -const IPPROTO_SATMON = 69; -const IPPROTO_VISA = 70; -const IPPROTO_IPCV = 71; -const IPPROTO_CPNX = 72; -const IPPROTO_CPHB = 73; -const IPPROTO_WSN = 74; -const IPPROTO_PVP = 75; -const IPPROTO_BRSATMON = 76; -const IPPROTO_ND = 77; -const IPPROTO_WBMON = 78; -const IPPROTO_WBEXPAK = 79; -const IPPROTO_EON = 80; -const IPPROTO_VMTP = 81; -const IPPROTO_SVMTP = 82; -const IPPROTO_VINES = 83; -const IPPROTO_TTP = 84; -const IPPROTO_IGP = 85; -const IPPROTO_DGP = 86; -const IPPROTO_TCF = 87; -const IPPROTO_IGRP = 88; -const IPPROTO_OSPFIGP = 89; -const IPPROTO_SRPC = 90; -const IPPROTO_LARP = 91; -const IPPROTO_MTP = 92; -const IPPROTO_AX25 = 93; -const IPPROTO_IPEIP = 94; -const IPPROTO_MICP = 95; -const IPPROTO_SCCSP = 96; -const IPPROTO_ETHERIP = 97; -const IPPROTO_ENCAP = 98; -const IPPROTO_APES = 99; -const IPPROTO_GMTP = 100; -const IPPROTO_PIM = 103; -const IPPROTO_IPCOMP = 108; -const IPPROTO_PGM = 113; -const IPPROTO_SCTP = 132; -const IPPROTO_DIVERT = 254; -const IPPROTO_RAW = 255; diff --git a/lib/std/net/os/common.c3 b/lib/std/net/os/common.c3 index c36906c3f..c375f6ba4 100644 --- a/lib/std/net/os/common.c3 +++ b/lib/std/net/os/common.c3 @@ -63,3 +63,106 @@ module std::net::os @if(!env::LIBC || !(env::WIN32 || env::DARWIN || env::LINUX) const AIFamily PLATFORM_AF_INET6 = 0; const AIFamily PLATFORM_AF_IPX = 0; const AIFamily PLATFORM_AF_APPLETALK = 0; + +const IPPPOTO_IP = 0; +const IPPROTO_ICMP = 1; +const IPPROTO_IGMP = 2; +const IPPROTO_IPV4 = 4; +const IPPROTO_TCP = 6; +const IPPROTO_ST = 7; +const IPPROTO_EGP = 8; +const IPPROTO_PIGP = 9; +const IPPROTO_RCCMON = 10; +const IPPROTO_NVPII = 11; +const IPPROTO_PUP = 12; +const IPPROTO_ARGUS = 13; +const IPPROTO_EMCON = 14; +const IPPROTO_XNET = 15; +const IPPROTO_CHAOS = 16; +const IPPROTO_UDP = 17; +const IPPROTO_MUX = 18; +const IPPROTO_MEAS = 19; +const IPPROTO_HMP = 20; +const IPPROTO_PRM = 21; +const IPPROTO_IDP = 22; +const IPPROTO_TRUNK1 = 23; +const IPPROTO_TRUNK2 = 24; +const IPPROTO_LEAF1 = 25; +const IPPROTO_LEAF2 = 26; +const IPPROTO_RDP = 27; +const IPPROTO_IRTP = 28; +const IPPROTO_TP = 29; +const IPPROTO_BLT = 30; +const IPPROTO_NSP = 31; +const IPPROTO_INP = 32; +const IPPROTO_SEP = 33; +const IPPROTO_3PC = 34; +const IPPROTO_IDPR = 35; +const IPPROTO_XTP = 36; +const IPPROTO_DDP = 37; +const IPPROTO_CMTP = 38; +const IPPROTO_TPXX = 39; +const IPPROTO_IL = 40; +const IPPROTO_IPV6 = 41; +const IPPROTO_SDRP = 42; +const IPPROTO_ROUTING = 43; +const IPPROTO_FRAGMENT = 44; +const IPPROTO_IDRP = 45; +const IPPROTO_RSVP = 46; +const IPPROTO_GRE = 47; +const IPPROTO_MHRP = 48; +const IPPROTO_BHA = 49; +const IPPROTO_ESP = 50; +const IPPROTO_AH = 51; +const IPPROTO_INLSP = 52; +const IPPROTO_SWIPE = 53; +const IPPROTO_NHRP = 54; +const IPPROTO_ICMPV6 = 58; +const IPPROTO_NONE = 59; +const IPPROTO_DSTOPTS = 60; +const IPPROTO_AHIP = 61; +const IPPROTO_CFTP = 62; +const IPPROTO_HELLO = 63; +const IPPROTO_SATEXPAK = 64; +const IPPROTO_KRYPTOLAN = 65; +const IPPROTO_RVD = 66; +const IPPROTO_IPPC = 67; +const IPPROTO_ADFS = 68; +const IPPROTO_SATMON = 69; +const IPPROTO_VISA = 70; +const IPPROTO_IPCV = 71; +const IPPROTO_CPNX = 72; +const IPPROTO_CPHB = 73; +const IPPROTO_WSN = 74; +const IPPROTO_PVP = 75; +const IPPROTO_BRSATMON = 76; +const IPPROTO_ND = 77; +const IPPROTO_WBMON = 78; +const IPPROTO_WBEXPAK = 79; +const IPPROTO_EON = 80; +const IPPROTO_VMTP = 81; +const IPPROTO_SVMTP = 82; +const IPPROTO_VINES = 83; +const IPPROTO_TTP = 84; +const IPPROTO_IGP = 85; +const IPPROTO_DGP = 86; +const IPPROTO_TCF = 87; +const IPPROTO_IGRP = 88; +const IPPROTO_OSPFIGP = 89; +const IPPROTO_SRPC = 90; +const IPPROTO_LARP = 91; +const IPPROTO_MTP = 92; +const IPPROTO_AX25 = 93; +const IPPROTO_IPEIP = 94; +const IPPROTO_MICP = 95; +const IPPROTO_SCCSP = 96; +const IPPROTO_ETHERIP = 97; +const IPPROTO_ENCAP = 98; +const IPPROTO_APES = 99; +const IPPROTO_GMTP = 100; +const IPPROTO_PIM = 103; +const IPPROTO_IPCOMP = 108; +const IPPROTO_PGM = 113; +const IPPROTO_SCTP = 132; +const IPPROTO_DIVERT = 254; +const IPPROTO_RAW = 255; \ No newline at end of file diff --git a/lib/std/net/os/posix.c3 b/lib/std/net/os/posix.c3 index 48ac59891..a8ce09843 100644 --- a/lib/std/net/os/posix.c3 +++ b/lib/std/net/os/posix.c3 @@ -43,10 +43,20 @@ macro void! NativeSocket.close(self) } } -macro void! NativeSocket.set_non_blocking(self) +macro void! NativeSocket.set_non_blocking(self, bool non_blocking) { int flags = fcntl(self, F_GETFL, 0); - if (fcntl(self, F_SETFL, flags | O_NONBLOCK) == -1) + if (non_blocking) + { + if (flags & O_NONBLOCK) return; + flags |= O_NONBLOCK; + } + else + { + if (!(flags & O_NONBLOCK)) return; + flags &= ~(int)O_NONBLOCK; + } + if (fcntl(self, F_SETFL, flags) == -1) { if (libc::errno() == errno::EBADF) return NetError.INVALID_SOCKET?; return NetError.GENERAL_ERROR?; diff --git a/lib/std/net/os/win32.c3 b/lib/std/net/os/win32.c3 index 71bfd1934..aba83a7af 100644 --- a/lib/std/net/os/win32.c3 +++ b/lib/std/net/os/win32.c3 @@ -19,6 +19,14 @@ extern fn int bind(NativeSocket, SockAddrPtr address, Socklen_t address_len); extern fn int listen(NativeSocket, int backlog); extern fn NativeSocket accept(NativeSocket, SockAddrPtr address, Socklen_t* address_len); +fn void! NativeSocket.set_non_blocking(self, bool non_blocking) +{ + if (ioctlsocket(self, win32::FIONBIO, &&(ulong)non_blocking)) + { + return socket_error()?; + } +} + macro void! NativeSocket.close(self) { WSAError error = closesocket(self); diff --git a/lib/std/net/socket.c3 b/lib/std/net/socket.c3 index 7d333b2a3..c5c52e90b 100644 --- a/lib/std/net/socket.c3 +++ b/lib/std/net/socket.c3 @@ -2,16 +2,6 @@ module std::net @if(os::SUPPORTS_INET); import std::io; import libc; -enum Network : char (AIFamily domain, AISockType type) -{ - TCP (os::AF_INET, os::SOCK_STREAM), - TCP6 (os::AF_INET6, os::SOCK_STREAM), - UDP (os::AF_INET, os::SOCK_DGRAM), - UDP6 (os::AF_INET6, os::SOCK_DGRAM), -} - - - struct Socket { NativeSocket sock; @@ -21,64 +11,6 @@ struct Socket char[128] ai_addr_storage; } -fn Socket! _connect(AddrInfo* addrinfo, SocketOption[] options) -{ - @loop_over_ai(addrinfo; NativeSocket sockfd, AddrInfo* ai) - { - apply_sockoptions(sockfd, options)!; - int errcode = os::connect(sockfd, ai.ai_addr, ai.ai_addrlen); - // Keep the first successful connection. - if (!errcode) return network_socket(sockfd, ai); - }; - return os::socket_error()?; -} - - -fn Socket! Network.connect(&self, String host, String port, SocketOption... options) -{ - @network_loop_over_ai(self, host, port; NativeSocket sockfd, AddrInfo* ai) - { - apply_sockoptions(sockfd, options)!; - int errcode = os::connect(sockfd, ai.ai_addr, ai.ai_addrlen); - // Keep the first successful connection. - if (errcode == 0) return network_socket(sockfd, ai); - }!; - return os::socket_error()?; -} - -fn Socket! Network.listen(&self, String host, String port, int backlog, SocketOption... options) -{ - @network_loop_over_ai(self, host, port; NativeSocket sockfd, AddrInfo* ai) - { - apply_sockoptions(sockfd, options)!; - int errcode = os::bind(sockfd, ai.ai_addr, ai.ai_addrlen); - if (errcode == 0) - { - errcode = os::listen(sockfd, backlog); - // Keep the first successful connection. - if (errcode == 0) return network_socket(sockfd, ai); - } - }!; - return os::socket_error()?; -} - -fn AddrInfo*! Network.addrinfo(&self, String host, String port) @private -{ - ZString zhost = host.zstr_tcopy(); - ZString zport = port.zstr_tcopy(); - AddrInfo hints = { .ai_family = self.domain, .ai_socktype = self.type }; - AddrInfo* ai; - int errcode = os::getaddrinfo(zhost, zport, &hints, &ai); - if (errcode != 0) return NetError.ADDRINFO_FAILED?; - return ai; -} - -macro apply_sockoptions(sockfd, options) -{ - Socket sock = { .sock = sockfd }; - foreach (o : options) sock.set_option(o, true)!; -} - macro void @loop_over_ai(AddrInfo* ai; @body(NativeSocket fd, AddrInfo* ai)) { while (ai) @@ -92,22 +24,6 @@ macro void @loop_over_ai(AddrInfo* ai; @body(NativeSocket fd, AddrInfo* ai)) } } -macro @network_loop_over_ai(network, host, port; @body(fd, ai)) @private -{ - AddrInfo* ai = network.addrinfo(host, port)!; - AddrInfo* first = ai; - defer os::freeaddrinfo(first); - while (ai) - { - NativeSocket sockfd = os::socket(ai.ai_family, ai.ai_socktype, ai.ai_protocol); - if (sockfd > 0) - { - @body(sockfd, ai); - } - ai = ai.ai_next; - } -} - macro Socket network_socket(fd, ai) { Socket sock = { .sock = fd, .ai_addrlen = ai.ai_addrlen }; @@ -126,8 +42,6 @@ enum SocketOption : char (CInt value) DONTROUTE (os::SO_DONTROUTE), } - - fn Stream Socket.as_stream(&self) { return { .fns = &socketstream_interface, .data = self }; @@ -158,12 +72,6 @@ fn void! Socket.set_option(&self, SocketOption option, bool value) if (errcode != 0) return NetError.SOCKOPT_FAILED?; } -macro void! @set_option_value(NativeSocket sock, CInt option, value) -{ - var val = value; - if (os::setsockopt(sock, os::SOL_SOCKET, option, &val, $sizeof(val))) return NetError.SOCKOPT_FAILED?; -} - fn bool! Socket.get_option(&self, SocketOption option) { CInt flag; @@ -190,26 +98,3 @@ fn void! Socket.close(&self) @inline { self.sock.close()!; } - -struct Listener -{ - Socket socket; -} - -fn void! Listener.init(&self, Network network, String host, String port, int backlog = 10, SocketOption... options) -{ - *self = { .socket = network.listen(host, port, backlog, ...options)! }; -} - -fn Socket! Listener.accept(&self) -{ - Socket sock = self.socket; - sock.sock = os::accept(sock.sock, (SockAddrPtr)&sock.ai_addr_storage, &sock.ai_addrlen); - if (sock.sock < 0) return NetError.ACCEPT_FAILED?; - return sock; -} - -fn void! Listener.close(&self) @inline -{ - self.socket.close()!; -} \ No newline at end of file diff --git a/lib/std/net/socket_private.c3 b/lib/std/net/socket_private.c3 new file mode 100644 index 000000000..b811c6c63 --- /dev/null +++ b/lib/std/net/socket_private.c3 @@ -0,0 +1,68 @@ +module std::net @if(os::SUPPORTS_INET); +import libc; +macro apply_sockoptions(sockfd, options) @private +{ + Socket sock = { .sock = sockfd }; + foreach (o : options) sock.set_option(o, true)!; +} + +fn Socket! connect_from_addrinfo(AddrInfo* addrinfo, SocketOption[] options) @private +{ + + @loop_over_ai(addrinfo; NativeSocket sockfd, AddrInfo* ai) + { + apply_sockoptions(sockfd, options)!; + int errcode = os::connect(sockfd, ai.ai_addr, ai.ai_addrlen); + // Keep the first successful connection. + if (!errcode) return network_socket(sockfd, ai); + }; + return os::socket_error()?; +} + +fn bool last_error_is_delayed_connect() +{ + $switch + $case env::WIN32: + switch (win32_WSAGetLastError()) + { + case wsa::EWOULDBLOCK: + case wsa::EINPROGRESS: return true; + default: return false; + } + $default: + Errno err = libc::errno(); + return err == errno::EINPROGRESS || err == errno::EAGAIN || err == errno::EWOULDBLOCK; + $endswitch +} +fn Socket! connect_async_from_addrinfo(AddrInfo* addrinfo, SocketOption[] options) @private +{ + @loop_over_ai(addrinfo; NativeSocket sockfd, AddrInfo* ai) + { + apply_sockoptions(sockfd, options)!; + sockfd.set_non_blocking(true)!; + int errcode = os::connect(sockfd, ai.ai_addr, ai.ai_addrlen); + if (!errcode || last_error_is_delayed_connect()) + { + // Keep the first successful connection. + return network_socket(sockfd, ai); + } + }; + return os::socket_error()?; + +} + +macro @network_loop_over_ai(network, host, port; @body(fd, ai)) @private +{ + AddrInfo* ai = network.addrinfo(host, port)!; + AddrInfo* first = ai; + defer os::freeaddrinfo(first); + while (ai) + { + NativeSocket sockfd = os::socket(ai.ai_family, ai.ai_socktype, ai.ai_protocol); + if (sockfd > 0) + { + @body(sockfd, ai); + } + ai = ai.ai_next; + } +} diff --git a/lib/std/net/tcp.c3 b/lib/std/net/tcp.c3 index fdcef5b82..48e0cb518 100644 --- a/lib/std/net/tcp.c3 +++ b/lib/std/net/tcp.c3 @@ -1,4 +1,5 @@ module std::net::tcp @if(os::SUPPORTS_INET); +import std::net @public; import libc; def TcpSocket = distinct inline Socket; @@ -11,9 +12,21 @@ fn TcpSocket! connect(String host, uint port, SocketOption... options, IpProtoco return connect_to(ai, ...options); } +fn TcpSocket! connect_async(String host, uint port, SocketOption... options, IpProtocol protocol = UNSPECIFIED) +{ + AddrInfo* ai = net::addrinfo(host, port, protocol.ai_family, os::SOCK_STREAM)!; + defer os::freeaddrinfo(ai); + return connect_async_to(ai, ...options); +} + fn TcpSocket! connect_to(AddrInfo* ai, SocketOption... options) { - return (TcpSocket)net::_connect(ai, options); + return (TcpSocket)net::connect_from_addrinfo(ai, options); +} + +fn TcpSocket! connect_async_to(AddrInfo* ai, SocketOption... options) +{ + return (TcpSocket)net::connect_async_from_addrinfo(ai, options); } fn TcpServerSocket! listen(String host, uint port, uint backlog, SocketOption... options, IpProtocol protocol = UNSPECIFIED) diff --git a/lib/std/net/udp.c3 b/lib/std/net/udp.c3 index 6cd14a0fa..79407ad97 100644 --- a/lib/std/net/udp.c3 +++ b/lib/std/net/udp.c3 @@ -1,4 +1,5 @@ module std::net::udp @if(os::SUPPORTS_INET); +import std::net @public; def UdpSocket = distinct inline Socket; @@ -11,5 +12,5 @@ fn UdpSocket! connect(String host, uint port, SocketOption... options, IpProtoco fn UdpSocket! connect_to(AddrInfo* ai, SocketOption... options) { - return (UdpSocket)net::_connect(ai, options); + return (UdpSocket)net::connect_from_addrinfo(ai, options); } diff --git a/lib/std/os/win32/wsa.c3 b/lib/std/os/win32/wsa.c3 index c26ae3237..9589ad4da 100644 --- a/lib/std/os/win32/wsa.c3 +++ b/lib/std/os/win32/wsa.c3 @@ -6,6 +6,10 @@ extern fn WSAError win32_WSAGetLastError() @extern("WSAGetLastError") @builtin; extern fn void win32_WSASetLastError(WSAError error) @extern("WSASetLastError") @builtin; extern fn CInt win32_WSAStartup(Win32_WORD, void*) @extern("WSAStartup") @builtin; +const int FIONBIO = -2147195266; +const int FIONREAD = 1074030207; +const int SIOCATMARK = 1074033415; + module std::os::win32::wsa @if(env::WIN32); const WSAError NO_ERROR = 0;