Files
zomq/zmq/err.odin
T

197 lines
6.1 KiB
Odin

package zmq
import "core:c"
import "core:os"
// ZMQ_HAUSNUMERO — base offset for ZMQ's private error codes.
//
// zmq.h defines two ranges on top of this base:
// +1..18 — fallback POSIX errnos (ENOTSUP, EPROTONOSUPPORT, ... ENETRESET).
// Only used when the platform's C <errno.h> lacks the symbol
// (e.g. MSVC on Windows). On Linux/macOS the system's native
// errno values are used instead, so these never appear from
// zmq_errno() — but we normalize to them for portability (see
// normalize_to_zmq).
// +51..54 — ZMQ-native codes (EFSM, ENOCOMPATPROTO, ETERM, EMTHREAD).
// Always ZMQ-specific, defined unconditionally.
//
// The value is fixed by libzmq's ABI-stability promise (zmq.h): "the value
// of constants must not change, and old values may not be reused". A C
// #define is not a linkable symbol, so hardcoding is the only option.
HAUSNUMERO :: 156384712
ZMQ_Error :: enum c.int {
// Fallback POSIX errnos — ZMQ's own values for these errnos, used on
// platforms where the C <errno.h> doesn't define them. We normalize
// all platforms to these values via normalize_to_zmq so that the same
// logical error always has the same value and lands in ZMQ_Error
// regardless of platform.
ENOTSUP = HAUSNUMERO + 1,
EPROTONOSUPPORT = HAUSNUMERO + 2,
ENOBUFS = HAUSNUMERO + 3,
ENETDOWN = HAUSNUMERO + 4,
EADDRINUSE = HAUSNUMERO + 5,
EADDRNOTAVAIL = HAUSNUMERO + 6,
ECONNREFUSED = HAUSNUMERO + 7,
EINPROGRESS = HAUSNUMERO + 8,
ENOTSOCK = HAUSNUMERO + 9,
EMSGSIZE = HAUSNUMERO + 10,
EAFNOSUPPORT = HAUSNUMERO + 11,
ENETUNREACH = HAUSNUMERO + 12,
ECONNABORTED = HAUSNUMERO + 13,
ECONNRESET = HAUSNUMERO + 14,
ENOTCONN = HAUSNUMERO + 15,
ETIMEDOUT = HAUSNUMERO + 16,
EHOSTUNREACH = HAUSNUMERO + 17,
ENETRESET = HAUSNUMERO + 18,
// ZMQ-native error codes.
EFSM = HAUSNUMERO + 51,
ENOCOMPATPROTO = HAUSNUMERO + 52,
ETERM = HAUSNUMERO + 53,
EMTHREAD = HAUSNUMERO + 54,
}
// Map platform-native POSIX errnos to ZMQ fallback values.
//
// The 18 errnos below have different numeric values on different platforms
// (e.g. EADDRINUSE is 98 on Linux, 100 on Windows, 48 on macOS). By
// translating them to ZMQ's canonical fallback values (HAUSNUMERO+offset),
// the same logical error always lands in ZMQ_Error with the same value
// on every platform — enabling portable pattern matching.
//
// Errnos not in this list (EAGAIN, EINTR, EACCES, ...) pass through
// unchanged and are classified as Platform_Error.
normalize_to_zmq :: proc(raw: c.int) -> c.int {
#partial switch os.Platform_Error(raw) {
// ENOTSUP shares its value with EOPNOTSUPP on Linux/macOS (both are
// the same constant). On Windows they differ (129 vs 130), but MSVC-
// compiled libzmq uses the ZMQ fallback (HAUSNUMERO+1) anyway, so
// .EOPNOTSUPP here only needs to match the Linux/macOS value.
case .EOPNOTSUPP:
return HAUSNUMERO + 1
case .EPROTONOSUPPORT:
return HAUSNUMERO + 2
case .ENOBUFS:
return HAUSNUMERO + 3
case .ENETDOWN:
return HAUSNUMERO + 4
case .EADDRINUSE:
return HAUSNUMERO + 5
case .EADDRNOTAVAIL:
return HAUSNUMERO + 6
case .ECONNREFUSED:
return HAUSNUMERO + 7
case .EINPROGRESS:
return HAUSNUMERO + 8
case .ENOTSOCK:
return HAUSNUMERO + 9
case .EMSGSIZE:
return HAUSNUMERO + 10
case .EAFNOSUPPORT:
return HAUSNUMERO + 11
case .ENETUNREACH:
return HAUSNUMERO + 12
case .ECONNABORTED:
return HAUSNUMERO + 13
case .ECONNRESET:
return HAUSNUMERO + 14
case .ENOTCONN:
return HAUSNUMERO + 15
case .ETIMEDOUT:
return HAUSNUMERO + 16
case .EHOSTUNREACH:
return HAUSNUMERO + 17
case .ENETRESET:
return HAUSNUMERO + 18
case:
return raw
}
}
// Reverse of normalize_to_zmq: maps ZMQ fallback values back to
// platform-native errno values.
//
// zmq_strerror only has string entries for ZMQ-native codes (HAUSNUMERO+51..54)
// and delegates everything else to C's strerror, which only knows platform-native
// errno values. The ZMQ fallback values (HAUSNUMERO+1..18) are in a gap — neither
// ZMQ-native nor platform-native — so zmq_strerror returns "Unknown error" for them.
// This function reverses the normalization so strerror produces the correct string.
denormalize_from_zmq :: proc(zmq_val: c.int) -> c.int {
#partial switch ZMQ_Error(zmq_val) {
case .ENOTSUP:
return c.int(os.Platform_Error.EOPNOTSUPP)
case .EPROTONOSUPPORT:
return c.int(os.Platform_Error.EPROTONOSUPPORT)
case .ENOBUFS:
return c.int(os.Platform_Error.ENOBUFS)
case .ENETDOWN:
return c.int(os.Platform_Error.ENETDOWN)
case .EADDRINUSE:
return c.int(os.Platform_Error.EADDRINUSE)
case .EADDRNOTAVAIL:
return c.int(os.Platform_Error.EADDRNOTAVAIL)
case .ECONNREFUSED:
return c.int(os.Platform_Error.ECONNREFUSED)
case .EINPROGRESS:
return c.int(os.Platform_Error.EINPROGRESS)
case .ENOTSOCK:
return c.int(os.Platform_Error.ENOTSOCK)
case .EMSGSIZE:
return c.int(os.Platform_Error.EMSGSIZE)
case .EAFNOSUPPORT:
return c.int(os.Platform_Error.EAFNOSUPPORT)
case .ENETUNREACH:
return c.int(os.Platform_Error.ENETUNREACH)
case .ECONNABORTED:
return c.int(os.Platform_Error.ECONNABORTED)
case .ECONNRESET:
return c.int(os.Platform_Error.ECONNRESET)
case .ENOTCONN:
return c.int(os.Platform_Error.ENOTCONN)
case .ETIMEDOUT:
return c.int(os.Platform_Error.ETIMEDOUT)
case .EHOSTUNREACH:
return c.int(os.Platform_Error.EHOSTUNREACH)
case .ENETRESET:
return c.int(os.Platform_Error.ENETRESET)
case:
return zmq_val
}
}
last_error :: proc() -> Error {
raw := errno()
normalized := normalize_to_zmq(raw)
#partial switch ZMQ_Error(normalized) {
case .ENOTSUP,
.EPROTONOSUPPORT,
.ENOBUFS,
.ENETDOWN,
.EADDRINUSE,
.EADDRNOTAVAIL,
.ECONNREFUSED,
.EINPROGRESS,
.ENOTSOCK,
.EMSGSIZE,
.EAFNOSUPPORT,
.ENETUNREACH,
.ECONNABORTED,
.ECONNRESET,
.ENOTCONN,
.ETIMEDOUT,
.EHOSTUNREACH,
.ENETRESET,
.EFSM,
.ENOCOMPATPROTO,
.ETERM,
.EMTHREAD:
return ZMQ_Error(normalized)
case:
return os.Platform_Error(raw)
}
}