mirror of
https://github.com/odin-lang/Odin.git
synced 2026-02-12 06:18:39 +00:00
net: implement OpenBSD and NetBSD support & add stubs for other targets & cleanup
This commit is contained in:
@@ -11,8 +11,7 @@ NO_CORE_NAMED_TYPES :: #config(ODIN_CORE_FLAGS_NO_CORE_NAMED_TYPES, false)
|
||||
IMPORTING_TIME :: #config(ODIN_CORE_FLAGS_USE_TIME, time.IS_SUPPORTED)
|
||||
|
||||
// Override support for parsing `net` types.
|
||||
// TODO: Update this when the BSDs are supported.
|
||||
IMPORTING_NET :: #config(ODIN_CORE_FLAGS_USE_NET, ODIN_OS == .Windows || ODIN_OS == .Linux || ODIN_OS == .Darwin || ODIN_OS == .FreeBSD)
|
||||
IMPORTING_NET :: #config(ODIN_CORE_FLAGS_USE_NET, ODIN_OS == .Windows || ODIN_OS == .Linux || ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD)
|
||||
|
||||
TAG_ARGS :: "args"
|
||||
SUBTAG_NAME :: "name"
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package flags
|
||||
|
||||
import "base:runtime"
|
||||
import "core:net"
|
||||
import "core:os"
|
||||
|
||||
Parse_Error_Reason :: enum {
|
||||
@@ -24,6 +26,12 @@ Parse_Error :: struct {
|
||||
message: string,
|
||||
}
|
||||
|
||||
Unified_Parse_Error_Reason :: union #shared_nil {
|
||||
Parse_Error_Reason,
|
||||
runtime.Allocator_Error,
|
||||
net.Parse_Endpoint_Error,
|
||||
}
|
||||
|
||||
// Raised during parsing.
|
||||
// Provides more granular information than what just a string could hold.
|
||||
Open_File_Error :: struct {
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
#+build netbsd, openbsd
|
||||
package flags
|
||||
|
||||
import "base:runtime"
|
||||
|
||||
Unified_Parse_Error_Reason :: union #shared_nil {
|
||||
Parse_Error_Reason,
|
||||
runtime.Allocator_Error,
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
#+build !netbsd
|
||||
#+build !openbsd
|
||||
package flags
|
||||
|
||||
import "base:runtime"
|
||||
import "core:net"
|
||||
|
||||
Unified_Parse_Error_Reason :: union #shared_nil {
|
||||
Parse_Error_Reason,
|
||||
runtime.Allocator_Error,
|
||||
net.Parse_Endpoint_Error,
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import "base:intrinsics"
|
||||
import "base:runtime"
|
||||
import "core:fmt"
|
||||
import "core:mem"
|
||||
import "core:net"
|
||||
import "core:os"
|
||||
import "core:reflect"
|
||||
import "core:strconv"
|
||||
@@ -310,7 +311,18 @@ parse_and_set_pointer_by_named_type :: proc(ptr: rawptr, str: string, data_type:
|
||||
}
|
||||
|
||||
when IMPORTING_NET {
|
||||
if try_net_parse_workaround(data_type, str, ptr, out_error) {
|
||||
if data_type == net.Host_Or_Endpoint {
|
||||
addr, net_error := net.parse_hostname_or_endpoint(str)
|
||||
if net_error != nil {
|
||||
// We pass along `net.Error` here.
|
||||
out_error^ = Parse_Error {
|
||||
net_error,
|
||||
"Invalid Host/Endpoint.",
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
(cast(^net.Host_Or_Endpoint)ptr)^ = addr
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
#+private
|
||||
#+build !netbsd
|
||||
#+build !openbsd
|
||||
package flags
|
||||
|
||||
import "core:net"
|
||||
|
||||
// This proc exists purely as a workaround for import restrictions.
|
||||
// Returns true if caller should return early.
|
||||
try_net_parse_workaround :: #force_inline proc (
|
||||
data_type: typeid,
|
||||
str: string,
|
||||
ptr: rawptr,
|
||||
out_error: ^Error,
|
||||
) -> bool {
|
||||
if data_type == net.Host_Or_Endpoint {
|
||||
addr, net_error := net.parse_hostname_or_endpoint(str)
|
||||
if net_error != nil {
|
||||
// We pass along `net.Error` here.
|
||||
out_error^ = Parse_Error {
|
||||
net_error,
|
||||
"Invalid Host/Endpoint.",
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
(cast(^net.Host_Or_Endpoint)ptr)^ = addr
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
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
|
||||
|
||||
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, 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
|
||||
}
|
||||
}
|
||||
|
||||
24
core/net/dns_os.odin
Normal file
24
core/net/dns_os.odin
Normal file
@@ -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)
|
||||
}
|
||||
|
||||
12
core/net/dns_others.odin
Normal file
12
core/net/dns_others.odin
Normal file
@@ -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
|
||||
}
|
||||
@@ -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[:])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
#+build darwin
|
||||
#+build darwin, netbsd, openbsd
|
||||
package net
|
||||
|
||||
/*
|
||||
@@ -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
|
||||
|
||||
11
core/net/interface_others.odin
Normal file
11
core/net/interface_others.odin
Normal file
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
_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
|
||||
|
||||
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_TCP_NODELAY :: -1
|
||||
|
||||
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_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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
105
core/net/socket_others.odin
Normal file
105
core/net/socket_others.odin
Normal file
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
@@ -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,
|
||||
_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
|
||||
|
||||
// bool: Whether other programs will be inhibited from binding the same endpoint as this socket.
|
||||
Exclusive_Addr_Use = win.SO_EXCLUSIVEADDRUSE,
|
||||
_SOCKET_OPTION_TCP_NODELAY :: win.TCP_NODELAY
|
||||
|
||||
// bool: When true, keepalive packets will be automatically be sent for this connection. TODO: verify this understanding
|
||||
Keep_Alive = win.SO_KEEPALIVE,
|
||||
_SOCKET_OPTION_USE_LOOPBACK :: -1
|
||||
_SOCKET_OPTION_REUSE_PORT :: -1
|
||||
_SOCKET_OPTION_NO_SIGPIPE_FROM_EPIPE :: -1
|
||||
_SOCKET_OPTION_REUSE_PORT_LOAD_BALANCING :: -1
|
||||
|
||||
// bool: When true, client connections will immediately be sent a TCP/IP RST response, rather than being accepted.
|
||||
Conditional_Accept = win.SO_CONDITIONAL_ACCEPT,
|
||||
_SOCKET_OPTION_EXCLUSIVE_ADDR_USE :: win.SO_EXCLUSIVEADDRUSE
|
||||
_SOCKET_OPTION_CONDITIONAL_ACCEPT :: win.SO_CONDITIONAL_ACCEPT
|
||||
_SOCKET_OPTION_DONT_LINGER :: win.SO_DONTLINGER
|
||||
|
||||
// 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,
|
||||
}
|
||||
_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)
|
||||
|
||||
@@ -10,8 +10,6 @@
|
||||
|
||||
A test suite for `core:net`
|
||||
*/
|
||||
#+build !netbsd
|
||||
#+build !openbsd
|
||||
#+feature dynamic-literals
|
||||
package test_core_net
|
||||
|
||||
|
||||
Reference in New Issue
Block a user