package core:net

⌘K
Ctrl+K
or
/

    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 (61)
    Procedures (63)
    Procedure Groups (4)

    Types

    Accept_Error ¶

    Accept_Error :: enum i32 {
    	None                                              = 0, 
    	Not_Listening                                     = 10022, 
    	No_Socket_Descriptors_Available_For_Client_Socket = 10024, 
    	No_Buffer_Space_Available                         = 10055, 
    	Not_Socket                                        = 10038, 
    	Not_Connection_Oriented_Socket                    = 10045, 
    	// TODO: we may need special handling for this; maybe make a socket a struct with metadata?
    	Would_Block                                       = 10035, 
    }

    Address ¶

    Address :: union {
    	IP4_Address, 
    	IP6_Address, 
    }
    Related Procedures With Parameters
    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
    Related Procedures With Returns

    Bind_Error ¶

    Bind_Error :: enum i32 {
    	None                    = 0, 
    	Address_In_Use          = 10048, // Another application is currently bound to this endpoint.
    	Given_Nonlocal_Address  = 10049, // The address is not a local address on this machine.
    	Broadcast_Disabled      = 10013, // To bind a UDP socket to the broadcast address, the appropriate socket option must be set.
    	Address_Family_Mismatch = 10014, // The address family of the address does not match that of the socket.
    	Already_Bound           = 10022, // The socket is already bound to an address.
    	No_Ports_Available      = 10055, // There are not enough ephemeral ports available.
    }

    Create_Socket_Error ¶

    Create_Socket_Error :: enum i32 {
    	None                                 = 0, 
    	Network_Subsystem_Failure            = 10050, 
    	Family_Not_Supported_For_This_Socket = 10047, 
    	No_Socket_Descriptors_Available      = 10024, 
    	No_Buffer_Space_Available            = 10055, 
    	Protocol_Unsupported_By_System       = 10043, 
    	Wrong_Protocol_For_Socket            = 10041, 
    	Family_And_Socket_Type_Mismatch      = 10044, 
    }

    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 {
    	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_Host_Entry ¶

    DNS_Host_Entry :: struct {
    	name: string,
    	addr: Address,
    }

    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_Base ¶

    DNS_Record_Base :: struct {
    	record_name: string,
    	ttl_seconds: u32,
    }
     

    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_Header ¶

    DNS_Record_Header :: struct #packed {
    	type:   u16be,
    	class:  u16be,
    	ttl:    u32be,
    	length: u16be,
    }

    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                      = 0, 
    	Port_Required             = -1, 
    	Address_In_Use            = 10048, 
    	In_Progress               = 10037, 
    	Cannot_Use_Any_Address    = 10049, 
    	Wrong_Family_For_Socket   = 10047, 
    	Refused                   = 10061, 
    	Is_Listening_Socket       = 10022, 
    	Already_Connected         = 10056, 
    	Network_Unreachable       = 10051, // Device is offline
    	Host_Unreachable          = 10065, // Remote host cannot be reached
    	No_Buffer_Space_Available = 10055, 
    	Not_Socket                = 10038, 
    	Timeout                   = 10060, 
    	Would_Block               = 10035, // TODO: we may need special handling for this; maybe make a socket a struct with metadata?
    }

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

    Digit_Parse_Bases ¶

    Digit_Parse_Bases :: bit_set[Digit_Parse_Base; u8]
    Related Constants

    Endpoint ¶

    Endpoint :: struct {
    	address: Address,
    	port:    int,
    }
    Related Procedures With Parameters
    Related Procedures With Returns

    General_Error ¶

    General_Error :: enum u32 {
    	None                                   = 0, 
    	Unable_To_Enumerate_Network_Interfaces = 1, 
    }

    Host ¶

    Host :: struct {
    	hostname: string,
    	port:     int,
    }

    Host_Or_Endpoint ¶

    Host_Or_Endpoint :: union {
    	Host, 
    	Endpoint, 
    }
    Related Procedures With Returns

    IP4_Address ¶

    IP4_Address :: distinct [4]u8
    Related Procedures With Returns

    IP6_Address ¶

    IP6_Address :: distinct [8]u16be
    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 :: bit_set[Link_States; u32]
    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                                    = 0, 
    	Address_In_Use                          = 10048, 
    	Already_Connected                       = 10056, 
    	No_Socket_Descriptors_Available         = 10024, 
    	No_Buffer_Space_Available               = 10055, 
    	Nonlocal_Address                        = 10049, 
    	Not_Socket                              = 10038, 
    	Listening_Not_Supported_For_This_Socket = 10045, 
    }

    Maybe ¶

    Maybe :: runtime.Maybe
     

    COMMON DEFINITIONS

    Related Procedures With Parameters
    Related Procedures With Returns

    Netmask ¶

    Netmask :: union {
    	IP4_Address, 
    	IP6_Address, 
    }

    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 int {
    	None         = 0, 
    	Bad_Port     = 1, 
    	Bad_Address, 
    	Bad_Hostname, 
    }
    Related Procedures With Returns

    Platform_Error ¶

    Platform_Error :: enum u32 {
    }
     

    Platform_Error is used to wrap errors returned by the different platforms that don't fit a common error.

    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                              = 0, 
    	Network_Subsystem_Failure         = 10050, 
    	Blocking_Call_In_Progress         = 10036, 
    	Not_Socket                        = 10038, 
    	// TODO: are those errors possible?
    	Network_Subsystem_Not_Initialized = 10093, 
    	Invalid_Argument_Pointer          = 10014, 
    }

    Shutdown_Error ¶

    Shutdown_Error :: enum i32 {
    	None           = 0, 
    	Aborted        = 10053, 
    	Reset          = 10054, 
    	Offline        = 10050, 
    	Not_Connected  = 10057, 
    	Not_Socket     = 10038, 
    	Invalid_Manner = 10022, 
    }

    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                               = 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          = 10050, 
    	Timeout_When_Keepalive_Set         = 10052, 
    	Invalid_Option_For_Socket          = 10042, 
    	Reset_When_Keepalive_Set           = 10057, 
    	Not_Socket                         = 10038, 
    }

    Socket_Protocol ¶

    Socket_Protocol :: enum int {
    	TCP, 
    	UDP, 
    }
    Related Procedures With Parameters

    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                      = 0, 
    	Network_Subsystem_Failure = 10050, 
    	Not_Connected             = 10057, 
    	Bad_Buffer                = 10014, 
    	Keepalive_Failure         = 10052, 
    	Not_Socket                = 10038, 
    	Shutdown                  = 10058, 
    	Would_Block               = 10035, 
    	Aborted                   = 10053, 
    	Timeout                   = 10060, 
    	// TODO(tetra): Determine when this is different from the syscall returning n=0 and maybe normalize them?
    	Connection_Closed         = 10054, 
    	// TODO: verify can actually happen
    	Host_Unreachable          = 10065, 
    }

    TCP_Send_Error ¶

    TCP_Send_Error :: enum i32 {
    	None                      = 0, 
    	Aborted                   = 10053, 
    	Not_Connected             = 10057, 
    	Shutdown                  = 10058, 
    	Connection_Closed         = 10054, 
    	No_Buffer_Space_Available = 10055, 
    	Network_Subsystem_Failure = 10050, 
    	Host_Unreachable          = 10065, 
    	// TODO: verify possible, as not mentioned in docs
    	Offline                   = 10051, 
    	Timeout                   = 10060, 
    	// A broadcast address was specified, but the .Broadcast socket option isn't set.
    	Broadcast_Disabled        = 10013, 
    	Bad_Buffer                = 10014, 
    	// Connection is broken due to keepalive activity detecting a failure during the operation.
    	Keepalive_Failure         = 10052, // TODO: not functionally different from Reset; merge?
    	Not_Socket                = 10038, // The so-called socket is not an open socket.
    }
     

    TODO: consider merging some errors to make handling them easier TODO: verify once more what errors to actually expose

    TCP_Socket ¶

    TCP_Socket :: distinct i64
    Related Procedures With Parameters
    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                      = 0, 
    	Network_Subsystem_Failure = 10050, 
    	Aborted                   = 10053, 
    	Buffer_Too_Small          = 10040, // The buffer is too small to fit the entire message, and the message was truncated. When this happens, the rest of message is lost.
    	Remote_Not_Listening      = 10054, // The machine at the remote endpoint doesn't have the given port open to receiving UDP data.
    	Shutdown                  = 10058, 
    	Broadcast_Disabled        = 10013, // A broadcast address was specified, but the .Broadcast socket option isn't set.
    	Bad_Buffer                = 10014, 
    	No_Buffer_Space_Available = 10055, 
    	Not_Socket                = 10038, // The socket is not valid socket handle.
    	Would_Block               = 10035, 
    	Host_Unreachable          = 10065, // The remote host cannot be reached from this host at this time.
    	Offline                   = 10051, // The network cannot be reached from this host at this time.
    	Timeout                   = 10060, 
    	// TODO: can this actually happen? The socket isn't bound; an unknown flag specified; or MSG_OOB specified with SO_OOBINLINE enabled.
    	Incorrectly_Configured    = 10022, 
    	TTL_Expired               = 10052, // The message took more hops than was allowed (the Time To Live) to reach the remote endpoint.
    }

    UDP_Send_Error ¶

    UDP_Send_Error :: enum i32 {
    	None                                 = 0, 
    	Network_Subsystem_Failure            = 10050, 
    	Aborted                              = 10053, 
    	Message_Too_Long                     = 10040, // The message is larger than the maximum UDP packet size.
    	Remote_Not_Listening                 = 10054, // The machine at the remote endpoint doesn't have the given port open to receiving UDP data.
    	Shutdown                             = 10058, // A broadcast address was specified, but the .Broadcast socket option isn't set.
    	Broadcast_Disabled                   = 10013, 
    	Bad_Buffer                           = 10014, // Connection is broken due to keepalive activity detecting a failure during the operation.
    	// TODO: not functionally different from Reset; merge?
    	Keepalive_Failure                    = 10052, 
    	No_Buffer_Space_Available            = 10055, 
    	Not_Socket                           = 10038, // 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                         = 10045, 
    	Would_Block                          = 10035, 
    	Host_Unreachable                     = 10065, // The remote host cannot be reached from this host at this time.
    	Cannot_Use_Any_Address               = 10049, // Attempt to send to the Any address.
    	Family_Not_Supported_For_This_Socket = 10047, // The address is of an incorrect address family for this socket.
    	Offline                              = 10051, // The network cannot be reached from this host at this time.
    	Timeout                              = 10060, 
    }

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

    IPv6_MAX_STRING_LENGTH ¶

    IPv6_MAX_STRING_LENGTH :: 45

    IPv6_MIN_COLONS ¶

    IPv6_MIN_COLONS :: 2

    IPv6_MIN_STRING_LENGTH ¶

    IPv6_MIN_STRING_LENGTH :: 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 :: 8

    LABEL_MAX ¶

    LABEL_MAX :: 63

    MAX_INTERFACE_ENUMERATION_TRIES ¶

    MAX_INTERFACE_ENUMERATION_TRIES :: 3

    NAME_MAX ¶

    NAME_MAX :: 255

    ODIN_NET_TCP_NODELAY_DEFAULT ¶

    ODIN_NET_TCP_NODELAY_DEFAULT :: #config(ODIN_NET_TCP_NODELAY_DEFAULT, true)

    Variables

    IP4_Loopback ¶

    IP4_Loopback: IP4_Address = …

    IP6_Loopback ¶

    IP6_Loopback: IP6_Address = …

    default_tcp_options ¶

    default_tcp_options: TCP_Options = …

    Procedures

    accept_tcp ¶

    accept_tcp :: proc(socket: TCP_Socket, options: TCP_Options = default_tcp_options) -> (client: TCP_Socket, source: Endpoint, err: Network_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: Network_Error) {…}

    close ¶

    close :: proc(socket: Any_Socket) {…}

    create_socket ¶

    create_socket :: proc(family: Address_Family, protocol: Socket_Protocol) -> (socket: Any_Socket, err: Network_Error) {…}

    decode_hostname ¶

    decode_hostname :: proc(packet: []u8, start_idx: int, allocator := context.allocator) -> (hostname: string, encode_size: int, ok: bool) {…}

    destroy_dns_configuration ¶

    destroy_dns_configuration :: proc() {…}

    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

    dial_tcp_from_endpoint ¶

    dial_tcp_from_endpoint :: proc(endpoint: Endpoint, options: TCP_Options = default_tcp_options) -> (socket: TCP_Socket, err: Network_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 resolve, then dial_tcp_from_endpoint.

    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.

    encode_hostname ¶

    encode_hostname :: proc(b: ^strings.Builder, hostname: string) -> (ok: bool) {…}
     

    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: Network_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.

    join_url ¶

    join_url :: proc(
    	scheme, host, path: string, 
    	queries:            map[string]string, 
    	fragment:           string, 
    	allocator := context.allocator, 
    ) -> string {…}

    listen_tcp ¶

    listen_tcp :: proc(interface_endpoint: Endpoint, backlog: int = 1000) -> (socket: TCP_Socket, err: Network_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.
    

    make_unbound_udp_socket ¶

    make_unbound_udp_socket :: proc(family: Address_Family) -> (socket: UDP_Socket, err: Network_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.
    

    map_to_ip6 ¶

    map_to_ip6 :: proc(addr: Address) -> Address {…}
     

    TODO(tetra): Do we need this?

    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_endpoint ¶

    parse_endpoint :: proc(endpoint_str: string) -> (ep: Endpoint, ok: bool) {…}

    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, 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`.
    

    recv_tcp ¶

    recv_tcp :: proc(socket: TCP_Socket, buf: []u8) -> (bytes_read: int, err: Network_Error) {…}

    recv_udp ¶

    recv_udp :: proc(socket: UDP_Socket, buf: []u8) -> (bytes_read: int, remote_endpoint: Endpoint, err: Network_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) {…}

    send_tcp ¶

    send_tcp :: proc(socket: TCP_Socket, buf: []u8) -> (bytes_written: int, err: Network_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: Network_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: Network_Error) {…}

    set_option ¶

    set_option :: proc(socket: Any_Socket, option: Socket_Option, value: any, loc := #caller_location) -> Network_Error {…}

    shutdown ¶

    shutdown :: proc(socket: Any_Socket, manner: Shutdown_Manner) -> (err: Network_Error) {…}

    skip_hostname ¶

    skip_hostname :: proc(packet: []u8, start_idx: int) -> (encode_size: int, ok: bool) {…}

    split_port ¶

    split_port :: proc(endpoint_str: string) -> (addr_or_host: string, port: int, ok: bool) {…}
     

    Takes an endpoint string and returns its parts. Returns ok=false if port is not a number.

    split_url ¶

    split_url :: proc(url: string, allocator := context.allocator) -> (scheme, host, path: string, queries: map[string]string, fragment: string) {…}

    unpack_dns_header ¶

    unpack_dns_header :: proc(id: u16be, bits: u16be) -> (hdr: DNS_Header) {…}

    validate_hostname ¶

    validate_hostname :: proc(hostname: string) -> (ok: bool) {…}
     

    Uses RFC 952 & RFC 1123

    Procedure Groups

    Source Files

    Generation Information

    Generated with odin version dev-2024-04 (vendor "odin") Windows_amd64 @ 2024-04-19 21:09:18.878920100 +0000 UTC