package core:net
Overview
Package net implements cross-platform Berkeley Sockets, DNS resolution and associated procedures. For other protocols and their features, see subdirectories of this package.
Features: Supports Windows, Linux and OSX. Opening and closing of TCP and UDP sockets. Sending to and receiving from these sockets. DNS name lookup, using either the OS or our own resolver.
Planned:
Nonblocking IO
Connection
struct; A "fat socket" struct that remembers how you opened it, etc, instead of just being a handle.
IP Range structs, CIDR/class ranges, netmask calculator and associated helper procedures.
Use context.temp_allocator
instead of stack-based arenas?
And check it's the default temp allocator or can give us 4 MiB worth of memory
without punting to the main allocator by comparing their addresses in an @(init) procedure.
Panic if this assumption is not met.
Document assumptions about libc usage (or avoidance thereof) for each platform.
Assumptions:
For performance reasons this package relies on the context.temp_allocator
in some places.
You can replace the default context.temp_allocator
with your own as long as it meets
this requirement: A minimum of 4 MiB of scratch space that's expected not to be freed.
If this expectation is not met, the package's @(init) procedure will attempt to detect this and panic to avoid temp allocations prematurely overwriting data and garbling results, or worse. This means that should you replace the temp allocator with an insufficient one, we'll do our best to loudly complain the first time you try it.
Index
Types (60)
- Accept_Error
- Address
- Address_Duplication
- Address_Family
- Any_Socket
- Bind_Error
- Create_Socket_Error
- DNS_Configuration
- DNS_Error
- DNS_Header
- DNS_Host_Entry
- DNS_Query
- DNS_Record
- DNS_Record_Base
- DNS_Record_CNAME
- DNS_Record_Header
- DNS_Record_IP4
- DNS_Record_IP6
- DNS_Record_MX
- DNS_Record_NS
- DNS_Record_SRV
- DNS_Record_TXT
- DNS_Record_Type
- DNS_Response_Code
- Dial_Error
- Digit_Parse_Base
- Digit_Parse_Bases
- Endpoint
- Host
- Host_Or_Endpoint
- IP4_Address
- IP6_Address
- Interfaces_Error
- Lease
- Link_State
- Link_States
- Listen_Error
- Maybe
- Netmask
- Network_Error
- Network_Interface
- Parse_Endpoint_Error
- Prefix_Origin
- Resolve_Error
- Set_Blocking_Error
- Shutdown_Error
- Shutdown_Manner
- Socket
- Socket_Option
- Socket_Option_Error
- Socket_Protocol
- Suffix_Origin
- TCP_Options
- TCP_Recv_Error
- TCP_Send_Error
- TCP_Socket
- Tunnel_Type
- UDP_Recv_Error
- UDP_Send_Error
- UDP_Socket
Procedures (68)
- accept_tcp
- address_to_string
- any_socket_to_socket
- aton
- bind
- bound_endpoint
- close
- create_socket
- decode_hostname
- destroy_dns_records
- destroy_interfaces
- dial_tcp_from_address_and_port
- dial_tcp_from_endpoint
- dial_tcp_from_host
- dial_tcp_from_host_or_endpoint
- dial_tcp_from_hostname_and_port_string
- dial_tcp_from_hostname_with_port_override
- encode_hostname
- endpoint_to_string
- enumerate_interfaces
- family_from_address
- family_from_endpoint
- get_dns_records_from_nameservers
- get_dns_records_from_os
- get_network_interfaces
- init_dns_configuration
- join_port
- join_url
- last_platform_error
- last_platform_error_string
- listen_tcp
- load_hosts
- load_resolv_conf
- make_bound_udp_socket
- make_unbound_udp_socket
- map_to_ip6
- pack_dns_header
- parse_address
- parse_endpoint
- parse_hostname_or_endpoint
- parse_ip4_address
- parse_ip6_address
- parse_ip_component
- parse_record
- parse_response
- parse_socket_address
- percent_decode
- percent_encode
- physical_address_to_string
- recv_any
- recv_tcp
- recv_udp
- replace_environment_path
- resolve
- resolve_ip4
- resolve_ip6
- send_any
- send_tcp
- send_udp
- set_blocking
- set_last_platform_error
- set_option
- shutdown
- skip_hostname
- split_port
- split_url
- unpack_dns_header
- validate_hostname
Types
Accept_Error ¶
Accept_Error :: enum i32 { None, // No network connection, or the network stack is not initialized. Network_Unreachable, // Not enough space in internal tables/buffers to create a new socket, or an unsupported protocol is given. Insufficient_Resources, // Invalid socket, or options. Invalid_Argument, // The given socket does not support accepting connections. Unsupported_Socket, // accept called on a socket which is not listening. Not_Listening, // A connection arrived but was closed while in the listen queue. Aborted, // Timed out before being able to accept a connection. Timeout, // Non-blocking socket that would need to block waiting for a connection. Would_Block, // Interrupted by a signal or other method of cancellation like WSACancelBlockingCall on Windows. Interrupted, // An error unable to be categorized in above categories, `last_platform_error` may have more info. Unknown, }
Related Procedures With Returns
Address ¶
Address :: union { IP4_Address, IP6_Address, }
Related Procedures With Parameters
- address_to_string
- dial_tcp_from_address_and_port
- family_from_address
- make_bound_udp_socket
- map_to_ip6
- dial_tcp (procedure groups)
- to_string (procedure groups)
Related Procedures With Returns
Address_Duplication ¶
Address_Duplication :: enum i32 { Invalid = 0, Tentative = 1, Duplicate = 2, Deprecated = 3, Preferred = 4, }
Address_Family ¶
Address_Family :: enum int { IP4, IP6, }
Related Procedures With Parameters
Related Procedures With Returns
Any_Socket ¶
Any_Socket :: union { TCP_Socket, UDP_Socket, }
Related Procedures With Parameters
- any_socket_to_socket
- bind
- bound_endpoint
- close
- recv_any
- send_any
- set_blocking
- set_option
- shutdown
- recv (procedure groups)
- send (procedure groups)
Related Procedures With Returns
Bind_Error ¶
Bind_Error :: enum i32 { None, // No network connection, or the network stack is not initialized. Network_Unreachable, // Not enough space in internal tables/buffers to create a new socket, or an unsupported protocol is given. Insufficient_Resources, // Invalid socket or endpoint, or invalid combination of the two. Invalid_Argument, // The socket is already bound to an address. Already_Bound, // The address is protected and the current user has insufficient permissions to access it. Insufficient_Permissions_For_Address, // The address is already in use. Address_In_Use, // An error unable to be categorized in above categories, `last_platform_error` may have more info. Unknown, }
Related Procedures With Returns
Create_Socket_Error ¶
Create_Socket_Error :: enum i32 { None, // No network connection, or the network stack is not initialized. Network_Unreachable, // Not enough space in internal tables/buffers to create a new socket, or an unsupported protocol is given. Insufficient_Resources, // Invalid/unsupported family or protocol. Invalid_Argument, // The user has no permission to create a socket of this type and/or protocol. Insufficient_Permissions, // An error unable to be categorized in above categories, `last_platform_error` may have more info. Unknown, }
Related Procedures With Returns
DNS_Configuration ¶
DNS_Configuration :: struct { // Configuration files. resolv_conf: string, hosts_file: string, // TODO: Allow loading these up with `reload_configuration()` call or the like, // so we don't have to do it each call. name_servers: []Endpoint, hosts_file_entries: []DNS_Record, }
DNS DEFINITIONS
Related Constants
DNS_Error ¶
DNS_Error :: enum u32 { None = 0, Invalid_Hostname_Error = 1, Invalid_Hosts_Config_Error, Invalid_Resolv_Config_Error, Connection_Error, Server_Error, System_Error, }
Related Procedures With Returns
DNS_Header ¶
DNS_Header :: struct { id: u16be, is_response: bool, opcode: u16be, is_authoritative: bool, is_truncated: bool, is_recursion_desired: bool, is_recursion_available: bool, response_code: DNS_Response_Code, }
Related Procedures With Parameters
Related Procedures With Returns
DNS_Query ¶
DNS_Query :: enum u16be { Host_Address = 1, Authoritative_Name_Server = 2, Mail_Destination = 3, Mail_Forwarder = 4, CNAME = 5, All = 255, }
DNS_Record ¶
DNS_Record :: union { DNS_Record_IP4, DNS_Record_IP6, DNS_Record_CNAME, DNS_Record_TXT, DNS_Record_NS, DNS_Record_MX, DNS_Record_SRV, }
Related Procedures With Returns
DNS_Record_Base ¶
Base DNS Record. All DNS responses will carry a hostname and TTL (time to live) field.
DNS_Record_CNAME ¶
DNS_Record_CNAME :: struct { using base: DNS_Record_Base, host_name: string, }
Another domain name that the domain name maps to.
Domains can be pointed to another domain instead of directly to an IP address.
get_dns_records
will recursively follow these if you request this type of record.
DNS_Record_IP4 ¶
DNS_Record_IP4 :: struct { using base: DNS_Record_Base, address: IP4_Address, }
An IP4 address that the domain name maps to. There can be any number of these.
DNS_Record_IP6 ¶
DNS_Record_IP6 :: struct { using base: DNS_Record_Base, address: IP6_Address, }
An IPv6 address that the domain name maps to. There can be any number of these.
DNS_Record_MX ¶
DNS_Record_MX :: struct { using base: DNS_Record_Base, host_name: string, preference: int, }
Domain names for email servers that are associated with the domain name. These records also have values which ranks them in the order they should be preferred. Lower is more-preferred.
DNS_Record_NS ¶
DNS_Record_NS :: struct { using base: DNS_Record_Base, host_name: string, }
Domain names of other DNS servers that are associated with the domain name. TODO(tetra): Expand on what these records are used for, and when you should use pay attention to these.
DNS_Record_SRV ¶
DNS_Record_SRV :: struct { // base contains the full name of this record. // e.g: _sip._tls.example.com using base: DNS_Record_Base, // The hostname or address where this service can be found. target: string, // The port on which this service can be found. port: int, service_name: string, // NOTE(tetra): These are substrings of 'record_name' protocol_name: string, // Lower is higher priority priority: int, // Relative weight of this host compared to other of same priority; the chance of using this host should be proporitional to this weight. // The number of seconds that it will take to update the record. weight: int, }
An endpoint for a service that is available through the domain name. This is the way to discover the services that a domain name provides.
Clients MUST attempt to contact the host with the lowest priority that they can reach. If two hosts have the same priority, they should be contacted in the order according to their weight. Hosts with larger weights should have a proportionally higher chance of being contacted by clients. A weight of zero indicates a very low weight, or, when there is no choice (to reduce visual noise).
The host may be "." to indicate that it is "decidedly not available" on this domain.
DNS_Record_TXT ¶
DNS_Record_TXT :: struct { using base: DNS_Record_Base, value: string, }
Arbitrary string data that is associated with the domain name.
Commonly of the form key=value
to be parsed, though there is no specific format for them.
These can be used for any purpose.
DNS_Record_Type ¶
DNS_Record_Type :: enum u16 { DNS_TYPE_A = 1, // IP4 address. DNS_TYPE_NS = 2, // IP6 address. DNS_TYPE_CNAME = 5, // Another host name. DNS_TYPE_MX = 15, // Arbitrary binary data or text. DNS_TYPE_AAAA = 28, // Address of a name (DNS) server. DNS_TYPE_TEXT = 16, // Address and preference priority of a mail exchange server. DNS_TYPE_SRV = 33, // Address, port, priority, and weight of a host that provides a particular service. IP4 = 1, IP6 = 28, CNAME = 5, TXT = 16, NS = 2, MX = 15, SRV = 33, }
Related Procedures With Parameters
DNS_Response_Code ¶
DNS_Response_Code :: enum u16be { No_Error, Format_Error, Server_Failure, Name_Error, Not_Implemented, Refused, }
Dial_Error ¶
Dial_Error :: enum i32 { None, // No network connection, or the network stack is not initialized. Network_Unreachable, // Not enough space in internal tables/buffers to create a new socket, or an unsupported protocol is given. Insufficient_Resources, // Invalid endpoint and/or options. Invalid_Argument, // An attempt was made to connect to a broadcast socket on a socket that doesn't support it. Broadcast_Not_Supported, // The socket is already connected. Already_Connected, // The socket is already in the progress of making a connection. Already_Connecting, // The address is already in use. Address_In_Use, // Could not reach the remote host. Host_Unreachable, // The remote host refused the connection or isn't listening. Refused, // The connection was reset by the remote host. Reset, // Timed out before making a connection. Timeout, // Non-blocking socket that would need to block waiting to connect. Would_Block, // Interrupted by a signal or other method of cancellation like WSACancelBlockingCall on Windows. Interrupted, // Endpoint given without a port, which is required. Port_Required, // An error unable to be categorized in above categories, `last_platform_error` may have more info. Unknown, }
Digit_Parse_Base ¶
Digit_Parse_Base :: enum u8 { Dec = 0, // No prefix Oct = 1, // Leading zero Hex = 2, // 0x prefix IPv6 = 3, // Unprefixed IPv6 piece hex. Can't be used with other bases. }
Endpoint ¶
Related Procedures With Parameters
- bind
- dial_tcp_from_endpoint
- endpoint_to_string
- family_from_endpoint
- listen_tcp
- send_udp
- dial_tcp (procedure groups)
- send (procedure groups)
- to_string (procedure groups)
Related Procedures With Returns
- accept_tcp
- bound_endpoint
- parse_endpoint
- parse_socket_address
- recv_udp
- resolve
- resolve_ip4
- resolve_ip6
- recv (procedure groups)
Host_Or_Endpoint ¶
Related Procedures With Parameters
- dial_tcp_from_host_or_endpoint
- dial_tcp (procedure groups)
Related Procedures With Returns
Interfaces_Error ¶
Interfaces_Error :: enum u32 { None, Unable_To_Enumerate_Network_Interfaces, Allocation_Failure, Unknown, }
Related Procedures With Returns
Lease ¶
Lease :: struct { address: Address, netmask: Netmask, lifetime: struct { valid: u32, preferred: u32, lease: u32, }, origin: struct { prefix: Prefix_Origin, suffix: Suffix_Origin, }, address_duplication: Address_Duplication, }
Link_State ¶
Link_State :: bit_set[Link_States; u32]
Link_States ¶
Link_States :: enum u32 { Up = 1, Down = 2, Testing = 3, Dormant = 4, Not_Present = 5, Lower_Layer_Down = 6, Loopback = 7, }
Empty bit set is unknown state.
Listen_Error ¶
Listen_Error :: enum i32 { None, // No network connection, or the network stack is not initialized. Network_Unreachable, // Not enough space in internal tables/buffers to create a new socket, or an unsupported protocol is given. Insufficient_Resources, // The socket or backlog is invalid. Invalid_Argument, // The socket is valid, but does not support listening. Unsupported_Socket, // The socket is already connected. Already_Connected, // The address is already in use. Address_In_Use, // An error unable to be categorized in above categories, `last_platform_error` may have more info. Unknown, }
Related Procedures With Returns
Maybe ¶
Maybe :: runtime.Maybe
COMMON DEFINITIONS
Related Procedures With Parameters
Related Procedures With Returns
Netmask ¶
Netmask :: union { IP4_Address, IP6_Address, }
Network_Error ¶
Network_Error :: union { Create_Socket_Error, Dial_Error, Listen_Error, Accept_Error, Bind_Error, TCP_Send_Error, UDP_Send_Error, TCP_Recv_Error, UDP_Recv_Error, Shutdown_Error, Interfaces_Error, Socket_Option_Error, Set_Blocking_Error, Parse_Endpoint_Error, Resolve_Error, DNS_Error, }
Related Procedures With Returns
- dial_tcp_from_address_and_port
- dial_tcp_from_endpoint
- dial_tcp_from_host
- dial_tcp_from_host_or_endpoint
- dial_tcp_from_hostname_and_port_string
- dial_tcp_from_hostname_with_port_override
- listen_tcp
- make_bound_udp_socket
- recv_any
- resolve
- resolve_ip4
- resolve_ip6
- send_any
- dial_tcp (procedure groups)
- recv (procedure groups)
- send (procedure groups)
Network_Interface ¶
Network_Interface :: struct { adapter_name: string, // On Windows this is a GUID that we could parse back into its u128 for more compact storage. friendly_name: string, description: string, dns_suffix: string, physical_address: string, // MAC address, etc. mtu: u32, unicast: [dynamic]Lease, multicast: [dynamic]Address, anycast: [dynamic]Address, gateways: [dynamic]Address, dhcp_v4: Address, dhcp_v6: Address, tunnel_type: Tunnel_Type, link: struct { state: bit_set[Link_States; u32], transmit_speed: u64, receive_speed: u64, }, }
INTERFACE / LINK STATE
Parse_Endpoint_Error ¶
Parse_Endpoint_Error :: enum u32 { None = 0, Bad_Port = 1, Bad_Address, Bad_Hostname, }
Related Procedures With Returns
Prefix_Origin ¶
Prefix_Origin :: enum i32 { Other = 0, Manual = 1, Well_Known = 2, DHCP = 3, Router_Advertisement = 4, Unchanged = 16, }
Resolve_Error ¶
Resolve_Error :: enum u32 { None = 0, Unable_To_Resolve = 1, }
Set_Blocking_Error ¶
Set_Blocking_Error :: enum i32 { None, // No network connection, or the network stack is not initialized. Network_Unreachable, // Socket is invalid. Invalid_Argument, // An error unable to be categorized in above categories, `last_platform_error` may have more info. Unknown, }
Related Procedures With Returns
Shutdown_Error ¶
Shutdown_Error :: enum i32 { None, // No network connection, or the network stack is not initialized. Network_Unreachable, // Socket is invalid or not connected, or the manner given is invalid. Invalid_Argument, // Connection was closed/aborted/shutdown. Connection_Closed, // An error unable to be categorized in above categories, `last_platform_error` may have more info. Unknown, }
Related Procedures With Returns
Shutdown_Manner ¶
Shutdown_Manner :: enum i32 { Receive = 0, Send = 1, Both = 2, }
Related Procedures With Parameters
Socket ¶
Socket :: distinct i64
To allow freely using Socket
in your own data structures in a cross-platform manner,
we treat it as a handle large enough to accomodate OS-specific notions of socket handles.
The platform code will perform the cast so you don't have to.
Related Procedures With Returns
Socket_Option ¶
Socket_Option :: enum i32 { // 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 = 4, // bool: Whether other programs will be inhibited from binding the same endpoint as this socket. Exclusive_Addr_Use = -5, // bool: When true, keepalive packets will be automatically be sent for this connection. TODO: verify this understanding Keep_Alive = 8, // bool: When true, client connections will immediately be sent a TCP/IP RST response, rather than being accepted. Conditional_Accept = 12290, // bool: If true, when the socket is closed, but data is still waiting to be sent, discard that data. Dont_Linger = -129, // 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 = 256, // bool: When true, disables send-coalescing, therefore reducing latency. TCP_Nodelay = 1, // 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 = 128, // win.DWORD: The size, in bytes, of the OS-managed receive-buffer for this socket. Receive_Buffer_Size = 4098, // win.DWORD: The size, in bytes, of the OS-managed send-buffer for this socket. Send_Buffer_Size = 4097, // 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 = 4102, // 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 = 4101, // bool: Allow sending to, receiving from, and binding to, a broadcast address. Broadcast = 32, }
Related Procedures With Parameters
Socket_Option_Error ¶
Socket_Option_Error :: enum i32 { None, // No network connection, or the network stack is not initialized. Network_Unreachable, // Not enough space in internal tables/buffers to create a new socket, or an unsupported protocol is given. Insufficient_Resources, // Socket is invalid, not connected, or the connection has been closed/reset/shutdown. Invalid_Socket, // Unknown or unsupported option for the socket. Invalid_Option, // Invalid level or value. Invalid_Value, // An error unable to be categorized in above categories, `last_platform_error` may have more info. Unknown, }
Related Procedures With Returns
Suffix_Origin ¶
Suffix_Origin :: enum i32 { Other = 0, Manual = 1, Well_Known = 2, DHCP = 3, Link_Layer_Address = 4, Random = 5, Unchanged = 16, }
TCP_Options ¶
TCP_Options :: struct { no_delay: bool, }
SOCKET OPTIONS & DEFINITIONS
Related Procedures With Parameters
TCP_Recv_Error ¶
TCP_Recv_Error :: enum i32 { None, // No network connection, or the network stack is not initialized. Network_Unreachable, // Not enough space in internal tables/buffers to create a new socket, or an unsupported protocol is given. Insufficient_Resources, // Invalid socket or buffer given. Invalid_Argument, // The socket is not connected. Not_Connected, // Connection was closed/broken/shutdown while receiving data. Connection_Closed, // Timed out before being able to receive any data. Timeout, // Non-blocking socket that would need to block waiting on data. Would_Block, // Interrupted by a signal or other method of cancellation like WSACancelBlockingCall on Windows. Interrupted, // An error unable to be categorized in above categories, `last_platform_error` may have more info. Unknown, }
Related Procedures With Returns
TCP_Send_Error ¶
TCP_Send_Error :: enum i32 { None, // No network connection, or the network stack is not initialized. Network_Unreachable, // Not enough space in internal tables/buffers to create a new socket, or an unsupported protocol is given. Insufficient_Resources, // Invalid socket or buffer given. Invalid_Argument, // Connection was closed/broken/shutdown while receiving data. Connection_Closed, // The socket is not connected. Not_Connected, // Could not reach the remote host. Host_Unreachable, // Timed out before being able to send any data. Timeout, // Non-blocking socket that would need to block waiting on the remote to be able to receive the data. Would_Block, // Interrupted by a signal or other method of cancellation like WSACancelBlockingCall on Windows. Interrupted, // An error unable to be categorized in above categories, `last_platform_error` may have more info. Unknown, }
Related Procedures With Returns
TCP_Socket ¶
TCP_Socket :: distinct i64
Related Procedures With Parameters
- accept_tcp
- recv_tcp
- send_tcp
- recv (procedure groups)
- send (procedure groups)
Related Procedures With Returns
Tunnel_Type ¶
Tunnel_Type :: enum i32 { None = 0, Other = 1, Direct = 2, IPv4_To_IPv6 = 11, ISA_TAP = 13, Teredo = 14, IP_HTTPS = 15, }
UDP_Recv_Error ¶
UDP_Recv_Error :: enum i32 { None, // No network connection, or the network stack is not initialized. Network_Unreachable, // Not enough space in internal tables/buffers to create a new socket, or an unsupported protocol is given. Insufficient_Resources, // Invalid socket or buffer given. Invalid_Argument, // "Connection" was refused by remote, or closed/broken/shutdown while receiving data. Connection_Refused, // Timed out before being able to receive any data. Timeout, // Non-blocking socket that would need to block waiting on data. Would_Block, // Interrupted by a signal or other method of cancellation like WSACancelBlockingCall on Windows. Interrupted, // Linux and UDP only: indicates the buffer was too small to receive all data, and the excess is truncated and discarded. Excess_Truncated, // An error unable to be categorized in above categories, `last_platform_error` may have more info. Unknown, }
Related Procedures With Returns
UDP_Send_Error ¶
UDP_Send_Error :: enum i32 { None, // No network connection, or the network stack is not initialized. Network_Unreachable, // Not enough space in internal tables/buffers to create a new socket, or an unsupported protocol is given. Insufficient_Resources, // Invalid socket or buffer given. Invalid_Argument, // Could not reach the remote host. Host_Unreachable, // "Connection" was refused by remote, or closed/broken/shutdown while sending data. Connection_Refused, // Timed out before being able to send any data. Timeout, // Non-blocking socket that would need to block waiting on the remote to be able to receive the data. Would_Block, // Interrupted by a signal or other method of cancellation like WSACancelBlockingCall on Windows. Interrupted, // An error unable to be categorized in above categories, `last_platform_error` may have more info. Unknown, }
Related Procedures With Returns
UDP_Socket ¶
UDP_Socket :: distinct i64
Related Procedures With Parameters
Related Procedures With Returns
Constants
DEFAULT_DIGIT_BASES ¶
DEFAULT_DIGIT_BASES: bit_set[Digit_Parse_Base; u8] : Digit_Parse_Bases{.Dec, .Oct, .Hex}
DEFAULT_DNS_CONFIGURATION ¶
DEFAULT_DNS_CONFIGURATION :: DNS_Configuration{resolv_conf = "", hosts_file = "%WINDIR%\\system32\\drivers\\etc\\hosts"}
IP4_Loopback ¶
IP4_Loopback :: IP4_Address{127, 0, 0, 1}
IP6_Loopback ¶
IP6_Loopback :: IP6_Address{0, 0, 0, 0, 0, 0, 0, 1}
IPv6_MAX_STRING_LENGTH ¶
IPv6_MAX_STRING_LENGTH: int : 45
IPv6_MIN_COLONS ¶
IPv6_MIN_COLONS: int : 2
IPv6_MIN_STRING_LENGTH ¶
IPv6_MIN_STRING_LENGTH: int : 2
The minimum length of a valid IPv6 address string is 2, e.g. ::
The maximum length of a valid IPv6 address string is 45, when it embeds an IPv4,
e.g. 0000:0000:0000:0000:0000:ffff:255.255.255.255
An IPv6 address must contain at least 3 pieces, e.g. ::
,
and at most 9 (using ::
for a trailing or leading 0)
IPv6_PIECE_COUNT ¶
IPv6_PIECE_COUNT: int : 8
LABEL_MAX ¶
LABEL_MAX: int : 63
MAX_INTERFACE_ENUMERATION_TRIES ¶
MAX_INTERFACE_ENUMERATION_TRIES: int : 3
NAME_MAX ¶
NAME_MAX: int : 255
ODIN_NET_TCP_NODELAY_DEFAULT ¶
ODIN_NET_TCP_NODELAY_DEFAULT: bool : #config(ODIN_NET_TCP_NODELAY_DEFAULT, true)
Variables
IP4_Any ¶
IP4_Any: IP4_Address = …
IP4_mDNS_Broadcast ¶
IP4_mDNS_Broadcast: Endpoint = …
IP6_Any ¶
IP6_Any: IP6_Address = …
IP6_mDNS_Broadcast ¶
IP6_mDNS_Broadcast: Endpoint = …
default_tcp_options ¶
default_tcp_options: TCP_Options = …
dns_configuration ¶
dns_configuration: DNS_Configuration = …
Procedures
accept_tcp ¶
accept_tcp :: proc(socket: TCP_Socket, options: TCP_Options = default_tcp_options) -> (client: TCP_Socket, source: Endpoint, err: Accept_Error) {…}
address_to_string ¶
address_to_string :: proc(addr: Address, allocator := context.temp_allocator) -> string {…}
Returns a temporarily-allocated string representation of the address.
See RFC 5952 section 4 for IPv6 representation recommendations.
any_socket_to_socket ¶
any_socket_to_socket :: proc "contextless" (socket: Any_Socket) -> Socket {…}
aton ¶
aton :: proc(address_and_maybe_port: string, family: Address_Family, allow_decimal_only: bool = false) -> (addr: Address, ok: bool) {…}
Parses an IP address in "non-decimal" inet_aton
form.
e.g."00377.0x0ff.65534" = 255.255.255.254
00377 = 255 in octal 0x0ff = 255 in hexadecimal This leaves 16 bits worth of address .65534 then accounts for the last two digits
For the address part the allowed forms are:
a.b.c.d - where each part represents a byte a.b.c - where `a` & `b` represent a byte and `c` a u16 a.b - where `a` represents a byte and `b` supplies the trailing 24 bits a - where `a` gives the entire 32-bit value
The port, if present, is required to be a base 10 number in the range 0-65535, inclusive.
bind ¶
bind :: proc(socket: Any_Socket, ep: Endpoint) -> (err: Bind_Error) {…}
bound_endpoint ¶
bound_endpoint :: proc(socket: Any_Socket) -> (endpoint: Endpoint, err: Listen_Error) {…}
Returns the endpoint that the given socket is listening / bound on.
close ¶
close :: proc(socket: Any_Socket) {…}
create_socket ¶
create_socket :: proc(family: Address_Family, protocol: Socket_Protocol) -> (socket: Any_Socket, err: Create_Socket_Error) {…}
destroy_dns_records ¶
destroy_dns_records :: proc(records: []DNS_Record, allocator := context.allocator) {…}
records
slice is also destroyed.
destroy_interfaces ¶
destroy_interfaces :: proc(interfaces: []Network_Interface, allocator := context.allocator) {…}
destroy_interfaces
cleans up a list of network interfaces retrieved by e.g. enumerate_interfaces
.
dial_tcp_from_address_and_port ¶
dial_tcp_from_address_and_port :: proc(address: Address, port: int, options: TCP_Options = default_tcp_options) -> (socket: TCP_Socket, err: Network_Error) {…}
Dial from an Address.
Errors that can be returned: Create_Socket_Error
, or Dial_Error
dial_tcp_from_endpoint ¶
dial_tcp_from_endpoint :: proc(endpoint: Endpoint, options: TCP_Options = default_tcp_options) -> (socket: TCP_Socket, err: Network_Error) {…}
Dial from an Endpoint.
Errors that can be returned: Create_Socket_Error
, or Dial_Error
dial_tcp_from_host ¶
dial_tcp_from_host :: proc(host: Host, options: TCP_Options = default_tcp_options) -> (socket: TCP_Socket, err: Network_Error) {…}
Expects the host
as Host.
Errors that can be returned: `Resolve_Error`, `DNS_Error`, `Create_Socket_Error`, or `Dial_Error`
dial_tcp_from_host_or_endpoint ¶
dial_tcp_from_host_or_endpoint :: proc(target: Host_Or_Endpoint, options: TCP_Options = default_tcp_options) -> (socket: TCP_Socket, err: Network_Error) {…}
Expects the target
as a Host_OrEndpoint.
Unwraps the underlying type and calls dial_tcp_from_host
or dial_tcp_from_endpoint
.
Errors that can be returned: `Parse_Endpoint_Error`, `Resolve_Error`, `DNS_Error`, `Create_Socket_Error`, or `Dial_Error`
dial_tcp_from_hostname_and_port_string ¶
dial_tcp_from_hostname_and_port_string :: proc(hostname_and_port: string, options: TCP_Options = default_tcp_options) -> (socket: TCP_Socket, err: Network_Error) {…}
Expects both hostname and port to be present in the hostname_and_port
parameter, either as:
a.host.name:9999
, or as 1.2.3.4:9999
, or IP6 equivalent.
Calls parse_hostname_or_endpoint
and dial_tcp_from_host_or_endpoint
.
Errors that can be returned: `Parse_Endpoint_Error`, `Resolve_Error`, `DNS_Error`, `Create_Socket_Error`, or `Dial_Error`
dial_tcp_from_hostname_with_port_override ¶
dial_tcp_from_hostname_with_port_override :: proc(hostname: string, port: int, options: TCP_Options = default_tcp_options) -> (socket: TCP_Socket, err: Network_Error) {…}
Expects the hostname
as a string and port
as a int
.
parse_hostname_or_endpoint
is called and the hostname
will be resolved into an IP.
If a hostname
of form a.host.name:9999
is given, the port will be ignored in favor of the explicit port
param.
Errors that can be returned: `Parse_Endpoint_Error`, `Resolve_Error`, `DNS_Error`, `Create_Socket_Error`, or `Dial_Error`
encode_hostname ¶
www.google.com -> 3www6google3com0
endpoint_to_string ¶
endpoint_to_string :: proc(ep: Endpoint, allocator := context.temp_allocator) -> string {…}
Returns a temporarily-allocated string representation of the endpoint.
If there's a port, uses the ip4address:port
or [ip6address]:port
format, respectively.
enumerate_interfaces ¶
enumerate_interfaces :: proc(allocator := context.allocator) -> (interfaces: []Network_Interface, err: Interfaces_Error) {…}
enumerate_interfaces
retrieves a list of network interfaces with their associated properties.
family_from_address ¶
family_from_address :: proc(addr: Address) -> Address_Family {…}
family_from_endpoint ¶
family_from_endpoint :: proc(ep: Endpoint) -> Address_Family {…}
get_dns_records_from_nameservers ¶
get_dns_records_from_nameservers :: proc(hostname: string, type: DNS_Record_Type, name_servers: []Endpoint, host_overrides: []DNS_Record, allocator := context.allocator) -> (records: []DNS_Record, err: DNS_Error) {…}
A generic DNS client usable on any platform. Performs a recursive DNS query for records of a particular type for the hostname.
NOTE: This procedure instructs the DNS resolver to recursively perform CNAME requests on our behalf, meaning that DNS queries for a hostname will resolve through CNAME records until an IP address is reached.
IMPORTANT: This procedure allocates memory for each record returned; deleting just the returned slice is not enough!
See destroy_records
.
get_dns_records_from_os ¶
get_dns_records_from_os :: proc(hostname: string, type: DNS_Record_Type, allocator := context.allocator) -> (records: []DNS_Record, err: DNS_Error) {…}
Performs a recursive DNS query for records of a particular type for the hostname using the OS.
NOTE: This procedure instructs the DNS resolver to recursively perform CNAME requests on our behalf, meaning that DNS queries for a hostname will resolve through CNAME records until an IP address is reached.
IMPORTANT: This procedure allocates memory for each record returned; deleting just the returned slice is not enough!
See destroy_records
.
get_network_interfaces ¶
get_network_interfaces :: proc() -> []Address {…}
Returns an address for each interface that can be bound to.
init_dns_configuration ¶
init_dns_configuration :: proc() {…}
join_port ¶
join_port :: proc(address_or_host: string, port: int, allocator := context.allocator) -> string {…}
Joins an address or hostname with a port.
last_platform_error ¶
last_platform_error :: proc() -> i32 {…}
Retrieve a platform specific error code, for when the categorized cross-platform errors are not enough.
Platforms specific returns:
Darwin: posix.Errno
(core:sys/posix
)
Linux: linux.Errno
(core:sys/linux
)
FreeBSD: freebsd.Errno
(core:sys/freebsd
)
Windows: windows.System_Error
(core:sys/windows
)
last_platform_error_string ¶
last_platform_error_string :: proc() -> string {…}
Retrieve a stringified version of the last platform error.
listen_tcp ¶
listen_tcp :: proc(interface_endpoint: Endpoint, backlog: int = 1000) -> (socket: TCP_Socket, err: Network_Error) {…}
Creates a TCP socket and starts listening on the given endpoint.
Errors that can be returned: Create_Socket_Error
, Bind_Error
, or Listen_Error
load_hosts ¶
load_hosts :: proc(hosts_file_path: string, allocator := context.allocator) -> (hosts: []DNS_Host_Entry, ok: bool) {…}
load_resolv_conf ¶
load_resolv_conf :: proc(resolv_conf_path: string, allocator := context.allocator) -> (name_servers: []Endpoint, ok: bool) {…}
make_bound_udp_socket ¶
make_bound_udp_socket :: proc(bound_address: Address, port: int) -> (socket: UDP_Socket, err: Network_Error) {…}
This type of socket is bound immediately, which enables it to receive data on the port. Since it's UDP, it's also able to send data without receiving any first.
This is like a listening TCP socket, except that data packets can be sent and received without needing to establish a connection first.
The bound_address
is the address of the network interface that you want to use, or a loopback address if you don't care which to use.
Errors that can be returned: Parse_Endpoint_Error
, Create_Socket_Error
, or Bind_Error
make_unbound_udp_socket ¶
make_unbound_udp_socket :: proc(family: Address_Family) -> (socket: UDP_Socket, err: Create_Socket_Error) {…}
This type of socket becomes bound when you try to send data. It is likely what you want if you want to send data unsolicited.
This is like a client TCP socket, except that it can send data to any remote endpoint without needing to establish a connection first.
pack_dns_header ¶
pack_dns_header :: proc(hdr: DNS_Header) -> (id: u16be, bits: u16be) {…}
parse_address ¶
parse_address :: proc(address_and_maybe_port: string, non_decimal_address: bool = false) -> Address {…}
Try parsing as an IPv6 address. If it's determined not to be, try as an IPv4 address, optionally in non-decimal format.
parse_hostname_or_endpoint ¶
parse_hostname_or_endpoint :: proc(endpoint_str: string) -> (target: Host_Or_Endpoint, err: Parse_Endpoint_Error) {…}
Takes a string consisting of a hostname or IP address, and an optional port, and return the component parts in a useful form.
parse_ip4_address ¶
parse_ip4_address :: proc(address_and_maybe_port: string, allow_non_decimal: bool = false) -> (addr: IP4_Address, ok: bool) {…}
Expects an IPv4 address with no leading or trailing whitespace: a.b.c.d a.b.c.d:port [a.b.c.d]:port
If the IP address is bracketed, the port must be present and valid (though it will be ignored): [a.b.c.d] will be treated as a parsing failure.
The port, if present, is required to be a base 10 number in the range 0-65535, inclusive.
If allow_non_decimal
is false, aton
is told each component must be decimal and max 255.
parse_ip6_address ¶
parse_ip6_address :: proc(address_and_maybe_port: string) -> (addr: IP6_Address, ok: bool) {…}
parse_ip_component ¶
parse_ip_component :: proc(input: string, max_value: u64 = u64(max(u32)), bases: bit_set[Digit_Parse_Base; u8] = DEFAULT_DIGIT_BASES) -> (value: u64, bytes_consumed: int, ok: bool) {…}
Parses a single unsigned number in requested bases
from input
.
max_value
represents the maximum allowed value for this number.
Returns the value
, the bytes_consumed
so far, and ok
to signal success or failure.
An out-of-range or invalid number will return the accumulated value so far (which can be out of range),
the number of bytes consumed leading up the error, and ok = false
.
When .
or :
are encountered, they'll be considered valid separators and will stop parsing,
returning the valid number leading up to it.
Other non-digit characters are treated as an error.
Octal numbers are expected to have a leading zero, with no 'o' format specifier. Hexadecimal numbers are expected to be preceded by '0x' or '0X'. Numbers will otherwise be considered to be in base 10.
parse_record ¶
parse_record :: proc(packet: []u8, cur_off: ^int, filter: DNS_Record_Type = nil) -> (record: DNS_Record, ok: bool) {…}
parse_response ¶
parse_response :: proc(response: []u8, filter: DNS_Record_Type = nil, allocator := context.allocator) -> (records: []DNS_Record, xid: u16be, ok: bool) {…}
parse_socket_address ¶
parse_socket_address :: proc(addr_in: sys_windows.SOCKET_ADDRESS) -> (addr: Endpoint) {…}
Interpret SOCKET_ADDRESS as an Address
percent_decode ¶
percent_decode :: proc(encoded_string: string, allocator := context.allocator) -> (decoded_string: string, ok: bool) {…}
percent_encode ¶
percent_encode :: proc(s: string, allocator := context.allocator) -> string {…}
physical_address_to_string ¶
physical_address_to_string :: proc(phy_addr: []u8, allocator := context.allocator) -> (phy_string: string) {…}
Turns a slice of bytes (from e.g. get_adapters_addresses
) into a "XX:XX:XX:..." string.
recv_any ¶
recv_any :: proc(socket: Any_Socket, buf: []u8) -> (bytes_read: int, remote_endpoint: runtime.Maybe($T=Endpoint), err: Network_Error) {…}
Receive data from into a buffer from any socket.
Note: remote_endpoint
parameter is non-nil only if the socket type is UDP. On TCP sockets it
will always return nil
.
Errors that can be returned: TCP_Recv_Error
, or UDP_Recv_Error
recv_tcp ¶
recv_tcp :: proc(socket: TCP_Socket, buf: []u8) -> (bytes_read: int, err: TCP_Recv_Error) {…}
recv_udp ¶
recv_udp :: proc(socket: UDP_Socket, buf: []u8) -> (bytes_read: int, remote_endpoint: Endpoint, err: UDP_Recv_Error) {…}
replace_environment_path ¶
replace_environment_path :: proc(path: string, allocator := context.allocator) -> (res: string, ok: bool) {…}
Always allocates for consistency.
resolve ¶
resolve :: proc(hostname_and_maybe_port: string) -> (ep4, ep6: Endpoint, err: Network_Error) {…}
Resolves a hostname to exactly one IP4 and IP6 endpoint. It's then up to you which one you use. Note that which address you use to open a socket, determines the type of the socket you get.
Returns ok=false
if the host name could not be resolved to any endpoints.
Returned endpoints have the same port as provided in the string, or 0 if absent. If you want to use a specific port, just modify the field after the call to this procedure.
If the hostname part of the endpoint is actually a string representation of an IP address, DNS resolution will be skipped. This allows you to pass both strings like "example.com:9000" and "1.2.3.4:9000" to this function end reliably get back an endpoint in both cases.
resolve_ip4 ¶
resolve_ip4 :: proc(hostname_and_maybe_port: string) -> (ep4: Endpoint, err: Network_Error) {…}
resolve_ip6 ¶
resolve_ip6 :: proc(hostname_and_maybe_port: string) -> (ep6: Endpoint, err: Network_Error) {…}
send_any ¶
send_any :: proc(socket: Any_Socket, buf: []u8, to: runtime.Maybe($T=Endpoint) = nil) -> (bytes_written: int, err: Network_Error) {…}
Sends data over the socket.
Errors that can be returned: TCP_Send_Error
, or UDP_Send_Error
send_tcp ¶
send_tcp :: proc(socket: TCP_Socket, buf: []u8) -> (bytes_written: int, err: TCP_Send_Error) {…}
Repeatedly sends data until the entire buffer is sent. If a send fails before all data is sent, returns the amount sent up to that point.
send_udp ¶
send_udp :: proc(socket: UDP_Socket, buf: []u8, to: Endpoint) -> (bytes_written: int, err: UDP_Send_Error) {…}
Sends a single UDP datagram packet.
Datagrams are limited in size; attempting to send more than this limit at once will result in a Message_Too_Long error. UDP packets are not guarenteed to be received in order.
set_blocking ¶
set_blocking :: proc(socket: Any_Socket, should_block: bool) -> (err: Set_Blocking_Error) {…}
set_last_platform_error ¶
set_last_platform_error :: proc(err: i32) {…}
set_option ¶
set_option :: proc(socket: Any_Socket, option: Socket_Option, value: any, loc := #caller_location) -> Socket_Option_Error {…}
shutdown ¶
shutdown :: proc(socket: Any_Socket, manner: Shutdown_Manner) -> (err: Shutdown_Error) {…}
split_port ¶
Takes an endpoint string and returns its parts. Returns ok=false if port is not a number.
unpack_dns_header ¶
unpack_dns_header :: proc(id: u16be, bits: u16be) -> (hdr: DNS_Header) {…}
validate_hostname ¶
Uses RFC 952 & RFC 1123
Procedure Groups
to_string ¶
to_string :: proc{ address_to_string, endpoint_to_string, }
Source Files
- addr.odin
- common.odin
- dns.odin
- doc.odin
- errors.odin
- interface.odin
- socket.odin
- url.odin
- (hidden platform specific files)
Generation Information
Generated with odin version dev-2025-04 (vendor "odin") Windows_amd64 @ 2025-04-15 11:45:54.807983900 +0000 UTC