aboutsummaryrefslogtreecommitdiff
path: root/core/net/errors_freebsd.odin
diff options
context:
space:
mode:
authorLaytan Laats <laytanlaats@hotmail.com>2025-04-05 15:53:11 +0200
committerLaytan Laats <laytanlaats@hotmail.com>2025-04-05 17:35:19 +0200
commitff7d55a8e1ab8fd031378d9994f4aaf8394e7255 (patch)
tree78e4dab5313eed54d40496f2aaa195972ff69347 /core/net/errors_freebsd.odin
parentf796b67a67bdd316ecf830b13cbd43fed7c0a64b (diff)
net: rework errors to be cross-platform
Diffstat (limited to 'core/net/errors_freebsd.odin')
-rw-r--r--core/net/errors_freebsd.odin407
1 files changed, 238 insertions, 169 deletions
diff --git a/core/net/errors_freebsd.odin b/core/net/errors_freebsd.odin
index 486732a95..707ffd0dd 100644
--- a/core/net/errors_freebsd.odin
+++ b/core/net/errors_freebsd.odin
@@ -20,198 +20,267 @@ package net
Feoramund: FreeBSD platform code
*/
-import "core:c"
+import "core:reflect"
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,
+@(private="file", thread_local)
+_last_error: freebsd.Errno
+
+_last_platform_error :: proc() -> i32 {
+ return i32(_last_error)
+}
+
+_last_platform_error_string :: proc() -> string {
+ description, _ := reflect.enum_name_from_value(_last_error)
+ return description
+}
+
+_set_last_platform_error :: proc(err: i32) {
+ _last_error = freebsd.Errno(err)
}
-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.
+_create_socket_error :: proc(errno: freebsd.Errno) -> Create_Socket_Error {
+ assert(errno != nil)
+ _last_error = errno
+
+ #partial switch errno {
+ case .EMFILE, .ENFILE, .ENOBUFS, .EPROTONOSUPPORT:
+ return .Insufficient_Resources
+ case .EAFNOSUPPORT, .EPROTOTYPE:
+ return .Invalid_Argument
+ case .EACCES, .EPERM:
+ return .Insufficient_Permissions
+ case:
+ return .Unknown
+ }
}
-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.
+_dial_error :: proc(errno: freebsd.Errno) -> Dial_Error {
+ assert(errno != nil)
+ _last_error = errno
+
+ #partial switch errno {
+ case .EBADF, .EINVAL, .ENOTSOCK, .EADDRNOTAVAIL, .EAFNOSUPPORT, .EFAULT, .EAGAIN:
+ return .Invalid_Argument
+ case .EISCONN:
+ return .Already_Connected
+ case .EALREADY:
+ return .Already_Connecting
+ case .EADDRINUSE:
+ return .Address_In_Use
+ case .ENETUNREACH:
+ return .Network_Unreachable
+ case .EHOSTUNREACH:
+ return .Host_Unreachable
+ case .ECONNREFUSED:
+ return .Refused
+ case .ECONNRESET:
+ return .Reset
+ case .ETIMEDOUT:
+ return .Timeout
+ case .EINPROGRESS:
+ return .Would_Block
+ case .EINTR:
+ return .Interrupted
+ case .EACCES:
+ return .Broadcast_Not_Supported
+ case:
+ return .Unknown
+ }
}
-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,
+_bind_error :: proc(errno: freebsd.Errno) -> Bind_Error {
+ assert(errno != nil)
+ _last_error = errno
+
+ #partial switch errno {
+ case .EAGAIN, .ENOTSOCK, .EADDRNOTAVAIL, .EAFNOSUPPORT, .EFAULT:
+ return .Insufficient_Resources
+ case .EBADF:
+ return .Invalid_Argument
+ case .EINVAL:
+ return .Already_Bound
+ case .EACCES:
+ return .Insufficient_Permissions_For_Address
+ case .EADDRINUSE:
+ return .Address_In_Use
+ case:
+ return .Unknown
+ }
}
-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,
+_listen_error :: proc(errno: freebsd.Errno) -> Listen_Error {
+ assert(errno != nil)
+ _last_error = errno
+
+ #partial switch errno {
+ case .EBADF, .ENOTSOCK:
+ return .Invalid_Argument
+ case .EDESTADDRREQ, .EOPNOTSUPP:
+ return .Unsupported_Socket
+ case .EINVAL:
+ return .Already_Connected
+ case:
+ return .Unknown
+ }
}
-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,
+_accept_error :: proc(errno: freebsd.Errno) -> Accept_Error {
+ assert(errno != nil)
+ _last_error = errno
+
+ #partial switch errno {
+ case .EMFILE, .ENFILE:
+ return .Insufficient_Resources
+ case .EBADF, .ENOTSOCK, .EFAULT:
+ return .Invalid_Argument
+ case .EINVAL:
+ return .Not_Listening
+ case .ECONNABORTED:
+ return .Aborted
+ case .EWOULDBLOCK:
+ return .Would_Block
+ case .EINTR:
+ return .Interrupted
+ case:
+ return .Unknown
+ }
}
-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_recv_error :: proc(errno: freebsd.Errno) -> TCP_Recv_Error {
+ assert(errno != nil)
+ _last_error = errno
+
+ #partial switch errno {
+ case .EBADF, .ENOTSOCK, .EFAULT:
+ return .Invalid_Argument
+ case .ENOTCONN:
+ return .Not_Connected
+ case .ECONNRESET:
+ return .Connection_Closed
+ case .ETIMEDOUT:
+ return .Timeout
+ case .EAGAIN:
+ return .Would_Block
+ case .EINTR:
+ return .Interrupted
+ case:
+ return .Unknown
+ }
}
-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,
+_udp_recv_error :: proc(errno: freebsd.Errno) -> UDP_Recv_Error {
+ assert(errno != nil)
+ _last_error = errno
+
+ #partial switch errno {
+ case .EBADF, .ENOTSOCK, .EFAULT:
+ return .Invalid_Argument
+ case .ECONNRESET, .ENOTCONN:
+ return .Connection_Refused
+ case .ETIMEDOUT:
+ return .Timeout
+ case .EAGAIN:
+ return .Would_Block
+ case .EINTR:
+ return .Interrupted
+ case:
+ return .Unknown
+ }
}
-// NOTE(Feoramund): The same as TCP errors go, as far as I'm aware.
-UDP_Send_Error :: distinct TCP_Send_Error
+_tcp_send_error :: proc(errno: freebsd.Errno) -> TCP_Send_Error {
+ assert(errno != nil)
+ _last_error = errno
+
+ #partial switch errno {
+ case .EBADF, .EACCES, .ENOTSOCK, .EFAULT, .EMSGSIZE:
+ return .Invalid_Argument
+ case .ENOBUFS:
+ return .Insufficient_Resources
+ case .ECONNRESET, .EPIPE:
+ return .Connection_Closed
+ case .ENOTCONN:
+ return .Not_Connected
+ case .EHOSTUNREACH:
+ return .Host_Unreachable
+ case .EHOSTDOWN:
+ return .Host_Unreachable
+ case .ENETDOWN:
+ return .Network_Unreachable
+ case .EAGAIN:
+ return .Would_Block
+ case .EINTR:
+ return .Interrupted
+ case:
+ return .Unknown
+ }
+}
-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,
+_udp_send_error :: proc(errno: freebsd.Errno) -> UDP_Send_Error {
+ assert(errno != nil)
+ _last_error = errno
+
+ #partial switch errno {
+ case .EBADF, .EACCES, .ENOTSOCK, .EFAULT, .EMSGSIZE:
+ return .Invalid_Argument
+ case .ENOBUFS:
+ return .Insufficient_Resources
+ case .ECONNRESET, .EPIPE:
+ return .Connection_Refused
+ case .EHOSTUNREACH:
+ return .Host_Unreachable
+ case .EHOSTDOWN:
+ return .Host_Unreachable
+ case .ENETDOWN:
+ return .Network_Unreachable
+ case .EAGAIN:
+ return .Would_Block
+ case .EINTR:
+ return .Interrupted
+ case:
+ return .Unknown
+ }
}
-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,
+_shutdown_error :: proc(errno: freebsd.Errno) -> Shutdown_Error {
+ assert(errno != nil)
+ _last_error = errno
+
+ #partial switch errno {
+ case .EBADF, .EINVAL, .ENOTSOCK, .ENOTCONN:
+ return .Invalid_Argument
+ case:
+ return .Unknown
+ }
}
-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,
+_socket_option_error :: proc(errno: freebsd.Errno) -> Socket_Option_Error {
+ assert(errno != nil)
+ _last_error = errno
+
+ #partial switch errno {
+ case .ENOMEM, .ENOBUFS:
+ return .Insufficient_Resources
+ case .EBADF, .ENOTSOCK:
+ return .Invalid_Socket
+ case .ENOPROTOOPT:
+ return .Invalid_Option
+ case .EINVAL, .EFAULT:
+ return .Invalid_Value
+ case:
+ return .Unknown
+ }
}
-Set_Blocking_Error :: enum c.int {
- None = 0,
- Not_Descriptor = cast(c.int)freebsd.Errno.EBADF,
- Wrong_Descriptor = cast(c.int)freebsd.Errno.ENOTTY,
+_set_blocking_error :: proc(errno: freebsd.Errno) -> Set_Blocking_Error {
+ assert(errno != nil)
+ _last_error = errno
+
+ #partial switch errno {
+ case .EBADF, .ENOTTY:
+ return .Invalid_Argument
+ case:
+ return .Unknown
+ }
}