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/net | |
| parent | bc6deab1759fa10177c7b2a09d2530ffa88d8cc8 (diff) | |
| parent | 6cc7f3b451f6465dcba0ac9c5a0befb734478a02 (diff) | |
Merge pull request #3810 from Feoramund/freebsd-core-net
Port `core:net` to FreeBSD
Diffstat (limited to 'core/net')
| -rw-r--r-- | core/net/addr.odin | 6 | ||||
| -rw-r--r-- | core/net/common.odin | 6 | ||||
| -rw-r--r-- | core/net/dns.odin | 6 | ||||
| -rw-r--r-- | core/net/dns_unix.odin | 4 | ||||
| -rw-r--r-- | core/net/dns_windows.odin | 2 | ||||
| -rw-r--r-- | core/net/doc.odin | 2 | ||||
| -rw-r--r-- | core/net/errors_darwin.odin | 2 | ||||
| -rw-r--r-- | core/net/errors_freebsd.odin | 217 | ||||
| -rw-r--r-- | core/net/errors_linux.odin | 2 | ||||
| -rw-r--r-- | core/net/errors_windows.odin | 2 | ||||
| -rw-r--r-- | core/net/interface.odin | 4 | ||||
| -rw-r--r-- | core/net/interface_darwin.odin | 3 | ||||
| -rw-r--r-- | core/net/interface_freebsd.odin | 177 | ||||
| -rw-r--r-- | core/net/interface_linux.odin | 2 | ||||
| -rw-r--r-- | core/net/interface_windows.odin | 2 | ||||
| -rw-r--r-- | core/net/socket.odin | 4 | ||||
| -rw-r--r-- | core/net/socket_darwin.odin | 2 | ||||
| -rw-r--r-- | core/net/socket_freebsd.odin | 404 | ||||
| -rw-r--r-- | core/net/socket_linux.odin | 2 | ||||
| -rw-r--r-- | core/net/socket_windows.odin | 2 | ||||
| -rw-r--r-- | core/net/url.odin | 2 |
21 files changed, 843 insertions, 10 deletions
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" |