diff --git a/chronos/transports/common.nim b/chronos/transports/common.nim index cbec5d6..5a9072c 100644 --- a/chronos/transports/common.nim +++ b/chronos/transports/common.nim @@ -574,10 +574,8 @@ template getTransportUseClosedError*(): ref TransportUseClosedError = newException(TransportUseClosedError, "Transport is already closed!") template getTransportOsError*(err: OSErrorCode): ref TransportOsError = - var msg = "(" & $int(err) & ") " & osErrorMsg(err) - var tre = newException(TransportOsError, msg) - tre.code = err - tre + (ref TransportOsError)( + code: err, msg: "(" & $int(err) & ") " & osErrorMsg(err)) template getTransportOsError*(err: cint): ref TransportOsError = getTransportOsError(OSErrorCode(err)) @@ -608,15 +606,16 @@ template getTransportTooManyError*( ): ref TransportTooManyError = let msg = when defined(posix): - if code == OSErrorCode(0): + case code + of OSErrorCode(0): "Too many open transports" - elif code == oserrno.EMFILE: + of EMFILE: "[EMFILE] Too many open files in the process" - elif code == oserrno.ENFILE: + of ENFILE: "[ENFILE] Too many open files in system" - elif code == oserrno.ENOBUFS: + of ENOBUFS: "[ENOBUFS] No buffer space available" - elif code == oserrno.ENOMEM: + of ENOMEM: "[ENOMEM] Not enough memory availble" else: "[" & $int(code) & "] Too many open transports" @@ -649,23 +648,26 @@ template getConnectionAbortedError*( ): ref TransportAbortedError = let msg = when defined(posix): - if code == OSErrorCode(0): + case code + of OSErrorCode(0), ECONNABORTED: "[ECONNABORTED] Connection has been aborted before being accepted" - elif code == oserrno.EPERM: + of EPERM: "[EPERM] Firewall rules forbid connection" - elif code == oserrno.ETIMEDOUT: + of ETIMEDOUT: "[ETIMEDOUT] Operation has been timed out" + of ENOTCONN: + "[ENOTCONN] Transport endpoint is not connected" else: "[" & $int(code) & "] Connection has been aborted" elif defined(windows): case code - of OSErrorCode(0), oserrno.WSAECONNABORTED: + of OSErrorCode(0), WSAECONNABORTED: "[ECONNABORTED] Connection has been aborted before being accepted" of WSAENETDOWN: "[ENETDOWN] Network is down" - of oserrno.WSAENETRESET: + of WSAENETRESET: "[ENETRESET] Network dropped connection on reset" - of oserrno.WSAECONNRESET: + of WSAECONNRESET: "[ECONNRESET] Connection reset by peer" of WSAETIMEDOUT: "[ETIMEDOUT] Connection timed out" @@ -675,3 +677,42 @@ template getConnectionAbortedError*( "[" & $int(code) & "] Connection has been aborted" newException(TransportAbortedError, msg) + +template getTransportError*(ecode: OSErrorCode): untyped = + when defined(posix): + case ecode + of ECONNABORTED, EPERM, ETIMEDOUT, ENOTCONN: + getConnectionAbortedError(ecode) + of EMFILE, ENFILE, ENOBUFS, ENOMEM: + getTransportTooManyError(ecode) + else: + getTransportOsError(ecode) + else: + case ecode + of WSAECONNABORTED, WSAENETDOWN, WSAENETRESET, WSAECONNRESET, WSAETIMEDOUT: + getConnectionAbortedError(ecode) + of ERROR_TOO_MANY_OPEN_FILES, WSAENOBUFS, WSAEMFILE: + getTransportTooManyError(ecode) + else: + getTransportOsError(ecode) + +proc raiseTransportError*(ecode: OSErrorCode) {. + raises: [TransportAbortedError, TransportTooManyError, TransportOsError], + noreturn.} = + ## Raises transport specific OS error. + when defined(posix): + case ecode + of ECONNABORTED, EPERM, ETIMEDOUT, ENOTCONN: + raise getConnectionAbortedError(ecode) + of EMFILE, ENFILE, ENOBUFS, ENOMEM: + raise getTransportTooManyError(ecode) + else: + raise getTransportOsError(ecode) + else: + case ecode + of WSAECONNABORTED, WSAENETDOWN, WSAENETRESET, WSAECONNRESET, WSAETIMEDOUT: + raise getConnectionAbortedError(ecode) + of ERROR_TOO_MANY_OPEN_FILES, WSAENOBUFS, WSAEMFILE: + raise getTransportTooManyError(ecode) + else: + raise getTransportOsError(ecode) diff --git a/chronos/transports/stream.nim b/chronos/transports/stream.nim index 18d6a50..3abd942 100644 --- a/chronos/transports/stream.nim +++ b/chronos/transports/stream.nim @@ -141,30 +141,28 @@ type # transport for new client proc remoteAddress*(transp: StreamTransport): TransportAddress {. - raises: [TransportError].} = + raises: [TransportAbortedError, TransportTooManyError, TransportOsError].} = ## Returns ``transp`` remote socket address. - if transp.kind != TransportKind.Socket: - raise newException(TransportError, "Socket required!") + doAssert(transp.kind == TransportKind.Socket, "Socket transport required!") if transp.remote.family == AddressFamily.None: var saddr: Sockaddr_storage var slen = SockLen(sizeof(saddr)) if getpeername(SocketHandle(transp.fd), cast[ptr SockAddr](addr saddr), addr slen) != 0: - raiseTransportOsError(osLastError()) + raiseTransportError(osLastError()) fromSAddr(addr saddr, slen, transp.remote) transp.remote proc localAddress*(transp: StreamTransport): TransportAddress {. - raises: [TransportError].} = + raises: [TransportAbortedError, TransportTooManyError, TransportOsError].} = ## Returns ``transp`` local socket address. - if transp.kind != TransportKind.Socket: - raise newException(TransportError, "Socket required!") + doAssert(transp.kind == TransportKind.Socket, "Socket transport required!") if transp.local.family == AddressFamily.None: var saddr: Sockaddr_storage var slen = SockLen(sizeof(saddr)) if getsockname(SocketHandle(transp.fd), cast[ptr SockAddr](addr saddr), addr slen) != 0: - raiseTransportOsError(osLastError()) + raiseTransportError(osLastError()) fromSAddr(addr saddr, slen, transp.local) transp.local