123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416 |
- // +build windows, linux, darwin
- package net
- /*
- Package net implements cross-platform Berkeley Sockets, DNS resolution and associated procedures.
- For other protocols and their features, see subdirectories of this package.
- This file collects structs, enums and settings applicable to the entire package in one handy place.
- Platform-specific ones can be found in their respective `*_windows.odin` and similar files.
- */
- /*
- Copyright 2022 Tetralux <[email protected]>
- Copyright 2022 Colin Davidson <[email protected]>
- Copyright 2022 Jeroen van Rijn <[email protected]>.
- 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 "base:runtime"
- /*
- TUNEABLES - See also top of `dns.odin` for DNS configuration.
- Determines the default value for whether dial_tcp() and accept_tcp() will set TCP_NODELAY on the new
- socket, and the client socket, respectively.
- This can also be set on a per-socket basis using the 'options' optional parameter to those procedures.
- When TCP_NODELAY is set, data will be sent out to the peer as quickly as possible, rather than being
- coalesced into fewer network packets.
- This makes the networking layer more eagerly send data when you ask it to,
- which can reduce latency by up to 200ms.
- This does mean that a lot of small writes will negatively effect throughput however,
- since the Nagle algorithm will be disabled, and each write becomes one
- IP packet. This will increase traffic by a factor of 40, with IP and TCP
- headers for each payload.
- However, you can avoid this by buffering things up yourself if you wish to send a lot of
- short data chunks, when TCP_NODELAY is enabled on that socket.
- */
- ODIN_NET_TCP_NODELAY_DEFAULT :: #config(ODIN_NET_TCP_NODELAY_DEFAULT, true)
- // COMMON DEFINITIONS
- Maybe :: runtime.Maybe
- Network_Error :: union #shared_nil {
- General_Error,
- Platform_Error,
- 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,
- Socket_Option_Error,
- Set_Blocking_Error,
- Parse_Endpoint_Error,
- Resolve_Error,
- DNS_Error,
- }
- General_Error :: enum u32 {
- None = 0,
- Unable_To_Enumerate_Network_Interfaces = 1,
- }
- // `Platform_Error` is used to wrap errors returned by the different platforms that don't fit a common error.
- Platform_Error :: enum u32 {}
- Parse_Endpoint_Error :: enum {
- None = 0,
- Bad_Port = 1,
- Bad_Address,
- Bad_Hostname,
- }
- Resolve_Error :: enum u32 {
- None = 0,
- Unable_To_Resolve = 1,
- }
- DNS_Error :: enum u32 {
- Invalid_Hostname_Error = 1,
- Invalid_Hosts_Config_Error,
- Invalid_Resolv_Config_Error,
- Connection_Error,
- Server_Error,
- System_Error,
- }
- // SOCKET OPTIONS & DEFINITIONS
- TCP_Options :: struct {
- no_delay: bool,
- }
- default_tcp_options := TCP_Options {
- no_delay = ODIN_NET_TCP_NODELAY_DEFAULT,
- }
- /*
- 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.
- */
- Socket :: distinct i64
- TCP_Socket :: distinct Socket
- UDP_Socket :: distinct Socket
- Socket_Protocol :: enum {
- TCP,
- UDP,
- }
- Any_Socket :: union {
- TCP_Socket,
- UDP_Socket,
- }
- /*
- ADDRESS DEFINITIONS
- */
- IP4_Address :: distinct [4]u8
- IP6_Address :: distinct [8]u16be
- Address :: union {IP4_Address, IP6_Address}
- IP4_Loopback := IP4_Address{127, 0, 0, 1}
- IP6_Loopback := IP6_Address{0, 0, 0, 0, 0, 0, 0, 1}
- IP4_Any := IP4_Address{}
- IP6_Any := IP6_Address{}
- Endpoint :: struct {
- address: Address,
- port: int,
- }
- Address_Family :: enum {
- IP4,
- IP6,
- }
- Netmask :: distinct Address
- /*
- INTERFACE / LINK STATE
- */
- 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: Link_State,
- transmit_speed: u64,
- receive_speed: u64,
- },
- }
- // Empty bit set is unknown state.
- Link_States :: enum u32 {
- Up = 1,
- Down = 2,
- Testing = 3,
- Dormant = 4,
- Not_Present = 5,
- Lower_Layer_Down = 6,
- Loopback = 7,
- }
- Link_State :: bit_set[Link_States; u32]
- 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,
- }
- Tunnel_Type :: enum i32 {
- None = 0,
- Other = 1,
- Direct = 2,
- IPv4_To_IPv6 = 11,
- ISA_TAP = 13,
- Teredo = 14,
- IP_HTTPS = 15,
- }
- Prefix_Origin :: enum i32 {
- Other = 0,
- Manual = 1,
- Well_Known = 2,
- DHCP = 3,
- Router_Advertisement = 4,
- Unchanged = 16,
- }
- Suffix_Origin :: enum i32 {
- Other = 0,
- Manual = 1,
- Well_Known = 2,
- DHCP = 3,
- Link_Layer_Address = 4,
- Random = 5,
- Unchanged = 16,
- }
- Address_Duplication :: enum i32 {
- Invalid = 0,
- Tentative = 1,
- Duplicate = 2,
- Deprecated = 3,
- Preferred = 4,
- }
- // DNS DEFINITIONS
- 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_Record_Type :: enum u16 {
- DNS_TYPE_A = 0x1, // IP4 address.
- DNS_TYPE_NS = 0x2, // IP6 address.
- DNS_TYPE_CNAME = 0x5, // Another host name.
- DNS_TYPE_MX = 0xf, // Arbitrary binary data or text.
- DNS_TYPE_AAAA = 0x1c, // Address of a name (DNS) server.
- DNS_TYPE_TEXT = 0x10, // Address and preference priority of a mail exchange server.
- DNS_TYPE_SRV = 0x21, // Address, port, priority, and weight of a host that provides a particular service.
- IP4 = DNS_TYPE_A,
- IP6 = DNS_TYPE_AAAA,
- CNAME = DNS_TYPE_CNAME,
- TXT = DNS_TYPE_TEXT,
- NS = DNS_TYPE_NS,
- MX = DNS_TYPE_MX,
- SRV = DNS_TYPE_SRV,
- }
- // Base DNS Record. All DNS responses will carry a hostname and TTL (time to live) field.
- DNS_Record_Base :: struct {
- record_name: string,
- ttl_seconds: u32, // The time in seconds that this service will take to update, after the record is updated.
- }
- // An IP4 address that the domain name maps to. There can be any number of these.
- DNS_Record_IP4 :: struct {
- using base: DNS_Record_Base,
- address: IP4_Address,
- }
- // An IPv6 address that the domain name maps to. There can be any number of these.
- DNS_Record_IP6 :: struct {
- using base: DNS_Record_Base,
- address: IP6_Address,
- }
- /*
- 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_CNAME :: struct {
- using base: DNS_Record_Base,
- host_name: 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_TXT :: struct {
- using base: DNS_Record_Base,
- value: 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_NS :: struct {
- using base: DNS_Record_Base,
- host_name: string,
- }
- // 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_MX :: struct {
- using base: DNS_Record_Base,
- host_name: string,
- preference: 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_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, // NOTE(tetra): These are substrings of 'record_name'
- // 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,
- }
- DNS_Record :: union {
- DNS_Record_IP4,
- DNS_Record_IP6,
- DNS_Record_CNAME,
- DNS_Record_TXT,
- DNS_Record_NS,
- DNS_Record_MX,
- DNS_Record_SRV,
- }
- DNS_Response_Code :: enum u16be {
- No_Error,
- Format_Error,
- Server_Failure,
- Name_Error,
- Not_Implemented,
- Refused,
- }
- DNS_Query :: enum u16be {
- Host_Address = 1,
- Authoritative_Name_Server = 2,
- Mail_Destination = 3,
- Mail_Forwarder = 4,
- CNAME = 5,
- All = 255,
- }
- 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,
- }
- DNS_Record_Header :: struct #packed {
- type: u16be,
- class: u16be,
- ttl: u32be,
- length: u16be,
- }
- DNS_Host_Entry :: struct {
- name: string,
- addr: Address,
- }
|