diff options
| author | Laytan Laats <laytanlaats@hotmail.com> | 2025-04-05 15:53:11 +0200 |
|---|---|---|
| committer | Laytan Laats <laytanlaats@hotmail.com> | 2025-04-05 17:35:19 +0200 |
| commit | ff7d55a8e1ab8fd031378d9994f4aaf8394e7255 (patch) | |
| tree | 78e4dab5313eed54d40496f2aaa195972ff69347 /core/net/errors_freebsd.odin | |
| parent | f796b67a67bdd316ecf830b13cbd43fed7c0a64b (diff) | |
net: rework errors to be cross-platform
Diffstat (limited to 'core/net/errors_freebsd.odin')
| -rw-r--r-- | core/net/errors_freebsd.odin | 407 |
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 + } } |