From 6c60b0d2a6c085e0b450510cf7cdad3cc8a195dc Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Sat, 19 Aug 2023 22:29:10 +0200 Subject: [PATCH] Update errno listings. Update ai flags in std::net. Fix incorrect socket error results on Win32. Change behaviour Socket set_option. TcpSocket/TcpServerSocket/UdpSocket. Rename "TimeDuration" to "Duration". Allow @if on enum values. --- lib/std/core/runtime.c3 | 6 +- lib/std/libc/libc.c3 | 283 ++++++++++++++++++------------------ lib/std/net/inetaddr.c3 | 22 +++ lib/std/net/net.c3 | 3 +- lib/std/net/os/common.c3 | 48 +++--- lib/std/net/os/darwin.c3 | 125 ++++++++++------ lib/std/net/os/linux.c3 | 85 +++++++++-- lib/std/net/os/posix.c3 | 23 ++- lib/std/net/os/win32.c3 | 79 +++++++--- lib/std/net/sock.c3 | 9 -- lib/std/net/socket.c3 | 125 +++++++++------- lib/std/net/tcp.c3 | 45 ++++++ lib/std/net/udp.c3 | 15 ++ lib/std/os/win32/wsa.c3 | 123 +++++++++++++--- lib/std/time/datetime.c3 | 2 +- lib/std/time/time.c3 | 18 +-- resources/grammar/grammar.y | 6 +- src/compiler/enums.h | 1 + src/compiler/parse_global.c | 1 + src/compiler/sema_decls.c | 19 +++ src/version.h | 2 +- 21 files changed, 697 insertions(+), 343 deletions(-) delete mode 100644 lib/std/net/sock.c3 create mode 100644 lib/std/net/tcp.c3 create mode 100644 lib/std/net/udp.c3 diff --git a/lib/std/core/runtime.c3 b/lib/std/core/runtime.c3 index 4ed5b04b3..57f43475c 100644 --- a/lib/std/core/runtime.c3 +++ b/lib/std/core/runtime.c3 @@ -12,13 +12,13 @@ struct StackTrace uint line; } -struct VirtualAny +struct AnyStruct { void* ptr; - typeid type_id; + typeid type; } -struct SubArrayContainer +struct SubArrayStruct { void* ptr; usz len; diff --git a/lib/std/libc/libc.c3 b/lib/std/libc/libc.c3 index c0e405de0..3d4c6e80c 100644 --- a/lib/std/libc/libc.c3 +++ b/lib/std/libc/libc.c3 @@ -420,160 +420,154 @@ const CLOCKS_PER_SEC = 1000000; module libc::errno; -const Errno OK = 0; -const Errno EPERM = 1; // Operation not permitted -const Errno ENOENT = 2; // No such file or directory -const Errno ESRCH = 3; // No such process -const Errno EINTR = 4; // Interrupted system call -const Errno EIO = 5; // I/O error -const Errno ENXIO = 6; // No such device or address -const Errno E2BIG = 7; // Argument list too long -const Errno ENOEXEC = 8; // Exec format error -const Errno EBADF = 9; // Bad file number -const Errno ECHILD = 10; // No child processes +const Errno OK = 0; +const Errno EPERM = 1; // Operation not permitted +const Errno ENOENT = 2; // No such file or directory +const Errno ESRCH = 3; // No such process +const Errno EINTR = 4; // Interrupted system call +const Errno EIO = 5; // I/O error +const Errno ENXIO = 6; // No such device or address +const Errno E2BIG = 7; // Argument list too long +const Errno ENOEXEC = 8; // Exec format error +const Errno EBADF = 9; // Bad file number +const Errno ECHILD = 10; // No child processes -const Errno EAGAIN @if(env::DARWIN) = 35; // Try again Macos -const Errno EAGAIN @if(!env::DARWIN) = 11; // Try again +const Errno EAGAIN @if(env::DARWIN) = 35; // Try again Macos +const Errno EAGAIN @if(!env::DARWIN) = 11; // Try again -const Errno ENOMEM = 12; // Out of memory -const Errno EACCES = 13; // Permission denied -const Errno EFAULT = 14; // Bad address -const Errno ENOTBLK = 15; // Block device required, not on Win32 -const Errno EBUSY = 16; // Device or resource busy -const Errno EEXIST = 17; // File exists -const Errno EXDEV = 18; // Cross-device link -const Errno ENODEV = 19; // No such device -const Errno ENOTDIR = 20; // Not a directory -const Errno EISDIR = 21; // Is a directory -const Errno EINVAL = 22; // Invalid argument -const Errno ENFILE = 23; // File table overflow -const Errno EMFILE = 24; // Too many open files -const Errno ENOTTY = 25; // Not a typewriter -const Errno ETXTBSY = 26; // Text file busy, not on Win32 -const Errno EFBIG = 27; // File too large -const Errno ENOSPC = 28; // No space left on device -const Errno ESPIPE = 29; // Illegal seek -const Errno EROFS = 30; // Read-only file system -const Errno EMLINK = 31; // Too many links -const Errno EPIPE = 32; // Broken pipe -const Errno EDOM = 33; // Math argument out of domain of func -const Errno ERANGE = 34; // Math result not representable +const Errno ENOMEM = 12; // Out of memory +const Errno EACCES = 13; // Permission denied +const Errno EFAULT = 14; // Bad address +const Errno ENOTBLK = 15; // Block device required, not on Win32 +const Errno EBUSY = 16; // Device or resource busy +const Errno EEXIST = 17; // File exists +const Errno EXDEV = 18; // Cross-device link +const Errno ENODEV = 19; // No such device +const Errno ENOTDIR = 20; // Not a directory +const Errno EISDIR = 21; // Is a directory +const Errno EINVAL = 22; // Invalid argument +const Errno ENFILE = 23; // File table overflow +const Errno EMFILE = 24; // Too many open files +const Errno ENOTTY = 25; // Not a typewriter +const Errno ETXTBSY = 26; // Text file busy, not on Win32 +const Errno EFBIG = 27; // File too large +const Errno ENOSPC = 28; // No space left on device +const Errno ESPIPE = 29; // Illegal seek +const Errno EROFS = 30; // Read-only file system +const Errno EMLINK = 31; // Too many links +const Errno EPIPE = 32; // Broken pipe +const Errno EDOM = 33; // Math argument out of domain of func +const Errno ERANGE = 34; // Math result not representable // https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/intro.2.html module libc::errno @if(env::DARWIN); -const Errno EWOULDBLOCK = EAGAIN; // Operation would block -const Errno EDEADLK = 11; // Resource deadlock would occur -const Errno EINPROGRESS = 36; // Operation now in progress -const Errno EALREADY = 37; // Operation already in progress -const Errno ENOTSOCK = 38; // Socket operation on non-socket -const Errno EDESTADDRREQ = 39; // Destination address required -const Errno EMSGSIZE = 40; // Message too long -const Errno EPROTOTYPE = 41; // Protocol wrong type for socket -const Errno ENOPROTOOPT = 42; // Protocol not available -const Errno EPROTONOSUPPORT = 43; // Protocol not supported -const Errno ESOCKTNOSUPPORT = 44; // Socket type not supported -const Errno ENOTSUP = 45; // Not supported -const Errno EPFNOSUPPORT = 46; // Protocol family not supported -const Errno EAFNOSUPPORT = 47; // Address family not supported by protocol family -const Errno EADDRINUSE = 48; // Address already in use -const Errno EADDRNOTAVAIL = 49; // Cannot assign requested address -const Errno ENETDOWN = 50; // Network is down -const Errno ENETUNREACH = 51; // Network is unreachable -const Errno ENETRESET = 52; // Network dropped connection on reset -const Errno ECONNABORTED = 53; // Software caused connection abort -const Errno ECONNRESET = 54; // Connection reset by peer -const Errno ENOBUFS = 55; // No buffer space available -const Errno EISCONN = 56; // Socket is already connected -const Errno ENOTCONN = 57; // Socket is not connected -const Errno ESHUTDOWN = 58; // Cannot send after socket shutdown -const Errno ETIMEDOUT = 60; // Operation timed out -const Errno ECONNREFUSED = 61; // Connection refused -const Errno ELOOP = 62; // Too many levels of symbolic links -const Errno ENAMETOOLONG = 63; // File name too long -const Errno EHOSTDOWN = 64; // Host is down -const Errno EHOSTUNREACH = 65; // No route to host -const Errno ENOTEMPTY = 66; // Directory not empty -const Errno EPROCLIM = 67; // Too many processes -const Errno EUSERS = 68; // Too many users -const Errno EDQUOT = 69; // Disc quota exceeded -const Errno ESTALE = 70; // Stale NFS file handle -const Errno EBADRPC = 72; // RPC struct is bad -const Errno ERPCMISMATCH = 73; // RPC version wrong -const Errno EPROGUNAVAIL = 74; // RPC prog. not avail -const Errno EPROGMISMATCH = 75; // Program version wrong -const Errno EPROCUNAVAIL = 76; // Bad procedure for program -const Errno ENOLCK = 77; // No locks available -const Errno ENOSYS = 78; // Function not implemented -const Errno EFTYPE = 79; // Inappropriate file type or format -const Errno EAUTH = 80; // Authentication error -const Errno ENEEDAUTH = 81; // Need authenticator -const Errno EPWROFF = 82; // Device power is off -const Errno EDEVERR = 83; // Device error -const Errno EOVERFLOW = 84; // Value too large to be stored in data type -const Errno EBADEXEC = 85; // Bad executable (or shared library) -const Errno EBADARCH = 86; // Bad CPU type in executable -const Errno ESHLIBVERS = 87; // Shared library version mismatch -const Errno EBADMACHO = 88; // Malformed Mach-o file -const Errno ECANCELED = 89; // Operation canceled -const Errno EIDRM = 90; // Identifier removed -const Errno ENOMSG = 91; // No message of desired type -const Errno EILSEQ = 92; // Illegal byte sequence -const Errno ENOATTR = 93; // Attribute not found -const Errno EBADMSG = 94; // Bad message -const Errno EMULTIHOP = 95; // Reserved -const Errno ENODATA = 96; // No message available -const Errno ENOLINK = 97; // Reserved -const Errno ENOSR = 98; // No STREAM resources -const Errno ENOSTR = 99; // Not a STREAM -const Errno EPROTO = 100; // Protocol error -const Errno ETIME = 101; // STREAM ioctl() timeout -const Errno EOPNOTSUPP = 102; // Operation not supported on socket +const Errno EWOULDBLOCK = EAGAIN; // Operation would block +const Errno EDEADLK = 11; // Resource deadlock would occur +const Errno EINPROGRESS = 36; // Operation now in progress +const Errno EALREADY = 37; // Operation already in progress +const Errno ENOTSOCK = 38; // Socket operation on non-socket +const Errno EDESTADDRREQ = 39; // Destination address required +const Errno EMSGSIZE = 40; // Message too long +const Errno EPROTOTYPE = 41; // Protocol wrong type for socket +const Errno ENOPROTOOPT = 42; // Protocol not available +const Errno EPROTONOSUPPORT = 43; // Protocol not supported +const Errno ESOCKTNOSUPPORT = 44; // Socket type not supported +const Errno ENOTSUP = 45; // Not supported +const Errno EPFNOSUPPORT = 46; // Protocol family not supported +const Errno EAFNOSUPPORT = 47; // Address family not supported by protocol family +const Errno EADDRINUSE = 48; // Address already in use +const Errno EADDRNOTAVAIL = 49; // Cannot assign requested address +const Errno ENETDOWN = 50; // Network is down +const Errno ENETUNREACH = 51; // Network is unreachable +const Errno ENETRESET = 52; // Network dropped connection on reset +const Errno ECONNABORTED = 53; // Software caused connection abort +const Errno ECONNRESET = 54; // Connection reset by peer +const Errno ENOBUFS = 55; // No buffer space available +const Errno EISCONN = 56; // Socket is already connected +const Errno ENOTCONN = 57; // Socket is not connected +const Errno ESHUTDOWN = 58; // Cannot send after socket shutdown +const Errno ETIMEDOUT = 60; // Operation timed out +const Errno ECONNREFUSED = 61; // Connection refused +const Errno ELOOP = 62; // Too many levels of symbolic links +const Errno ENAMETOOLONG = 63; // File name too long +const Errno EHOSTDOWN = 64; // Host is down +const Errno EHOSTUNREACH = 65; // No route to host +const Errno ENOTEMPTY = 66; // Directory not empty +const Errno EPROCLIM = 67; // Too many processes +const Errno EUSERS = 68; // Too many users +const Errno EDQUOT = 69; // Disc quota exceeded +const Errno ESTALE = 70; // Stale NFS file handle +const Errno EBADRPC = 72; // RPC struct is bad +const Errno ERPCMISMATCH = 73; // RPC version wrong +const Errno EPROGUNAVAIL = 74; // RPC prog. not avail +const Errno EPROGMISMATCH = 75; // Program version wrong +const Errno EPROCUNAVAIL = 76; // Bad procedure for program +const Errno ENOLCK = 77; // No locks available +const Errno ENOSYS = 78; // Function not implemented +const Errno EFTYPE = 79; // Inappropriate file type or format +const Errno EAUTH = 80; // Authentication error +const Errno ENEEDAUTH = 81; // Need authenticator +const Errno EPWROFF = 82; // Device power is off +const Errno EDEVERR = 83; // Device error +const Errno EOVERFLOW = 84; // Value too large to be stored in data type +const Errno EBADEXEC = 85; // Bad executable (or shared library) +const Errno EBADARCH = 86; // Bad CPU type in executable +const Errno ESHLIBVERS = 87; // Shared library version mismatch +const Errno EBADMACHO = 88; // Malformed Mach-o file +const Errno ECANCELED = 89; // Operation canceled +const Errno EIDRM = 90; // Identifier removed +const Errno ENOMSG = 91; // No message of desired type +const Errno EILSEQ = 92; // Illegal byte sequence +const Errno ENOATTR = 93; // Attribute not found +const Errno EBADMSG = 94; // Bad message +const Errno EMULTIHOP = 95; // Reserved +const Errno ENODATA = 96; // No message available +const Errno ENOLINK = 97; // Reserved +const Errno ENOSR = 98; // No STREAM resources +const Errno ENOSTR = 99; // Not a STREAM +const Errno EPROTO = 100; // Protocol error +const Errno ETIME = 101; // STREAM ioctl() timeout +const Errno EOPNOTSUPP = 102; // Operation not supported on socket module libc::errno @if(env::WIN32); -const Errno EDEADLK = 36; // Resource deadlock would occur Win32 -const Errno ENAMETOOLONG = 38; // File name too long Win32 -const Errno ELOOP = 114; // Too many symbolic links encountered -const Errno EOVERFLOW = 132; // Value too large for defined data type -const Errno ENETDOWN = 116; // Network is down -const Errno ECONNRESET = 108; // Connection reset by peer -const Errno ENETUNREACH = 118; // Network is unreachable -const Errno ENETRESET = 117; // Network dropped connection because of reset -const Errno EOPNOTSUPP = 130; // Operation not supported on transport endpoint -const Errno ENOTEMPTY = 41; // Directory not empty -const Errno ETIMEDOUT = 138; // Connection timed out -const Errno EALREADY = 103; // Operation already in progress -const Errno EINPROGRESS = 112; // Operation now in progress Win32 -const Errno EDQUOT = -122; // Quota exceeded, not in Win32 -const Errno EWOULDBLOCK = 140; // Operation would block -// https://learn.microsoft.com/en-us/windows/win32/winsock/windows-sockets-error-codes-2 -const Errno ENOTSOCK = 10038; // Network is unreachable -//const Errno EOPNOTSUPP = 10045; // Operation not supported on transport endpoint -const Errno EADDRINUSE = 10048; // Address already in use -const Errno EISCONN = 10056; // Socket is already connected -const Errno ECONNREFUSED = 10061; // Connection refused -//const Errno ENETUNREACH = 10065; // Network is unreachable +const Errno EDEADLK = 36; // Resource deadlock would occur Win32 +const Errno ENAMETOOLONG = 38; // File name too long Win32 +const Errno ENOTEMPTY = 41; // Directory not empty +const Errno ELOOP = 114; // Too many symbolic links encountered +const Errno EOVERFLOW = 132; // Value too large for defined data type +const Errno ENETDOWN = 116; // Network is down +const Errno ECONNRESET = 108; // Connection reset by peer +const Errno ENETUNREACH = 118; // Network is unreachable +const Errno ENETRESET = 117; // Network dropped connection because of reset +const Errno EOPNOTSUPP = 130; // Operation not supported on transport endpoint +const Errno ETIMEDOUT = 138; // Connection timed out +const Errno EALREADY = 103; // Operation already in progress +const Errno EINPROGRESS = 112; // Operation now in progress Win32 +const Errno EDQUOT = -122; // Quota exceeded, not in Win32 +const Errno EWOULDBLOCK = 140; // Operation would block module libc::errno @if(!env::WIN32 && !env::DARWIN); -const Errno EDEADLK = 35; // Resource deadlock would occur Linux (others?) -const Errno ENAMETOOLONG = 36; // File name too long Linux (others?) -const Errno ENOTEMPTY = 39; // Directory not empty -const Errno ELOOP = 40; // Too many symbolic links encountered -const Errno EWOULDBLOCK = EAGAIN; // Operation would block -const Errno EOVERFLOW = 75; // Value too large for defined data type -const Errno ENOTSOCK = 88; // Socket operation on non-socket -const Errno EOPNOTSUPP = 95; // Operation not supported on transport endpoint -const Errno EADDRINUSE = 98; // Address already in use -const Errno ENETDOWN = 100; // Network is down -const Errno ENETUNREACH = 101; // Network is unreachable -const Errno ENETRESET = 102; // Network dropped connection because of reset -const Errno ECONNRESET = 104; // Connection reset by peer -const Errno EISCONN = 106; // Socket is already connected -const Errno ETIMEDOUT = 110; // Connection timed out -const Errno ECONNREFUSED = 111; // Connection refused -const Errno EALREADY = 114; // Operation already in progress -const Errno EINPROGRESS = 115; // Operation now in progress -const Errno EDQUOT = 122; // Quota exceeded +const Errno EDEADLK = 35; // Resource deadlock would occur Linux (others?) +const Errno ENAMETOOLONG = 36; // File name too long Linux (others?) +const Errno ENOTEMPTY = 39; // Directory not empty +const Errno ELOOP = 40; // Too many symbolic links encountered +const Errno EWOULDBLOCK = EAGAIN; // Operation would block +const Errno EOVERFLOW = 75; // Value too large for defined data type +const Errno ENOTSOCK = 88; // Socket operation on non-socket +const Errno EOPNOTSUPP = 95; // Operation not supported on transport endpoint +const Errno EADDRINUSE = 98; // Address already in use +const Errno EADDRNOTAVAIL = 99; // Cannot assign requested address +const Errno ENETDOWN = 100; // Network is down +const Errno ENETUNREACH = 101; // Network is unreachable +const Errno ENETRESET = 102; // Network dropped connection because of reset +const Errno ECONNRESET = 104; // Connection reset by peer +const Errno EISCONN = 106; // Socket is already connected +const Errno ETIMEDOUT = 110; // Connection timed out +const Errno ECONNREFUSED = 111; // Connection refused +const Errno EALREADY = 114; // Operation already in progress +const Errno EINPROGRESS = 115; // Operation now in progress +const Errno EDQUOT = 122; // Quota exceeded /* @@ -635,7 +629,6 @@ const Errno ESOCKTNOSUPPORT = 94; /* Socket type not supported */ const Errno EPFNOSUPPORT = 96; /* Protocol family not supported */ const Errno EAFNOSUPPORT = 97; /* Address family not supported by protocol */ const Errno EADDRINUSE = 98; /* Address already in use */ -const Errno EADDRNOTAVAIL = 99; /* Cannot assign requested address */ const Errno ECONNABORTED = 103; /* Software caused connection abort */ const Errno ENOBUFS = 105; /* No buffer space available */ const Errno EISCONN = 106; /* Transport endpoint is already connected */ diff --git a/lib/std/net/inetaddr.c3 b/lib/std/net/inetaddr.c3 index 4ce9cfc1f..76e980ead 100644 --- a/lib/std/net/inetaddr.c3 +++ b/lib/std/net/inetaddr.c3 @@ -2,6 +2,13 @@ module std::net; import std::io; import std::ascii; +enum IpProtocol : char (AIFamily ai_family) +{ + UNSPECIFIED (os::AF_UNSPEC), + IPV4 (os::AF_INET), + IPV6 (os::AF_INET6), +} + struct InetAddress { bool is_ipv6; @@ -250,3 +257,18 @@ fn bool InetAddress.is_multicast_link_local(InetAddress* addr) } return addr.ipv4.a == 224 && addr.ipv4.b == 0 && addr.ipv4.c == 0; } + +fn AddrInfo*! addrinfo(String host, uint port, AIFamily ai_family, AISockType ai_socktype) @if(os::SUPPORTS_INET) +{ + @pool() + { + ZString zhost = host.zstr_tcopy(); + DString str; + str.tinit(); + str.printf("%d", port); + AddrInfo hints = { .ai_family = ai_family, .ai_socktype = ai_socktype }; + AddrInfo* ai; + if (os::getaddrinfo(zhost, str.copy_zstr(mem::temp()), &hints, &ai)) return NetError.ADDRINFO_FAILED?; + return ai; + }; +} diff --git a/lib/std/net/net.c3 b/lib/std/net/net.c3 index f9b149433..0d35391fb 100644 --- a/lib/std/net/net.c3 +++ b/lib/std/net/net.c3 @@ -1,5 +1,4 @@ module std::net; -import std::net::os; fault NetError { @@ -16,6 +15,8 @@ fault NetError READ_FAILED, SOCKOPT_FAILED, + SOCKETS_NOT_INITIALIZED, + STILL_PROCESSING_CALLBACK, BAD_SOCKET_DESCRIPTOR, NOT_A_SOCKET, CONNECTION_REFUSED, diff --git a/lib/std/net/os/common.c3 b/lib/std/net/os/common.c3 index 58071c1b2..c36906c3f 100644 --- a/lib/std/net/os/common.c3 +++ b/lib/std/net/os/common.c3 @@ -1,6 +1,11 @@ module std::net::os; const bool SUPPORTS_INET = env::LIBC && (env::WIN32 || env::DARWIN || env::LINUX); +def AIFamily = distinct CInt; +def AIProtocol = distinct CInt; +def AISockType = distinct CInt; +def AIFlags = distinct CInt; + def Socklen_t = CUInt @if(!env::WIN32); def Socklen_t = usz @if(env::WIN32); @@ -8,10 +13,10 @@ def SockAddrPtr = distinct void*; struct AddrInfo { - CInt ai_flags; - CInt ai_family; - CInt ai_socktype; - CInt ai_protocol; + AIFlags ai_flags; + AIFamily ai_family; + AISockType ai_socktype; + AIProtocol ai_protocol; Socklen_t ai_addrlen; struct @if(env::WIN32 || env::DARWIN) { @@ -26,26 +31,35 @@ struct AddrInfo AddrInfo* ai_next; } + const PLATFORM_O_NONBLOCK @if(!$defined(PLATFORM_O_NONBLOCK)) = 0; -const int PLATFORM_AF_UNIX = 1; -const int PLATFORM_AF_INET = 2; -const int PLATFORM_AF_INET6 @if(env::WIN32) = 23; -const int PLATFORM_AF_INET6 @if(env::DARWIN) = 30; -const int PLATFORM_AF_INET6 @if(env::LINUX) = 10; +const AISockType SOCK_STREAM = 1; // Stream +const AISockType SOCK_DGRAM = 2; // Datagram +const AISockType SOCK_RAW = 3; // Raw +const AISockType SOCK_RDM = 4; // Reliably delivered +const AISockType SOCK_SEQPACKET = 5; // Sequential packet -const AI_PASSIVE = 0x1; -const AI_CANONNAME = 0x2; -const AI_NUMERICHOST = 0x4; +const AIFlags AI_PASSIVE = 0x1; +const AIFlags AI_CANONNAME = 0x2; +const AIFlags AI_NUMERICHOST = 0x4; -const int AF_UNSPEC = 0; -const int AF_INET @if(SUPPORTS_INET) = PLATFORM_AF_INET; -const int AF_APPLETALK @if(SUPPORTS_INET) = PLATFORM_AF_APPLETALK; -const int AF_IPX @if(SUPPORTS_INET) = PLATFORM_AF_IPX; -const int AF_INET6 @if(SUPPORTS_INET) = PLATFORM_AF_INET6; +const AIFamily AF_UNSPEC = 0; +const AIFamily AF_UNIX = 1; +const AIFamily AF_INET = 2; +const AIFamily AF_INET6 = PLATFORM_AF_INET6; +const AIFamily AF_IPX = PLATFORM_AF_IPX; +const AIFamily AF_APPLETALK = PLATFORM_AF_APPLETALK; const O_NONBLOCK = PLATFORM_O_NONBLOCK; extern fn CInt getaddrinfo(ZString nodename, ZString servname, AddrInfo* hints, AddrInfo** res) @if(SUPPORTS_INET); extern fn void freeaddrinfo(AddrInfo* res) @if(SUPPORTS_INET); extern fn CInt setsockopt(NativeSocket socket, CInt level, CInt optname, void* optval, Socklen_t optlen) @if(SUPPORTS_INET); +extern fn CInt getsockopt(NativeSocket socket, CInt level, CInt optname, void* optval, Socklen_t optlen) @if(SUPPORTS_INET); + +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; diff --git a/lib/std/net/os/darwin.c3 b/lib/std/net/os/darwin.c3 index 5b51bab3c..879f898a2 100644 --- a/lib/std/net/os/darwin.c3 +++ b/lib/std/net/os/darwin.c3 @@ -1,54 +1,85 @@ module std::net::os @if(env::DARWIN); import libc; -const AI_NUMERICSERV = 0x1000; -const AI_ALL = 0x100; -const AI_V4MAPPED_CFG = 0x200; -const AI_ADDRCONFIG = 0x400; -const AI_V4MAPPED = 0x800; -const AI_UNUSABLE = 0x10000000; -const AI_DEFAULT = AI_V4MAPPED_CFG | AI_ADDRCONFIG; +const AIFlags AI_NUMERICSERV = 0x1000; +const AIFlags AI_ALL = 0x100; +const AIFlags AI_V4MAPPED_CFG = 0x200; +const AIFlags AI_ADDRCONFIG = 0x400; +const AIFlags AI_V4MAPPED = 0x800; +const AIFlags AI_UNUSABLE = 0x10000000; +const AIFlags AI_DEFAULT = AI_V4MAPPED_CFG | AI_ADDRCONFIG; + +const AIFamily PLATFORM_AF_IMPLINK = 3; +const AIFamily PLATFORM_AF_PUP = 4; +const AIFamily PLATFORM_AF_CHAOS = 5; +const AIFamily PLATFORM_AF_NS = 6; +const AIFamily PLATFORM_AF_ISO = 7; +const AIFamily PLATFORM_AF_ECMA = 8; +const AIFamily PLATFORM_AF_DATAKIT = 9; +const AIFamily PLATFORM_AF_CCITT = 10; +const AIFamily PLATFORM_AF_SNA = 11; +const AIFamily PLATFORM_AF_DECNET = 12; +const AIFamily PLATFORM_AF_DLI = 13; +const AIFamily PLATFORM_AF_LAT = 14; +const AIFamily PLATFORM_AF_HYLINK = 15; +const AIFamily PLATFORM_AF_APPLETALK = 16; +const AIFamily PLATFORM_AF_ROUTE = 17; +const AIFamily PLATFORM_AF_LINK = 18; +const AIFamily PLATFORM_PSEUDO_AF_XTP = 19; +const AIFamily PLATFORM_AF_COIP = 20; +const AIFamily PLATFORM_AF_CNT = 21; +const AIFamily PLATFORM_PSEUDO_AF_RTIP = 22; +const AIFamily PLATFORM_AF_IPX = 23; +const AIFamily PLATFORM_AF_SIP = 24; +const AIFamily PLATFORM_PSEUDO_AF_PIP = 25; +const AIFamily PLATFORM_AF_NDRV = 27; +const AIFamily PLATFORM_AF_ISDN = 28; +const AIFamily PLATFORM_PSEUDO_AF_KEY = 29; +const AIFamily PLATFORM_AF_INET6 = 30; +const AIFamily PLATFORM_AF_NATM = 31; +const AIFamily PLATFORM_AF_SYSTEM = 32; +const AIFamily PLATFORM_AF_NETBIOS = 33; +const AIFamily PLATFORM_AF_PPP = 34; +const AIFamily PLATFORM_PSEUDO_AF_HDRCMPLT = 35; +const AIFamily PLATFORM_AF_IEEE80211 = 37; +const AIFamily PLATFORM_AF_UTUN = 38; +const AIFamily PLATFORM_AF_VSOCK = 40; +const AIFamily PLATFORM_AF_MAX = 41; -const int PLATFORM_AF_IMPLINK = 3; -const int PLATFORM_AF_PUP = 4; -const int PLATFORM_AF_CHAOS = 5; -const int PLATFORM_AF_NS = 6; -const int PLATFORM_AF_ISO = 7; -const int PLATFORM_AF_ECMA = 8; -const int PLATFORM_AF_DATAKIT = 9; -const int PLATFORM_AF_CCITT = 10; -const int PLATFORM_AF_SNA = 11; -const int PLATFORM_AF_DECNET = 12; -const int PLATFORM_AF_DLI = 13; -const int PLATFORM_AF_LAT = 14; -const int PLATFORM_AF_HYLINK = 15; -const int PLATFORM_AF_APPLETALK = 16; -const int PLATFORM_AF_ROUTE = 17; -const int PLATFORM_AF_LINK = 18; -const int PLATFORM_PSEUDO_AF_XTP = 19; -const int PLATFORM_AF_COIP = 20; -const int PLATFORM_AF_CNT = 21; -const int PLATFORM_PSEUDO_AF_RTIP = 22; -const int PLATFORM_AF_IPX = 23; -const int PLATFORM_AF_SIP = 24; -const int PLATFORM_PSEUDO_AF_PIP = 25; -const int PLATFORM_AF_NDRV = 27; -const int PLATFORM_AF_ISDN = 28; -const int PLATFORM_PSEUDO_AF_KEY = 29; -const int PLATFORM_AF_NATM = 31; -const int PLATFORM_AF_SYSTEM = 32; -const int PLATFORM_AF_NETBIOS = 33; -const int PLATFORM_AF_PPP = 34; -const int PLATFORM_PSEUDO_AF_HDRCMPLT = 35; -const int PLATFORM_AF_IEEE80211 = 37; -const int PLATFORM_AF_UTUN = 38; -const int PLATFORM_AF_VSOCK = 40; -const int PLATFORM_AF_MAX = 41; const int PLATFORM_O_NONBLOCK = 0x30; // https://opensource.apple.com/source/xnu/xnu-4570.41.2/bsd/sys/socket.h.auto.html -const int SOL_SOCKET = 0xffff; -const int SO_REUSEADDR = 0x0004; -const int SO_KEEPALIVE = 0x0008; -const int SO_BROADCAST = 0x0020; -const int SO_REUSEPORT = 0x0200; \ No newline at end of file +const int SOL_SOCKET = 0xffff; +const int SO_DEBUG = 0x0001; // turn on debugging info recording +const int SO_ACCEPTCONN = 0x0002; // socket has had listen() +const int SO_REUSEADDR = 0x0004; // allow local address reuse +const int SO_KEEPALIVE = 0x0008; // keep connections alive +const int SO_DONTROUTE = 0x0010; // just use interface addresses +const int SO_BROADCAST = 0x0020; // permit sending of broadcast msgs +const int SO_USELOOPBACK = 0x0040; // bypass hardware when possible +const int SO_LINGER = 0x0080; // linger on close if data present (in ticks) +const int SO_OOBINLINE = 0x0100; // leave received OOB data in line +const int SO_REUSEPORT = 0x0200; // allow local address & port reuse +const int SO_TIMESTAMP = 0x0400; // timestamp received dgram traffic +const int SO_TIMESTAMP_MONOTONIC = 0x0800; // Monotonically increasing timestamp on rcvd dgram +const int SO_DONTTRUNC = 0x2000; // Apple Retain unread data +const int SO_WANTMORE = 0x4000; // Apple: Give hint when more data ready +const int SO_WANTOOBFLAG = 0x8000; // Apple: Want OOB in MSG_FLAG on receive + +const int SO_SNDBUF = 0x1001; // Send buffer size +const int SO_RCVBUF = 0x1002; // Recieve buffer size +const int SO_SNDLOWAT = 0x1003; // Send low-water mark +const int SO_RCVLOWAT = 0x1004; // Receive low-water mark +const int SO_SNDTIMEO = 0x1005; // Send timeout +const int SO_RCVTIMEO = 0x1006; // Receive timeout +const int SO_ERROR = 0x1007; // Get error status and clear +const int SO_TYPE = 0x1008; // Socket type +const int SO_LABEL = 0x1010; // Socket MAC label +const int SO_PEERLABEL = 0x1011; // Socket peer MAC label +const int SO_NREAD = 0x1020; // Apple: get 1st-packet byte count +const int SO_NKE = 0x1021; // Apple: Install socket-level NKE +const int SO_NOSIGPIPE = 0x1022; // Apple: No SIGPIPE on EPIPE +const int SO_NOADDRERR = 0x1023; // Apple: Returns EADDRNOTAVAIL when src is not available anymore +const int SO_NWRITE = 0x1024; // Apple: Get number of bytes currently in send socket buffer +const int SO_REUSESHAREUID = 0x1025; // Apple: Allow reuse of port/socket by different userids +const int SO_LINGER_SEC = 0x1080; // linger on close if data present (in seconds) \ No newline at end of file diff --git a/lib/std/net/os/linux.c3 b/lib/std/net/os/linux.c3 index 6c1e99e4a..1c1c85dcf 100644 --- a/lib/std/net/os/linux.c3 +++ b/lib/std/net/os/linux.c3 @@ -1,19 +1,80 @@ module std::net::os @if(env::LINUX); import libc; -const int PLATFORM_AF_AX25 = 3; -const int PLATFORM_AF_IPX = 4; -const int PLATFORM_AF_APPLETALK = 5; -const int PLATFORM_AF_NETROM = 6; -const int PLATFORM_AF_BRIDGE = 7; -const int PLATFORM_AF_AAL5 = 8; -const int PLATFORM_AF_X25 = 9; +const AIFamily PLATFORM_AF_AX25 = 3; +const AIFamily PLATFORM_AF_IPX = 4; +const AIFamily PLATFORM_AF_APPLETALK = 5; +const AIFamily PLATFORM_AF_NETROM = 6; +const AIFamily PLATFORM_AF_BRIDGE = 7; +const AIFamily PLATFORM_AF_AAL5 = 8; +const AIFamily PLATFORM_AF_X25 = 9; +const AIFamily PLATFORM_AF_INET6 = 10; const PLATFORM_O_NONBLOCK = 0o4000; -// https://git.sr.ht/~sircmpwn/hare/tree/master/item/rt/+linux/socket.ha +// https://github.com/torvalds/linux/blob/master/include/uapi/asm-generic/socket.h const int SOL_SOCKET = 1; -const int SO_REUSEADDR = 2; -const int SO_BROADCAST = 6; -const int SO_KEEPALIVE = 9; -const int SO_REUSEPORT = 15; \ No newline at end of file + +const int SO_DEBUG = 1; // turn on debugging info recording +const int SO_REUSEADDR = 2; // allow local address reuse +const int SO_TYPE = 3; +const int SO_ERROR = 4; +const int SO_DONTROUTE = 5; // just use interface addresses +const int SO_BROADCAST = 6; // permit sending of broadcast msgs +const int SO_SNDBUF = 7; // Send buffer size +const int SO_RCVBUF = 8; // Recieve buffer size +const int SO_KEEPALIVE = 9; // keep connections alive +const int SO_OOBINLINE = 10; // leave received OOB data in line +const int SO_NO_CHECK = 11; +const int SO_PRIORITY = 12; +const int SO_LINGER = 13; // linger on close if data present (in ticks) +const int SO_BSDCOMPAT = 14; +const int SO_REUSEPORT = 15; // allow local address & port reuse +const int SO_RCVLOWAT = 18; +const int SO_SNDLOWAT = 19; +const int SO_RCVTIMEO = 20; // IMPORTANT Verify before use +const int SO_SNDTIMEO = 21; // IMPORTANT Verify before use +const int SO_BINDTODEVICE = 25; +const int SO_ATTACH_FILTER = 26; +const int SO_DETACH_FILTER = 27; +const int SO_PEERNAME = 28; +const int SO_TIMESTAMP = 29; // IMPORTANT Verify before use timestamp received dgram traffic +const int SO_ACCEPTCONN = 30; +const int SO_PEERSEC = 31; +const int SO_SNDBUFFORCE = 32; +const int SO_RCVBUFFORCE = 33; +const int SO_PASSSEC = 34; +const int SO_MARK = 36; +const int SO_PROTOCOL = 38; +const int SO_DOMAIN = 39; +const int SO_RXQ_OVFL = 40; +const int SO_WIFI_STATUS = 41; +const int SO_PEEK_OFF = 42; +const int SO_NOFCS = 43; +const int SO_LOCK_FILTER = 44; +const int SO_SELECT_ERR_QUEUE = 45; +const int SO_BUSY_POLL = 46; +const int SO_MAX_PACING_RATE = 47; +const int SO_BPF_EXTENSIONS = 48; +const int SO_INCOMING_CPU = 49; +const int SO_ATTACH_BPF = 50; +const int SO_ATTACH_REUSEPORT_CBPF = 51; +const int SO_ATTACH_REUSEPORT_EBPF = 52; +const int SO_CNX_ADVICE = 53; +const int SO_MEMINFO = 55; +const int SO_INCOMING_NAPI_ID = 56; +const int SO_COOKIE = 57; +const int SO_PEERGROUPS = 59; +const int SO_ZEROCOPY = 60; +const int SO_TXTIME = 61; +const int SO_BINDTOIFINDEX = 62; +const int SO_DETACH_REUSEPORT_BPF = 68; +const int SO_PREFER_BUSY_POLL = 69; +const int SO_BUSY_POLL_BUDGET = 70; +const int SO_NETNS_COOKIE = 71; +const int SO_BUF_LOCK = 72; +const int SO_RESERVE_MEM = 73; +const int SO_TXREHASH = 74; +const int SO_RCVMARK = 75; +const int SO_PASSPIDFD = 76; +const int SO_PEERPIDFD = 77; \ No newline at end of file diff --git a/lib/std/net/os/posix.c3 b/lib/std/net/os/posix.c3 index d9e87427c..48ac59891 100644 --- a/lib/std/net/os/posix.c3 +++ b/lib/std/net/os/posix.c3 @@ -6,13 +6,34 @@ const int F_SETFL = 4; def NativeSocket = distinct inline Fd; + extern fn CInt connect(NativeSocket socket, SockAddrPtr address, Socklen_t address_len); -extern fn NativeSocket socket(CInt af, CInt type, CInt protocol) @extern("socket"); +extern fn NativeSocket socket(AIFamily af, AISockType type, AIProtocol protocol) @extern("socket"); extern fn int fcntl(NativeSocket socket, int cmd, ...) @extern("fcntl"); extern fn CInt bind(NativeSocket socket, SockAddrPtr address, Socklen_t address_len) @extern("bind"); extern fn CInt listen(NativeSocket socket, CInt backlog) @extern("listen"); extern fn NativeSocket accept(NativeSocket socket, SockAddrPtr address, Socklen_t* address_len) @extern("accept"); +fn anyfault socket_error() +{ + switch (libc::errno()) + { + case errno::EACCES: return IoError.NO_PERMISSION; + case errno::EADDRINUSE: return NetError.ADDRESS_IN_USE; + case errno::EALREADY: return NetError.CONNECTION_ALREADY_IN_PROGRESS; + case errno::EBADF: return NetError.BAD_SOCKET_DESCRIPTOR; + case errno::ECONNREFUSED: return NetError.CONNECTION_REFUSED; + case errno::EISCONN: return NetError.ALREADY_CONNECTED; + case errno::ENETUNREACH: return NetError.NETWORK_UNREACHABLE; + case errno::ENOTSOCK: return NetError.NOT_A_SOCKET; + case errno::EINTR: return IoError.INTERRUPTED; + case errno::EWOULDBLOCK: return IoError.WOULD_BLOCK; + case errno::EOPNOTSUPP: return NetError.OPERATION_NOT_SUPPORTED_ON_SOCKET; + case errno::ETIMEDOUT: return NetError.CONNECTION_TIMED_OUT; + default: return IoError.GENERAL_ERROR; + } +} + macro void! NativeSocket.close(self) { if (libc::close(self)) diff --git a/lib/std/net/os/win32.c3 b/lib/std/net/os/win32.c3 index c40254d3d..71bfd1934 100644 --- a/lib/std/net/os/win32.c3 +++ b/lib/std/net/os/win32.c3 @@ -1,35 +1,74 @@ module std::net::os @if(env::WIN32); +import std::os::win32; +import libc; -const int PLATFORM_AF_IPX = 6; -const int PLATFORM_AF_APPLETALK = 16; -const int PLATFORM_AF_NETBIOS = 17; -const int PLATFORM_AF_IRDA = 26; -const int PLATFORM_AF_BTH = 32; +const AIFamily PLATFORM_AF_IPX = 6; +const AIFamily PLATFORM_AF_APPLETALK = 16; +const AIFamily PLATFORM_AF_NETBIOS = 17; +const AIFamily PLATFORM_AF_INET6 = 23; +const AIFamily PLATFORM_AF_IRDA = 26; +const AIFamily PLATFORM_AF_BTH = 32; def NativeSocket = distinct uptr; -extern fn int wsa_startup(int, void*) @extern("WSAStartup"); extern fn int ioctlsocket(NativeSocket, long cmd, ulong *argp); -extern fn int closesocket(NativeSocket); -extern fn NativeSocket socket(int af, int type, int protocol); +extern fn WSAError closesocket(NativeSocket); +extern fn NativeSocket socket(AIFamily af, AISockType type, AIProtocol protocol); extern fn int connect(NativeSocket, SockAddrPtr address, Socklen_t address_len); 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); -macro NativeSocket.close(self) +macro void! NativeSocket.close(self) { - if (int err = closesocket(self)) - { - if (err == WSAENOTSOCK) return NetError.INVALID_SOCKET?; - return NetError.GENERAL_ERROR?; - } + WSAError error = closesocket(self); + if (error) return convert_error(error)?; } -const int WSAENOTSOCK = 10038; - // https://github.com/wine-mirror/wine/blob/master/include/winsock.h -const int SOL_SOCKET = 0xffff; -const int SO_REUSEADDR = 0x0004; -const int SO_KEEPALIVE = 0x0008; -const int SO_BROADCAST = 0x0200; \ No newline at end of file +const int SOL_SOCKET = 0xffff; +const int SO_DEBUG = 0x0001; +const int SO_ACCEPTCONN = 0x0002; +const int SO_REUSEADDR = 0x0004; +const int SO_KEEPALIVE = 0x0008; +const int SO_DONTROUTE = 0x0010; +const int SO_BROADCAST = 0x0020; +const int SO_USELOOPBACK = 0x0040; +const int SO_LINGER = 0x0080; +const int SO_OOBINLINE = 0x0100; +const int SO_SNDBUF = 0x1001; +const int SO_RCVBUF = 0x1002; +const int SO_SNDLOWAT = 0x1003; +const int SO_RCVLOWAT = 0x1004; +const int SO_SNDTIMEO = 0x1005; +const int SO_RCVTIMEO = 0x1006; +const int SO_ERROR = 0x1007; +const int SO_TYPE = 0x1008; + +fn anyfault convert_error(WSAError error) +{ + switch (error) + { + case wsa::NOTINITIALISED: return NetError.SOCKETS_NOT_INITIALIZED; + case wsa::ENETDOWN: return NetError.NETWORK_UNREACHABLE; + case wsa::INVALID_HANDLE: return NetError.BAD_SOCKET_DESCRIPTOR; + case wsa::EACCESS: return IoError.NO_PERMISSION; + case wsa::EINPROGRESS: return NetError.STILL_PROCESSING_CALLBACK; + case wsa::EADDRINUSE: return NetError.ADDRESS_IN_USE; + case wsa::EALREADY: return NetError.CONNECTION_ALREADY_IN_PROGRESS; + case wsa::EBADF: return NetError.BAD_SOCKET_DESCRIPTOR; + case wsa::EINTR: return IoError.INTERRUPTED; + case wsa::EWOULDBLOCK: return IoError.WOULD_BLOCK; + case wsa::ECONNREFUSED: return NetError.CONNECTION_REFUSED; + case wsa::EISCONN: return NetError.ALREADY_CONNECTED; + case wsa::ENETUNREACH: return NetError.NETWORK_UNREACHABLE; + case wsa::ENOTSOCK: return NetError.NOT_A_SOCKET; + case wsa::EOPNOTSUPP: return NetError.OPERATION_NOT_SUPPORTED_ON_SOCKET; + case wsa::ETIMEDOUT: return NetError.CONNECTION_TIMED_OUT; + default: return IoError.GENERAL_ERROR; + } +} +fn anyfault socket_error() +{ + return convert_error(win32_WSAGetLastError()); +} diff --git a/lib/std/net/sock.c3 b/lib/std/net/sock.c3 deleted file mode 100644 index 142afa31a..000000000 --- a/lib/std/net/sock.c3 +++ /dev/null @@ -1,9 +0,0 @@ -module std::net; -import std::io; -import libc; - -const int SOCK_STREAM = 1; // Stream -const int SOCK_DGRAM = 2; // Datagram -const int SOCK_RAW = 3; // Raw -const int SOCK_RDM = 4; // Reliably delivered -const int SOCK_SEQPACKET = 5; // Sequential packet \ No newline at end of file diff --git a/lib/std/net/socket.c3 b/lib/std/net/socket.c3 index ddd3737e7..7d333b2a3 100644 --- a/lib/std/net/socket.c3 +++ b/lib/std/net/socket.c3 @@ -2,14 +2,38 @@ module std::net @if(os::SUPPORTS_INET); import std::io; import libc; -enum Network : char (int domain, int type) +enum Network : char (AIFamily domain, AISockType type) { - TCP (os::AF_INET, SOCK_STREAM), - TCP6 (os::AF_INET6, SOCK_STREAM), - UDP (os::AF_INET, SOCK_DGRAM), - UDP6 (os::AF_INET6, SOCK_DGRAM), + 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; + Socklen_t ai_addrlen; + // TODO proper way to get the size of sockaddr_storage + // https://learn.microsoft.com/en-us/previous-versions/windows/desktop/legacy/ms740504(v=vs.85) + 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) @@ -19,20 +43,7 @@ fn Socket! Network.connect(&self, String host, String port, SocketOption... opti // Keep the first successful connection. if (errcode == 0) return network_socket(sockfd, ai); }!; - switch (libc::errno()) - { - case errno::EACCES: return IoError.NO_PERMISSION?; - case errno::EADDRINUSE: return NetError.ADDRESS_IN_USE?; - case errno::EALREADY: return NetError.CONNECTION_ALREADY_IN_PROGRESS?; - case errno::EBADF: return NetError.BAD_SOCKET_DESCRIPTOR?; - case errno::ECONNREFUSED: return NetError.CONNECTION_REFUSED?; - case errno::EISCONN: return NetError.ALREADY_CONNECTED?; - case errno::ENETUNREACH: return NetError.NETWORK_UNREACHABLE?; - case errno::ENOTSOCK: return NetError.NOT_A_SOCKET?; - case errno::EOPNOTSUPP: return NetError.OPERATION_NOT_SUPPORTED_ON_SOCKET?; - case errno::ETIMEDOUT: return NetError.CONNECTION_TIMED_OUT?; - } -return NetError.CONNECT_FAILED?; + return os::socket_error()?; } fn Socket! Network.listen(&self, String host, String port, int backlog, SocketOption... options) @@ -48,14 +59,7 @@ fn Socket! Network.listen(&self, String host, String port, int backlog, SocketOp if (errcode == 0) return network_socket(sockfd, ai); } }!; - switch (libc::errno()) - { - case errno::EADDRINUSE: return NetError.ADDRESS_IN_USE?; - case errno::EBADF: return NetError.BAD_SOCKET_DESCRIPTOR?; - case errno::ENOTSOCK: return NetError.NOT_A_SOCKET?; - case errno::EOPNOTSUPP: return NetError.OPERATION_NOT_SUPPORTED_ON_SOCKET?; - } - return NetError.LISTEN_FAILED?; + return os::socket_error()?; } fn AddrInfo*! Network.addrinfo(&self, String host, String port) @private @@ -69,10 +73,23 @@ fn AddrInfo*! Network.addrinfo(&self, String host, String port) @private return ai; } -macro apply_sockoptions(sockfd, options) @private +macro apply_sockoptions(sockfd, options) { Socket sock = { .sock = sockfd }; - foreach (o : options) sock.set_option(o)!; + foreach (o : options) sock.set_option(o, true)!; +} + +macro void @loop_over_ai(AddrInfo* ai; @body(NativeSocket fd, AddrInfo* ai)) +{ + 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 @network_loop_over_ai(network, host, port; @body(fd, ai)) @private @@ -91,7 +108,7 @@ macro @network_loop_over_ai(network, host, port; @body(fd, ai)) @private } } -macro Socket network_socket(fd, ai) @private +macro Socket network_socket(fd, ai) { Socket sock = { .sock = fd, .ai_addrlen = ai.ai_addrlen }; assert(sock.ai_addr_storage.len >= ai.ai_addrlen, "storage %d < addrlen %d", sock.ai_addr_storage.len, ai.ai_addrlen); @@ -99,28 +116,17 @@ macro Socket network_socket(fd, ai) @private return sock; } -enum SocketOption : char (CInt value) @if(!env::WIN32) -{ - REUSEADDR (os::SO_REUSEADDR), - REUSEPORT (os::SO_REUSEPORT), - KEEPALIVE (os::SO_KEEPALIVE), - BROADCAST (os::SO_BROADCAST), -} -enum SocketOption : char (CInt value) @if(env::WIN32) +enum SocketOption : char (CInt value) { REUSEADDR (os::SO_REUSEADDR), + REUSEPORT (os::SO_REUSEPORT) @if(!env::WIN32), KEEPALIVE (os::SO_KEEPALIVE), BROADCAST (os::SO_BROADCAST), + OOBINLINE (os::SO_OOBINLINE), + DONTROUTE (os::SO_DONTROUTE), } -struct Socket -{ - NativeSocket sock; - Socklen_t ai_addrlen; - // TODO proper way to get the size of sockaddr_storage - // https://learn.microsoft.com/en-us/previous-versions/windows/desktop/legacy/ms740504(v=vs.85) - char[128] ai_addr_storage; -} + fn Stream Socket.as_stream(&self) { @@ -133,18 +139,37 @@ StreamInterface socketstream_interface = { .close_fn = fn(s) => ((Socket*)s.data).close(), }; -fn void! Socket.set_option(&self, SocketOption option) +fn bool! Socket.get_broadcast(&self) => self.get_option(BROADCAST); +fn bool! Socket.get_keepalive(&self) => self.get_option(KEEPALIVE); +fn bool! Socket.get_reuseaddr(&self) => self.get_option(REUSEADDR); +fn bool! Socket.get_dontroute(&self) => self.get_option(DONTROUTE); +fn bool! Socket.get_oobinline(&self) => self.get_option(OOBINLINE); + +fn void! Socket.set_broadcast(&self, bool value) => self.set_option(BROADCAST, value); +fn void! Socket.set_keepalive(&self, bool value) => self.set_option(KEEPALIVE, value); +fn void! Socket.set_reuseaddr(&self, bool value) => self.set_option(REUSEADDR, value); +fn void! Socket.set_dontroute(&self, bool value) => self.set_option(DONTROUTE, value); +fn void! Socket.set_oobinline(&self, bool value) => self.set_option(OOBINLINE, value); + +fn void! Socket.set_option(&self, SocketOption option, bool value) { - CInt flag = 1; + CInt flag = (CInt)value; int errcode = os::setsockopt(self.sock, os::SOL_SOCKET, option.value, &flag, CInt.sizeof); if (errcode != 0) return NetError.SOCKOPT_FAILED?; } -fn void! Socket.unset_option(&self, SocketOption option) +macro void! @set_option_value(NativeSocket sock, CInt option, value) { - CInt flag = 0; + 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; int errcode = os::setsockopt(self.sock, os::SOL_SOCKET, option.value, &flag, CInt.sizeof); if (errcode != 0) return NetError.SOCKOPT_FAILED?; + return (bool)flag; } fn usz! Socket.read(&self, char[] bytes) diff --git a/lib/std/net/tcp.c3 b/lib/std/net/tcp.c3 new file mode 100644 index 000000000..fdcef5b82 --- /dev/null +++ b/lib/std/net/tcp.c3 @@ -0,0 +1,45 @@ +module std::net::tcp @if(os::SUPPORTS_INET); +import libc; + +def TcpSocket = distinct inline Socket; +def TcpServerSocket = distinct inline Socket; + +fn TcpSocket! connect(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_to(ai, ...options); +} + +fn TcpSocket! connect_to(AddrInfo* ai, SocketOption... options) +{ + return (TcpSocket)net::_connect(ai, options); +} + +fn TcpServerSocket! listen(String host, uint port, uint backlog, SocketOption... options, IpProtocol protocol = UNSPECIFIED) +{ + AddrInfo* ai = net::addrinfo(host, port, protocol.ai_family, os::SOCK_STREAM)!; + defer os::freeaddrinfo(ai); + return listen_to(ai, backlog, ...options); +} + +fn TcpSocket! accept(TcpServerSocket* server_socket) +{ + TcpSocket socket; + socket.sock = os::accept(server_socket.sock, (SockAddrPtr)&socket.ai_addr_storage, &socket.ai_addrlen); + if (socket.sock < 0) return NetError.ACCEPT_FAILED?; + return socket; +} + +fn TcpServerSocket! listen_to(AddrInfo* ai, uint backlog, SocketOption... options) +{ + net::@loop_over_ai(ai; NativeSocket sockfd, AddrInfo* ai_candidate) + { + net::apply_sockoptions(sockfd, options)!; + bool err = os::bind(sockfd, ai_candidate.ai_addr, ai_candidate.ai_addrlen) || os::listen(sockfd, backlog); + if (!err) return (TcpServerSocket)net::network_socket(sockfd, ai_candidate); + }; + return os::socket_error()?; +} + + diff --git a/lib/std/net/udp.c3 b/lib/std/net/udp.c3 new file mode 100644 index 000000000..6cd14a0fa --- /dev/null +++ b/lib/std/net/udp.c3 @@ -0,0 +1,15 @@ +module std::net::udp @if(os::SUPPORTS_INET); + +def UdpSocket = distinct inline Socket; + +fn UdpSocket! connect(String host, uint port, SocketOption... options, IpProtocol protocol = UNSPECIFIED) +{ + AddrInfo* ai = net::addrinfo(host, port, protocol.ai_family, os::SOCK_DGRAM)!; + defer os::freeaddrinfo(ai); + return connect_to(ai, ...options); +} + +fn UdpSocket! connect_to(AddrInfo* ai, SocketOption... options) +{ + return (UdpSocket)net::_connect(ai, options); +} diff --git a/lib/std/os/win32/wsa.c3 b/lib/std/os/win32/wsa.c3 index 121bbe2af..c26ae3237 100644 --- a/lib/std/os/win32/wsa.c3 +++ b/lib/std/os/win32/wsa.c3 @@ -2,30 +2,105 @@ module std::os::win32 @if(env::WIN32); def WSAError = distinct int; -extern fn WSAError win32_WSAGetLastError() @extern("WSAGetLastError"); -extern fn void win32_WSASetLastError(WSAError error) @extern("WSASetLastError"); +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; module std::os::win32::wsa @if(env::WIN32); -const WSAError INVALID_HANDLE = 6; -const WSAError NOT_ENOUGHT_MEMORY = 8; -const WSAError INVALID_PARAMETER = 87; -const WSAError OPERATION_ABORTED = 995; -const WSAError IO_INCOMPLETE = 996; -const WSAError IO_PENDING = 997; -const WSAError EINTR = 10004; -const WSAError EBADF = 10009; -const WSAError ACCESS = 10013; -const WSAError EFAULT = 10014; -const WSAError EINVAL = 10022; -const WSAError EMFILE = 10024; -const WSAError EWOULDBLOCK = 10035; -const WSAError EINPROGRESS = 10036; -const WSAError EALREADY = 10037; -const WSAError ENOTSOCK = 10038; -const WSAError EDESTADDRREQ = 10039; -const WSAError EMSGSIZE = 10040; -const WSAError EPROTOTYPE = 10041; -const WSAError ENOPROTOOPT = 10042; -const WSAError EPROTONOSUPPORT = 10043; -const WSAError ESOCKTNOSUPPORT = 10044; \ No newline at end of file +const WSAError NO_ERROR = 0; +const WSAError INVALID_HANDLE = 6; +const WSAError NOT_ENOUGH_MEMORY = 8; +const WSAError INVALID_PARAMETER = 87; +const WSAError OPERATION_ABORTED = 995; +const WSAError IO_INCOMPLETE = 996; +const WSAError IO_PENDING = 997; +const WSAError EINTR = 10004; +const WSAError EBADF = 10009; +const WSAError EACCESS = 10013; +const WSAError EFAULT = 10014; +const WSAError EINVAL = 10022; +const WSAError EMFILE = 10024; +const WSAError EWOULDBLOCK = 10035; +const WSAError EINPROGRESS = 10036; +const WSAError EALREADY = 10037; +const WSAError ENOTSOCK = 10038; +const WSAError EDESTADDRREQ = 10039; +const WSAError EMSGSIZE = 10040; +const WSAError EPROTOTYPE = 10041; +const WSAError ENOPROTOOPT = 10042; +const WSAError EPROTONOSUPPORT = 10043; +const WSAError ESOCKTNOSUPPORT = 10044; +const WSAError EOPNOTSUPP = 10045; +const WSAError EPFNOSUPPORT = 10046; +const WSAError EAFNOSUPPORT = 10047; +const WSAError EADDRINUSE = 10048; +const WSAError EADDRNOTAVAIL = 10049; +const WSAError ENETDOWN = 10050; +const WSAError ENETUNREACH = 10051; +const WSAError ENETRESET = 10052; +const WSAError ECONNABORTED = 10053; +const WSAError ECONNRESET = 10054; +const WSAError ENOBUFS = 10055; +const WSAError EISCONN = 10056; +const WSAError ENOTCONN = 10057; +const WSAError ESHUTDOWN = 10058; +const WSAError ETOOMANYREFS = 10059; +const WSAError ETIMEDOUT = 10060; +const WSAError ECONNREFUSED = 10061; +const WSAError ELOOP = 10062; +const WSAError ENAMETOOLONG = 10063; +const WSAError EHOSTDOWN = 10064; +const WSAError EHOSTUNREACH = 10065; +const WSAError ENOTEMPTY = 10066; +const WSAError EPROCLIM = 10067; +const WSAError EUSERS = 10068; +const WSAError EDQUOT = 10069; +const WSAError ESTALE = 10070; +const WSAError EREMOTE = 10071; +const WSAError SYSNOTREADY = 10091; +const WSAError VERNOTSUPPORTED = 10092; +const WSAError NOTINITIALISED = 10093; +const WSAError EDISCON = 10101; +const WSAError ENOMORE = 10102; +const WSAError ECANCELLED = 10103; +const WSAError EINVALIDPROCTABLE = 10104; +const WSAError EINVALIDPROVIDER = 10105; +const WSAError EPROVIDERFAILEDINIT = 10106; +const WSAError SYSCALLFAILURE = 10107; +const WSAError SERVICE_NOT_FOUND = 10108; +const WSAError TYPE_NOT_FOUND = 10109; +const WSAError E_NO_MORE = 10110; +const WSAError E_CANCELLED = 10111; +const WSAError REFUSED = 10112; +const WSAError HOST_NOT_FOUND = 11001; +const WSAError TRY_AGAIN = 11002; +const WSAError NO_RECOVERY = 11003; +const WSAError NO_DATA = 11004; +const WSAError QOS_RECEIVERS = 11005; +const WSAError QOS_SENDERS = 11006; +const WSAError QOS_NO_SENDERS = 11007; +const WSAError QOS_NO_RECEIVERS = 11008; +const WSAError QOS_REQUEST_CONFIRMED = 11009; +const WSAError QOS_ADMISSION_FAILURE = 11010; +const WSAError QOS_POLICY_FAILURE = 11011; +const WSAError QOS_BAD_STYLE = 11012; +const WSAError QOS_BAD_OBJECT = 11013; +const WSAError QOS_TRAFFIC_CTRL_ERROR = 11014; +const WSAError QOS_GENERIC_ERROR = 11015; +const WSAError QOS_ESERVICETYPE = 11016; +const WSAError QOS_EFLOWSPEC = 11017; +const WSAError QOS_EPROVSPECBUF = 11018; +const WSAError QOS_EFILTERSTYLE = 11019; +const WSAError QOS_EFILTERTYPE = 11020; +const WSAError QOS_EFILTERCOUNT = 11021; +const WSAError QOS_EOBJLENGTH = 11022; +const WSAError QOS_EFLOWCOUNT = 11023; +const WSAError QOS_EUNKOWNPSOBJ = 11024; +const WSAError QOS_EPOLICYOBJ = 11025; +const WSAError QOS_EFLOWDESC = 11026; +const WSAError QOS_EPSFLOWSPEC = 11027; +const WSAError QOS_EPSFILTERSPEC = 11028; +const WSAError QOS_ESDMODEOBJ = 11029; +const WSAError QOS_ESHAPERATEOBJ = 11030; +const WSAError QOS_RESERVED_PETYPE = 11031; diff --git a/lib/std/time/datetime.c3 b/lib/std/time/datetime.c3 index d56bf6af8..c4057b9fb 100644 --- a/lib/std/time/datetime.c3 +++ b/lib/std/time/datetime.c3 @@ -164,7 +164,7 @@ fn double DateTime.diff_sec(self, DateTime from) { return (double)self.time.diff_us(from.time) / (double)time::MICROSECONDS_PER_SECOND; } -fn TimeDuration DateTime.diff_us(self, DateTime from) +fn Duration DateTime.diff_us(self, DateTime from) { return self.time.diff_us(from.time); } \ No newline at end of file diff --git a/lib/std/time/time.c3 b/lib/std/time/time.c3 index 25a5a47d9..aa36001fc 100644 --- a/lib/std/time/time.c3 +++ b/lib/std/time/time.c3 @@ -1,15 +1,15 @@ module std::time; def Time = distinct long @inline; -def TimeDuration = distinct long @inline; +def Duration = distinct long @inline; def Clock = distinct ulong @inline; def NanoDuration = distinct long @inline; -const TimeDuration MICROSECONDS_PER_SECOND = 1_000_000; -const TimeDuration MICROSECONDS_PER_MINUTE = MICROSECONDS_PER_SECOND * 60; -const TimeDuration MICROSECONDS_PER_HOUR = MICROSECONDS_PER_MINUTE * 60; -const TimeDuration MICROSECONDS_PER_DAY = MICROSECONDS_PER_HOUR * 24; -const TimeDuration MICROSECONDS_PER_WEEK = MICROSECONDS_PER_DAY * 7; +const Duration MICROSECONDS_PER_SECOND = 1_000_000; +const Duration MICROSECONDS_PER_MINUTE = MICROSECONDS_PER_SECOND * 60; +const Duration MICROSECONDS_PER_HOUR = MICROSECONDS_PER_MINUTE * 60; +const Duration MICROSECONDS_PER_DAY = MICROSECONDS_PER_HOUR * 24; +const Duration MICROSECONDS_PER_WEEK = MICROSECONDS_PER_DAY * 7; struct DateTime { @@ -74,7 +74,7 @@ fn Time Time.add_hours(time, long hours) => time + (Time)(hours * (long)MICROSEC fn Time Time.add_days(time, long days) => time + (Time)(days * (long)MICROSECONDS_PER_DAY); fn Time Time.add_weeks(time, long weeks) => time + (Time)(weeks * (long)MICROSECONDS_PER_WEEK); fn double Time.to_seconds(time) => (long)time / (double)MICROSECONDS_PER_SECOND; -fn TimeDuration Time.diff_us(time, Time other) => (TimeDuration)(time - other); +fn Duration Time.diff_us(time, Time other) => (Duration)(time - other); fn double Time.diff_sec(time, Time other) => (long)time.diff_us(other) / (double)MICROSECONDS_PER_SECOND; fn double Time.diff_min(time, Time other) => (long)time.diff_us(other) / (double)MICROSECONDS_PER_MINUTE; fn double Time.diff_hour(time, Time other) => (long)time.diff_us(other) / (double)MICROSECONDS_PER_HOUR; @@ -83,8 +83,8 @@ fn double Time.diff_weeks(time, Time other) => (long)time.diff_us(other) / (doub fn double NanoDuration.to_sec(nd) => (double)nd / 1_000_000_000.0; fn long NanoDuration.to_ms(nd) => (long)nd / 1_000_000; -fn TimeDuration NanoDuration.to_duration(nd) => (TimeDuration)nd / 1_000; -fn NanoDuration TimeDuration.to_nano(td) => (NanoDuration)td * 1_000; +fn Duration NanoDuration.to_duration(nd) => (Duration)nd / 1_000; +fn NanoDuration Duration.to_nano(td) => (NanoDuration)td * 1_000; fn void! NanoDuration.to_format(&self, Formatter* formatter) @dynamic { diff --git a/resources/grammar/grammar.y b/resources/grammar/grammar.y index f085c9a36..515d7c892 100644 --- a/resources/grammar/grammar.y +++ b/resources/grammar/grammar.y @@ -465,9 +465,9 @@ enum_list ; enum_constant - : CONST_IDENT - | CONST_IDENT '(' arg_list ')' - | CONST_IDENT '(' arg_list ',' ')' + : CONST_IDENT opt_attributes + | CONST_IDENT '(' arg_list ')' opt_attributes + | CONST_IDENT '(' arg_list ',' ')' opt_attributes ; identifier_list diff --git a/src/compiler/enums.h b/src/compiler/enums.h index 5d7b24f48..10e48b85e 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -748,6 +748,7 @@ typedef enum ATTR_INITIALIZER = 1 << 15, ATTR_FINALIZER = 1 << 16, ATTR_DEFINE = 1 << 17, + ATTR_ENUM_VALUE = 1 << 18, ATTR_XXLIZER = ATTR_INITIALIZER | ATTR_FINALIZER } AttributeDomain; diff --git a/src/compiler/parse_global.c b/src/compiler/parse_global.c index ccdb6db40..78ea04054 100644 --- a/src/compiler/parse_global.c +++ b/src/compiler/parse_global.c @@ -2189,6 +2189,7 @@ static inline Decl *parse_enum_declaration(ParseContext *c) enum_const->enum_constant.args = result; CONSUME_OR_RET(TOKEN_RPAREN, poisoned_decl); } + if (!parse_attributes_for_global(c, enum_const)) return poisoned_decl; vec_add(decl->enums.values, enum_const); // Allow trailing ',' if (!try_consume(c, TOKEN_COMMA)) diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index c7ee59725..7001329c0 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -1184,7 +1184,24 @@ static inline bool sema_analyse_enum(SemaContext *context, Decl *decl, bool *era for (unsigned i = 0; i < enums; i++) { + Decl *enum_value = enum_values[i]; + + bool erase_val = false; + if (!sema_analyse_attributes(context, decl, enum_value->attributes, ATTR_ENUM, &erase_val)) return decl_poison(decl); + + if (erase_val) + { + if (enums == 1) + { + SEMA_ERROR(decl, "No enum values left in enum after @if resolution, there must be at least one."); + return decl_poison(decl); + } + vec_erase_ptr_at(enum_values, i); + enums--; + i--; + continue; + } enum_value->type = decl->type; DEBUG_LOG("* Checking enum constant %s.", enum_value->name); enum_value->enum_constant.ordinal = i; @@ -1586,6 +1603,8 @@ static const char *attribute_domain_to_string(AttributeDomain domain) return "bitstruct member"; case ATTR_FUNC: return "function"; + case ATTR_ENUM_VALUE: + return "enum value"; case ATTR_GLOBAL: return "global variable"; case ATTR_ENUM: diff --git a/src/version.h b/src/version.h index 2252f8397..4e831048b 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "0.4.614" \ No newline at end of file +#define COMPILER_VERSION "0.4.615" \ No newline at end of file