package net // +build windows /* Package net implements cross-platform Berkeley Sockets, DNS resolution and associated procedures. For other protocols and their features, see subdirectories of this package. */ /* Copyright 2022 Tetralux Copyright 2022 Colin Davidson Copyright 2022 Jeroen van Rijn . Made available under Odin's BSD-3 license. List of contributors: Tetralux: Initial implementation Colin Davidson: Linux platform code, OSX platform code, Odin-native DNS resolver Jeroen van Rijn: Cross platform unification, code style, documentation */ import "core:c" import win "core:sys/windows" Create_Socket_Error :: enum c.int { None = 0, Network_Subsystem_Failure = win.WSAENETDOWN, Family_Not_Supported_For_This_Socket = win.WSAEAFNOSUPPORT, No_Socket_Descriptors_Available = win.WSAEMFILE, No_Buffer_Space_Available = win.WSAENOBUFS, Protocol_Unsupported_By_System = win.WSAEPROTONOSUPPORT, Wrong_Protocol_For_Socket = win.WSAEPROTOTYPE, Family_And_Socket_Type_Mismatch = win.WSAESOCKTNOSUPPORT, } Dial_Error :: enum c.int { None = 0, Port_Required = -1, Address_In_Use = win.WSAEADDRINUSE, In_Progress = win.WSAEALREADY, Cannot_Use_Any_Address = win.WSAEADDRNOTAVAIL, Wrong_Family_For_Socket = win.WSAEAFNOSUPPORT, Refused = win.WSAECONNREFUSED, Is_Listening_Socket = win.WSAEINVAL, Already_Connected = win.WSAEISCONN, Network_Unreachable = win.WSAENETUNREACH, // Device is offline Host_Unreachable = win.WSAEHOSTUNREACH, // Remote host cannot be reached No_Buffer_Space_Available = win.WSAENOBUFS, Not_Socket = win.WSAENOTSOCK, Timeout = win.WSAETIMEDOUT, Would_Block = win.WSAEWOULDBLOCK, // TODO: we may need special handling for this; maybe make a socket a struct with metadata? } Bind_Error :: enum c.int { None = 0, Address_In_Use = win.WSAEADDRINUSE, // Another application is currently bound to this endpoint. Given_Nonlocal_Address = win.WSAEADDRNOTAVAIL, // The address is not a local address on this machine. Broadcast_Disabled = win.WSAEACCES, // To bind a UDP socket to the broadcast address, the appropriate socket option must be set. Address_Family_Mismatch = win.WSAEFAULT, // The address family of the address does not match that of the socket. Already_Bound = win.WSAEINVAL, // The socket is already bound to an address. No_Ports_Available = win.WSAENOBUFS, // There are not enough ephemeral ports available. } Listen_Error :: enum c.int { None = 0, Address_In_Use = win.WSAEADDRINUSE, Already_Connected = win.WSAEISCONN, No_Socket_Descriptors_Available = win.WSAEMFILE, No_Buffer_Space_Available = win.WSAENOBUFS, Nonlocal_Address = win.WSAEADDRNOTAVAIL, Not_Socket = win.WSAENOTSOCK, Listening_Not_Supported_For_This_Socket = win.WSAEOPNOTSUPP, } Accept_Error :: enum c.int { None = 0, Not_Listening = win.WSAEINVAL, No_Socket_Descriptors_Available_For_Client_Socket = win.WSAEMFILE, No_Buffer_Space_Available = win.WSAENOBUFS, Not_Socket = win.WSAENOTSOCK, Not_Connection_Oriented_Socket = win.WSAEOPNOTSUPP, // TODO: we may need special handling for this; maybe make a socket a struct with metadata? Would_Block = win.WSAEWOULDBLOCK, } TCP_Recv_Error :: enum c.int { None = 0, Network_Subsystem_Failure = win.WSAENETDOWN, Not_Connected = win.WSAENOTCONN, Bad_Buffer = win.WSAEFAULT, Keepalive_Failure = win.WSAENETRESET, Not_Socket = win.WSAENOTSOCK, Shutdown = win.WSAESHUTDOWN, Would_Block = win.WSAEWOULDBLOCK, // TODO: not functionally different from Reset; merge? Aborted = win.WSAECONNABORTED, Timeout = win.WSAETIMEDOUT, // TODO(tetra): Determine when this is different from the syscall returning n=0 and maybe normalize them? Connection_Closed = win.WSAECONNRESET, // TODO: verify can actually happen Host_Unreachable = win.WSAEHOSTUNREACH, } UDP_Recv_Error :: enum c.int { None = 0, Network_Subsystem_Failure = win.WSAENETDOWN, // TODO: not functionally different from Reset; merge? // UDP packets are limited in size, and the length of the incoming message exceeded it. Aborted = win.WSAECONNABORTED, Truncated = win.WSAEMSGSIZE, Remote_Not_Listening = win.WSAECONNRESET, // The machine at the remote endpoint doesn't have the given port open to receiving UDP data. Shutdown = win.WSAESHUTDOWN, Broadcast_Disabled = win.WSAEACCES, // A broadcast address was specified, but the .Broadcast socket option isn't set. Bad_Buffer = win.WSAEFAULT, No_Buffer_Space_Available = win.WSAENOBUFS, Not_Socket = win.WSAENOTSOCK, // The socket is not valid socket handle. Would_Block = win.WSAEWOULDBLOCK, Host_Unreachable = win.WSAEHOSTUNREACH, // The remote host cannot be reached from this host at this time. Offline = win.WSAENETUNREACH, // The network cannot be reached from this host at this time. Timeout = win.WSAETIMEDOUT, // TODO: can this actually happen? The socket isn't bound; an unknown flag specified; or MSG_OOB specified with SO_OOBINLINE enabled. Incorrectly_Configured = win.WSAEINVAL, TTL_Expired = win.WSAENETRESET, // The message took more hops than was allowed (the Time To Live) to reach the remote endpoint. } // TODO: consider merging some errors to make handling them easier // TODO: verify once more what errors to actually expose TCP_Send_Error :: enum c.int { None = 0, // TODO: not functionally different from Reset; merge? Aborted = win.WSAECONNABORTED, Not_Connected = win.WSAENOTCONN, Shutdown = win.WSAESHUTDOWN, Connection_Closed = win.WSAECONNRESET, No_Buffer_Space_Available = win.WSAENOBUFS, Network_Subsystem_Failure = win.WSAENETDOWN, Host_Unreachable = win.WSAEHOSTUNREACH, // TODO: verify possible, as not mentioned in docs Offline = win.WSAENETUNREACH, Timeout = win.WSAETIMEDOUT, // A broadcast address was specified, but the .Broadcast socket option isn't set. Broadcast_Disabled = win.WSAEACCES, Bad_Buffer = win.WSAEFAULT, // Connection is broken due to keepalive activity detecting a failure during the operation. Keepalive_Failure = win.WSAENETRESET, // TODO: not functionally different from Reset; merge? Not_Socket = win.WSAENOTSOCK, // The so-called socket is not an open socket. } UDP_Send_Error :: enum c.int { None = 0, Network_Subsystem_Failure = win.WSAENETDOWN, // TODO: not functionally different from Reset; merge? Aborted = win.WSAECONNABORTED, // UDP packets are limited in size, and len(buf) exceeded it. Message_Too_Long = win.WSAEMSGSIZE, // The machine at the remote endpoint doesn't have the given port open to receiving UDP data. Remote_Not_Listening = win.WSAECONNRESET, Shutdown = win.WSAESHUTDOWN, // A broadcast address was specified, but the .Broadcast socket option isn't set. Broadcast_Disabled = win.WSAEACCES, Bad_Buffer = win.WSAEFAULT, // Connection is broken due to keepalive activity detecting a failure during the operation. // TODO: not functionally different from Reset; merge? Keepalive_Failure = win.WSAENETRESET, No_Buffer_Space_Available = win.WSAENOBUFS, Not_Socket = win.WSAENOTSOCK, // The socket is not valid socket handle. // This socket is unidirectional and cannot be used to send any data. // TODO: verify possible; decide whether to keep if not Receive_Only = win.WSAEOPNOTSUPP, Would_Block = win.WSAEWOULDBLOCK, Host_Unreachable = win.WSAEHOSTUNREACH, // The remote host cannot be reached from this host at this time. Cannot_Use_Any_Address = win.WSAEADDRNOTAVAIL, // Attempt to send to the Any address. Family_Not_Supported_For_This_Socket = win.WSAEAFNOSUPPORT, // The address is of an incorrect address family for this socket. Offline = win.WSAENETUNREACH, // The network cannot be reached from this host at this time. Timeout = win.WSAETIMEDOUT, } Shutdown_Manner :: enum c.int { Receive = win.SD_RECEIVE, Send = win.SD_SEND, Both = win.SD_BOTH, } Shutdown_Error :: enum c.int { None = 0, Aborted = win.WSAECONNABORTED, Reset = win.WSAECONNRESET, Offline = win.WSAENETDOWN, Not_Connected = win.WSAENOTCONN, Not_Socket = win.WSAENOTSOCK, Invalid_Manner = win.WSAEINVAL, } Socket_Option :: enum c.int { // bool: Whether the address that this socket is bound to can be reused by other sockets. // This allows you to bypass the cooldown period if a program dies while the socket is bound. Reuse_Address = win.SO_REUSEADDR, // bool: Whether other programs will be inhibited from binding the same endpoint as this socket. Exclusive_Addr_Use = win.SO_EXCLUSIVEADDRUSE, // bool: When true, keepalive packets will be automatically be sent for this connection. TODO: verify this understanding Keep_Alive = win.SO_KEEPALIVE, // bool: When true, client connections will immediately be sent a TCP/IP RST response, rather than being accepted. Conditional_Accept = win.SO_CONDITIONAL_ACCEPT, // bool: If true, when the socket is closed, but data is still waiting to be sent, discard that data. Dont_Linger = win.SO_DONTLINGER, // bool: When true, 'out-of-band' data sent over the socket will be read by a normal net.recv() call, the same as normal 'in-band' data. Out_Of_Bounds_Data_Inline = win.SO_OOBINLINE, // bool: When true, disables send-coalescing, therefore reducing latency. TCP_Nodelay = win.TCP_NODELAY, // win.LINGER: Customizes how long (if at all) the socket will remain open when there // is some remaining data waiting to be sent, and net.close() is called. Linger = win.SO_LINGER, // win.DWORD: The size, in bytes, of the OS-managed receive-buffer for this socket. Receive_Buffer_Size = win.SO_RCVBUF, // win.DWORD: The size, in bytes, of the OS-managed send-buffer for this socket. Send_Buffer_Size = win.SO_SNDBUF, // win.DWORD: For blocking sockets, the time in milliseconds to wait for incoming data to be received, before giving up and returning .Timeout. // For non-blocking sockets, ignored. // Use a value of zero to potentially wait forever. Receive_Timeout = win.SO_RCVTIMEO, // win.DWORD: For blocking sockets, the time in milliseconds to wait for outgoing data to be sent, before giving up and returning .Timeout. // For non-blocking sockets, ignored. // Use a value of zero to potentially wait forever. Send_Timeout = win.SO_SNDTIMEO, // bool: Allow sending to, receiving from, and binding to, a broadcast address. Broadcast = win.SO_BROADCAST, } Socket_Option_Error :: enum c.int { None = 0, Linger_Only_Supports_Whole_Seconds = 1, // The given value is too big or small to be given to the OS. Value_Out_Of_Range, Network_Subsystem_Failure = win.WSAENETDOWN, Timeout_When_Keepalive_Set = win.WSAENETRESET, Invalid_Option_For_Socket = win.WSAENOPROTOOPT, Reset_When_Keepalive_Set = win.WSAENOTCONN, Not_Socket = win.WSAENOTSOCK, } Set_Blocking_Error :: enum c.int { None = 0, Network_Subsystem_Failure = win.WSAENETDOWN, Blocking_Call_In_Progress = win.WSAEINPROGRESS, Not_Socket = win.WSAENOTSOCK, // TODO: are those errors possible? Network_Subsystem_Not_Initialized = win.WSAENOTINITIALISED, Invalid_Argument_Pointer = win.WSAEFAULT, }