aboutsummaryrefslogtreecommitdiff
path: root/core/net
diff options
context:
space:
mode:
authorLaytan Laats <laytanlaats@hotmail.com>2026-01-11 20:07:03 +0100
committerLaytan Laats <laytanlaats@hotmail.com>2026-01-11 20:21:21 +0100
commitc10771305d91b966f7520b830c398abffe4e9e1d (patch)
tree185497758d0298c4e23f15992a0bb48a44936863 /core/net
parenta6ec199a52ae83603921fcf948fdf45e327fd17d (diff)
net: implement OpenBSD and NetBSD support & add stubs for other targets & cleanup
Diffstat (limited to 'core/net')
-rw-r--r--core/net/addr.odin51
-rw-r--r--core/net/common.odin10
-rw-r--r--core/net/dns.odin182
-rw-r--r--core/net/dns_os.odin24
-rw-r--r--core/net/dns_others.odin12
-rw-r--r--core/net/dns_unix.odin13
-rw-r--r--core/net/dns_windows.odin22
-rw-r--r--core/net/errors.odin10
-rw-r--r--core/net/errors_others.odin9
-rw-r--r--core/net/errors_posix.odin (renamed from core/net/errors_darwin.odin)2
-rw-r--r--core/net/errors_windows.odin4
-rw-r--r--core/net/interface_others.odin11
-rw-r--r--core/net/interface_posix.odin (renamed from core/net/interface_darwin.odin)59
-rw-r--r--core/net/socket.odin30
-rw-r--r--core/net/socket_freebsd.odin60
-rw-r--r--core/net/socket_linux.odin47
-rw-r--r--core/net/socket_others.odin105
-rw-r--r--core/net/socket_posix.odin (renamed from core/net/socket_darwin.odin)47
-rw-r--r--core/net/socket_windows.odin81
19 files changed, 502 insertions, 277 deletions
diff --git a/core/net/addr.odin b/core/net/addr.odin
index 6e2881ac8..a3fa02cce 100644
--- a/core/net/addr.odin
+++ b/core/net/addr.odin
@@ -1,4 +1,3 @@
-#+build windows, linux, darwin, freebsd
package net
/*
@@ -22,7 +21,6 @@ package net
import "core:strconv"
import "core:strings"
-import "core:fmt"
/*
Expects an IPv4 address with no leading or trailing whitespace:
@@ -473,13 +471,20 @@ join_port :: proc(address_or_host: string, port: int, allocator := context.alloc
addr := parse_address(addr_or_host)
if addr == nil {
// hostname
- fmt.sbprintf(&b, "%v:%v", addr_or_host, port)
+ strings.write_string(&b, addr_or_host)
+ strings.write_string(&b, ":")
+ strings.write_int(&b, port)
} else {
switch _ in addr {
case IP4_Address:
- fmt.sbprintf(&b, "%v:%v", address_to_string(addr), port)
+ strings.write_string(&b, address_to_string(addr))
+ strings.write_string(&b, ":")
+ strings.write_int(&b, port)
case IP6_Address:
- fmt.sbprintf(&b, "[%v]:%v", address_to_string(addr), port)
+ strings.write_string(&b, "[")
+ strings.write_string(&b, address_to_string(addr))
+ strings.write_string(&b, "]:")
+ strings.write_int(&b, port)
}
}
return strings.to_string(b)
@@ -509,7 +514,13 @@ address_to_string :: proc(addr: Address, allocator := context.temp_allocator) ->
b := strings.builder_make(allocator)
switch v in addr {
case IP4_Address:
- fmt.sbprintf(&b, "%v.%v.%v.%v", v[0], v[1], v[2], v[3])
+ strings.write_uint(&b, uint(v[0]))
+ strings.write_byte(&b, '.')
+ strings.write_uint(&b, uint(v[1]))
+ strings.write_byte(&b, '.')
+ strings.write_uint(&b, uint(v[2]))
+ strings.write_byte(&b, '.')
+ strings.write_uint(&b, uint(v[3]))
case IP6_Address:
// First find the longest run of zeroes.
Zero_Run :: struct {
@@ -563,25 +574,33 @@ address_to_string :: proc(addr: Address, allocator := context.temp_allocator) ->
for val, i in v {
if best.start == i || best.end == i {
// For the left and right side of the best zero run, print a `:`.
- fmt.sbprint(&b, ":")
+ strings.write_string(&b, ":")
} else if i < best.start {
/*
If we haven't made it to the best run yet, print the digit.
Make sure we only print a `:` after the digit if it's not
immediately followed by the run's own leftmost `:`.
*/
- fmt.sbprintf(&b, "%x", val)
+
+ buf: [32]byte
+ str := strconv.write_bits(buf[:], u64(val), 16, false, size_of(val), strconv.digits, {})
+ strings.write_string(&b, str)
+
if i < best.start - 1 {
- fmt.sbprintf(&b, ":")
+ strings.write_string(&b, ":")
}
} else if i > best.end {
/*
If there are any digits after the zero run, print them.
But don't print the `:` at the end of the IP number.
*/
- fmt.sbprintf(&b, "%x", val)
+
+ buf: [32]byte
+ str := strconv.write_bits(buf[:], u64(val), 16, false, size_of(val), strconv.digits, {})
+ strings.write_string(&b, str)
+
if i != 7 {
- fmt.sbprintf(&b, ":")
+ strings.write_string(&b, ":")
}
}
}
@@ -598,8 +617,14 @@ endpoint_to_string :: proc(ep: Endpoint, allocator := context.temp_allocator) ->
s := address_to_string(ep.address, context.temp_allocator)
b := strings.builder_make(allocator)
switch a in ep.address {
- case IP4_Address: fmt.sbprintf(&b, "%v:%v", s, ep.port)
- case IP6_Address: fmt.sbprintf(&b, "[%v]:%v", s, ep.port)
+ case IP4_Address:
+ strings.write_string(&b, s)
+ strings.write_int(&b, ep.port)
+ case IP6_Address:
+ strings.write_string(&b, "[")
+ strings.write_string(&b, s)
+ strings.write_string(&b, "]:")
+ strings.write_int(&b, ep.port)
}
return strings.to_string(b)
}
diff --git a/core/net/common.odin b/core/net/common.odin
index 70523050f..2758a7359 100644
--- a/core/net/common.odin
+++ b/core/net/common.odin
@@ -1,4 +1,3 @@
-#+build windows, linux, darwin, freebsd
package net
/*
@@ -91,6 +90,7 @@ Parse_Endpoint_Error :: enum u32 {
Resolve_Error :: enum u32 {
None = 0,
Unable_To_Resolve = 1,
+ Allocation_Failure,
}
DNS_Error :: enum u32 {
@@ -144,11 +144,11 @@ 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{}
+IP4_Any :: IP4_Address{}
+IP6_Any :: IP6_Address{}
-IP4_mDNS_Broadcast := Endpoint{address=IP4_Address{224, 0, 0, 251}, port=5353}
-IP6_mDNS_Broadcast := Endpoint{address=IP6_Address{65282, 0, 0, 0, 0, 0, 0, 251}, port = 5353}
+IP4_mDNS_Broadcast :: Endpoint{address=IP4_Address{224, 0, 0, 251}, port=5353}
+IP6_mDNS_Broadcast :: Endpoint{address=IP6_Address{65282, 0, 0, 0, 0, 0, 0, 251}, port = 5353}
Endpoint :: struct {
address: Address,
diff --git a/core/net/dns.odin b/core/net/dns.odin
index 540991fe7..983f82681 100644
--- a/core/net/dns.odin
+++ b/core/net/dns.odin
@@ -1,4 +1,3 @@
-#+build windows, linux, darwin, freebsd
package net
/*
@@ -22,13 +21,18 @@ package net
Haesbaert: Security fixes
*/
-@(require) import "base:runtime"
+@(require)
+import "base:runtime"
+
+import "core:bufio"
+import "core:io"
+import "core:math/rand"
import "core:mem"
import "core:strings"
import "core:time"
-import "core:os"
-import "core:math/rand"
-@(require) import "core:sync"
+
+@(require)
+import "core:sync"
dns_config_initialized: sync.Once
when ODIN_OS == .Windows {
@@ -42,20 +46,12 @@ when ODIN_OS == .Windows {
hosts_file = "/etc/hosts",
}
} else {
- #panic("Please add a configuration for this OS.")
+ DEFAULT_DNS_CONFIGURATION :: DNS_Configuration{}
}
-/*
- Replaces environment placeholders in `dns_configuration`. Only necessary on Windows.
- Is automatically called, once, by `get_dns_records_*`.
-*/
-@(private)
init_dns_configuration :: proc() {
when ODIN_OS == .Windows {
- runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
- val := os.replace_environment_placeholders(dns_configuration.hosts_file, context.temp_allocator)
- copy(dns_configuration.hosts_file_buf[:], val)
- dns_configuration.hosts_file = string(dns_configuration.hosts_file_buf[:len(val)])
+ _init_dns_configuration()
}
}
@@ -178,9 +174,7 @@ resolve_ip6 :: proc(hostname_and_maybe_port: string) -> (ep6: Endpoint, err: Net
See `destroy_records`.
*/
get_dns_records_from_os :: proc(hostname: string, type: DNS_Record_Type, allocator := context.allocator) -> (records: []DNS_Record, err: DNS_Error) {
- when ODIN_OS == .Windows {
- sync.once_do(&dns_config_initialized, init_dns_configuration)
- }
+ init_dns_configuration()
return _get_dns_records_os(hostname, type, allocator)
}
@@ -196,51 +190,14 @@ get_dns_records_from_os :: proc(hostname: string, type: DNS_Record_Type, allocat
See `destroy_records`.
*/
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) {
- when ODIN_OS == .Windows {
- sync.once_do(&dns_config_initialized, init_dns_configuration)
- }
+ init_dns_configuration()
context.allocator = allocator
- if type != .SRV {
- // NOTE(tetra): 'hostname' can contain underscores when querying SRV records
- ok := validate_hostname(hostname)
- if !ok {
- return nil, .Invalid_Hostname_Error
- }
- }
-
- hdr := DNS_Header{
- id = u16be(rand.uint32()),
- is_response = false,
- opcode = 0,
- is_authoritative = false,
- is_truncated = false,
- is_recursion_desired = true,
- is_recursion_available = false,
- response_code = DNS_Response_Code.No_Error,
- }
+ id := u16be(rand.uint32())
+ dns_packet_buf: [DNS_PACKET_MIN_LEN]byte = ---
+ dns_packet := make_dns_packet(dns_packet_buf[:], id, hostname, type) or_return
- id, bits := pack_dns_header(hdr)
- dns_hdr := [6]u16be{}
- dns_hdr[0] = id
- dns_hdr[1] = bits
- dns_hdr[2] = 1
-
- dns_query := [2]u16be{ u16be(type), 1 }
-
- output := [(size_of(u16be) * 6) + NAME_MAX + (size_of(u16be) * 2)]u8{}
- b := strings.builder_from_slice(output[:])
-
- strings.write_bytes(&b, mem.slice_data_cast([]u8, dns_hdr[:]))
- ok := encode_hostname(&b, hostname)
- if !ok {
- return nil, .Invalid_Hostname_Error
- }
- strings.write_bytes(&b, mem.slice_data_cast([]u8, dns_query[:]))
-
- dns_packet := output[:strings.builder_len(b)]
-
- dns_response_buf := [4096]u8{}
+ dns_response_buf: [4096]u8 = ---
dns_response: []u8
for name_server in name_servers {
conn, sock_err := make_unbound_udp_socket(family_from_endpoint(name_server))
@@ -283,6 +240,42 @@ get_dns_records_from_nameservers :: proc(hostname: string, type: DNS_Record_Type
return
}
+DNS_PACKET_MIN_LEN :: (size_of(u16be) * 6) + NAME_MAX + (size_of(u16be) * 2)
+
+make_dns_packet :: proc(buf: []byte, id: u16be, hostname: string, type: DNS_Record_Type) -> (packet: []byte, err: DNS_Error) {
+ assert(len(buf) >= DNS_PACKET_MIN_LEN)
+
+ hdr := DNS_Header{
+ id = id,
+ is_response = false,
+ opcode = 0,
+ is_authoritative = false,
+ is_truncated = false,
+ is_recursion_desired = true,
+ is_recursion_available = false,
+ response_code = DNS_Response_Code.No_Error,
+ }
+
+ _, bits := pack_dns_header(hdr)
+ dns_hdr := [6]u16be{}
+ dns_hdr[0] = id
+ dns_hdr[1] = bits
+ dns_hdr[2] = 1
+
+ dns_query := [2]u16be{ u16be(type), 1 }
+
+ b := strings.builder_from_slice(buf[:])
+
+ strings.write_bytes(&b, mem.slice_data_cast([]u8, dns_hdr[:]))
+ ok := encode_hostname(&b, hostname)
+ if !ok {
+ return nil, .Invalid_Hostname_Error
+ }
+ strings.write_bytes(&b, mem.slice_data_cast([]u8, dns_query[:]))
+
+ return buf[:strings.builder_len(b)], nil
+}
+
// `records` slice is also destroyed.
destroy_dns_records :: proc(records: []DNS_Record, allocator := context.allocator) {
context.allocator = allocator
@@ -364,13 +357,8 @@ unpack_dns_header :: proc(id: u16be, bits: u16be) -> (hdr: DNS_Header) {
return hdr
}
-load_resolv_conf :: proc(resolv_conf_path: string, allocator := context.allocator) -> (name_servers: []Endpoint, ok: bool) {
- context.allocator = allocator
-
- res := os.read_entire_file_from_filename(resolv_conf_path) or_return
- defer delete(res)
- resolv_str := string(res)
-
+parse_resolv_conf :: proc(resolv_str: string, allocator := context.allocator) -> (name_servers: []Endpoint) {
+ resolv_str := resolv_str
id_str := "nameserver"
id_len := len(id_str)
@@ -401,41 +389,51 @@ load_resolv_conf :: proc(resolv_conf_path: string, allocator := context.allocato
append(&_name_servers, endpoint)
}
- return _name_servers[:], true
+ return _name_servers[:]
}
-load_hosts :: proc(hosts_file_path: string, allocator := context.allocator) -> (hosts: []DNS_Host_Entry, ok: bool) {
- context.allocator = allocator
+parse_hosts :: proc(stream: io.Stream, allocator := context.allocator) -> (hosts: []DNS_Host_Entry, ok: bool) {
+ s := bufio.scanner_init(&{}, stream, allocator)
+ defer bufio.scanner_destroy(s)
- res := os.read_entire_file_from_filename(hosts_file_path, allocator) or_return
- defer delete(res)
+ resize(&s.buf, 256)
- _hosts := make([dynamic]DNS_Host_Entry, 0, allocator)
- hosts_str := string(res)
- for line in strings.split_lines_iterator(&hosts_str) {
- if len(line) == 0 || line[0] == '#' {
- continue
+ _hosts: [dynamic]DNS_Host_Entry
+ _hosts.allocator = allocator
+ defer if !ok {
+ for host in _hosts {
+ delete(host.name, allocator)
}
+ delete(_hosts)
+ }
- splits := strings.fields(line)
- defer delete(splits)
+ for bufio.scanner_scan(s) {
+ line := bufio.scanner_text(s)
- (len(splits) >= 2) or_continue
+ line, _, _ = strings.partition(line, "#")
+ (len(line) > 0) or_continue
+
+ ip_str := strings.fields_iterator(&line) or_continue
- ip_str := splits[0]
addr := parse_address(ip_str)
- if addr == nil {
- continue
- }
+ (addr != nil) or_continue
- for hostname in splits[1:] {
- if len(hostname) != 0 {
- append(&_hosts, DNS_Host_Entry{hostname, addr})
- }
+ for hostname in strings.fields_iterator(&line) {
+ (len(hostname) > 0) or_continue
+
+ clone, alloc_err := strings.clone(hostname, allocator)
+ if alloc_err != nil { return }
+
+ _, alloc_err = append(&_hosts, DNS_Host_Entry{clone, addr})
+ if alloc_err != nil { return }
}
}
- return _hosts[:], true
+ if bufio.scanner_error(s) != nil { return }
+
+ hosts = _hosts[:]
+ ok = true
+ return
}
// www.google.com -> 3www6google3com0
@@ -594,7 +592,7 @@ decode_hostname :: proc(packet: []u8, start_idx: int, allocator := context.alloc
// Uses RFC 952 & RFC 1123
validate_hostname :: proc(hostname: string) -> (ok: bool) {
- if len(hostname) > 255 || len(hostname) == 0 {
+ if len(hostname) > NAME_MAX || len(hostname) == 0 {
return
}
@@ -604,7 +602,7 @@ validate_hostname :: proc(hostname: string) -> (ok: bool) {
_hostname := hostname
for label in strings.split_iterator(&_hostname, ".") {
- if len(label) > 63 || len(label) == 0 {
+ if len(label) > LABEL_MAX || len(label) == 0 {
return
}
@@ -868,4 +866,4 @@ parse_response :: proc(response: []u8, filter: DNS_Record_Type = nil, allocator
xid = hdr.id
return _records[:], xid, true
-} \ No newline at end of file
+}
diff --git a/core/net/dns_os.odin b/core/net/dns_os.odin
new file mode 100644
index 000000000..19db0097a
--- /dev/null
+++ b/core/net/dns_os.odin
@@ -0,0 +1,24 @@
+#+build darwin, freebsd, openbsd, netbsd, linux, windows, wasi
+#+private
+package net
+
+import "core:os"
+
+load_resolv_conf :: proc(resolv_conf_path: string, allocator := context.allocator) -> (name_servers: []Endpoint, ok: bool) {
+ context.allocator = allocator
+
+ res := os.read_entire_file_from_filename(resolv_conf_path) or_return
+ defer delete(res)
+ resolv_str := string(res)
+
+ return parse_resolv_conf(resolv_str), true
+}
+
+load_hosts :: proc(hosts_file_path: string, allocator := context.allocator) -> (hosts: []DNS_Host_Entry, ok: bool) {
+ hosts_file, err := os.open(hosts_file_path)
+ if err != nil { return }
+ defer os.close(hosts_file)
+
+ return parse_hosts(os.stream_from_handle(hosts_file), allocator)
+}
+
diff --git a/core/net/dns_others.odin b/core/net/dns_others.odin
new file mode 100644
index 000000000..842e833aa
--- /dev/null
+++ b/core/net/dns_others.odin
@@ -0,0 +1,12 @@
+#+build !windows
+#+build !linux
+#+build !darwin
+#+build !freebsd
+#+build !netbsd
+#+build !openbsd
+package net
+
+@(private)
+_get_dns_records_os :: proc(hostname: string, type: DNS_Record_Type, allocator := context.allocator) -> (records: []DNS_Record, err: DNS_Error) {
+ return
+}
diff --git a/core/net/dns_unix.odin b/core/net/dns_unix.odin
index fbc1909cd..be95b8341 100644
--- a/core/net/dns_unix.odin
+++ b/core/net/dns_unix.odin
@@ -1,4 +1,4 @@
-#+build linux, darwin, freebsd
+#+build linux, darwin, freebsd, openbsd, netbsd
package net
/*
Package net implements cross-platform Berkeley Sockets, DNS resolution and associated procedures.
@@ -42,14 +42,19 @@ _get_dns_records_os :: proc(hostname: string, type: DNS_Record_Type, allocator :
}
hosts, hosts_ok := load_hosts(dns_configuration.hosts_file)
- defer delete(hosts)
if !hosts_ok {
return nil, .Invalid_Hosts_Config_Error
}
+ defer {
+ for h in hosts {
+ delete(h.name)
+ }
+ delete(hosts)
+ }
host_overrides := make([dynamic]DNS_Record)
for host in hosts {
- if strings.compare(host.name, hostname) != 0 {
+ if host.name != hostname {
continue
}
@@ -79,4 +84,4 @@ _get_dns_records_os :: proc(hostname: string, type: DNS_Record_Type, allocator :
}
return get_dns_records_from_nameservers(hostname, type, name_servers, host_overrides[:])
-} \ No newline at end of file
+}
diff --git a/core/net/dns_windows.odin b/core/net/dns_windows.odin
index b1e7da97d..393df5fa7 100644
--- a/core/net/dns_windows.odin
+++ b/core/net/dns_windows.odin
@@ -20,11 +20,29 @@ package net
Feoramund: FreeBSD platform code
*/
-import "core:strings"
+import "base:runtime"
+
import "core:mem"
+import "core:os"
+import "core:strings"
+import "core:sync"
import win "core:sys/windows"
+/*
+ Replaces environment placeholders in `dns_configuration`. Only necessary on Windows.
+ Is automatically called, once, by `get_dns_records_*`.
+*/
+@(private)
+_init_dns_configuration :: proc() {
+ sync.once_do(&dns_config_initialized, proc() {
+ runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
+ val := os.replace_environment_placeholders(dns_configuration.hosts_file, context.temp_allocator)
+ copy(dns_configuration.hosts_file_buf[:], val)
+ dns_configuration.hosts_file = string(dns_configuration.hosts_file_buf[:len(val)])
+ })
+}
+
@(private)
_get_dns_records_os :: proc(hostname: string, type: DNS_Record_Type, allocator := context.allocator) -> (records: []DNS_Record, err: DNS_Error) {
context.allocator = allocator
@@ -171,4 +189,4 @@ _get_dns_records_os :: proc(hostname: string, type: DNS_Record_Type, allocator :
records = recs[:]
return
-} \ No newline at end of file
+}
diff --git a/core/net/errors.odin b/core/net/errors.odin
index de53640fc..28153375c 100644
--- a/core/net/errors.odin
+++ b/core/net/errors.odin
@@ -139,6 +139,11 @@ Accept_Error :: enum i32 {
Unknown,
}
+Recv_Error :: union #shared_nil {
+ TCP_Recv_Error,
+ UDP_Recv_Error,
+}
+
TCP_Recv_Error :: enum i32 {
None,
// No network connection, or the network stack is not initialized.
@@ -187,6 +192,11 @@ UDP_Recv_Error :: enum i32 {
Unknown,
}
+Send_Error :: union #shared_nil {
+ TCP_Send_Error,
+ UDP_Send_Error,
+}
+
TCP_Send_Error :: enum i32 {
None,
// No network connection, or the network stack is not initialized.
diff --git a/core/net/errors_others.odin b/core/net/errors_others.odin
index b80ead79c..3a752d58e 100644
--- a/core/net/errors_others.odin
+++ b/core/net/errors_others.odin
@@ -2,6 +2,8 @@
#+build !linux
#+build !freebsd
#+build !windows
+#+build !netbsd
+#+build !openbsd
package net
@(private="file", thread_local)
@@ -18,10 +20,3 @@ _last_platform_error_string :: proc() -> string {
_set_last_platform_error :: proc(err: i32) {
_last_error = err
}
-
-Parse_Endpoint_Error :: enum u32 {
- None = 0,
- Bad_Port = 1,
- Bad_Address,
- Bad_Hostname,
-} \ No newline at end of file
diff --git a/core/net/errors_darwin.odin b/core/net/errors_posix.odin
index a35e96bc0..b59cbc30b 100644
--- a/core/net/errors_darwin.odin
+++ b/core/net/errors_posix.odin
@@ -1,4 +1,4 @@
-#+build darwin
+#+build darwin, netbsd, openbsd
package net
/*
diff --git a/core/net/errors_windows.odin b/core/net/errors_windows.odin
index 83c45ee7f..6d3724c82 100644
--- a/core/net/errors_windows.odin
+++ b/core/net/errors_windows.odin
@@ -63,7 +63,7 @@ _dial_error :: proc() -> Dial_Error {
return .Already_Connecting
case .WSAEADDRNOTAVAIL, .WSAEAFNOSUPPORT, .WSAEFAULT, .WSAENOTSOCK, .WSAEINPROGRESS, .WSAEINVAL:
return .Invalid_Argument
- case .WSAECONNREFUSED:
+ case .WSAECONNREFUSED, .CONNECTION_REFUSED:
return .Refused
case .WSAEISCONN:
return .Already_Connected
@@ -122,7 +122,7 @@ _accept_error :: proc() -> Accept_Error {
return .Aborted
case .WSAEFAULT, .WSAEINPROGRESS, .WSAENOTSOCK:
return .Invalid_Argument
- case .WSAEINTR:
+ case .WSAEINTR, .OPERATION_ABORTED:
return .Interrupted
case .WSAEINVAL:
return .Not_Listening
diff --git a/core/net/interface_others.odin b/core/net/interface_others.odin
new file mode 100644
index 000000000..9a8a141df
--- /dev/null
+++ b/core/net/interface_others.odin
@@ -0,0 +1,11 @@
+#+build !darwin
+#+build !linux
+#+build !freebsd
+#+build !windows
+#+build !netbsd
+#+build !openbsd
+package net
+
+_enumerate_interfaces :: proc(allocator := context.allocator) -> (interfaces: []Network_Interface, err: Interfaces_Error) {
+ return
+}
diff --git a/core/net/interface_darwin.odin b/core/net/interface_posix.odin
index f18cff995..202951b29 100644
--- a/core/net/interface_darwin.odin
+++ b/core/net/interface_posix.odin
@@ -1,4 +1,4 @@
-#+build darwin
+#+build darwin, openbsd, netbsd
package net
/*
@@ -117,32 +117,47 @@ IF_Flag :: enum u32 {
BROADCAST,
DEBUG,
LOOPBACK,
- POINTTOPOINT,
- NOTRAILERS,
- RUNNING,
- NOARP,
- PROMISC,
- ALLMULTI,
- OACTIVE,
- SIMPLEX,
- LINK0,
- LINK1,
- LINK2,
- MULTICAST,
+ // NOTE: different order on other BSDs but we don't even need these.
+ // POINTTOPOINT,
+ // NOTRAILERS,
+ // RUNNING,
+ // NOARP,
+ // PROMISC,
+ // ALLMULTI,
+ // OACTIVE,
+ // SIMPLEX,
+ // LINK0,
+ // LINK1,
+ // LINK2,
+ // MULTICAST,
}
@(private)
IF_Flags :: bit_set[IF_Flag; u32]
-@(private)
-ifaddrs :: struct {
- next: ^ifaddrs,
- name: cstring,
- flags: IF_Flags,
- addr: ^posix.sockaddr,
- netmask: ^posix.sockaddr,
- dstaddr: ^posix.sockaddr,
- data: rawptr,
+when ODIN_OS == .Darwin || ODIN_OS == .OpenBSD {
+ @(private)
+ ifaddrs :: struct {
+ next: ^ifaddrs,
+ name: cstring,
+ flags: IF_Flags,
+ addr: ^posix.sockaddr,
+ netmask: ^posix.sockaddr,
+ dstaddr: ^posix.sockaddr,
+ data: rawptr,
+ }
+} else when ODIN_OS == .NetBSD {
+ @(private)
+ ifaddrs :: struct {
+ next: ^ifaddrs,
+ name: cstring,
+ flags: IF_Flags,
+ addr: ^posix.sockaddr,
+ netmask: ^posix.sockaddr,
+ dstaddr: ^posix.sockaddr,
+ data: rawptr,
+ addrflags: u32,
+ }
}
@(private)
diff --git a/core/net/socket.odin b/core/net/socket.odin
index edb47cd0b..e2f96e2f3 100644
--- a/core/net/socket.odin
+++ b/core/net/socket.odin
@@ -1,4 +1,3 @@
-#+build windows, linux, darwin, freebsd
package net
/*
@@ -20,6 +19,35 @@ package net
Feoramund: FreeBSD platform code
*/
+Socket_Option :: enum i32 {
+ Broadcast = i32(_SOCKET_OPTION_BROADCAST),
+ Reuse_Address = i32(_SOCKET_OPTION_REUSE_ADDRESS),
+ Keep_Alive = i32(_SOCKET_OPTION_KEEP_ALIVE),
+ Out_Of_Bounds_Data_Inline = i32(_SOCKET_OPTION_OUT_OF_BOUNDS_DATA_INLINE),
+ Linger = i32(_SOCKET_OPTION_LINGER),
+ Receive_Buffer_Size = i32(_SOCKET_OPTION_RECEIVE_BUFFER_SIZE),
+ Send_Buffer_Size = i32(_SOCKET_OPTION_SEND_BUFFER_SIZE),
+ Receive_Timeout = i32(_SOCKET_OPTION_RECEIVE_TIMEOUT),
+ Send_Timeout = i32(_SOCKET_OPTION_SEND_TIMEOUT),
+
+ TCP_Nodelay = i32(_SOCKET_OPTION_TCP_NODELAY),
+
+ Use_Loopback = i32(_SOCKET_OPTION_USE_LOOPBACK),
+ Reuse_Port = i32(_SOCKET_OPTION_REUSE_PORT),
+ No_SIGPIPE_From_EPIPE = i32(_SOCKET_OPTION_NO_SIGPIPE_FROM_EPIPE),
+ Reuse_Port_Load_Balancing = i32(_SOCKET_OPTION_REUSE_PORT_LOAD_BALANCING),
+
+ Exclusive_Addr_Use = i32(_SOCKET_OPTION_EXCLUSIVE_ADDR_USE),
+ Conditional_Accept = i32(_SOCKET_OPTION_CONDITIONAL_ACCEPT),
+ Dont_Linger = i32(_SOCKET_OPTION_DONT_LINGER),
+}
+
+Shutdown_Manner :: enum i32 {
+ Receive = i32(_SHUTDOWN_MANNER_RECEIVE),
+ Send = i32(_SHUTDOWN_MANNER_SEND),
+ Both = i32(_SHUTDOWN_MANNER_BOTH),
+}
+
any_socket_to_socket :: proc "contextless" (socket: Any_Socket) -> Socket {
switch s in socket {
case TCP_Socket: return Socket(s)
diff --git a/core/net/socket_freebsd.odin b/core/net/socket_freebsd.odin
index fa20742cb..bd600fd99 100644
--- a/core/net/socket_freebsd.odin
+++ b/core/net/socket_freebsd.odin
@@ -20,45 +20,35 @@ package net
Feoramund: FreeBSD platform code
*/
-import "core:c"
import "core:sys/freebsd"
import "core:time"
Fd :: freebsd.Fd
-Socket_Option :: enum c.int {
- // TODO: Test and implement more socket options.
- // DEBUG
- Reuse_Address = cast(c.int)freebsd.Socket_Option.REUSEADDR,
- Keep_Alive = cast(c.int)freebsd.Socket_Option.KEEPALIVE,
- // DONTROUTE
- Broadcast = cast(c.int)freebsd.Socket_Option.BROADCAST,
- Use_Loopback = cast(c.int)freebsd.Socket_Option.USELOOPBACK,
- Linger = cast(c.int)freebsd.Socket_Option.LINGER,
- Out_Of_Bounds_Data_Inline = cast(c.int)freebsd.Socket_Option.OOBINLINE,
- Reuse_Port = cast(c.int)freebsd.Socket_Option.REUSEPORT,
- // TIMESTAMP
- No_SIGPIPE_From_EPIPE = cast(c.int)freebsd.Socket_Option.NOSIGPIPE,
- // ACCEPTFILTER
- // BINTIME
- // NO_OFFLOAD
- // NO_DDP
- Reuse_Port_Load_Balancing = cast(c.int)freebsd.Socket_Option.REUSEPORT_LB,
- // RERROR
-
- Send_Buffer_Size = cast(c.int)freebsd.Socket_Option.SNDBUF,
- Receive_Buffer_Size = cast(c.int)freebsd.Socket_Option.RCVBUF,
- // SNDLOWAT
- // RCVLOWAT
- Send_Timeout = cast(c.int)freebsd.Socket_Option.SNDTIMEO,
- Receive_Timeout = cast(c.int)freebsd.Socket_Option.RCVTIMEO,
-}
+_SOCKET_OPTION_BROADCAST :: freebsd.Socket_Option.BROADCAST
+_SOCKET_OPTION_REUSE_ADDRESS :: freebsd.Socket_Option.REUSEADDR
+_SOCKET_OPTION_KEEP_ALIVE :: freebsd.Socket_Option.KEEPALIVE
+_SOCKET_OPTION_OUT_OF_BOUNDS_DATA_INLINE :: freebsd.Socket_Option.OOBINLINE
+_SOCKET_OPTION_LINGER :: freebsd.Socket_Option.LINGER
+_SOCKET_OPTION_RECEIVE_BUFFER_SIZE :: freebsd.Socket_Option.RCVBUF
+_SOCKET_OPTION_SEND_BUFFER_SIZE :: freebsd.Socket_Option.SNDBUF
+_SOCKET_OPTION_RECEIVE_TIMEOUT :: freebsd.Socket_Option.RCVTIMEO
+_SOCKET_OPTION_SEND_TIMEOUT :: freebsd.Socket_Option.SNDTIMEO
-Shutdown_Manner :: enum c.int {
- Receive = cast(c.int)freebsd.Shutdown_Method.RD,
- Send = cast(c.int)freebsd.Shutdown_Method.WR,
- Both = cast(c.int)freebsd.Shutdown_Method.RDWR,
-}
+_SOCKET_OPTION_TCP_NODELAY :: -1
+
+_SOCKET_OPTION_USE_LOOPBACK :: freebsd.Socket_Option.USELOOPBACK
+_SOCKET_OPTION_REUSE_PORT :: freebsd.Socket_Option.REUSEPORT
+_SOCKET_OPTION_NO_SIGPIPE_FROM_EPIPE :: freebsd.Socket_Option.NOSIGPIPE
+_SOCKET_OPTION_REUSE_PORT_LOAD_BALANCING :: freebsd.Socket_Option.REUSEPORT_LB
+
+_SOCKET_OPTION_EXCLUSIVE_ADDR_USE :: -1
+_SOCKET_OPTION_CONDITIONAL_ACCEPT :: -1
+_SOCKET_OPTION_DONT_LINGER :: -1
+
+_SHUTDOWN_MANNER_RECEIVE :: freebsd.Shutdown_Method.RD
+_SHUTDOWN_MANNER_SEND :: freebsd.Shutdown_Method.WR
+_SHUTDOWN_MANNER_BOTH :: freebsd.Shutdown_Method.RDWR
@(private)
_create_socket :: proc(family: Address_Family, protocol: Socket_Protocol) -> (socket: Any_Socket, err: Create_Socket_Error) {
@@ -272,7 +262,7 @@ _set_option :: proc(socket: Any_Socket, option: Socket_Option, value: any, loc :
ptr: rawptr
len: freebsd.socklen_t
- switch option {
+ #partial switch option {
case
.Reuse_Address,
.Keep_Alive,
@@ -344,7 +334,7 @@ _set_option :: proc(socket: Any_Socket, option: Socket_Option, value: any, loc :
ptr = &int_value
len = size_of(int_value)
case:
- unimplemented("set_option() option not yet implemented", loc)
+ return .Invalid_Option
}
real_socket := any_socket_to_socket(socket)
diff --git a/core/net/socket_linux.odin b/core/net/socket_linux.odin
index 9719ff61b..8348ce114 100644
--- a/core/net/socket_linux.odin
+++ b/core/net/socket_linux.odin
@@ -21,28 +21,33 @@ package net
Feoramund: FreeBSD platform code
*/
-import "core:c"
import "core:time"
import "core:sys/linux"
-Socket_Option :: enum c.int {
- Reuse_Address = c.int(linux.Socket_Option.REUSEADDR),
- Keep_Alive = c.int(linux.Socket_Option.KEEPALIVE),
- Out_Of_Bounds_Data_Inline = c.int(linux.Socket_Option.OOBINLINE),
- TCP_Nodelay = c.int(linux.Socket_TCP_Option.NODELAY),
- Linger = c.int(linux.Socket_Option.LINGER),
- Receive_Buffer_Size = c.int(linux.Socket_Option.RCVBUF),
- Send_Buffer_Size = c.int(linux.Socket_Option.SNDBUF),
- Receive_Timeout = c.int(linux.Socket_Option.RCVTIMEO),
- Send_Timeout = c.int(linux.Socket_Option.SNDTIMEO),
- Broadcast = c.int(linux.Socket_Option.BROADCAST),
-}
+_SOCKET_OPTION_BROADCAST :: linux.Socket_Option.BROADCAST
+_SOCKET_OPTION_REUSE_ADDRESS :: linux.Socket_Option.REUSEADDR
+_SOCKET_OPTION_KEEP_ALIVE :: linux.Socket_Option.KEEPALIVE
+_SOCKET_OPTION_OUT_OF_BOUNDS_DATA_INLINE :: linux.Socket_Option.OOBINLINE
+_SOCKET_OPTION_LINGER :: linux.Socket_Option.LINGER
+_SOCKET_OPTION_RECEIVE_BUFFER_SIZE :: linux.Socket_Option.RCVBUF
+_SOCKET_OPTION_SEND_BUFFER_SIZE :: linux.Socket_Option.SNDBUF
+_SOCKET_OPTION_RECEIVE_TIMEOUT :: linux.Socket_Option.RCVTIMEO
+_SOCKET_OPTION_SEND_TIMEOUT :: linux.Socket_Option.SNDTIMEO
-Shutdown_Manner :: enum c.int {
- Receive = c.int(linux.Shutdown_How.RD),
- Send = c.int(linux.Shutdown_How.WR),
- Both = c.int(linux.Shutdown_How.RDWR),
-}
+_SOCKET_OPTION_TCP_NODELAY :: linux.Socket_TCP_Option.NODELAY
+
+_SOCKET_OPTION_USE_LOOPBACK :: -1
+_SOCKET_OPTION_REUSE_PORT :: -1
+_SOCKET_OPTION_NO_SIGPIPE_FROM_EPIPE :: -1
+_SOCKET_OPTION_REUSE_PORT_LOAD_BALANCING :: -1
+
+_SOCKET_OPTION_EXCLUSIVE_ADDR_USE :: -1
+_SOCKET_OPTION_CONDITIONAL_ACCEPT :: -1
+_SOCKET_OPTION_DONT_LINGER :: -1
+
+_SHUTDOWN_MANNER_RECEIVE :: linux.Shutdown_How.RD
+_SHUTDOWN_MANNER_SEND :: linux.Shutdown_How.WR
+_SHUTDOWN_MANNER_BOTH :: linux.Shutdown_How.RDWR
// Wrappers and unwrappers for system-native types
@@ -347,7 +352,7 @@ _set_option :: proc(sock: Any_Socket, option: Socket_Option, value: any, loc :=
int_value: i32
timeval_value: linux.Time_Val
errno: linux.Errno
- switch option {
+ #partial switch option {
case
.Reuse_Address,
.Keep_Alive,
@@ -400,10 +405,14 @@ _set_option :: proc(sock: Any_Socket, option: Socket_Option, value: any, loc :=
panic("set_option() value must be an integer here", loc)
}
errno = linux.setsockopt(os_sock, level, int(option), &int_value)
+ case:
+ return .Invalid_Socket
}
+
if errno != .NONE {
return _socket_option_error(errno)
}
+
return nil
}
diff --git a/core/net/socket_others.odin b/core/net/socket_others.odin
new file mode 100644
index 000000000..61cf7240e
--- /dev/null
+++ b/core/net/socket_others.odin
@@ -0,0 +1,105 @@
+#+build !darwin
+#+build !linux
+#+build !freebsd
+#+build !windows
+#+build !netbsd
+#+build !openbsd
+#+private
+package net
+
+_SOCKET_OPTION_BROADCAST :: -1
+_SOCKET_OPTION_REUSE_ADDRESS :: -1
+_SOCKET_OPTION_KEEP_ALIVE :: -1
+_SOCKET_OPTION_OUT_OF_BOUNDS_DATA_INLINE :: -1
+_SOCKET_OPTION_LINGER :: -1
+_SOCKET_OPTION_RECEIVE_BUFFER_SIZE :: -1
+_SOCKET_OPTION_SEND_BUFFER_SIZE :: -1
+_SOCKET_OPTION_RECEIVE_TIMEOUT :: -1
+_SOCKET_OPTION_SEND_TIMEOUT :: -1
+
+_SOCKET_OPTION_TCP_NODELAY :: -1
+
+_SOCKET_OPTION_USE_LOOPBACK :: -1
+_SOCKET_OPTION_REUSE_PORT :: -1
+_SOCKET_OPTION_NO_SIGPIPE_FROM_EPIPE :: -1
+_SOCKET_OPTION_REUSE_PORT_LOAD_BALANCING :: -1
+
+_SOCKET_OPTION_EXCLUSIVE_ADDR_USE :: -1
+_SOCKET_OPTION_CONDITIONAL_ACCEPT :: -1
+_SOCKET_OPTION_DONT_LINGER :: -1
+
+_SHUTDOWN_MANNER_RECEIVE :: -1
+_SHUTDOWN_MANNER_SEND :: -1
+_SHUTDOWN_MANNER_BOTH :: -1
+
+_dial_tcp_from_endpoint :: proc(endpoint: Endpoint, options := DEFAULT_TCP_OPTIONS) -> (sock: TCP_Socket, err: Network_Error) {
+ err = Create_Socket_Error.Network_Unreachable
+ return
+}
+
+_create_socket :: proc(family: Address_Family, protocol: Socket_Protocol) -> (sock: Any_Socket, err: Create_Socket_Error) {
+ err = .Network_Unreachable
+ return
+}
+
+_bind :: proc(skt: Any_Socket, ep: Endpoint) -> (err: Bind_Error) {
+ err = .Network_Unreachable
+ return
+}
+
+_listen_tcp :: proc(interface_endpoint: Endpoint, backlog := 1000) -> (skt: TCP_Socket, err: Network_Error) {
+ err = Create_Socket_Error.Network_Unreachable
+ return
+}
+
+_bound_endpoint :: proc(sock: Any_Socket) -> (ep: Endpoint, err: Socket_Info_Error) {
+ err = .Network_Unreachable
+ return
+}
+
+_peer_endpoint :: proc(sock: Any_Socket) -> (ep: Endpoint, err: Socket_Info_Error) {
+ err = .Network_Unreachable
+ return
+}
+
+_accept_tcp :: proc(sock: TCP_Socket, options := DEFAULT_TCP_OPTIONS) -> (client: TCP_Socket, source: Endpoint, err: Accept_Error) {
+ err = .Network_Unreachable
+ return
+}
+
+_close :: proc(skt: Any_Socket) {
+}
+
+_recv_tcp :: proc(skt: TCP_Socket, buf: []byte) -> (bytes_read: int, err: TCP_Recv_Error) {
+ err = .Network_Unreachable
+ return
+}
+
+_recv_udp :: proc(skt: UDP_Socket, buf: []byte) -> (bytes_read: int, remote_endpoint: Endpoint, err: UDP_Recv_Error) {
+ err = .Network_Unreachable
+ return
+}
+
+_send_tcp :: proc(skt: TCP_Socket, buf: []byte) -> (bytes_written: int, err: TCP_Send_Error) {
+ err = .Network_Unreachable
+ return
+}
+
+_send_udp :: proc(skt: UDP_Socket, buf: []byte, to: Endpoint) -> (bytes_written: int, err: UDP_Send_Error) {
+ err = .Network_Unreachable
+ return
+}
+
+_shutdown :: proc(skt: Any_Socket, manner: Shutdown_Manner) -> (err: Shutdown_Error) {
+ err = .Network_Unreachable
+ return
+}
+
+_set_option :: proc(s: Any_Socket, option: Socket_Option, value: any, loc := #caller_location) -> Socket_Option_Error {
+ return .Network_Unreachable
+}
+
+_set_blocking :: proc(socket: Any_Socket, should_block: bool) -> (err: Set_Blocking_Error) {
+ err = .Network_Unreachable
+ return
+}
diff --git a/core/net/socket_darwin.odin b/core/net/socket_posix.odin
index 8e01eb4a8..243b2e06f 100644
--- a/core/net/socket_darwin.odin
+++ b/core/net/socket_posix.odin
@@ -1,4 +1,4 @@
-#+build darwin
+#+build darwin, netbsd, openbsd
package net
/*
@@ -20,28 +20,33 @@ package net
Feoramund: FreeBSD platform code
*/
-import "core:c"
import "core:sys/posix"
import "core:time"
-Socket_Option :: enum c.int {
- Broadcast = c.int(posix.Sock_Option.BROADCAST),
- Reuse_Address = c.int(posix.Sock_Option.REUSEADDR),
- Keep_Alive = c.int(posix.Sock_Option.KEEPALIVE),
- Out_Of_Bounds_Data_Inline = c.int(posix.Sock_Option.OOBINLINE),
- TCP_Nodelay = c.int(posix.TCP_NODELAY),
- Linger = c.int(posix.Sock_Option.LINGER),
- Receive_Buffer_Size = c.int(posix.Sock_Option.RCVBUF),
- Send_Buffer_Size = c.int(posix.Sock_Option.SNDBUF),
- Receive_Timeout = c.int(posix.Sock_Option.RCVTIMEO),
- Send_Timeout = c.int(posix.Sock_Option.SNDTIMEO),
-}
+_SOCKET_OPTION_BROADCAST :: posix.Sock_Option.BROADCAST
+_SOCKET_OPTION_REUSE_ADDRESS :: posix.Sock_Option.REUSEADDR
+_SOCKET_OPTION_KEEP_ALIVE :: posix.Sock_Option.KEEPALIVE
+_SOCKET_OPTION_OUT_OF_BOUNDS_DATA_INLINE :: posix.Sock_Option.OOBINLINE
+_SOCKET_OPTION_LINGER :: posix.Sock_Option.LINGER
+_SOCKET_OPTION_RECEIVE_BUFFER_SIZE :: posix.Sock_Option.RCVBUF
+_SOCKET_OPTION_SEND_BUFFER_SIZE :: posix.Sock_Option.SNDBUF
+_SOCKET_OPTION_RECEIVE_TIMEOUT :: posix.Sock_Option.RCVTIMEO
+_SOCKET_OPTION_SEND_TIMEOUT :: posix.Sock_Option.SNDTIMEO
-Shutdown_Manner :: enum c.int {
- Receive = c.int(posix.SHUT_RD),
- Send = c.int(posix.SHUT_WR),
- Both = c.int(posix.SHUT_RDWR),
-}
+_SOCKET_OPTION_TCP_NODELAY :: posix.TCP_NODELAY
+
+_SOCKET_OPTION_USE_LOOPBACK :: -1
+_SOCKET_OPTION_REUSE_PORT :: -1
+_SOCKET_OPTION_NO_SIGPIPE_FROM_EPIPE :: -1
+_SOCKET_OPTION_REUSE_PORT_LOAD_BALANCING :: -1
+
+_SOCKET_OPTION_EXCLUSIVE_ADDR_USE :: -1
+_SOCKET_OPTION_CONDITIONAL_ACCEPT :: -1
+_SOCKET_OPTION_DONT_LINGER :: -1
+
+_SHUTDOWN_MANNER_RECEIVE :: posix.SHUT_RD
+_SHUTDOWN_MANNER_SEND :: posix.SHUT_WR
+_SHUTDOWN_MANNER_BOTH :: posix.SHUT_RDWR
@(private)
_create_socket :: proc(family: Address_Family, protocol: Socket_Protocol) -> (socket: Any_Socket, err: Create_Socket_Error) {
@@ -273,7 +278,7 @@ _set_option :: proc(s: Any_Socket, option: Socket_Option, value: any, loc := #ca
ptr: rawptr
len: posix.socklen_t
- switch option {
+ #partial switch option {
case
.Broadcast,
.Reuse_Address,
@@ -327,6 +332,8 @@ _set_option :: proc(s: Any_Socket, option: Socket_Option, value: any, loc := #ca
}
ptr = &int_value
len = size_of(int_value)
+ case:
+ return .Invalid_Option
}
skt := any_socket_to_socket(s)
diff --git a/core/net/socket_windows.odin b/core/net/socket_windows.odin
index 6dd2f0458..4eea0ea65 100644
--- a/core/net/socket_windows.odin
+++ b/core/net/socket_windows.odin
@@ -24,59 +24,30 @@ import "core:c"
import win "core:sys/windows"
import "core:time"
-Socket_Option :: enum c.int {
- // bool: Whether the address that this socket is bound to can be reused by other sockets.
- // This allows you to bypass the cooldown period if a program dies while the socket is bound.
- Reuse_Address = win.SO_REUSEADDR,
-
- // bool: Whether other programs will be inhibited from binding the same endpoint as this socket.
- Exclusive_Addr_Use = win.SO_EXCLUSIVEADDRUSE,
-
- // bool: When true, keepalive packets will be automatically be sent for this connection. TODO: verify this understanding
- Keep_Alive = win.SO_KEEPALIVE,
-
- // bool: When true, client connections will immediately be sent a TCP/IP RST response, rather than being accepted.
- Conditional_Accept = win.SO_CONDITIONAL_ACCEPT,
-
- // bool: If true, when the socket is closed, but data is still waiting to be sent, discard that data.
- Dont_Linger = win.SO_DONTLINGER,
-
- // bool: When true, 'out-of-band' data sent over the socket will be read by a normal net.recv() call, the same as normal 'in-band' data.
- Out_Of_Bounds_Data_Inline = win.SO_OOBINLINE,
-
- // bool: When true, disables send-coalescing, therefore reducing latency.
- TCP_Nodelay = win.TCP_NODELAY,
-
- // win.LINGER: Customizes how long (if at all) the socket will remain open when there
- // is some remaining data waiting to be sent, and net.close() is called.
- Linger = win.SO_LINGER,
-
- // win.DWORD: The size, in bytes, of the OS-managed receive-buffer for this socket.
- Receive_Buffer_Size = win.SO_RCVBUF,
-
- // win.DWORD: The size, in bytes, of the OS-managed send-buffer for this socket.
- Send_Buffer_Size = win.SO_SNDBUF,
-
- // win.DWORD: For blocking sockets, the time in milliseconds to wait for incoming data to be received, before giving up and returning .Timeout.
- // For non-blocking sockets, ignored.
- // Use a value of zero to potentially wait forever.
- Receive_Timeout = win.SO_RCVTIMEO,
-
- // win.DWORD: For blocking sockets, the time in milliseconds to wait for outgoing data to be sent, before giving up and returning .Timeout.
- // For non-blocking sockets, ignored.
- // Use a value of zero to potentially wait forever.
- Send_Timeout = win.SO_SNDTIMEO,
-
- // bool: Allow sending to, receiving from, and binding to, a broadcast address.
- Broadcast = win.SO_BROADCAST,
-}
-
-
-Shutdown_Manner :: enum c.int {
- Receive = win.SD_RECEIVE,
- Send = win.SD_SEND,
- Both = win.SD_BOTH,
-}
+_SOCKET_OPTION_BROADCAST :: win.SO_BROADCAST
+_SOCKET_OPTION_REUSE_ADDRESS :: win.SO_REUSEADDR
+_SOCKET_OPTION_KEEP_ALIVE :: win.SO_KEEPALIVE
+_SOCKET_OPTION_OUT_OF_BOUNDS_DATA_INLINE :: win.SO_OOBINLINE
+_SOCKET_OPTION_LINGER :: win.SO_LINGER
+_SOCKET_OPTION_RECEIVE_BUFFER_SIZE :: win.SO_RCVBUF
+_SOCKET_OPTION_SEND_BUFFER_SIZE :: win.SO_SNDBUF
+_SOCKET_OPTION_RECEIVE_TIMEOUT :: win.SO_RCVTIMEO
+_SOCKET_OPTION_SEND_TIMEOUT :: win.SO_SNDTIMEO
+
+_SOCKET_OPTION_TCP_NODELAY :: win.TCP_NODELAY
+
+_SOCKET_OPTION_USE_LOOPBACK :: -1
+_SOCKET_OPTION_REUSE_PORT :: -1
+_SOCKET_OPTION_NO_SIGPIPE_FROM_EPIPE :: -1
+_SOCKET_OPTION_REUSE_PORT_LOAD_BALANCING :: -1
+
+_SOCKET_OPTION_EXCLUSIVE_ADDR_USE :: win.SO_EXCLUSIVEADDRUSE
+_SOCKET_OPTION_CONDITIONAL_ACCEPT :: win.SO_CONDITIONAL_ACCEPT
+_SOCKET_OPTION_DONT_LINGER :: win.SO_DONTLINGER
+
+_SHUTDOWN_MANNER_RECEIVE :: win.SD_RECEIVE
+_SHUTDOWN_MANNER_SEND :: win.SD_SEND
+_SHUTDOWN_MANNER_BOTH :: win.SD_BOTH
@(init, private)
ensure_winsock_initialized :: proc "contextless" () {
@@ -322,7 +293,7 @@ _set_option :: proc(s: Any_Socket, option: Socket_Option, value: any, loc := #ca
ptr: rawptr
len: c.int
- switch option {
+ #partial switch option {
case
.Reuse_Address,
.Exclusive_Addr_Use,
@@ -383,6 +354,8 @@ _set_option :: proc(s: Any_Socket, option: Socket_Option, value: any, loc := #ca
}
ptr = &int_value
len = size_of(int_value)
+ case:
+ return .Invalid_Option
}
socket := any_socket_to_socket(s)