diff options
| author | Jeroen van Rijn <Kelimion@users.noreply.github.com> | 2024-08-09 09:50:05 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-08-09 09:50:05 +0200 |
| commit | cc24d2de3e5cce8f7f3ee969479d66e512478eb5 (patch) | |
| tree | d58859d25514aca1942cb7da52e2b3f20d73c21d /core | |
| parent | bc6deab1759fa10177c7b2a09d2530ffa88d8cc8 (diff) | |
| parent | 6cc7f3b451f6465dcba0ac9c5a0befb734478a02 (diff) | |
Merge pull request #3810 from Feoramund/freebsd-core-net
Port `core:net` to FreeBSD
Diffstat (limited to 'core')
28 files changed, 2966 insertions, 38 deletions
diff --git a/core/flags/constants.odin b/core/flags/constants.odin index ab3dc9a0a..6f5281928 100644 --- a/core/flags/constants.odin +++ b/core/flags/constants.odin @@ -12,7 +12,7 @@ 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) +IMPORTING_NET :: #config(ODIN_CORE_FLAGS_USE_NET, ODIN_OS == .Windows || ODIN_OS == .Linux || ODIN_OS == .Darwin || ODIN_OS == .FreeBSD) TAG_ARGS :: "args" SUBTAG_NAME :: "name" diff --git a/core/flags/errors_bsd.odin b/core/flags/errors_bsd.odin index 10c04b506..1fe6de90b 100644 --- a/core/flags/errors_bsd.odin +++ b/core/flags/errors_bsd.odin @@ -1,4 +1,4 @@ -//+build freebsd, netbsd, openbsd +//+build netbsd, openbsd package flags import "base:runtime" diff --git a/core/flags/errors_nonbsd.odin b/core/flags/errors_nonbsd.odin index ff46f38ed..a77f12abf 100644 --- a/core/flags/errors_nonbsd.odin +++ b/core/flags/errors_nonbsd.odin @@ -1,4 +1,4 @@ -//+build !freebsd !netbsd !openbsd +//+build !netbsd !openbsd package flags import "base:runtime" diff --git a/core/flags/internal_rtti_nonbsd.odin b/core/flags/internal_rtti_nonbsd.odin index 196c27ab8..27fdb3b75 100644 --- a/core/flags/internal_rtti_nonbsd.odin +++ b/core/flags/internal_rtti_nonbsd.odin @@ -1,5 +1,5 @@ //+private -//+build !freebsd !netbsd !openbsd +//+build !netbsd !openbsd package flags import "core:net" diff --git a/core/net/addr.odin b/core/net/addr.odin index eed3fb3b9..1972d8c22 100644 --- a/core/net/addr.odin +++ b/core/net/addr.odin @@ -1,4 +1,4 @@ -// +build windows, linux, darwin +// +build windows, linux, darwin, freebsd package net /* @@ -10,12 +10,14 @@ package net Copyright 2022 Tetralux <tetraluxonpc@gmail.com> Copyright 2022 Colin Davidson <colrdavidson@gmail.com> Copyright 2022 Jeroen van Rijn <nom@duclavier.com>. + Copyright 2024 Feoramund <rune@swevencraft.org>. 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 + Feoramund: FreeBSD platform code */ import "core:strconv" @@ -742,4 +744,4 @@ parse_ip_component :: proc(input: string, max_value := u64(max(u32)), bases := D get_network_interfaces :: proc() -> []Address { // TODO: Implement using `enumerate_interfaces` and returning only the addresses of active interfaces. return nil -}
\ No newline at end of file +} diff --git a/core/net/common.odin b/core/net/common.odin index db969eab8..b9af9ce9b 100644 --- a/core/net/common.odin +++ b/core/net/common.odin @@ -1,4 +1,4 @@ -// +build windows, linux, darwin +// +build windows, linux, darwin, freebsd package net /* @@ -13,12 +13,14 @@ package net Copyright 2022 Tetralux <tetraluxonpc@gmail.com> Copyright 2022 Colin Davidson <colrdavidson@gmail.com> Copyright 2022 Jeroen van Rijn <nom@duclavier.com>. + Copyright 2024 Feoramund <rune@swevencraft.org>. 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 + Feoramund: FreeBSD platform code */ import "base:runtime" @@ -413,4 +415,4 @@ DNS_Record_Header :: struct #packed { DNS_Host_Entry :: struct { name: string, addr: Address, -}
\ No newline at end of file +} diff --git a/core/net/dns.odin b/core/net/dns.odin index 408fd201b..e82b54262 100644 --- a/core/net/dns.odin +++ b/core/net/dns.odin @@ -1,4 +1,4 @@ -// +build windows, linux, darwin +// +build windows, linux, darwin, freebsd package net /* @@ -10,12 +10,14 @@ package net Copyright 2022 Tetralux <tetraluxonpc@gmail.com> Copyright 2022 Colin Davidson <colrdavidson@gmail.com> Copyright 2022 Jeroen van Rijn <nom@duclavier.com>. + Copyright 2024 Feoramund <rune@swevencraft.org>. 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 + Feoramund: FreeBSD platform code */ import "core:mem" @@ -30,7 +32,7 @@ when ODIN_OS == .Windows { resolv_conf = "", hosts_file = "%WINDIR%\\system32\\drivers\\etc\\hosts", } -} else when ODIN_OS == .Linux || ODIN_OS == .Darwin || ODIN_OS == .OpenBSD || ODIN_OS == .NetBSD { +} else when ODIN_OS == .Linux || ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .OpenBSD || ODIN_OS == .NetBSD { DEFAULT_DNS_CONFIGURATION :: DNS_Configuration{ resolv_conf = "/etc/resolv.conf", hosts_file = "/etc/hosts", diff --git a/core/net/dns_unix.odin b/core/net/dns_unix.odin index e9b7bd066..0448b8d9e 100644 --- a/core/net/dns_unix.odin +++ b/core/net/dns_unix.odin @@ -1,4 +1,4 @@ -//+build linux, darwin +//+build linux, darwin, freebsd package net /* Package net implements cross-platform Berkeley Sockets, DNS resolution and associated procedures. @@ -9,12 +9,14 @@ package net Copyright 2022 Tetralux <tetraluxonpc@gmail.com> Copyright 2022 Colin Davidson <colrdavidson@gmail.com> Copyright 2022 Jeroen van Rijn <nom@duclavier.com>. + Copyright 2024 Feoramund <rune@swevencraft.org>. 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 + Feoramund: FreeBSD platform code */ import "core:strings" diff --git a/core/net/dns_windows.odin b/core/net/dns_windows.odin index ccec7ea4b..b7af050b1 100644 --- a/core/net/dns_windows.odin +++ b/core/net/dns_windows.odin @@ -10,12 +10,14 @@ package net Copyright 2022 Tetralux <tetraluxonpc@gmail.com> Copyright 2022 Colin Davidson <colrdavidson@gmail.com> Copyright 2022 Jeroen van Rijn <nom@duclavier.com>. + Copyright 2024 Feoramund <rune@swevencraft.org>. 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 + Feoramund: FreeBSD platform code */ import "core:strings" diff --git a/core/net/doc.odin b/core/net/doc.odin index 0f1b33172..996f8147e 100644 --- a/core/net/doc.odin +++ b/core/net/doc.odin @@ -2,12 +2,14 @@ Copyright 2022 Tetralux <tetraluxonpc@gmail.com> Copyright 2022 Colin Davidson <colrdavidson@gmail.com> Copyright 2022 Jeroen van Rijn <nom@duclavier.com>. + Copyright 2024 Feoramund <rune@swevencraft.org>. 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 + Feoramund: FreeBSD platform code */ /* diff --git a/core/net/errors_darwin.odin b/core/net/errors_darwin.odin index 3116af0ab..f2a0d6262 100644 --- a/core/net/errors_darwin.odin +++ b/core/net/errors_darwin.odin @@ -10,12 +10,14 @@ package net Copyright 2022 Tetralux <tetraluxonpc@gmail.com> Copyright 2022 Colin Davidson <colrdavidson@gmail.com> Copyright 2022 Jeroen van Rijn <nom@duclavier.com>. + Copyright 2024 Feoramund <rune@swevencraft.org>. 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 + Feoramund: FreeBSD platform code */ import "core:c" diff --git a/core/net/errors_freebsd.odin b/core/net/errors_freebsd.odin new file mode 100644 index 000000000..4830d1c03 --- /dev/null +++ b/core/net/errors_freebsd.odin @@ -0,0 +1,217 @@ +//+build freebsd +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. +*/ + +/* + Copyright 2022 Tetralux <tetraluxonpc@gmail.com> + Copyright 2022 Colin Davidson <colrdavidson@gmail.com> + Copyright 2022 Jeroen van Rijn <nom@duclavier.com>. + Copyright 2024 Feoramund <rune@swevencraft.org>. + 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 + Feoramund: FreeBSD platform code +*/ + +import "core:c" +import "core:sys/freebsd" + +Create_Socket_Error :: enum c.int { + None = 0, + Access_Denied = cast(c.int)freebsd.Errno.EACCES, + Family_Not_Supported_For_This_Socket = cast(c.int)freebsd.Errno.EAFNOSUPPORT, + Full_Per_Process_Descriptor_Table = cast(c.int)freebsd.Errno.EMFILE, + Full_System_File_Table = cast(c.int)freebsd.Errno.ENFILE, + No_Buffer_Space_Available = cast(c.int)freebsd.Errno.ENOBUFS, + Insufficient_Permission = cast(c.int)freebsd.Errno.EPERM, + Protocol_Unsupported_In_Family = cast(c.int)freebsd.Errno.EPROTONOSUPPORT, + Socket_Type_Unsupported_By_Protocol = cast(c.int)freebsd.Errno.EPROTOTYPE, +} + +Dial_Error :: enum c.int { + None = 0, + Port_Required = -1, + Not_Descriptor = cast(c.int)freebsd.Errno.EBADF, + Invalid_Namelen = cast(c.int)freebsd.Errno.EINVAL, + Not_Socket = cast(c.int)freebsd.Errno.ENOTSOCK, + Address_Unavailable = cast(c.int)freebsd.Errno.EADDRNOTAVAIL, + Wrong_Family_For_Socket = cast(c.int)freebsd.Errno.EAFNOSUPPORT, + Already_Connected = cast(c.int)freebsd.Errno.EISCONN, + Timeout = cast(c.int)freebsd.Errno.ETIMEDOUT, + Refused_By_Remote_Host = cast(c.int)freebsd.Errno.ECONNREFUSED, + // `Refused` alias for `core:net` tests. + // The above default name `Refused_By_Remote_Host` is more explicit. + Refused = Refused_By_Remote_Host, + Reset_By_Remote_Host = cast(c.int)freebsd.Errno.ECONNRESET, + Network_Unreachable = cast(c.int)freebsd.Errno.ENETUNREACH, + Host_Unreachable = cast(c.int)freebsd.Errno.EHOSTUNREACH, + Address_In_Use = cast(c.int)freebsd.Errno.EADDRINUSE, + Invalid_Address_Space = cast(c.int)freebsd.Errno.EFAULT, + In_Progress = cast(c.int)freebsd.Errno.EINPROGRESS, + Interrupted_By_Signal = cast(c.int)freebsd.Errno.EINTR, + Previous_Attempt_Incomplete = cast(c.int)freebsd.Errno.EALREADY, + Broadcast_Unavailable = cast(c.int)freebsd.Errno.EACCES, + Auto_Port_Unavailable = cast(c.int)freebsd.Errno.EAGAIN, + + // NOTE: There are additional connect() error possibilities, but they are + // strictly for addresses in the UNIX domain. +} + +Bind_Error :: enum c.int { + None = 0, + Kernel_Resources_Unavailable = cast(c.int)freebsd.Errno.EAGAIN, + Not_Descriptor = cast(c.int)freebsd.Errno.EBADF, + + // NOTE: bind() can also return EINVAL if the underlying `addrlen` is an + // invalid length for the address family. This shouldn't happen for the net + // package, but it's worth noting. + Already_Bound = cast(c.int)freebsd.Errno.EINVAL, + Not_Socket = cast(c.int)freebsd.Errno.ENOTSOCK, + Given_Nonlocal_Address = cast(c.int)freebsd.Errno.EADDRNOTAVAIL, + Address_In_Use = cast(c.int)freebsd.Errno.EADDRINUSE, + Address_Family_Mismatch = cast(c.int)freebsd.Errno.EAFNOSUPPORT, + Protected_Address = cast(c.int)freebsd.Errno.EACCES, + Invalid_Address_Space = cast(c.int)freebsd.Errno.EFAULT, + + // NOTE: There are additional bind() error possibilities, but they are + // strictly for addresses in the UNIX domain. +} + +Listen_Error :: enum c.int { + None = 0, + Not_Descriptor = cast(c.int)freebsd.Errno.EBADF, + Socket_Not_Bound = cast(c.int)freebsd.Errno.EDESTADDRREQ, + Already_Connected = cast(c.int)freebsd.Errno.EINVAL, + Not_Socket = cast(c.int)freebsd.Errno.ENOTSOCK, + Listening_Not_Supported_For_This_Socket = cast(c.int)freebsd.Errno.EOPNOTSUPP, +} + +Accept_Error :: enum c.int { + None = 0, + Not_Descriptor = cast(c.int)freebsd.Errno.EBADF, + Interrupted = cast(c.int)freebsd.Errno.EINTR, + Full_Per_Process_Descriptor_Table = cast(c.int)freebsd.Errno.EMFILE, + Full_System_File_Table = cast(c.int)freebsd.Errno.ENFILE, + Not_Socket = cast(c.int)freebsd.Errno.ENOTSOCK, + Listen_Not_Called_On_Socket_Yet = cast(c.int)freebsd.Errno.EINVAL, + Address_Not_Writable = cast(c.int)freebsd.Errno.EFAULT, + + // NOTE: This is the same as EWOULDBLOCK. + No_Connections_Available = cast(c.int)freebsd.Errno.EAGAIN, + // `Would_Block` alias for `core:net` tests. + Would_Block = cast(c.int)freebsd.Errno.EAGAIN, + + New_Connection_Aborted = cast(c.int)freebsd.Errno.ECONNABORTED, +} + +TCP_Recv_Error :: enum c.int { + None = 0, + Not_Descriptor = cast(c.int)freebsd.Errno.EBADF, + Connection_Closed = cast(c.int)freebsd.Errno.ECONNRESET, + Not_Connected = cast(c.int)freebsd.Errno.ENOTCONN, + Not_Socket = cast(c.int)freebsd.Errno.ENOTSOCK, + + // NOTE(Feoramund): The next two errors are only relevant for recvmsg(), + // but I'm including them for completeness's sake. + Full_Table_And_Pending_Data = cast(c.int)freebsd.Errno.EMFILE, + Invalid_Message_Size = cast(c.int)freebsd.Errno.EMSGSIZE, + + Timeout = cast(c.int)freebsd.Errno.EAGAIN, + Interrupted_By_Signal = cast(c.int)freebsd.Errno.EINTR, + Buffer_Pointer_Outside_Address_Space = cast(c.int)freebsd.Errno.EFAULT, +} + +UDP_Recv_Error :: enum c.int { + None = 0, + Not_Descriptor = cast(c.int)freebsd.Errno.EBADF, + Connection_Closed = cast(c.int)freebsd.Errno.ECONNRESET, + Not_Connected = cast(c.int)freebsd.Errno.ENOTCONN, + Not_Socket = cast(c.int)freebsd.Errno.ENOTSOCK, + + // NOTE(Feoramund): The next two errors are only relevant for recvmsg(), + // but I'm including them for completeness's sake. + Full_Table_And_Data_Discarded = cast(c.int)freebsd.Errno.EMFILE, + Invalid_Message_Size = cast(c.int)freebsd.Errno.EMSGSIZE, + + Timeout = cast(c.int)freebsd.Errno.EAGAIN, + Interrupted_By_Signal = cast(c.int)freebsd.Errno.EINTR, + Buffer_Pointer_Outside_Address_Space = cast(c.int)freebsd.Errno.EFAULT, +} + +TCP_Send_Error :: enum c.int { + None = 0, + Connection_Closed = cast(c.int)freebsd.Errno.ECONNRESET, + Not_Descriptor = cast(c.int)freebsd.Errno.EBADF, + Broadcast_Status_Mismatch = cast(c.int)freebsd.Errno.EACCES, + Not_Connected = cast(c.int)freebsd.Errno.ENOTCONN, + Not_Socket = cast(c.int)freebsd.Errno.ENOTSOCK, + Argument_In_Invalid_Address_Space = cast(c.int)freebsd.Errno.EFAULT, + + Message_Size_Breaks_Atomicity = cast(c.int)freebsd.Errno.EMSGSIZE, + + /* The socket is marked non-blocking, or MSG_DONTWAIT is + specified, and the requested operation would block. */ + Would_Block = cast(c.int)freebsd.Errno.EAGAIN, + + /* NOTE: This error arises for two distinct reasons: + + 1. The system was unable to allocate an internal buffer. + The operation may succeed when buffers become available. + + 2. The output queue for a network interface was full. + This generally indicates that the interface has stopped + sending, but may be caused by transient congestion. + */ + No_Buffer_Space_Available = cast(c.int)freebsd.Errno.ENOBUFS, + + Host_Unreachable = cast(c.int)freebsd.Errno.EHOSTUNREACH, + Already_Connected = cast(c.int)freebsd.Errno.EISCONN, + ICMP_Unreachable = cast(c.int)freebsd.Errno.ECONNREFUSED, + Host_Down = cast(c.int)freebsd.Errno.EHOSTDOWN, + Network_Down = cast(c.int)freebsd.Errno.ENETDOWN, + Jailed_Socket_Tried_To_Escape = cast(c.int)freebsd.Errno.EADDRNOTAVAIL, + Cannot_Send_More_Data = cast(c.int)freebsd.Errno.EPIPE, +} + +// NOTE(Feoramund): The same as TCP errors go, as far as I'm aware. +UDP_Send_Error :: distinct TCP_Send_Error + +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, +} + +Shutdown_Error :: enum c.int { + None = 0, + Not_Descriptor = cast(c.int)freebsd.Errno.EBADF, + Invalid_Manner = cast(c.int)freebsd.Errno.EINVAL, + Not_Connected = cast(c.int)freebsd.Errno.ENOTCONN, + Not_Socket = cast(c.int)freebsd.Errno.ENOTSOCK, +} + +Socket_Option_Error :: enum c.int { + None = 0, + Value_Out_Of_Range = -1, + Not_Descriptor = cast(c.int)freebsd.Errno.EBADF, + Not_Socket = cast(c.int)freebsd.Errno.ENOTSOCK, + Unknown_Option_For_Level = cast(c.int)freebsd.Errno.ENOPROTOOPT, + Argument_In_Invalid_Address_Space = cast(c.int)freebsd.Errno.EFAULT, + // This error can arise for many different reasons. + Invalid_Value = cast(c.int)freebsd.Errno.EINVAL, + System_Memory_Allocation_Failed = cast(c.int)freebsd.Errno.ENOMEM, + Insufficient_System_Resources = cast(c.int)freebsd.Errno.ENOBUFS, +} + +Set_Blocking_Error :: enum c.int { + None = 0, + Not_Descriptor = cast(c.int)freebsd.Errno.EBADF, + Wrong_Descriptor = cast(c.int)freebsd.Errno.ENOTTY, +} diff --git a/core/net/errors_linux.odin b/core/net/errors_linux.odin index 2370dd0d8..9047b4020 100644 --- a/core/net/errors_linux.odin +++ b/core/net/errors_linux.odin @@ -10,6 +10,7 @@ package net Copyright 2022 Tetralux <tetraluxonpc@gmail.com> Copyright 2022 Colin Davidson <colrdavidson@gmail.com> Copyright 2022 Jeroen van Rijn <nom@duclavier.com>. + Copyright 2024 Feoramund <rune@swevencraft.org>. Made available under Odin's BSD-3 license. List of contributors: @@ -17,6 +18,7 @@ package net Colin Davidson: Linux platform code, OSX platform code, Odin-native DNS resolver Jeroen van Rijn: Cross platform unification, code style, documentation flysand: Move dependency from core:linux.Errno to core:sys/linux + Feoramund: FreeBSD platform code */ import "core:c" diff --git a/core/net/errors_windows.odin b/core/net/errors_windows.odin index f63f17f4e..ae928a05c 100644 --- a/core/net/errors_windows.odin +++ b/core/net/errors_windows.odin @@ -10,12 +10,14 @@ package net Copyright 2022 Tetralux <tetraluxonpc@gmail.com> Copyright 2022 Colin Davidson <colrdavidson@gmail.com> Copyright 2022 Jeroen van Rijn <nom@duclavier.com>. + Copyright 2024 Feoramund <rune@swevencraft.org>. 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 + Feoramund: FreeBSD platform code */ import "core:c" diff --git a/core/net/interface.odin b/core/net/interface.odin index df7d0223e..90444fb63 100644 --- a/core/net/interface.odin +++ b/core/net/interface.odin @@ -1,4 +1,4 @@ -// +build windows, linux, darwin +// +build windows, linux, darwin, freebsd package net /* @@ -10,12 +10,14 @@ package net Copyright 2022 Tetralux <tetraluxonpc@gmail.com> Copyright 2022 Colin Davidson <colrdavidson@gmail.com> Copyright 2022 Jeroen van Rijn <nom@duclavier.com>. + Copyright 2024 Feoramund <rune@swevencraft.org>. 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 + Feoramund: FreeBSD platform code */ import "core:strings" diff --git a/core/net/interface_darwin.odin b/core/net/interface_darwin.odin index e2a9a73ca..7a33682de 100644 --- a/core/net/interface_darwin.odin +++ b/core/net/interface_darwin.odin @@ -10,13 +10,14 @@ package net Copyright 2022 Tetralux <tetraluxonpc@gmail.com> Copyright 2022 Colin Davidson <colrdavidson@gmail.com> Copyright 2022 Jeroen van Rijn <nom@duclavier.com>. + Copyright 2024 Feoramund <rune@swevencraft.org>. 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 - + Feoramund: FreeBSD platform code */ import "core:os" diff --git a/core/net/interface_freebsd.odin b/core/net/interface_freebsd.odin new file mode 100644 index 000000000..a9a125299 --- /dev/null +++ b/core/net/interface_freebsd.odin @@ -0,0 +1,177 @@ +//+build freebsd +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. +*/ + +/* + Copyright 2022 Tetralux <tetraluxonpc@gmail.com> + Copyright 2022 Colin Davidson <colrdavidson@gmail.com> + Copyright 2022 Jeroen van Rijn <nom@duclavier.com>. + Copyright 2024 Feoramund <rune@swevencraft.org>. + 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 + Feoramund: FreeBSD platform code +*/ + +import "core:c" +import "core:strings" +import "core:sys/freebsd" + +@(private) +_enumerate_interfaces :: proc(allocator := context.allocator) -> (interfaces: []Network_Interface, err: Network_Error) { + // This is a simplified implementation of `getifaddrs` from the FreeBSD + // libc using only Odin and syscalls. + context.allocator = allocator + + mib := [6]freebsd.MIB_Identifier { + .CTL_NET, + cast(freebsd.MIB_Identifier)freebsd.Protocol_Family.ROUTE, + freebsd.MIB_Identifier(0), + freebsd.MIB_Identifier(0), + .NET_RT_IFLISTL, + freebsd.MIB_Identifier(0), + } + + // Figure out how much space we need. + needed: c.size_t = --- + + errno := freebsd.sysctl(mib[:], nil, &needed, nil, 0) + if errno != nil { + return nil, .Unable_To_Enumerate_Network_Interfaces + } + + // Allocate and get the entries. + buf, alloc_err := make([]byte, needed) + if alloc_err != nil { + return nil, .Unable_To_Enumerate_Network_Interfaces + } + defer delete(buf) + + errno = freebsd.sysctl(mib[:], &buf[0], &needed, nil, 0) + if errno != nil { + return nil, .Unable_To_Enumerate_Network_Interfaces + } + + // Build the interfaces with each message. + if_builder: [dynamic]Network_Interface + for message_pointer: uintptr = 0; message_pointer < cast(uintptr)needed; /**/ { + rtm := cast(^freebsd.Route_Message_Header)&buf[message_pointer] + if rtm.version != freebsd.RTM_VERSION { + continue + } + + #partial switch rtm.type { + case .IFINFO: + ifm := cast(^freebsd.Interface_Message_Header_Len)&buf[message_pointer] + if .IFP not_in ifm.addrs { + // No name available. + break + } + + dl := cast(^freebsd.Socket_Address_Data_Link)&buf[message_pointer + cast(uintptr)ifm.len] + + if_data := cast(^freebsd.Interface_Data)&buf[message_pointer + cast(uintptr)ifm.data_off] + + // This is done this way so the different message types can + // dynamically build a `Network_Interface`. + resize(&if_builder, max(len(if_builder), 1 + cast(int)ifm.index)) + interface := if_builder[ifm.index] + + interface.adapter_name = strings.clone_from_bytes(dl.data[0:dl.nlen]) + interface.mtu = if_data.mtu + + switch if_data.link_state { + case .UNKNOWN: /* Do nothing; the default value is valid. */ + case .UP: interface.link.state |= { .Up } + case .DOWN: interface.link.state |= { .Down } + } + + // TODO: Uncertain if these are equivalent: + // interface.link.transmit_speed = if_data.baudrate + // interface.link.receive_speed = if_data.baudrate + + if dl.type == .LOOP { + interface.link.state |= { .Loopback } + } else { + interface.physical_address = physical_address_to_string(dl.data[dl.nlen:][:6]) + } + + if_builder[ifm.index] = interface + + case .NEWADDR: + RTA_MASKS :: freebsd.Route_Address_Flags { .IFA, .NETMASK } + ifam := cast(^freebsd.Interface_Address_Message_Header_Len)&buf[message_pointer] + if ifam.addrs & RTA_MASKS == {} { + break + } + + resize(&if_builder, max(len(if_builder), 1 + cast(int)ifam.index)) + interface := if_builder[ifam.index] + + address_pointer := message_pointer + cast(uintptr)ifam.len + + lease: Lease + address_set: bool + for address_type in ifam.addrs { + ptr := cast(^freebsd.Socket_Address_Basic)&buf[address_pointer] + + #partial switch address_type { + case .IFA: + #partial switch ptr.family { + case .INET: + real := cast(^freebsd.Socket_Address_Internet)ptr + lease.address = cast(IP4_Address)real.addr.addr8 + address_set = true + case .INET6: + real := cast(^freebsd.Socket_Address_Internet6)ptr + lease.address = cast(IP6_Address)real.addr.addr16 + address_set = true + } + case .NETMASK: + #partial switch ptr.family { + case .INET: + real := cast(^freebsd.Socket_Address_Internet)ptr + lease.netmask = cast(Netmask)cast(IP4_Address)real.addr.addr8 + case .INET6: + real := cast(^freebsd.Socket_Address_Internet6)ptr + lease.netmask = cast(Netmask)cast(IP6_Address)real.addr.addr16 + } + } + + SALIGN : u8 : size_of(c.long) - 1 + address_advance: uintptr = --- + if ptr.len > 0 { + address_advance = cast(uintptr)((ptr.len + SALIGN) & ~SALIGN) + } else { + address_advance = cast(uintptr)(SALIGN + 1) + } + + address_pointer += address_advance + } + + if address_set { + append(&interface.unicast, lease) + } + + if_builder[ifam.index] = interface + } + + message_pointer += cast(uintptr)rtm.msglen + } + + // Remove any interfaces that were allocated but had no name. + #no_bounds_check for i := len(if_builder) - 1; i >= 0; i -= 1 { + if len(if_builder[i].adapter_name) == 0 { + ordered_remove(&if_builder, i) + } + } + + return if_builder[:], nil +} diff --git a/core/net/interface_linux.odin b/core/net/interface_linux.odin index 7c99cf23b..c6df8f0a2 100644 --- a/core/net/interface_linux.odin +++ b/core/net/interface_linux.odin @@ -10,12 +10,14 @@ package net Copyright 2022 Tetralux <tetraluxonpc@gmail.com> Copyright 2022 Colin Davidson <colrdavidson@gmail.com> Copyright 2022 Jeroen van Rijn <nom@duclavier.com>. + Copyright 2024 Feoramund <rune@swevencraft.org>. 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 + Feoramund: FreeBSD platform code This file uses `getifaddrs` libc call to enumerate interfaces. TODO: When we have raw sockets, split off into its own file for Linux so we can use the NETLINK protocol and bypass libc. diff --git a/core/net/interface_windows.odin b/core/net/interface_windows.odin index b9abcff48..67da6d034 100644 --- a/core/net/interface_windows.odin +++ b/core/net/interface_windows.odin @@ -10,12 +10,14 @@ package net Copyright 2022 Tetralux <tetraluxonpc@gmail.com> Copyright 2022 Colin Davidson <colrdavidson@gmail.com> Copyright 2022 Jeroen van Rijn <nom@duclavier.com>. + Copyright 2024 Feoramund <rune@swevencraft.org>. 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 + Feoramund: FreeBSD platform code */ import sys "core:sys/windows" diff --git a/core/net/socket.odin b/core/net/socket.odin index 5f137401e..e36c67d21 100644 --- a/core/net/socket.odin +++ b/core/net/socket.odin @@ -1,4 +1,4 @@ -// +build windows, linux, darwin +// +build windows, linux, darwin, freebsd package net /* @@ -10,12 +10,14 @@ package net Copyright 2022-2023 Tetralux <tetraluxonpc@gmail.com> Copyright 2022-2023 Colin Davidson <colrdavidson@gmail.com> Copyright 2022-2023 Jeroen van Rijn <nom@duclavier.com>. + Copyright 2024 Feoramund <rune@swevencraft.org>. 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 + Feoramund: FreeBSD platform code */ any_socket_to_socket :: proc "contextless" (socket: Any_Socket) -> Socket { diff --git a/core/net/socket_darwin.odin b/core/net/socket_darwin.odin index ba369810b..a56d36de6 100644 --- a/core/net/socket_darwin.odin +++ b/core/net/socket_darwin.odin @@ -10,12 +10,14 @@ package net Copyright 2022 Tetralux <tetraluxonpc@gmail.com> Copyright 2022 Colin Davidson <colrdavidson@gmail.com> Copyright 2022 Jeroen van Rijn <nom@duclavier.com>. + Copyright 2024 Feoramund <rune@swevencraft.org>. 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 + Feoramund: FreeBSD platform code */ import "core:c" diff --git a/core/net/socket_freebsd.odin b/core/net/socket_freebsd.odin new file mode 100644 index 000000000..00da5ec06 --- /dev/null +++ b/core/net/socket_freebsd.odin @@ -0,0 +1,404 @@ +//+build freebsd +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. +*/ + +/* + Copyright 2022 Tetralux <tetraluxonpc@gmail.com> + Copyright 2022 Colin Davidson <colrdavidson@gmail.com> + Copyright 2022 Jeroen van Rijn <nom@duclavier.com>. + Copyright 2024 Feoramund <rune@swevencraft.org>. + 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 + 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, +} + +@(private) +_create_socket :: proc(family: Address_Family, protocol: Socket_Protocol) -> (socket: Any_Socket, err: Network_Error) { + sys_family: freebsd.Protocol_Family = --- + sys_protocol: freebsd.Protocol = --- + sys_socket_type: freebsd.Socket_Type = --- + + switch family { + case .IP4: sys_family = .INET + case .IP6: sys_family = .INET6 + } + + switch protocol { + case .TCP: sys_protocol = .TCP; sys_socket_type = .STREAM + case .UDP: sys_protocol = .UDP; sys_socket_type = .DGRAM + } + + new_socket, errno := freebsd.socket(sys_family, sys_socket_type, sys_protocol) + if errno != nil { + err = cast(Create_Socket_Error)errno + return + } + + // NOTE(Feoramund): By default, FreeBSD will generate SIGPIPE if an EPIPE + // error is raised during the writing of a socket that may be closed. + // This behavior is unlikely to be expected by general users. + // + // There are two workarounds. One is to apply the .NOSIGNAL flag when using + // the `sendto` syscall. However, that would prevent users of this library + // from re-enabling the SIGPIPE-raising functionality, if they really + // wanted it. + // + // So I have disabled it here with this socket option for all sockets. + truth: b32 = true + errno = freebsd.setsockopt(new_socket, .SOCKET, .NOSIGPIPE, &truth, size_of(truth)) + if errno != nil { + err = cast(Socket_Option_Error)errno + return + } + + switch protocol { + case .TCP: return cast(TCP_Socket)new_socket, nil + case .UDP: return cast(UDP_Socket)new_socket, nil + } + + return +} + +@(private) +_dial_tcp_from_endpoint :: proc(endpoint: Endpoint, options := default_tcp_options) -> (socket: TCP_Socket, err: Network_Error) { + if endpoint.port == 0 { + return 0, .Port_Required + } + + family := family_from_endpoint(endpoint) + new_socket := create_socket(family, .TCP) or_return + socket = new_socket.(TCP_Socket) + + sockaddr := _endpoint_to_sockaddr(endpoint) + errno := freebsd.connect(cast(Fd)socket, &sockaddr, cast(freebsd.socklen_t)sockaddr.len) + if errno != nil { + err = cast(Dial_Error)errno + return + } + + return +} + +@(private) +_bind :: proc(socket: Any_Socket, ep: Endpoint) -> (err: Network_Error) { + sockaddr := _endpoint_to_sockaddr(ep) + real_socket := any_socket_to_socket(socket) + errno := freebsd.bind(cast(Fd)real_socket, &sockaddr, cast(freebsd.socklen_t)sockaddr.len) + if errno != nil { + err = cast(Bind_Error)errno + } + return +} + +@(private) +_listen_tcp :: proc(interface_endpoint: Endpoint, backlog := 1000) -> (socket: TCP_Socket, err: Network_Error) { + family := family_from_endpoint(interface_endpoint) + new_socket := create_socket(family, .TCP) or_return + socket = new_socket.(TCP_Socket) + + bind(socket, interface_endpoint) or_return + + errno := freebsd.listen(cast(Fd)socket, backlog) + if errno != nil { + err = cast(Listen_Error)errno + return + } + + return +} + +@(private) +_accept_tcp :: proc(sock: TCP_Socket, options := default_tcp_options) -> (client: TCP_Socket, source: Endpoint, err: Network_Error) { + sockaddr: freebsd.Socket_Address_Storage + + result, errno := freebsd.accept(cast(Fd)sock, &sockaddr) + if errno != nil { + err = cast(Accept_Error)errno + return + } + + client = cast(TCP_Socket)result + source = _sockaddr_to_endpoint(&sockaddr) + return +} + +@(private) +_close :: proc(socket: Any_Socket) { + real_socket := cast(Fd)any_socket_to_socket(socket) + // TODO: This returns an error number, but the `core:net` interface does not handle it. + _ = freebsd.close(real_socket) +} + +@(private) +_recv_tcp :: proc(socket: TCP_Socket, buf: []byte) -> (bytes_read: int, err: Network_Error) { + if len(buf) == 0 { + return + } + result, errno := freebsd.recv(cast(Fd)socket, buf, .NONE) + if errno != nil { + err = cast(TCP_Recv_Error)errno + return + } + return result, nil +} + +@(private) +_recv_udp :: proc(socket: UDP_Socket, buf: []byte) -> (bytes_read: int, remote_endpoint: Endpoint, err: Network_Error) { + if len(buf) == 0 { + return + } + from: freebsd.Socket_Address_Storage + + result, errno := freebsd.recvfrom(cast(Fd)socket, buf, .NONE, &from) + if errno != nil { + err = cast(UDP_Recv_Error)errno + return + } + return result, _sockaddr_to_endpoint(&from), nil +} + +@(private) +_send_tcp :: proc(socket: TCP_Socket, buf: []byte) -> (bytes_written: int, err: Network_Error) { + for bytes_written < len(buf) { + limit := min(int(max(i32)), len(buf) - bytes_written) + remaining := buf[bytes_written:][:limit] + + result, errno := freebsd.send(cast(Fd)socket, remaining, .NONE) + if errno != nil { + err = cast(TCP_Send_Error)errno + return + } + bytes_written += result + } + return +} + +@(private) +_send_udp :: proc(socket: UDP_Socket, buf: []byte, to: Endpoint) -> (bytes_written: int, err: Network_Error) { + toaddr := _endpoint_to_sockaddr(to) + for bytes_written < len(buf) { + limit := min(int(max(i32)), len(buf) - bytes_written) + remaining := buf[bytes_written:][:limit] + + result, errno := freebsd.sendto(cast(Fd)socket, remaining, .NONE, &toaddr) + if errno != nil { + err = cast(UDP_Send_Error)errno + return + } + bytes_written += result + } + return +} + +@(private) +_shutdown :: proc(socket: Any_Socket, manner: Shutdown_Manner) -> (err: Network_Error) { + real_socket := cast(Fd)any_socket_to_socket(socket) + errno := freebsd.shutdown(real_socket, cast(freebsd.Shutdown_Method)manner) + if errno != nil { + return cast(Shutdown_Error)errno + } + return +} + +@(private) +_set_option :: proc(socket: Any_Socket, option: Socket_Option, value: any, loc := #caller_location) -> Network_Error { + // NOTE(Feoramund): I found that FreeBSD, like Linux, requires at least 32 + // bits for a boolean socket option value. Nothing less will work. + bool_value: b32 + // TODO: Assuming no larger than i32, but the system may accept i64. + int_value: i32 + timeval_value: freebsd.timeval + + ptr: rawptr + len: freebsd.socklen_t + + switch option { + case + .Reuse_Address, + .Keep_Alive, + .Broadcast, + .Use_Loopback, + .Out_Of_Bounds_Data_Inline, + .Reuse_Port, + .No_SIGPIPE_From_EPIPE, + .Reuse_Port_Load_Balancing: + switch real in value { + case bool: bool_value = cast(b32)real + case b8: bool_value = cast(b32)real + case b16: bool_value = cast(b32)real + case b32: bool_value = real + case b64: bool_value = cast(b32)real + case: + panic("set_option() value must be a boolean here", loc) + } + ptr = &bool_value + len = size_of(bool_value) + case + .Linger, + .Send_Timeout, + .Receive_Timeout: + t, ok := value.(time.Duration) + if !ok { + panic("set_option() value must be a time.Duration here", loc) + } + + micros := cast(freebsd.time_t)time.duration_microseconds(t) + timeval_value.usec = cast(freebsd.suseconds_t)micros % 1e6 + timeval_value.sec = (micros - cast(freebsd.time_t)timeval_value.usec) / 1e6 + + ptr = &timeval_value + len = size_of(timeval_value) + case + .Receive_Buffer_Size, + .Send_Buffer_Size: + switch real in value { + case i8: int_value = cast(i32)real + case u8: int_value = cast(i32)real + case i16: int_value = cast(i32)real + case u16: int_value = cast(i32)real + case i32: int_value = real + case u32: + if real > u32(max(i32)) { return .Value_Out_Of_Range } + int_value = cast(i32)real + case i64: + if real > i64(max(i32)) || real < i64(min(i32)) { return .Value_Out_Of_Range } + int_value = cast(i32)real + case u64: + if real > u64(max(i32)) { return .Value_Out_Of_Range } + int_value = cast(i32)real + case i128: + if real > i128(max(i32)) || real < i128(min(i32)) { return .Value_Out_Of_Range } + int_value = cast(i32)real + case u128: + if real > u128(max(i32)) { return .Value_Out_Of_Range } + int_value = cast(i32)real + case int: + if real > int(max(i32)) || real < int(min(i32)) { return .Value_Out_Of_Range } + int_value = cast(i32)real + case uint: + if real > uint(max(i32)) { return .Value_Out_Of_Range } + int_value = cast(i32)real + case: + panic("set_option() value must be an integer here", loc) + } + ptr = &int_value + len = size_of(int_value) + case: + unimplemented("set_option() option not yet implemented", loc) + } + + real_socket := any_socket_to_socket(socket) + errno := freebsd.setsockopt(cast(Fd)real_socket, .SOCKET, cast(freebsd.Socket_Option)option, ptr, len) + if errno != nil { + return cast(Socket_Option_Error)errno + } + + return nil +} + +@(private) +_set_blocking :: proc(socket: Any_Socket, should_block: bool) -> (err: Network_Error) { + real_socket := any_socket_to_socket(socket) + + flags, errno := freebsd.fcntl_getfl(cast(freebsd.Fd)real_socket) + if errno != nil { + return cast(Set_Blocking_Error)errno + } + + if should_block { + flags &= ~{ .NONBLOCK } + } else { + flags |= { .NONBLOCK } + } + + errno = freebsd.fcntl_setfl(cast(freebsd.Fd)real_socket, flags) + if errno != nil { + return cast(Set_Blocking_Error)errno + } + + return +} + +@(private) +_endpoint_to_sockaddr :: proc(ep: Endpoint) -> (sockaddr: freebsd.Socket_Address_Storage) { + switch addr in ep.address { + case IP4_Address: + (cast(^freebsd.Socket_Address_Internet)(&sockaddr))^ = { + len = size_of(freebsd.Socket_Address_Internet), + family = .INET, + port = cast(freebsd.in_port_t)ep.port, + addr = transmute(freebsd.IP4_Address)addr, + } + case IP6_Address: + (cast(^freebsd.Socket_Address_Internet6)(&sockaddr))^ = { + len = size_of(freebsd.Socket_Address_Internet), + family = .INET6, + port = cast(freebsd.in_port_t)ep.port, + addr = transmute(freebsd.IP6_Address)addr, + } + } + return +} + +@(private) +_sockaddr_to_endpoint :: proc(native_addr: ^freebsd.Socket_Address_Storage) -> (ep: Endpoint) { + #partial switch native_addr.family { + case .INET: + addr := cast(^freebsd.Socket_Address_Internet)native_addr + ep = { + address = cast(IP4_Address)addr.addr.addr8, + port = cast(int)addr.port, + } + case .INET6: + addr := cast(^freebsd.Socket_Address_Internet6)native_addr + ep = { + address = cast(IP6_Address)addr.addr.addr16, + port = cast(int)addr.port, + } + case: + panic("native_addr is neither an IP4 or IP6 address") + } + return +} diff --git a/core/net/socket_linux.odin b/core/net/socket_linux.odin index 350d3947c..dce428685 100644 --- a/core/net/socket_linux.odin +++ b/core/net/socket_linux.odin @@ -10,6 +10,7 @@ package net Copyright 2022 Tetralux <tetraluxonpc@gmail.com> Copyright 2022 Colin Davidson <colrdavidson@gmail.com> Copyright 2022 Jeroen van Rijn <nom@duclavier.com>. + Copyright 2024 Feoramund <rune@swevencraft.org>. Made available under Odin's BSD-3 license. List of contributors: @@ -17,6 +18,7 @@ package net Colin Davidson: Linux platform code, OSX platform code, Odin-native DNS resolver Jeroen van Rijn: Cross platform unification, code style, documentation flysand: Move dependency from core:os to core:sys/linux + Feoramund: FreeBSD platform code */ import "core:c" diff --git a/core/net/socket_windows.odin b/core/net/socket_windows.odin index eef0df583..8ee75bc3b 100644 --- a/core/net/socket_windows.odin +++ b/core/net/socket_windows.odin @@ -10,12 +10,14 @@ package net Copyright 2022 Tetralux <tetraluxonpc@gmail.com> Copyright 2022 Colin Davidson <colrdavidson@gmail.com> Copyright 2022 Jeroen van Rijn <nom@duclavier.com>. + Copyright 2024 Feoramund <rune@swevencraft.org>. 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 + Feoramund: FreeBSD platform code */ import "core:c" diff --git a/core/net/url.odin b/core/net/url.odin index 16aa57ec5..aadcf5e48 100644 --- a/core/net/url.odin +++ b/core/net/url.odin @@ -8,12 +8,14 @@ package net Copyright 2022 Tetralux <tetraluxonpc@gmail.com> Copyright 2022 Colin Davidson <colrdavidson@gmail.com> Copyright 2022 Jeroen van Rijn <nom@duclavier.com>. + Copyright 2024 Feoramund <rune@swevencraft.org>. 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 + Feoramund: FreeBSD platform code */ import "core:strings" diff --git a/core/sync/futex_freebsd.odin b/core/sync/futex_freebsd.odin index 60b1d6e0d..ac6e2400a 100644 --- a/core/sync/futex_freebsd.odin +++ b/core/sync/futex_freebsd.odin @@ -3,35 +3,27 @@ package sync import "core:c" +import "core:sys/freebsd" import "core:time" -UMTX_OP_WAIT :: 2 -UMTX_OP_WAKE :: 3 - -ETIMEDOUT :: 60 - -foreign import libc "system:c" - -foreign libc { - _umtx_op :: proc "c" (obj: rawptr, op: c.int, val: c.ulong, uaddr: rawptr, uaddr2: rawptr) -> c.int --- - __error :: proc "c" () -> ^c.int --- -} - _futex_wait :: proc "contextless" (f: ^Futex, expected: u32) -> bool { - timeout := [2]i64{14400, 0} // 4 hours + timeout := freebsd.timespec {14400, 0} // 4 hours + timeout_size := cast(rawptr)cast(uintptr)size_of(timeout) + for { - res := _umtx_op(f, UMTX_OP_WAIT, c.ulong(expected), nil, &timeout) + errno := freebsd._umtx_op(f, .WAIT_UINT, cast(c.ulong)expected, timeout_size, &timeout) - if res != -1 { + if errno == nil { return true } - if __error()^ == ETIMEDOUT { + if errno == .ETIMEDOUT { continue } _panic("_futex_wait failure") } + unreachable() } @@ -40,14 +32,15 @@ _futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expected: u32, durati return false } - timeout := [2]i64{i64(duration/1e9), i64(duration%1e9)} + timeout := freebsd.timespec {cast(freebsd.time_t)duration / 1e9, cast(c.long)duration % 1e9} + timeout_size := cast(rawptr)cast(uintptr)size_of(timeout) - res := _umtx_op(f, UMTX_OP_WAIT, c.ulong(expected), nil, &timeout) - if res != -1 { + errno := freebsd._umtx_op(f, .WAIT_UINT, cast(c.ulong)expected, timeout_size, &timeout) + if errno == nil { return true } - if __error()^ == ETIMEDOUT { + if errno == .ETIMEDOUT { return false } @@ -55,17 +48,17 @@ _futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expected: u32, durati } _futex_signal :: proc "contextless" (f: ^Futex) { - res := _umtx_op(f, UMTX_OP_WAKE, 1, nil, nil) + errno := freebsd._umtx_op(f, .WAKE, 1, nil, nil) - if res == -1 { + if errno != nil { _panic("_futex_signal failure") } } _futex_broadcast :: proc "contextless" (f: ^Futex) { - res := _umtx_op(f, UMTX_OP_WAKE, c.ulong(max(i32)), nil, nil) + errno := freebsd._umtx_op(f, .WAKE, cast(c.ulong)max(i32), nil, nil) - if res == -1 { + if errno != nil { _panic("_futex_broadcast failure") } } diff --git a/core/sys/freebsd/syscalls.odin b/core/sys/freebsd/syscalls.odin new file mode 100644 index 000000000..4a79bd56c --- /dev/null +++ b/core/sys/freebsd/syscalls.odin @@ -0,0 +1,515 @@ +package sys_freebsd + +/* + (c) Copyright 2024 Feoramund <rune@swevencraft.org>. + Made available under Odin's BSD-3 license. + + List of contributors: + Feoramund: Initial implementation. +*/ + +import "base:intrinsics" +import "core:c" + +// FreeBSD 15 syscall numbers +// See: https://alfonsosiciliano.gitlab.io/posts/2023-08-28-freebsd-15-system-calls.html + +SYS_open : uintptr : 5 +SYS_close : uintptr : 6 +SYS_getpid : uintptr : 20 +SYS_recvfrom : uintptr : 29 +SYS_accept : uintptr : 30 +SYS_fcntl : uintptr : 92 +SYS_socket : uintptr : 97 +SYS_connect : uintptr : 98 +SYS_bind : uintptr : 104 +SYS_listen : uintptr : 106 +SYS_sendto : uintptr : 133 +SYS_shutdown : uintptr : 134 +SYS_setsockopt : uintptr : 105 +SYS_sysctl : uintptr : 202 +SYS__umtx_op : uintptr : 454 +SYS_accept4 : uintptr : 541 + +// +// Odin syscall wrappers +// + +// Open or create a file for reading, writing or executing. +// +// The open() function appeared in Version 1 AT&T UNIX. +// The openat() function was introduced in FreeBSD 8.0. +open :: proc "contextless" (path: string, flags: File_Status_Flags, mode: int = 0o000) -> (Fd, Errno) { + result, ok := intrinsics.syscall_bsd(SYS_open, + cast(uintptr)raw_data(path), + cast(uintptr)transmute(c.int)flags, + cast(uintptr)mode) + + if !ok { + return 0, cast(Errno)result + } + + return cast(Fd)result, nil +} + +// Delete a descriptor. +// +// The open() function appeared in Version 1 AT&T UNIX. +close :: proc "contextless" (fd: Fd) -> Errno { + result, _ := intrinsics.syscall_bsd(SYS_close, + cast(uintptr)fd) + + return cast(Errno)result +} + +// Get parent or calling process identification. +// +// The getpid() function appeared in Version 7 AT&T UNIX. +getpid :: proc "contextless" () -> pid_t { + // This always succeeds. + result, _ := intrinsics.syscall_bsd(SYS_getpid) + return cast(pid_t)result +} + +// Receive message(s) from a socket. +// +// The recv() function appeared in 4.2BSD. +// The recvmmsg() function appeared in FreeBSD 11.0. +recvfrom :: proc "contextless" (s: Fd, buf: []u8, flags: Recv_Flags, from: ^$T) -> (int, Errno) +where + intrinsics.type_is_subtype_of(T, Socket_Address_Header) +{ + fromlen: socklen_t = size_of(T) + + result, ok := intrinsics.syscall_bsd(SYS_recvfrom, + cast(uintptr)s, + cast(uintptr)raw_data(buf), + cast(uintptr)len(buf), + cast(uintptr)flags, + cast(uintptr)from, + cast(uintptr)&fromlen) + + // `from.len` will be modified by the syscall, so we shouldn't need to pass + // `fromlen` back from this API. + + if !ok { + return 0, cast(Errno)result + } + + return cast(int)result, nil +} + +// Receive message(s) from a socket. +// +// The recv() function appeared in 4.2BSD. +// The recvmmsg() function appeared in FreeBSD 11.0. +recv :: proc "contextless" (s: Fd, buf: []u8, flags: Recv_Flags) -> (int, Errno) { + // This is a wrapper over recvfrom(). + result, ok := intrinsics.syscall_bsd(SYS_recvfrom, + cast(uintptr)s, + cast(uintptr)raw_data(buf), + cast(uintptr)len(buf), + cast(uintptr)flags, + 0, + 0) + + if !ok { + return 0, cast(Errno)result + } + + return cast(int)result, nil +} + +// Accept a connection on a socket. +// +// The accept() system call appeared in 4.2BSD. +accept_T :: proc "contextless" (s: Fd, sockaddr: ^$T) -> (Fd, Errno) +where + intrinsics.type_is_subtype_of(T, Socket_Address_Header) +{ + // sockaddr must contain a valid pointer, or this will segfault because + // we're telling the syscall that there's memory available to write to. + addrlen: socklen_t = size_of(T) + + result, ok := intrinsics.syscall_bsd(SYS_accept, + cast(uintptr)s, + cast(uintptr)sockaddr, + cast(uintptr)&addrlen) + + if !ok { + return 0, cast(Errno)result + } + + sockaddr.len = cast(u8)addrlen + + return cast(Fd)result, nil +} + + +// Accept a connection on a socket. +// +// The accept() system call appeared in 4.2BSD. +accept_nil :: proc "contextless" (s: Fd) -> (Fd, Errno) { + result, ok := intrinsics.syscall_bsd(SYS_accept, + cast(uintptr)s, + cast(uintptr)0, + cast(uintptr)0) + + if !ok { + return 0, cast(Errno)result + } + + return cast(Fd)result, nil +} + +accept :: proc { accept_T, accept_nil } + +// File control. +// +// The fcntl() system call appeared in 4.2BSD. +// The F_DUP2FD constant first appeared in FreeBSD 7.1. +// +// NOTE: If you know at compile-time what command you're calling, use one of the +// `fcntl_*` procedures instead to preserve type safety. +fcntl :: proc "contextless" (fd: Fd, cmd: File_Control_Command, arg: c.int) -> (int, Errno) { + result, ok := intrinsics.syscall_bsd(SYS_fcntl, + cast(uintptr)fd, + cast(uintptr)cmd, + cast(uintptr)arg) + + if !ok { + return 0, cast(Errno)result + } + + return cast(int)result, nil +} + +// TODO: Implement more type-safe fcntl commands. + +fcntl_dupfd :: proc "contextless" (fd: Fd, newfd: Fd) -> (Fd, Errno) { + result, ok := intrinsics.syscall_bsd(SYS_fcntl, + cast(uintptr)fd, + cast(uintptr)File_Control_Command.DUPFD, + cast(uintptr)newfd) + + if !ok { + return 0, cast(Errno)result + } + + return cast(Fd)result, nil +} + +fcntl_getfd :: proc "contextless" (fd: Fd) -> (bool, Errno) { + result, ok := intrinsics.syscall_bsd(SYS_fcntl, + cast(uintptr)fd, + cast(uintptr)File_Control_Command.GETFD) + + if !ok { + return false, cast(Errno)result + } + + return result & FD_CLOEXEC > 0, nil +} + +fcntl_setfd :: proc "contextless" (fd: Fd, close_on_exec: bool) -> Errno { + result, _ := intrinsics.syscall_bsd(SYS_fcntl, + cast(uintptr)fd, + cast(uintptr)File_Control_Command.SETFD, + (close_on_exec ? FD_CLOEXEC : 0)) + + return cast(Errno)result +} + +fcntl_getfl :: proc "contextless" (fd: Fd) -> (File_Status_Flags, Errno) { + result, ok := intrinsics.syscall_bsd(SYS_fcntl, + cast(uintptr)fd, + cast(uintptr)File_Control_Command.GETFL) + + if !ok { + return nil, cast(Errno)result + } + + return transmute(File_Status_Flags)cast(c.int)result, nil +} + +fcntl_setfl :: proc "contextless" (fd: Fd, flags: File_Status_Flags) -> Errno { + result, _ := intrinsics.syscall_bsd(SYS_fcntl, + cast(uintptr)fd, + cast(uintptr)File_Control_Command.SETFL, + cast(uintptr)transmute(c.int)flags) + + return cast(Errno)result +} + +fcntl_getown :: proc "contextless" (fd: Fd) -> (pid_t, Errno) { + result, ok := intrinsics.syscall_bsd(SYS_fcntl, + cast(uintptr)fd, + cast(uintptr)File_Control_Command.GETOWN) + + if !ok { + return 0, cast(Errno)result + } + + return cast(pid_t)result, nil +} + +fcntl_setown :: proc "contextless" (fd: Fd, pid: pid_t) -> Errno { + result, _ := intrinsics.syscall_bsd(SYS_fcntl, + cast(uintptr)fd, + cast(uintptr)File_Control_Command.SETOWN, + cast(uintptr)pid) + + return cast(Errno)result +} + +fcntl_getlk :: proc "contextless" (fd: Fd, flock: ^File_Lock) -> Errno { + result, _ := intrinsics.syscall_bsd(SYS_fcntl, + cast(uintptr)fd, + cast(uintptr)File_Control_Command.GETLK, + cast(uintptr)flock) + + return cast(Errno)result +} + +fcntl_setlk :: proc "contextless" (fd: Fd, flock: ^File_Lock) -> Errno { + result, _ := intrinsics.syscall_bsd(SYS_fcntl, + cast(uintptr)fd, + cast(uintptr)File_Control_Command.SETLK, + cast(uintptr)flock) + + return cast(Errno)result +} + +fcntl_add_seals :: proc "contextless" (fd: Fd, seals: File_Seals) -> Errno { + result, _ := intrinsics.syscall_bsd(SYS_fcntl, + cast(uintptr)fd, + cast(uintptr)File_Control_Command.ADD_SEALS, + cast(uintptr)transmute(c.int)seals) + + return cast(Errno)result +} + +fcntl_get_seals :: proc "contextless" (fd: Fd) -> (File_Seals, Errno) { + result, ok := intrinsics.syscall_bsd(SYS_fcntl, + cast(uintptr)fd, + cast(uintptr)File_Control_Command.GET_SEALS) + + if !ok { + return nil, cast(Errno)result + } + + return transmute(File_Seals)cast(c.int)result, nil +} + +// +// End type-safe fcntl commands. +// + +// Create an endpoint for communication. +// +// The socket() system call appeared in 4.2BSD. +socket :: proc "contextless" (domain: Protocol_Family, type: Socket_Type, protocol: Protocol) -> (Fd, Errno) { + result, ok := intrinsics.syscall_bsd(SYS_socket, + cast(uintptr)domain, + cast(uintptr)type, + cast(uintptr)protocol) + + if !ok { + return 0, cast(Errno)result + } + + return cast(Fd)result, nil +} + +// Initiate a connection on a socket. +// +// The connect() system call appeared in 4.2BSD. +connect :: proc "contextless" (fd: Fd, sockaddr: ^$T, addrlen: socklen_t) -> Errno +where + intrinsics.type_is_subtype_of(T, Socket_Address_Header) +{ + result, _ := intrinsics.syscall_bsd(SYS_connect, + cast(uintptr)fd, + cast(uintptr)sockaddr, + cast(uintptr)addrlen) + + return cast(Errno)result +} + + +// Assign a local protocol address to a socket. +// +// The bind() system call appeared in 4.2BSD. +bind :: proc "contextless" (s: Fd, sockaddr: ^$T, addrlen: socklen_t) -> Errno +where + intrinsics.type_is_subtype_of(T, Socket_Address_Header) +{ + result, _ := intrinsics.syscall_bsd(SYS_bind, + cast(uintptr)s, + cast(uintptr)sockaddr, + cast(uintptr)addrlen) + + return cast(Errno)result +} + +// Listen for connections on a socket. +// +// The listen() system call appeared in 4.2BSD. +listen :: proc "contextless" (s: Fd, backlog: int) -> Errno { + result, _ := intrinsics.syscall_bsd(SYS_listen, + cast(uintptr)s, + cast(uintptr)backlog) + + return cast(Errno)result +} + +// Send message(s) from a socket. +// +// The send() function appeared in 4.2BSD. +// The sendmmsg() function appeared in FreeBSD 11.0. +sendto :: proc "contextless" (s: Fd, msg: []u8, flags: Send_Flags, to: ^$T) -> (int, Errno) +where + intrinsics.type_is_subtype_of(T, Socket_Address_Header) +{ + result, ok := intrinsics.syscall_bsd(SYS_sendto, + cast(uintptr)s, + cast(uintptr)raw_data(msg), + cast(uintptr)len(msg), + cast(uintptr)flags, + cast(uintptr)to, + cast(uintptr)to.len) + + if !ok { + return 0, cast(Errno)result + } + + return cast(int)result, nil +} + +// Send message(s) from a socket. +// +// The send() function appeared in 4.2BSD. +// The sendmmsg() function appeared in FreeBSD 11.0. +send :: proc "contextless" (s: Fd, msg: []u8, flags: Send_Flags) -> (int, Errno) { + // This is a wrapper over sendto(). + result, ok := intrinsics.syscall_bsd(SYS_sendto, + cast(uintptr)s, + cast(uintptr)raw_data(msg), + cast(uintptr)len(msg), + cast(uintptr)flags, + 0, + 0) + + if !ok { + return 0, cast(Errno)result + } + + return cast(int)result, nil +} + +// Disable sends and/or receives on a socket. +// +// The shutdown() system call appeared in 4.2BSD. +shutdown :: proc "contextless" (s: Fd, how: Shutdown_Method) -> Errno { + result, _ := intrinsics.syscall_bsd(SYS_shutdown, + cast(uintptr)s, + cast(uintptr)how) + + return cast(Errno)result +} + +// Get and set options on sockets. +// +// The getsockopt() and setsockopt() system calls appeared in 4.2BSD. +setsockopt :: proc "contextless" (s: Fd, level: Valid_Socket_Option_Level, optname: Socket_Option, optval: rawptr, optlen: socklen_t) -> Errno { + real_level: uintptr + switch which in level { + case Protocol_Family: real_level = cast(uintptr)which + case Socket_Option_Level: real_level = cast(uintptr)which + } + + result, _ := intrinsics.syscall_bsd(SYS_setsockopt, + cast(uintptr)s, + real_level, + cast(uintptr)optname, + cast(uintptr)optval, + cast(uintptr)optlen) + + return cast(Errno)result +} + +// Get or set system information. +// +// The sysctl() function first appeared in 4.4BSD. +sysctl :: proc "contextless" (mib: []MIB_Identifier, oldp: rawptr, oldlenp: ^c.size_t, newp: rawptr, newlen: c.size_t) -> Errno { + result, _ := intrinsics.syscall_bsd(SYS_sysctl, + cast(uintptr)raw_data(mib), + cast(uintptr)len(mib), + cast(uintptr)oldp, + cast(uintptr)oldlenp, + cast(uintptr)newp, + cast(uintptr)newlen) + + return cast(Errno)result +} + +// Interface for implementation of userspace threading synchronization primitives. +// +// The _umtx_op() system call is non-standard and is used by the 1:1 Threading +// Library (libthr, -lthr) to implement IEEE Std 1003.1-2001 (“POSIX.1”) +// pthread(3) functionality. +_umtx_op :: proc "contextless" (obj: rawptr, op: Userland_Mutex_Operation, val: c.ulong, uaddr, uaddr2: rawptr) -> Errno { + result, _ := intrinsics.syscall_bsd(SYS__umtx_op, + cast(uintptr)obj, + cast(uintptr)op, + cast(uintptr)val, + cast(uintptr)uaddr, + cast(uintptr)uaddr2) + + return cast(Errno)result +} + +// Accept a connection on a socket. +// +// The accept4() system call appeared in FreeBSD 10.0. +accept4_T :: proc "contextless" (s: Fd, sockaddr: ^$T, flags: Socket_Flags = {}) -> (Fd, Errno) +where + intrinsics.type_is_subtype_of(T, Socket_Address_Header) +{ + // `sockaddr` must contain a valid pointer, or this will segfault because + // we're telling the syscall that there's memory available to write to. + addrlen: u32 = size_of(T) + + result, ok := intrinsics.syscall_bsd(SYS_accept4, + cast(uintptr)s, + cast(uintptr)sockaddr, + cast(uintptr)&addrlen, + cast(uintptr)transmute(c.int)flags) + + if !ok { + return 0, cast(Errno)result + } + + sockaddr.len = cast(u8)addrlen + + return cast(Fd)result, nil +} + +// Accept a connection on a socket. +// +// The accept4() system call appeared in FreeBSD 10.0. +accept4_nil :: proc "contextless" (s: Fd, flags: Socket_Flags = {}) -> (Fd, Errno) { + result, ok := intrinsics.syscall_bsd(SYS_accept4, + cast(uintptr)s, + cast(uintptr)0, + cast(uintptr)0, + cast(uintptr)transmute(c.int)flags) + + if !ok { + return 0, cast(Errno)result + } + + return cast(Fd)result, nil +} + +accept4 :: proc { accept4_nil, accept4_T } diff --git a/core/sys/freebsd/types.odin b/core/sys/freebsd/types.odin new file mode 100644 index 000000000..a13961a47 --- /dev/null +++ b/core/sys/freebsd/types.odin @@ -0,0 +1,1587 @@ +package sys_freebsd + +/* + (c) Copyright 2024 Feoramund <rune@swevencraft.org>. + Made available under Odin's BSD-3 license. + + List of contributors: + Feoramund: Initial implementation. +*/ + +import "core:c" + +// These definitions have been extracted from a system running FreeBSD 14.0-RELEASE. +// Most comments come from system header files. +// +// Where applicable, original C struct and define names are indicated in line +// comments above Odin declarations. +// +// This data is separated into blocks by original header file. If you happen to +// add or change something in this file, mind the organizational structure. + +Fd :: distinct c.int + +// +// #include <x86/_types.h> +// & +// #include <arm/_types.h> +// + +time_t :: distinct i64 + +// +// #include <sys/_types.h> +// + +off_t :: distinct i64 +pid_t :: distinct i32 +sa_family_t :: distinct u8 +socklen_t :: distinct u32 +suseconds_t :: distinct c.long /* microseconds (signed) */ + +// +// #include <sys/types.h> +// + +in_port_t :: distinct u16be + +// +// #include <sys/_timespec.h> +// + +timespec :: struct { + sec: time_t, /* seconds */ + nsec: c.long, /* and nanoseconds */ +} + +// +// #include <sys/_timeval.h> +// + +timeval :: struct { + sec: time_t, /* seconds */ + usec: suseconds_t, /* and microseconds */ +} + +// +// #include <sys/errno.h> +// + +Errno :: enum c.int { + NONE = 0, + EPERM = 1, + ENOENT = 2, + ESRCH = 3, + EINTR = 4, + EIO = 5, + ENXIO = 6, + E2BIG = 7, + ENOEXEC = 8, + EBADF = 9, + ECHILD = 10, + EDEADLK = 11, + ENOMEM = 12, + EACCES = 13, + EFAULT = 14, + ENOTBLK = 15, + EBUSY = 16, + EEXIST = 17, + EXDEV = 18, + ENODEV = 19, + ENOTDIR = 20, + EISDIR = 21, + EINVAL = 22, + ENFILE = 23, + EMFILE = 24, + ENOTTY = 25, + ETXTBSY = 26, + EFBIG = 27, + ENOSPC = 28, + ESPIPE = 29, + EROFS = 30, + EMLINK = 31, + EPIPE = 32, + EDOM = 33, + ERANGE = 34, + EAGAIN = 35, + EWOULDBLOCK = EAGAIN, + EINPROGRESS = 36, + EALREADY = 37, + ENOTSOCK = 38, + EDESTADDRREQ = 39, + EMSGSIZE = 40, + EPROTOTYPE = 41, + ENOPROTOOPT = 42, + EPROTONOSUPPORT = 43, + ESOCKTNOSUPPORT = 44, + EOPNOTSUPP = 45, + ENOTSUP = EOPNOTSUPP, + EPFNOSUPPORT = 46, + EAFNOSUPPORT = 47, + EADDRINUSE = 48, + EADDRNOTAVAIL = 49, + ENETDOWN = 50, + ENETUNREACH = 51, + ENETRESET = 52, + ECONNABORTED = 53, + ECONNRESET = 54, + ENOBUFS = 55, + EISCONN = 56, + ENOTCONN = 57, + ESHUTDOWN = 58, + ETOOMANYREFS = 59, + ETIMEDOUT = 60, + ECONNREFUSED = 61, + ELOOP = 62, + ENAMETOOLONG = 63, + EHOSTDOWN = 64, + EHOSTUNREACH = 65, + ENOTEMPTY = 66, + EPROCLIM = 67, + EUSERS = 68, + EDQUOT = 69, + ESTALE = 70, + EREMOTE = 71, + EBADRPC = 72, + ERPCMISMATCH = 73, + EPROGUNAVAIL = 74, + EPROGMISMATCH = 75, + EPROCUNAVAIL = 76, + ENOLCK = 77, + ENOSYS = 78, + EFTYPE = 79, + EAUTH = 80, + ENEEDAUTH = 81, + EIDRM = 82, + ENOMSG = 83, + EOVERFLOW = 84, + ECANCELED = 85, + EILSEQ = 86, + ENOATTR = 87, + EDOOFUS = 88, + EBADMSG = 89, + EMULTIHOP = 90, + ENOLINK = 91, + EPROTO = 92, + ENOTCAPABLE = 93, + ECAPMODE = 94, + ENOTRECOVERABLE = 95, + EOWNERDEAD = 96, + EINTEGRITY = 97, +} + +// +// #include <sys/socket.h> +// + +/* + * Types + */ +// #define SOCK_* +Socket_Type :: enum c.int { + STREAM = 1, /* stream socket */ + DGRAM = 2, /* datagram socket */ + RAW = 3, /* raw-protocol interface */ + RDM = 4, /* reliably-delivered message */ + SEQPACKET = 5, /* sequenced packet stream */ + + /* + * Creation flags, OR'ed into socket() and socketpair() type argument. + */ + CLOEXEC = 0x10000000, + NONBLOCK = 0x20000000, +} + +Socket_Flag_Index :: enum c.int { + CLOEXEC = 28, // 0x10000000 + NONBLOCK = 29, // 0x20000000 +} + +Socket_Flags :: bit_set[Socket_Flag_Index; c.int] + +/* + * Option flags per-socket. + */ +// #define SO_* +Socket_Option :: enum c.int { + DEBUG = 0x00000001, /* turn on debugging info recording */ + ACCEPTCONN = 0x00000002, /* socket has had listen() */ + REUSEADDR = 0x00000004, /* allow local address reuse */ + KEEPALIVE = 0x00000008, /* keep connections alive */ + DONTROUTE = 0x00000010, /* just use interface addresses */ + BROADCAST = 0x00000020, /* permit sending of broadcast msgs */ + USELOOPBACK = 0x00000040, /* bypass hardware when possible */ + LINGER = 0x00000080, /* linger on close if data present */ + OOBINLINE = 0x00000100, /* leave received OOB data in line */ + REUSEPORT = 0x00000200, /* allow local address & port reuse */ + TIMESTAMP = 0x00000400, /* timestamp received dgram traffic */ + NOSIGPIPE = 0x00000800, /* no SIGPIPE from EPIPE */ + ACCEPTFILTER = 0x00001000, /* there is an accept filter */ + BINTIME = 0x00002000, /* timestamp received dgram traffic */ + NO_OFFLOAD = 0x00004000, /* socket cannot be offloaded */ + NO_DDP = 0x00008000, /* disable direct data placement */ + REUSEPORT_LB = 0x00010000, /* reuse with load balancing */ + RERROR = 0x00020000, /* keep track of receive errors */ + + /* + * Additional options, not kept in so_options. + */ + SNDBUF = 0x1001, /* send buffer size */ + RCVBUF = 0x1002, /* receive buffer size */ + SNDLOWAT = 0x1003, /* send low-water mark */ + RCVLOWAT = 0x1004, /* receive low-water mark */ + SNDTIMEO = 0x1005, /* send timeout */ + RCVTIMEO = 0x1006, /* receive timeout */ + ERROR = 0x1007, /* get error status and clear */ + TYPE = 0x1008, /* get socket type */ + LABEL = 0x1009, /* socket's MAC label */ + PEERLABEL = 0x1010, /* socket's peer's MAC label */ + LISTENQLIMIT = 0x1011, /* socket's backlog limit */ + LISTENQLEN = 0x1012, /* socket's complete queue length */ + LISTENINCQLEN = 0x1013, /* socket's incomplete queue length */ + SETFIB = 0x1014, /* use this FIB to route */ + USER_COOKIE = 0x1015, /* user cookie (dummynet etc.) */ + PROTOCOL = 0x1016, /* get socket protocol (Linux name) */ + PROTOTYPE = PROTOCOL, /* alias for SO_PROTOCOL (SunOS name) */ + TS_CLOCK = 0x1017, /* clock type used for SO_TIMESTAMP */ + MAX_PACING_RATE = 0x1018, /* socket's max TX pacing rate (Linux name) */ + DOMAIN = 0x1019, /* get socket domain */ + + TS_REALTIME_MICRO = 0, /* microsecond resolution, realtime */ + TS_BINTIME = 1, /* sub-nanosecond resolution, realtime */ + TS_REALTIME = 2, /* nanosecond resolution, realtime */ + TS_MONOTONIC = 3, /* nanosecond resolution, monotonic */ + TS_DEFAULT = TS_REALTIME_MICRO, + TS_CLOCK_MAX = TS_MONOTONIC, +} + +Valid_Socket_Option_Level :: union #no_nil { + Protocol_Family, + Socket_Option_Level, +} + +/* + * Level number for (get/set)sockopt() to apply to socket itself. + */ +// #define SOL_* +Socket_Option_Level :: enum c.int { + SOCKET = 0xffff, /* options for socket level */ +} + +// #define MSG_* +Message_Flag :: enum c.int { + OOB = 0x00000001, /* process out-of-band data */ + PEEK = 0x00000002, /* peek at incoming message */ + DONTROUTE = 0x00000004, /* send without using routing tables */ + EOR = 0x00000008, /* data completes record */ + TRUNC = 0x00000010, /* data discarded before delivery */ + CTRUNC = 0x00000020, /* control data lost before delivery */ + WAITALL = 0x00000040, /* wait for full request or error */ + DONTWAIT = 0x00000080, /* this message should be nonblocking */ + EOF = 0x00000100, /* data completes connection */ + /* 0x00000200 unused */ + /* 0x00000400 unused */ + /* 0x00000800 unused */ + /* 0x00001000 unused */ + NOTIFICATION = 0x00002000, /* SCTP notification */ + NBIO = 0x00004000, /* FIONBIO mode, used by fifofs */ + COMPAT = 0x00008000, /* used in sendit() */ + SOCALLBCK = 0x00010000, /* for use by socket callbacks - soreceive (TCP) */ + NOSIGNAL = 0x00020000, /* do not generate SIGPIPE on EOF */ + CMSG_CLOEXEC = 0x00040000, /* make received fds close-on-exec */ + WAITFORONE = 0x00080000, /* for recvmmsg() */ +} + +// Specific subset of `MSG_*` defines that are only for `recv*`. +Recv_Flags :: enum c.int { + NONE = 0, + OOB = cast(c.int)Message_Flag.OOB, /* process out-of-band data */ + PEEK = cast(c.int)Message_Flag.PEEK, /* peek at incoming message */ + TRUNC = cast(c.int)Message_Flag.TRUNC, /* return real packet or datagram length */ + WAITALL = cast(c.int)Message_Flag.WAITALL, /* wait for full request or error */ + DONTWAIT = cast(c.int)Message_Flag.DONTWAIT, /* do not block */ + CMSG_CLOEXEC = cast(c.int)Message_Flag.CMSG_CLOEXEC, /* set received fds close-on-exec */ + WAITFORONE = cast(c.int)Message_Flag.WAITFORONE, /* do not block after receiving the first message */ +} + +// Specific subset of `MSG_*` defines that are only for `send*`. +Send_Flags :: enum c.int { + NONE = 0, + OOB = cast(c.int)Message_Flag.OOB, /* process out-of-band data */ + DONTROUTE = cast(c.int)Message_Flag.DONTROUTE, /* bypass routing, use direct interface */ + EOR = cast(c.int)Message_Flag.EOR, /* data completes record */ + DONTWAIT = cast(c.int)Message_Flag.DONTWAIT, /* do not block */ + EOF = cast(c.int)Message_Flag.EOF, /* data completes transaction */ + NOSIGNAL = cast(c.int)Message_Flag.NOSIGNAL, /* do not generate SIGPIPE on EOF */ +} + +// Socket address struct header without protocol-specific data. +// +// Inherit from this if you want a custom socket address datatype for use with +// bind(), listen(), et cetera. +Socket_Address_Header :: struct #packed { + len: c.uchar, /* address length */ + family: Address_Family, /* address family */ +} + +// struct sockaddr +Socket_Address_Basic :: struct #packed { + using _: Socket_Address_Header, + data: [14]c.char, +} + +/* + * howto arguments for shutdown(2), specified by Posix.1g. + */ +// #define SHUT_* +Shutdown_Method :: enum c.int { + RD = 0, /* shut down the reading side */ + WR = 1, /* shut down the writing side */ + RDWR = 2, /* shut down both sides */ +} + +// #define AF_* +Address_Family :: enum sa_family_t { + UNSPEC = 0, + LOCAL = 1, + UNIX = LOCAL, + INET = 2, + IMPLINK = 3, + PUP = 4, + CHAOS = 5, + NETBIOS = 6, + ISO = 7, + OSI = ISO, + ECMA = 8, + DATAKIT = 9, + CCITT = 10, + SNA = 11, + DECnet = 12, + DLI = 13, + LAT = 14, + HYLINK = 15, + APPLETALK = 16, + ROUTE = 17, + LINK = 18, + PSEUDO_XTP = 19, + COIP = 20, + CNT = 21, + PSEUDO_RTIP = 22, + IPX = 23, + SIP = 24, + PSEUDO_PIP = 25, + ISDN = 26, + E164 = ISDN, + PSEUDO_KEY = 27, + INET6 = 28, + NATM = 29, + ATM = 30, + NETGRAPH = 32, + SLOW = 33, + SCLUSTER = 34, + ARP = 35, + BLUETOOTH = 36, + IEEE80211 = 37, + NETLINK = 38, + INET_SDP = 40, + INET6_SDP = 42, + HYPERV = 43, + DIVERT = 44, + MAX = 44, + VENDOR00 = 39, + VENDOR01 = 41, + VENDOR03 = 45, + VENDOR04 = 47, + VENDOR05 = 49, + VENDOR06 = 51, + VENDOR07 = 53, + VENDOR08 = 55, + VENDOR09 = 57, + VENDOR10 = 59, + VENDOR11 = 61, + VENDOR12 = 63, + VENDOR13 = 65, + VENDOR14 = 67, + VENDOR15 = 69, + VENDOR16 = 71, + VENDOR17 = 73, + VENDOR18 = 75, + VENDOR19 = 77, + VENDOR20 = 79, + VENDOR21 = 81, + VENDOR22 = 83, + VENDOR23 = 85, + VENDOR24 = 87, + VENDOR25 = 89, + VENDOR26 = 91, + VENDOR27 = 93, + VENDOR28 = 95, + VENDOR29 = 97, + VENDOR30 = 99, + VENDOR31 = 101, + VENDOR32 = 103, + VENDOR33 = 105, + VENDOR34 = 107, + VENDOR35 = 109, + VENDOR36 = 111, + VENDOR37 = 113, + VENDOR38 = 115, + VENDOR39 = 117, + VENDOR40 = 119, + VENDOR41 = 121, + VENDOR42 = 123, + VENDOR43 = 125, + VENDOR44 = 127, + VENDOR45 = 129, + VENDOR46 = 131, + VENDOR47 = 133, +} + +// #define PF_* +Protocol_Family :: enum sa_family_t { + UNSPEC = cast(sa_family_t)Address_Family.UNSPEC, + LOCAL = cast(sa_family_t)Address_Family.LOCAL, + UNIX = LOCAL, + INET = cast(sa_family_t)Address_Family.INET, + IMPLINK = cast(sa_family_t)Address_Family.IMPLINK, + PUP = cast(sa_family_t)Address_Family.PUP, + CHAOS = cast(sa_family_t)Address_Family.CHAOS, + NETBIOS = cast(sa_family_t)Address_Family.NETBIOS, + ISO = cast(sa_family_t)Address_Family.ISO, + OSI = cast(sa_family_t)Address_Family.ISO, + ECMA = cast(sa_family_t)Address_Family.ECMA, + DATAKIT = cast(sa_family_t)Address_Family.DATAKIT, + CCITT = cast(sa_family_t)Address_Family.CCITT, + SNA = cast(sa_family_t)Address_Family.SNA, + DECnet = cast(sa_family_t)Address_Family.DECnet, + DLI = cast(sa_family_t)Address_Family.DLI, + LAT = cast(sa_family_t)Address_Family.LAT, + HYLINK = cast(sa_family_t)Address_Family.HYLINK, + APPLETALK = cast(sa_family_t)Address_Family.APPLETALK, + ROUTE = cast(sa_family_t)Address_Family.ROUTE, + LINK = cast(sa_family_t)Address_Family.LINK, + XTP = cast(sa_family_t)Address_Family.PSEUDO_XTP, + COIP = cast(sa_family_t)Address_Family.COIP, + CNT = cast(sa_family_t)Address_Family.CNT, + SIP = cast(sa_family_t)Address_Family.SIP, + IPX = cast(sa_family_t)Address_Family.IPX, + RTIP = cast(sa_family_t)Address_Family.PSEUDO_RTIP, + PIP = cast(sa_family_t)Address_Family.PSEUDO_PIP, + ISDN = cast(sa_family_t)Address_Family.ISDN, + KEY = cast(sa_family_t)Address_Family.PSEUDO_KEY, + INET6 = cast(sa_family_t)Address_Family.INET6, + NATM = cast(sa_family_t)Address_Family.NATM, + ATM = cast(sa_family_t)Address_Family.ATM, + NETGRAPH = cast(sa_family_t)Address_Family.NETGRAPH, + SLOW = cast(sa_family_t)Address_Family.SLOW, + SCLUSTER = cast(sa_family_t)Address_Family.SCLUSTER, + ARP = cast(sa_family_t)Address_Family.ARP, + BLUETOOTH = cast(sa_family_t)Address_Family.BLUETOOTH, + IEEE80211 = cast(sa_family_t)Address_Family.IEEE80211, + NETLINK = cast(sa_family_t)Address_Family.NETLINK, + INET_SDP = cast(sa_family_t)Address_Family.INET_SDP, + INET6_SDP = cast(sa_family_t)Address_Family.INET6_SDP, + DIVERT = cast(sa_family_t)Address_Family.DIVERT, + MAX = cast(sa_family_t)Address_Family.MAX, +} + +// +// /etc/protocols +// + +Protocol :: enum c.int { + IP = 0, + ICMP = 1, + IGMP = 2, + GGP = 3, + IP_ENCAP = 4, + ST2 = 5, + TCP = 6, + CBT = 7, + EGP = 8, + IGP = 9, + BBN_RCC_MON = 10, + NVP_II = 11, + PUP = 12, + ARGUS = 13, + EMCON = 14, + XNET = 15, + CHAOS = 16, + UDP = 17, + MUX = 18, + DCN_MEAS = 19, + HMP = 20, + PRM = 21, + XNS_IDP = 22, + TRUNK_1 = 23, + TRUNK_2 = 24, + LEAF_1 = 25, + LEAF_2 = 26, + RDP = 27, + IRTP = 28, + ISO_TP4 = 29, + NETBLT = 30, + MFE_NSP = 31, + MERIT_INP = 32, + DCCP = 33, + THREE_PC = 34, + IDPR = 35, + XTP = 36, + DDP = 37, + IDPR_CMTP = 38, + TP_PlusPlus = 39, + IL = 40, + IPV6 = 41, + SDRP = 42, + IPV6_ROUTE = 43, + IPV6_FRAG = 44, + IDRP = 45, + RSVP = 46, + GRE = 47, + DSR = 48, + BNA = 49, + ESP = 50, + AH = 51, + I_NLSP = 52, + SWIPE = 53, + NARP = 54, + MOBILE = 55, + TLSP = 56, + SKIP = 57, + IPV6_ICMP = 58, + IPV6_NONXT = 59, + IPV6_OPTS = 60, + CFTP = 62, + SAT_EXPAK = 64, + KRYPTOLAN = 65, + RVD = 66, + IPPC = 67, + SAT_MON = 69, + VISA = 70, + IPCV = 71, + CPNX = 72, + CPHB = 73, + WSN = 74, + PVP = 75, + BR_SAT_MON = 76, + SUN_ND = 77, + WB_MON = 78, + WB_EXPAK = 79, + ISO_IP = 80, + VMTP = 81, + SECURE_VMTP = 82, + VINES = 83, + TTP = 84, + IPTM = 84, + NSFNET_IGP = 85, + DGP = 86, + TCF = 87, + EIGRP = 88, + OSPFIGP = 89, + Sprite_RPC = 90, + LARP = 91, + MTP = 92, + AX_25 = 93, + IPIP = 94, + MICP = 95, + SCC_SP = 96, + ETHERIP = 97, + ENCAP = 98, + GMTP = 100, + IFMP = 101, + PNNI = 102, + PIM = 103, + ARIS = 104, + SCPS = 105, + QNX = 106, + A_N = 107, + IPComp = 108, + SNP = 109, + Compaq_Peer = 110, + IPX_in_IP = 111, + CARP = 112, + PGM = 113, + L2TP = 115, + DDX = 116, + IATP = 117, + STP = 118, + SRP = 119, + UTI = 120, + SMP = 121, + SM = 122, + PTP = 123, + ISIS = 124, + FIRE = 125, + CRTP = 126, + CRUDP = 127, + SSCOPMCE = 128, + IPLT = 129, + SPS = 130, + PIPE = 131, + SCTP = 132, + FC = 133, + RSVP_E2E_IGNORE = 134, + Mobility_Header = 135, + UDPLite = 136, + MPLS_IN_IP = 137, + MANET = 138, + HIP = 139, + SHIM6 = 140, + WESP = 141, + ROHC = 142, + PFSYNC = 240, + DIVERT = 258, +} + +// +// #include <sys/fcntl.h> +// + +/* + * Constants used for fcntl(2) + */ + +/* command values */ +// #define F_* +File_Control_Command :: enum c.int { + DUPFD = 0, /* duplicate file descriptor */ + GETFD = 1, /* get file descriptor flags */ + SETFD = 2, /* set file descriptor flags */ + GETFL = 3, /* get file status flags */ + SETFL = 4, /* set file status flags */ + GETOWN = 5, /* get SIGIO/SIGURG proc/pgrp */ + SETOWN = 6, /* set SIGIO/SIGURG proc/pgrp */ + OGETLK = 7, /* get record locking information */ + OSETLK = 8, /* set record locking information */ + OSETLKW = 9, /* F_SETLK; wait if blocked */ + DUP2FD = 10, /* duplicate file descriptor to arg */ + GETLK = 11, /* get record locking information */ + SETLK = 12, /* set record locking information */ + SETLKW = 13, /* F_SETLK; wait if blocked */ + SETLK_REMOTE = 14, /* debugging support for remote locks */ + READAHEAD = 15, /* read ahead */ + RDAHEAD = 16, /* Darwin compatible read ahead */ + DUPFD_CLOEXEC = 17, /* Like F_DUPFD, but FD_CLOEXEC is set */ + DUP2FD_CLOEXEC = 18, /* Like F_DUP2FD, but FD_CLOEXEC is set */ + ADD_SEALS = 19, + GET_SEALS = 20, + ISUNIONSTACK = 21, /* Kludge for libc, don't use it. */ + KINFO = 22, /* Return kinfo_file for this fd */ +} + +/* Seals (F_ADD_SEALS, F_GET_SEALS). */ +// #define F_SEAL_* +File_Seal_Index :: enum c.int { + SEAL = 0, // 0x0001, /* Prevent adding sealings */ + SHRINK = 1, // 0x0002, /* May not shrink */ + GROW = 2, // 0x0004, /* May not grow */ + WRITE = 3, // 0x0008, /* May not write */ +} + +File_Seals :: bit_set[File_Seal_Index; c.int] + +/* file descriptor flags (F_GETFD, F_SETFD) */ +FD_CLOEXEC :: 1 /* close-on-exec flag */ + +/* record locking flags (F_GETLK, F_SETLK, F_SETLKW) */ +// #define F_* +Record_Lock_Flag :: enum c.int { + RDLCK = 1, /* shared or read lock */ + UNLCK = 2, /* unlock */ + WRLCK = 3, /* exclusive or write lock */ + UNLCKSYS = 4, /* purge locks for a given system ID */ + CANCEL = 5, /* cancel an async lock request */ +} + +// struct flock +File_Lock :: struct { + start: off_t, /* starting offset */ + len: off_t, /* len = 0 means until end of file */ + pid: pid_t, /* lock owner */ + type: Record_Lock_Flag, /* lock type: read/write, etc. */ + whence: c.short, /* type of l_start */ + sysid: c.int, /* remote system id or zero for local */ +} + +/* + * File status flags: these are used by open(2), fcntl(2). + * They are also used (indirectly) in the kernel file structure f_flags, + * which is a superset of the open/fcntl flags. Open flags and f_flags + * are inter-convertible using OFLAGS(fflags) and FFLAGS(oflags). + * Open/fcntl flags begin with O_; kernel-internal flags begin with F. + */ +File_Status_Flag :: enum c.int { + /* open-only flags */ + RDONLY = 0x0000, /* open for reading only */ + WRONLY = 0x0001, /* open for writing only */ + RDWR = 0x0002, /* open for reading and writing */ + ACCMODE = 0x0003, /* mask for above modes */ + + /**/ + NONBLOCK = 0x0004, /* no delay */ + APPEND = 0x0008, /* set append mode */ + SHLOCK = 0x0010, /* open with shared file lock */ + EXLOCK = 0x0020, /* open with exclusive file lock */ + ASYNC = 0x0040, /* signal pgrp when data ready */ + FSYNC = 0x0080, /* synchronous writes */ + SYNC = 0x0080, /* POSIX synonym for O_FSYNC */ + NOFOLLOW = 0x0100, /* don't follow symlinks */ + CREAT = 0x0200, /* create if nonexistent */ + TRUNC = 0x0400, /* truncate to zero length */ + EXCL = 0x0800, /* error if already exists */ + + /* Defined by POSIX 1003.1; BSD default, but must be distinct from O_RDONLY. */ + NOCTTY = 0x8000, /* don't assign controlling terminal */ + + /* Attempt to bypass buffer cache */ + DIRECT = 0x00010000, + + DIRECTORY = 0x00020000, /* Fail if not directory */ + EXEC = 0x00040000, /* Open for execute only */ + SEARCH = EXEC, + + /* Defined by POSIX 1003.1-2008; BSD default, but reserve for future use. */ + TTY_INIT = 0x00080000, /* Restore default termios attributes */ + + CLOEXEC = 0x00100000, + VERIFY = 0x00200000, /* open only after verification */ + PATH = 0x00400000, /* fd is only a path */ + RESOLVE_BENEATH = 0x00800000, /* Do not allow name resolution to walk out of cwd */ + DSYNC = 0x01000000, /* POSIX data sync */ + EMPTY_PATH = 0x02000000, +} + +File_Status_Index :: enum c.int { + // No RDONLY (0x00), as that is implied and also impossible to express in a bit_set. + + // The comments below come from the documentation for `fcntl`. + WRONLY = 0, + RDWR = 1, + + /* Non-blocking I/O; if no data is available to a read(2) + system call, or if a write(2) operation would block, the + read or write call returns -1 with the error EAGAIN. */ + NONBLOCK = 2, + + /* Force each write to append at the end of file; corresponds + to the O_APPEND flag of open(2). */ + APPEND = 3, + + SHLOCK = 4, + EXLOCK = 5, + + /* Enable the SIGIO signal to be sent to the process group when + I/O is possible, e.g., upon availability of data to be read. */ + ASYNC = 6, + + /* Enable synchronous writes. Corresponds to the O_SYNC flag + of open(2). O_FSYNC is an historical synonym for O_SYNC. */ + SYNC = 7, + + FSYNC = 7, + NOFOLLOW = 8, + CREAT = 9, + TRUNC = 10, + EXCL = 11, + + NOCTTY = 15, + + /* Minimize or eliminate the cache effects of reading and + writing. The system will attempt to avoid caching the data + you read or write. If it cannot avoid caching the data, it + will minimize the impact the data has on the cache. Use of + this flag can drastically reduce performance if not used + with care. */ + DIRECT = 16, + + DIRECTORY = 17, + EXEC = 18, + TTY_INIT = 19, + CLOEXEC = 20, + VERIFY = 21, + PATH = 22, + RESOLVE_BENEATH = 23, + + /* Enable synchronous data writes. Corresponds to the O_DSYNC + flag of open(2). */ + DSYNC = 24, + + EMPTY_PATH = 25, +} + +File_Status_Flags :: bit_set[File_Status_Index; c.int] + +// +// #include <sys/_sockaddr_storage.h> +// + +@private _SS_MAXSIZE :: 128 +@private _SS_ALIGNSIZE :: size_of(i64) +@private _SS_PAD1SIZE :: _SS_ALIGNSIZE - size_of(c.uchar) - size_of(Address_Family) +@private _SS_PAD2SIZE :: _SS_MAXSIZE - size_of(c.uchar) - size_of(Address_Family) - _SS_PAD1SIZE - _SS_ALIGNSIZE + +/* + * RFC 2553: protocol-independent placeholder for socket addresses + */ +// struct sockaddr_storage +Socket_Address_Storage :: struct { + using _: Socket_Address_Header, + _pad1: [_SS_PAD1SIZE]c.char, + _align: i64, /* force desired struct alignment */ + _pad2: [_SS_PAD2SIZE]c.char, +} + +// +// #include <sys/sysctl.h> +// + +// MIB, or Management Information Base. Used in sysctl(). +MIB_Identifier :: enum c.int { + /* + * Top-level identifiers + */ + CTL_SYSCTL = 0, /* "magic" numbers */ + CTL_KERN = 1, /* "high kernel": proc, limits */ + CTL_VM = 2, /* virtual memory */ + CTL_VFS = 3, /* filesystem, mount type is next */ + CTL_NET = 4, /* network, see socket.h */ + CTL_DEBUG = 5, /* debugging parameters */ + CTL_HW = 6, /* generic cpu/io */ + CTL_MACHDEP = 7, /* machine dependent */ + CTL_USER = 8, /* user-level */ + CTL_P1003_1B = 9, /* POSIX 1003.1B */ + + /* + * CTL_SYSCTL identifiers + */ + CTL_SYSCTL_DEBUG = 0, /* printf all nodes */ + CTL_SYSCTL_NAME = 1, /* string name of OID */ + CTL_SYSCTL_NEXT = 2, /* next OID, honoring CTLFLAG_SKIP */ + CTL_SYSCTL_NAME2OID = 3, /* int array of name */ + CTL_SYSCTL_OIDFMT = 4, /* OID's kind and format */ + CTL_SYSCTL_OIDDESCR = 5, /* OID's description */ + CTL_SYSCTL_OIDLABEL = 6, /* aggregation label */ + CTL_SYSCTL_NEXTNOSKIP = 7, /* next OID, ignoring CTLFLAG_SKIP */ + + /* + * CTL_KERN identifiers + */ + KERN_OSTYPE = 1, /* string: system version */ + KERN_OSRELEASE = 2, /* string: system release */ + KERN_OSREV = 3, /* int: system revision */ + KERN_VERSION = 4, /* string: compile time info */ + KERN_MAXVNODES = 5, /* int: max vnodes */ + KERN_MAXPROC = 6, /* int: max processes */ + KERN_MAXFILES = 7, /* int: max open files */ + KERN_ARGMAX = 8, /* int: max arguments to exec */ + KERN_SECURELVL = 9, /* int: system security level */ + KERN_HOSTNAME = 10, /* string: hostname */ + KERN_HOSTID = 11, /* int: host identifier */ + KERN_CLOCKRATE = 12, /* struct: struct clockrate */ + /* was: #define KERN_VNODE13; disabled in 2003 and removed in 2023 */ + KERN_PROC = 14, /* struct: process entries */ + KERN_FILE = 15, /* struct: file entries */ + KERN_PROF = 16, /* node: kernel profiling info */ + KERN_POSIX1 = 17, /* int: POSIX.1 version */ + KERN_NGROUPS = 18, /* int: # of supplemental group ids */ + KERN_JOB_CONTROL = 19, /* int: is job control available */ + KERN_SAVED_IDS = 20, /* int: saved set-user/group-ID */ + KERN_BOOTTIME = 21, /* struct: time kernel was booted */ + KERN_NISDOMAINNAME = 22, /* string: YP domain name */ + KERN_UPDATEINTERVAL = 23, /* int: update process sleep time */ + KERN_OSRELDATE = 24, /* int: kernel release date */ + KERN_NTP_PLL = 25, /* node: NTP PLL control */ + KERN_BOOTFILE = 26, /* string: name of booted kernel */ + KERN_MAXFILESPERPROC = 27, /* int: max open files per proc */ + KERN_MAXPROCPERUID = 28, /* int: max processes per uid */ + KERN_DUMPDEV = 29, /* struct cdev *: device to dump on */ + KERN_IPC = 30, /* node: anything related to IPC */ + KERN_DUMMY = 31, /* unused */ + KERN_PS_STRINGS = 32, /* int: address of PS_STRINGS */ + KERN_USRSTACK = 33, /* int: address of USRSTACK */ + KERN_LOGSIGEXIT = 34, /* int: do we log sigexit procs? */ + KERN_IOV_MAX = 35, /* int: value of UIO_MAXIOV */ + KERN_HOSTUUID = 36, /* string: host UUID identifier */ + KERN_ARND = 37, /* int: from arc4rand() */ + KERN_MAXPHYS = 38, /* int: MAXPHYS value */ + KERN_LOCKF = 39, /* struct: lockf reports */ + /* + * KERN_PROC subtypes + */ + KERN_PROC_ALL = 0, /* everything */ + KERN_PROC_PID = 1, /* by process id */ + KERN_PROC_PGRP = 2, /* by process group id */ + KERN_PROC_SESSION = 3, /* by session of pid */ + KERN_PROC_TTY = 4, /* by controlling tty */ + KERN_PROC_UID = 5, /* by effective uid */ + KERN_PROC_RUID = 6, /* by real uid */ + KERN_PROC_ARGS = 7, /* get/set arguments/proctitle */ + KERN_PROC_PROC = 8, /* only return procs */ + KERN_PROC_SV_NAME = 9, /* get syscall vector name */ + KERN_PROC_RGID = 10, /* by real group id */ + KERN_PROC_GID = 11, /* by effective group id */ + KERN_PROC_PATHNAME = 12, /* path to executable */ + KERN_PROC_OVMMAP = 13, /* Old VM map entries for process */ + KERN_PROC_OFILEDESC = 14, /* Old file descriptors for process */ + KERN_PROC_KSTACK = 15, /* Kernel stacks for process */ + KERN_PROC_INC_THREAD = 0x10, /* modifier for pid, pgrp, tty, uid, ruid, gid, rgid and proc. This effectively uses 16-31 */ + KERN_PROC_VMMAP = 32, /* VM map entries for process */ + KERN_PROC_FILEDESC = 33, /* File descriptors for process */ + KERN_PROC_GROUPS = 34, /* process groups */ + KERN_PROC_ENV = 35, /* get environment */ + KERN_PROC_AUXV = 36, /* get ELF auxiliary vector */ + KERN_PROC_RLIMIT = 37, /* process resource limits */ + KERN_PROC_PS_STRINGS = 38, /* get ps_strings location */ + KERN_PROC_UMASK = 39, /* process umask */ + KERN_PROC_OSREL = 40, /* osreldate for process binary */ + KERN_PROC_SIGTRAMP = 41, /* signal trampoline location */ + KERN_PROC_CWD = 42, /* process current working directory */ + KERN_PROC_NFDS = 43, /* number of open file descriptors */ + KERN_PROC_SIGFASTBLK = 44, /* address of fastsigblk magic word */ + KERN_PROC_VM_LAYOUT = 45, /* virtual address space layout info */ + + /* + * KERN_IPC identifiers + */ + KIPC_MAXSOCKBUF = 1, /* int: max size of a socket buffer */ + KIPC_SOCKBUF_WASTE = 2, /* int: wastage factor in sockbuf */ + KIPC_SOMAXCONN = 3, /* int: max length of connection q */ + KIPC_MAX_LINKHDR = 4, /* int: max length of link header */ + KIPC_MAX_PROTOHDR = 5, /* int: max length of network header */ + KIPC_MAX_HDR = 6, /* int: max total length of headers */ + KIPC_MAX_DATALEN = 7, /* int: max length of data? */ + + /* + * Definitions for network related sysctl, CTL_NET. + * + * Second level is protocol family. + * Third level is protocol number. + * + * Further levels are defined by the individual families. + */ + + /* + * PF_ROUTE - Routing table + * + * Three additional levels are defined: + * Fourth: address family, 0 is wildcard + * Fifth: type of info, defined below + * Sixth: flag(s) to mask with for NET_RT_FLAGS + */ + NET_RT_DUMP = 1, /* dump; may limit to a.f. */ + NET_RT_FLAGS = 2, /* by flags, e.g. RESOLVING */ + NET_RT_IFLIST = 3, /* survey interface list */ + NET_RT_IFMALIST = 4, /* return multicast address list */ + NET_RT_IFLISTL = 5, /* Survey interface list, using 'l'en versions of msghdr structs. */ + NET_RT_NHOP = 6, /* dump routing nexthops */ + NET_RT_NHGRP = 7, /* dump routing nexthop groups */ + + /* + * CTL_HW identifiers + */ + HW_MACHINE = 1, /* string: machine class */ + HW_MODEL = 2, /* string: specific machine model */ + HW_NCPU = 3, /* int: number of cpus */ + HW_BYTEORDER = 4, /* int: machine byte order */ + HW_PHYSMEM = 5, /* int: total memory */ + HW_USERMEM = 6, /* int: non-kernel memory */ + HW_PAGESIZE = 7, /* int: software page size */ + HW_DISKNAMES = 8, /* strings: disk drive names */ + HW_DISKSTATS = 9, /* struct: diskstats[] */ + HW_FLOATINGPT = 10, /* int: has HW floating point? */ + HW_MACHINE_ARCH = 11, /* string: machine architecture */ + HW_REALMEM = 12, /* int: 'real' memory */ + + /* + * CTL_USER definitions + */ + USER_CS_PATH = 1, /* string: _CS_PATH */ + USER_BC_BASE_MAX = 2, /* int: BC_BASE_MAX */ + USER_BC_DIM_MAX = 3, /* int: BC_DIM_MAX */ + USER_BC_SCALE_MAX = 4, /* int: BC_SCALE_MAX */ + USER_BC_STRING_MAX = 5, /* int: BC_STRING_MAX */ + USER_COLL_WEIGHTS_MAX = 6, /* int: COLL_WEIGHTS_MAX */ + USER_EXPR_NEST_MAX = 7, /* int: EXPR_NEST_MAX */ + USER_LINE_MAX = 8, /* int: LINE_MAX */ + USER_RE_DUP_MAX = 9, /* int: RE_DUP_MAX */ + USER_POSIX2_VERSION = 10, /* int: POSIX2_VERSION */ + USER_POSIX2_C_BIND = 11, /* int: POSIX2_C_BIND */ + USER_POSIX2_C_DEV = 12, /* int: POSIX2_C_DEV */ + USER_POSIX2_CHAR_TERM = 13, /* int: POSIX2_CHAR_TERM */ + USER_POSIX2_FORT_DEV = 14, /* int: POSIX2_FORT_DEV */ + USER_POSIX2_FORT_RUN = 15, /* int: POSIX2_FORT_RUN */ + USER_POSIX2_LOCALEDEF = 16, /* int: POSIX2_LOCALEDEF */ + USER_POSIX2_SW_DEV = 17, /* int: POSIX2_SW_DEV */ + USER_POSIX2_UPE = 18, /* int: POSIX2_UPE */ + USER_STREAM_MAX = 19, /* int: POSIX2_STREAM_MAX */ + USER_TZNAME_MAX = 20, /* int: POSIX2_TZNAME_MAX */ + USER_LOCALBASE = 21, /* string: _PATH_LOCALBASE */ + + CTL_P1003_1B_ASYNCHRONOUS_IO = 1, /* boolean */ + CTL_P1003_1B_MAPPED_FILES = 2, /* boolean */ + CTL_P1003_1B_MEMLOCK = 3, /* boolean */ + CTL_P1003_1B_MEMLOCK_RANGE = 4, /* boolean */ + CTL_P1003_1B_MEMORY_PROTECTION = 5, /* boolean */ + CTL_P1003_1B_MESSAGE_PASSING = 6, /* boolean */ + CTL_P1003_1B_PRIORITIZED_IO = 7, /* boolean */ + CTL_P1003_1B_PRIORITY_SCHEDULING = 8, /* boolean */ + CTL_P1003_1B_REALTIME_SIGNALS = 9, /* boolean */ + CTL_P1003_1B_SEMAPHORES = 10, /* boolean */ + CTL_P1003_1B_FSYNC = 11, /* boolean */ + CTL_P1003_1B_SHARED_MEMORY_OBJECTS = 12, /* boolean */ + CTL_P1003_1B_SYNCHRONIZED_IO = 13, /* boolean */ + CTL_P1003_1B_TIMERS = 14, /* boolean */ + CTL_P1003_1B_AIO_LISTIO_MAX = 15, /* int */ + CTL_P1003_1B_AIO_MAX = 16, /* int */ + CTL_P1003_1B_AIO_PRIO_DELTA_MAX = 17, /* int */ + CTL_P1003_1B_DELAYTIMER_MAX = 18, /* int */ + CTL_P1003_1B_MQ_OPEN_MAX = 19, /* int */ + CTL_P1003_1B_PAGESIZE = 20, /* int */ + CTL_P1003_1B_RTSIG_MAX = 21, /* int */ + CTL_P1003_1B_SEM_NSEMS_MAX = 22, /* int */ + CTL_P1003_1B_SEM_VALUE_MAX = 23, /* int */ + CTL_P1003_1B_SIGQUEUE_MAX = 24, /* int */ + CTL_P1003_1B_TIMER_MAX = 25, /* int */ +} + +// +// #include <net/route.h> +// + +// struct rt_metrics +Route_Metrics :: struct { + locks: c.ulong, /* Kernel must leave these values alone */ + mtu: c.ulong, /* MTU for this path */ + hopcount: c.ulong, /* max hops expected */ + expire: c.ulong, /* lifetime for route, e.g. redirect */ + recvpipe: c.ulong, /* inbound delay-bandwidth product */ + sendpipe: c.ulong, /* outbound delay-bandwidth product */ + ssthresh: c.ulong, /* outbound gateway buffer limit */ + rtt: c.ulong, /* estimated round trip time */ + rttvar: c.ulong, /* estimated rtt variance */ + pksent: c.ulong, /* packets sent using this route */ + weight: c.ulong, /* route weight */ + nhidx: c.ulong, /* route nexhop index */ + filler: [2]c.ulong, /* will be used for T/TCP later */ +} + +// struct rt_msghdr +Route_Message_Header :: struct { + msglen: c.ushort, /* to skip over non-understood messages */ + version: c.uchar, /* future binary compatibility */ + type: Route_Message_Type, /* message type */ + index: c.ushort, /* index for associated ifp */ + _spare1: c.ushort, + flags: c.int, /* flags, incl. kern & message, e.g. DONE */ + addrs: c.int, /* bitmask identifying sockaddrs in msg */ + pid: pid_t, /* identify sender */ + seq: c.int, /* for sender to identify action */ + errno: c.int, /* why failed */ + fmask: c.int, /* bitmask used in RTM_CHANGE message */ + inits: c.ulong, /* which metrics we are initializing */ + rmx: Route_Metrics, /* metrics themselves */ +} + +RTM_VERSION :: 5 /* Up the ante and ignore older versions */ + +/* + * Message types. + * + * The format for each message is annotated below using the following + * identifiers: + * + * (1) struct rt_msghdr + * (2) struct ifa_msghdr + * (3) struct if_msghdr + * (4) struct ifma_msghdr + * (5) struct if_announcemsghdr + * + */ +// #define RTM_* +Route_Message_Type :: enum c.uchar { + ADD = 0x1, /* (1) Add Route */ + DELETE = 0x2, /* (1) Delete Route */ + CHANGE = 0x3, /* (1) Change Metrics or flags */ + GET = 0x4, /* (1) Report Metrics */ + LOSING = 0x5, /* (1) Kernel Suspects Partitioning */ + REDIRECT = 0x6, /* (1) Told to use different route */ + MISS = 0x7, /* (1) Lookup failed on this address */ + LOCK = 0x8, /* (1) fix specified metrics */ + /* = 0x9 */ + /* = 0xa */ + RESOLVE = 0xb, /* (1) req to resolve dst to LL addr */ + NEWADDR = 0xc, /* (2) address being added to iface */ + DELADDR = 0xd, /* (2) address being removed from iface */ + IFINFO = 0xe, /* (3) iface going up/down etc. */ + NEWMADDR = 0xf, /* (4) mcast group membership being added to if */ + DELMADDR = 0x10, /* (4) mcast group membership being deleted */ + IFANNOUNCE = 0x11, /* (5) iface arrival/departure */ + IEEE80211 = 0x12, /* (5) IEEE80211 wireless event */ +} + +/* + * Bitmask values for rtm_addrs. + */ +// #define RTA_* +Route_Address_Flag :: enum c.int { + DST = 0x1, /* destination sockaddr present */ + GATEWAY = 0x2, /* gateway sockaddr present */ + NETMASK = 0x4, /* netmask sockaddr present */ + GENMASK = 0x8, /* cloning mask sockaddr present */ + IFP = 0x10, /* interface name sockaddr present */ + IFA = 0x20, /* interface addr sockaddr present */ + AUTHOR = 0x40, /* sockaddr for author of redirect */ + BRD = 0x80, /* for NEWADDR, broadcast or p-p dest addr */ +} + +/* + * Index offsets for sockaddr array for alternate internal encoding. + */ +// #define RTAX_* +Route_Address_Index :: enum c.int { + DST = 0, /* destination sockaddr present */ + GATEWAY = 1, /* gateway sockaddr present */ + NETMASK = 2, /* netmask sockaddr present */ + GENMASK = 3, /* cloning mask sockaddr present */ + IFP = 4, /* interface name sockaddr present */ + IFA = 5, /* interface addr sockaddr present */ + AUTHOR = 6, /* sockaddr for author of redirect */ + BRD = 7, /* for NEWADDR, broadcast or p-p dest addr */ + MAX = 8, /* size of array to allocate */ +} + +// The value stored in rtm_addrs and similar (ifm_addrs, etc.) +Route_Address_Flags :: bit_set[Route_Address_Index; c.int] + +// +// #include <net/if.h> +// + +/* + * Values for if_link_state. + */ +// #define LINK_STATE_* +Link_State :: enum u8 { + UNKNOWN = 0, /* link invalid/unknown */ + DOWN = 1, /* link is down */ + UP = 2, /* link is up */ +} + +/* + * Structure describing information about an interface + * which may be of interest to management entities. + */ +// struct if_data +Interface_Data :: struct { + /* generic interface information */ + type: u8, /* ethernet, tokenring, etc */ + physical: u8, /* e.g., AUI, Thinnet, 10base-T, etc */ + addrlen: u8, /* media address length */ + hdrlen: u8, /* media header length */ + link_state: Link_State, /* current link state */ + vhid: u8, /* carp vhid */ + datalen: u16, /* length of this data struct */ + mtu: u32, /* maximum transmission unit */ + metric: u32, /* routing metric (external only) */ + baudrate: u64, /* linespeed */ + /* volatile statistics */ + ipackets: u64, /* packets received on interface */ + ierrors: u64, /* input errors on interface */ + opackets: u64, /* packets sent on interface */ + oerrors: u64, /* output errors on interface */ + collisions: u64, /* collisions on csma interfaces */ + ibytes: u64, /* total number of octets received */ + obytes: u64, /* total number of octets sent */ + imcasts: u64, /* packets received via multicast */ + omcasts: u64, /* packets sent via multicast */ + iqdrops: u64, /* dropped on input */ + oqdrops: u64, /* dropped on output */ + noproto: u64, /* destined for unsupported protocol */ + hwassist: u64, /* HW offload capabilities, see IFCAP */ + + /* Unions are here to make sizes MI. */ + _epoch: struct #raw_union { /* uptime at attach or stat reset */ + tt: time_t, + ph: u64, + }, + + _lastchange: struct #raw_union { /* time of last administrative change */ + tv: timeval, + ph: struct { + ph1: u64, + ph2: u64, + }, + }, +} + +/* + * The 'l' version shall be used by new interfaces, like NET_RT_IFLISTL. It is + * extensible after ifm_data_off or within ifm_data. Both the if_msghdr and + * if_data now have a member field detailing the struct length in addition to + * the routing message length. Macros are provided to find the start of + * ifm_data and the start of the socket address strucutres immediately following + * struct if_msghdrl given a pointer to struct if_msghdrl. + */ +// struct if_msghdrl +Interface_Message_Header_Len :: struct { + msglen: c.ushort, /* to skip over non-understood messages */ + version: c.uchar, /* future binary compatibility */ + type: c.uchar, /* message type */ + addrs: Route_Address_Flags, /* like rtm_addrs */ + flags: c.int, /* value of if_flags */ + index: c.ushort, /* index for associated ifp */ + _spare1: c.ushort, /* spare space to grow if_index, see if_var.h */ + len: c.ushort, /* length of if_msghdrl incl. if_data */ + data_off: c.ushort, /* offset of if_data from beginning */ + _spare2: c.int, + data: Interface_Data, /* statistics and other data about if */ +} + +/* + * The 'l' version shall be used by new interfaces, like NET_RT_IFLISTL. It is + * extensible after ifam_metric or within ifam_data. Both the ifa_msghdrl and + * if_data now have a member field detailing the struct length in addition to + * the routing message length. Macros are provided to find the start of + * ifm_data and the start of the socket address strucutres immediately following + * struct ifa_msghdrl given a pointer to struct ifa_msghdrl. + */ +// struct ifa_msghdrl +Interface_Address_Message_Header_Len :: struct { + msglen: c.ushort, /* to skip over non-understood messages */ + version: c.uchar, /* future binary compatibility */ + type: c.uchar, /* message type */ + addrs: Route_Address_Flags, /* like rtm_addrs */ + flags: c.int, /* value of ifa_flags */ + index: c.ushort, /* index for associated ifp */ + _spare1: c.ushort, /* spare space to grow if_index, see if_var.h */ + len: c.ushort, /* length of ifa_msghdrl incl. if_data */ + data_off: c.ushort, /* offset of if_data from beginning */ + metric: c.int, /* value of ifa_ifp->if_metric */ + data: Interface_Data, /* statistics and other data about if or address */ +} + +// +// #include <net/if_types.h> +// + +// enum ifType +Interface_Type :: enum c.uchar { + OTHER = 0x1, /* none of the following */ + ARPA_1822 = 0x2, /* old-style arpanet imp */ + HDH1822 = 0x3, /* HDH arpanet imp */ + X25DDN = 0x4, /* x25 to imp */ + X25 = 0x5, /* PDN X25 interface (RFC877) */ + ETHER = 0x6, /* Ethernet CSMA/CD */ + ISO88023 = 0x7, /* CMSA/CD */ + ISO88024 = 0x8, /* Token Bus */ + ISO88025 = 0x9, /* Token Ring */ + ISO88026 = 0xa, /* MAN */ + STARLAN = 0xb, + P10 = 0xc, /* Proteon 10MBit ring */ + P80 = 0xd, /* Proteon 80MBit ring */ + HY = 0xe, /* Hyperchannel */ + FDDI = 0xf, + LAPB = 0x10, + SDLC = 0x11, + T1 = 0x12, + CEPT = 0x13, /* E1 - european T1 */ + ISDNBASIC = 0x14, + ISDNPRIMARY = 0x15, + PTPSERIAL = 0x16, /* Proprietary PTP serial */ + PPP = 0x17, /* RFC 1331 */ + LOOP = 0x18, /* loopback */ + EON = 0x19, /* ISO over IP */ + XETHER = 0x1a, /* obsolete 3MB experimental ethernet */ + NSIP = 0x1b, /* XNS over IP */ + SLIP = 0x1c, /* IP over generic TTY */ + ULTRA = 0x1d, /* Ultra Technologies */ + DS3 = 0x1e, /* Generic T3 */ + SIP = 0x1f, /* SMDS */ + FRELAY = 0x20, /* Frame Relay DTE only */ + RS232 = 0x21, + PARA = 0x22, /* parallel-port */ + ARCNET = 0x23, + ARCNETPLUS = 0x24, + ATM = 0x25, /* ATM cells */ + MIOX25 = 0x26, + SONET = 0x27, /* SONET or SDH */ + X25PLE = 0x28, + ISO88022LLC = 0x29, + LOCALTALK = 0x2a, + SMDSDXI = 0x2b, + FRELAYDCE = 0x2c, /* Frame Relay DCE */ + V35 = 0x2d, + HSSI = 0x2e, + HIPPI = 0x2f, + MODEM = 0x30, /* Generic Modem */ + AAL5 = 0x31, /* AAL5 over ATM */ + SONETPATH = 0x32, + SONETVT = 0x33, + SMDSICIP = 0x34, /* SMDS InterCarrier Interface */ + PROPVIRTUAL = 0x35, /* Proprietary Virtual/internal */ + PROPMUX = 0x36, /* Proprietary Multiplexing */ + IEEE80212 = 0x37, /* 100BaseVG */ + FIBRECHANNEL = 0x38, /* Fibre Channel */ + HIPPIINTERFACE = 0x39, /* HIPPI interfaces */ + FRAMERELAYINTERCONNECT = 0x3a, /* Obsolete, use 0x20 either 0x2c */ + AFLANE8023 = 0x3b, /* ATM Emulated LAN for 802.3 */ + AFLANE8025 = 0x3c, /* ATM Emulated LAN for 802.5 */ + CCTEMUL = 0x3d, /* ATM Emulated circuit */ + FASTETHER = 0x3e, /* Fast Ethernet (100BaseT) */ + ISDN = 0x3f, /* ISDN and X.25 */ + V11 = 0x40, /* CCITT V.11/X.21 */ + V36 = 0x41, /* CCITT V.36 */ + G703AT64K = 0x42, /* CCITT G703 at 64Kbps */ + G703AT2MB = 0x43, /* Obsolete see DS1-MIB */ + QLLC = 0x44, /* SNA QLLC */ + FASTETHERFX = 0x45, /* Fast Ethernet (100BaseFX) */ + CHANNEL = 0x46, /* channel */ + IEEE80211 = 0x47, /* radio spread spectrum (unused) */ + IBM370PARCHAN = 0x48, /* IBM System 360/370 OEMI Channel */ + ESCON = 0x49, /* IBM Enterprise Systems Connection */ + DLSW = 0x4a, /* Data Link Switching */ + ISDNS = 0x4b, /* ISDN S/T interface */ + ISDNU = 0x4c, /* ISDN U interface */ + LAPD = 0x4d, /* Link Access Protocol D */ + IPSWITCH = 0x4e, /* IP Switching Objects */ + RSRB = 0x4f, /* Remote Source Route Bridging */ + ATMLOGICAL = 0x50, /* ATM Logical Port */ + DS0 = 0x51, /* Digital Signal Level 0 */ + DS0BUNDLE = 0x52, /* group of ds0s on the same ds1 */ + BSC = 0x53, /* Bisynchronous Protocol */ + ASYNC = 0x54, /* Asynchronous Protocol */ + CNR = 0x55, /* Combat Net Radio */ + ISO88025DTR = 0x56, /* ISO 802.5r DTR */ + EPLRS = 0x57, /* Ext Pos Loc Report Sys */ + ARAP = 0x58, /* Appletalk Remote Access Protocol */ + PROPCNLS = 0x59, /* Proprietary Connectionless Protocol*/ + HOSTPAD = 0x5a, /* CCITT-ITU X.29 PAD Protocol */ + TERMPAD = 0x5b, /* CCITT-ITU X.3 PAD Facility */ + FRAMERELAYMPI = 0x5c, /* Multiproto Interconnect over FR */ + X213 = 0x5d, /* CCITT-ITU X213 */ + ADSL = 0x5e, /* Asymmetric Digital Subscriber Loop */ + RADSL = 0x5f, /* Rate-Adapt. Digital Subscriber Loop*/ + SDSL = 0x60, /* Symmetric Digital Subscriber Loop */ + VDSL = 0x61, /* Very H-Speed Digital Subscrib. Loop*/ + ISO88025CRFPINT = 0x62, /* ISO 802.5 CRFP */ + MYRINET = 0x63, /* Myricom Myrinet */ + VOICEEM = 0x64, /* voice recEive and transMit */ + VOICEFXO = 0x65, /* voice Foreign Exchange Office */ + VOICEFXS = 0x66, /* voice Foreign Exchange Station */ + VOICEENCAP = 0x67, /* voice encapsulation */ + VOICEOVERIP = 0x68, /* voice over IP encapsulation */ + ATMDXI = 0x69, /* ATM DXI */ + ATMFUNI = 0x6a, /* ATM FUNI */ + ATMIMA = 0x6b, /* ATM IMA */ + PPPMULTILINKBUNDLE = 0x6c, /* PPP Multilink Bundle */ + IPOVERCDLC = 0x6d, /* IBM ipOverCdlc */ + IPOVERCLAW = 0x6e, /* IBM Common Link Access to Workstn */ + STACKTOSTACK = 0x6f, /* IBM stackToStack */ + VIRTUALIPADDRESS = 0x70, /* IBM VIPA */ + MPC = 0x71, /* IBM multi-protocol channel support */ + IPOVERATM = 0x72, /* IBM ipOverAtm */ + ISO88025FIBER = 0x73, /* ISO 802.5j Fiber Token Ring */ + TDLC = 0x74, /* IBM twinaxial data link control */ + GIGABITETHERNET = 0x75, /* Gigabit Ethernet */ + HDLC = 0x76, /* HDLC */ + LAPF = 0x77, /* LAP F */ + V37 = 0x78, /* V.37 */ + X25MLP = 0x79, /* Multi-Link Protocol */ + X25HUNTGROUP = 0x7a, /* X25 Hunt Group */ + TRANSPHDLC = 0x7b, /* Transp HDLC */ + INTERLEAVE = 0x7c, /* Interleave channel */ + FAST = 0x7d, /* Fast channel */ + IP = 0x7e, /* IP (for APPN HPR in IP networks) */ + DOCSCABLEMACLAYER = 0x7f, /* CATV Mac Layer */ + DOCSCABLEDOWNSTREAM = 0x80, /* CATV Downstream interface */ + DOCSCABLEUPSTREAM = 0x81, /* CATV Upstream interface */ + A12MPPSWITCH = 0x82, /* Avalon Parallel Processor */ + TUNNEL = 0x83, /* Encapsulation interface */ + COFFEE = 0x84, /* coffee pot */ + CES = 0x85, /* Circiut Emulation Service */ + ATMSUBINTERFACE = 0x86, /* (x) ATM Sub Interface */ + L2VLAN = 0x87, /* Layer 2 Virtual LAN using 802.1Q */ + L3IPVLAN = 0x88, /* Layer 3 Virtual LAN - IP Protocol */ + L3IPXVLAN = 0x89, /* Layer 3 Virtual LAN - IPX Prot. */ + DIGITALPOWERLINE = 0x8a, /* IP over Power Lines */ + MEDIAMAILOVERIP = 0x8b, /* (xxx) Multimedia Mail over IP */ + DTM = 0x8c, /* Dynamic synchronous Transfer Mode */ + DCN = 0x8d, /* Data Communications Network */ + IPFORWARD = 0x8e, /* IP Forwarding Interface */ + MSDSL = 0x8f, /* Multi-rate Symmetric DSL */ + IEEE1394 = 0x90, /* IEEE1394 High Performance SerialBus*/ + IFGSN = 0x91, /* HIPPI-6400 */ + DVBRCCMACLAYER = 0x92, /* DVB-RCC MAC Layer */ + DVBRCCDOWNSTREAM = 0x93, /* DVB-RCC Downstream Channel */ + DVBRCCUPSTREAM = 0x94, /* DVB-RCC Upstream Channel */ + ATMVIRTUAL = 0x95, /* ATM Virtual Interface */ + MPLSTUNNEL = 0x96, /* MPLS Tunnel Virtual Interface */ + SRP = 0x97, /* Spatial Reuse Protocol */ + VOICEOVERATM = 0x98, /* Voice over ATM */ + VOICEOVERFRAMERELAY = 0x99, /* Voice Over Frame Relay */ + IDSL = 0x9a, /* Digital Subscriber Loop over ISDN */ + COMPOSITELINK = 0x9b, /* Avici Composite Link Interface */ + SS7SIGLINK = 0x9c, /* SS7 Signaling Link */ + PROPWIRELESSP2P = 0x9d, /* Prop. P2P wireless interface */ + FRFORWARD = 0x9e, /* Frame forward Interface */ + RFC1483 = 0x9f, /* Multiprotocol over ATM AAL5 */ + USB = 0xa0, /* USB Interface */ + IEEE8023ADLAG = 0xa1, /* IEEE 802.3ad Link Aggregate*/ + BGPPOLICYACCOUNTING = 0xa2, /* BGP Policy Accounting */ + FRF16MFRBUNDLE = 0xa3, /* FRF.16 Multilink Frame Relay*/ + H323GATEKEEPER = 0xa4, /* H323 Gatekeeper */ + H323PROXY = 0xa5, /* H323 Voice and Video Proxy */ + MPLS = 0xa6, /* MPLS */ + MFSIGLINK = 0xa7, /* Multi-frequency signaling link */ + HDSL2 = 0xa8, /* High Bit-Rate DSL, 2nd gen. */ + SHDSL = 0xa9, /* Multirate HDSL2 */ + DS1FDL = 0xaa, /* Facility Data Link (4Kbps) on a DS1*/ + POS = 0xab, /* Packet over SONET/SDH Interface */ + DVBASILN = 0xac, /* DVB-ASI Input */ + DVBASIOUT = 0xad, /* DVB-ASI Output */ + PLC = 0xae, /* Power Line Communications */ + NFAS = 0xaf, /* Non-Facility Associated Signaling */ + TR008 = 0xb0, /* TROO8 */ + GR303RDT = 0xb1, /* Remote Digital Terminal */ + GR303IDT = 0xb2, /* Integrated Digital Terminal */ + ISUP = 0xb3, /* ISUP */ + PROPDOCSWIRELESSMACLAYER = 0xb4, /* prop/Wireless MAC Layer */ + PROPDOCSWIRELESSDOWNSTREAM = 0xb5, /* prop/Wireless Downstream */ + PROPDOCSWIRELESSUPSTREAM = 0xb6, /* prop/Wireless Upstream */ + HIPERLAN2 = 0xb7, /* HIPERLAN Type 2 Radio Interface */ + PROPBWAP2MP = 0xb8, /* PropBroadbandWirelessAccess P2MP*/ + SONETOVERHEADCHANNEL = 0xb9, /* SONET Overhead Channel */ + DIGITALWRAPPEROVERHEADCHANNEL = 0xba, /* Digital Wrapper Overhead */ + AAL2 = 0xbb, /* ATM adaptation layer 2 */ + RADIOMAC = 0xbc, /* MAC layer over radio links */ + ATMRADIO = 0xbd, /* ATM over radio links */ + IMT = 0xbe, /* Inter-Machine Trunks */ + MVL = 0xbf, /* Multiple Virtual Lines DSL */ + REACHDSL = 0xc0, /* Long Reach DSL */ + FRDLCIENDPT = 0xc1, /* Frame Relay DLCI End Point */ + ATMVCIENDPT = 0xc2, /* ATM VCI End Point */ + OPTICALCHANNEL = 0xc3, /* Optical Channel */ + OPTICALTRANSPORT = 0xc4, /* Optical Transport */ + INFINIBAND = 0xc7, /* Infiniband */ + INFINIBANDLAG = 0xc8, /* Infiniband Link Aggregate */ + BRIDGE = 0xd1, /* Transparent bridge interface */ + STF = 0xd7, /* 6to4 interface */ + + /* + * Not based on IANA assignments. Conflicting with IANA assignments. + * We should make them negative probably. + * This requires changes to struct if_data. + */ + GIF = 0xf0, /* Generic tunnel interface */ + PVC = 0xf1, /* Unused */ + ENC = 0xf4, /* Encapsulating interface */ + PFLOG = 0xf6, /* PF packet filter logging */ + PFSYNC = 0xf7, /* PF packet filter synchronization */ + WIREGUARD = 0xf8, /* WireGuard tunnel */ +} + +// +// #include <net/if_dl.h> +// + +/* + * Structure of a Link-Level sockaddr: + */ +// struct sockaddr_dl +Socket_Address_Data_Link :: struct { + using _: Socket_Address_Header, + index: c.ushort, /* if != 0, system given index for interface */ + type: Interface_Type, /* interface type */ + nlen: c.uchar, /* interface name length, no trailing 0 reqd. */ + alen: c.uchar, /* link level address length */ + slen: c.uchar, /* link layer selector length */ + data: [46]c.char, /* minimum work area, can be larger; contains both if name and ll address */ +} + +// +// #include <netinet/in.h> +// + +in_addr_t :: distinct u32be + +/* Internet address (a structure for historical reasons). */ +// struct in_addr +IP4_Address :: struct #raw_union { + // NOTE(Feoramund): I have modified this struct from its C definition by + // introducing the byte variant to make it easier to work with. + addr8: [4]u8, + addr32: in_addr_t, +} + +/* Socket address, internet style. */ +// struct sockaddr_in +Socket_Address_Internet :: struct #packed { + using _: Socket_Address_Header, + port: in_port_t, + addr: IP4_Address, + zero: [8]c.char, +} + +// +// #include <netinet6/in6.h> +// + +/* + * IPv6 address + */ +// struct in6_addr +IP6_Address :: struct #raw_union { + addr8: [16]u8, + addr16: [8]u16be, + addr32: [4]u32be, +} + +/* + * Socket address for IPv6 + */ +// struct sockaddr_in6 +Socket_Address_Internet6 :: struct #packed { + using _: Socket_Address_Header, + port: in_port_t, /* Transport layer port # */ + flowinfo: u32, /* IP6 flow information */ + addr: IP6_Address, /* IP6 address */ + scope_id: u32, /* scope zone index */ +} + +// +// #include <sys/umtx.h> +// + +/* op code for _umtx_op */ +// #define UMTX_OP_* +Userland_Mutex_Operation :: enum c.int { + LOCK = 0, /* COMPAT10 */ + UNLOCK = 1, /* COMPAT10 */ + WAIT = 2, + WAKE = 3, + MUTEX_TRYLOCK = 4, + MUTEX_LOCK = 5, + MUTEX_UNLOCK = 6, + SET_CEILING = 7, + CV_WAIT = 8, + CV_SIGNAL = 9, + CV_BROADCAST = 10, + WAIT_UINT = 11, + RW_RDLOCK = 12, + RW_WRLOCK = 13, + RW_UNLOCK = 14, + WAIT_UINT_PRIVATE = 15, + WAKE_PRIVATE = 16, + MUTEX_WAIT = 17, + MUTEX_WAKE = 18, /* deprecated */ + SEM_WAIT = 19, /* deprecated */ + SEM_WAKE = 20, /* deprecated */ + NWAKE_PRIVATE = 21, + MUTEX_WAKE2 = 22, + SEM2_WAIT = 23, + SEM2_WAKE = 24, + SHM = 25, + ROBUST_LISTS = 26, + GET_MIN_TIMEOUT = 27, + SET_MIN_TIMEOUT = 28, +} |