/* net6 - Library providing IPv4/IPv6 network access * Copyright (C) 2005 Armin Burgmeier / 0x539 dev group * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifdef WIN32 #include #include #else #include #include #endif #include #include "error.hpp" #include "common.hpp" // Login error codes const net6::login::error net6::login::ERROR_NAME_INVALID = 0x01; const net6::login::error net6::login::ERROR_NAME_IN_USE = 0x02; const net6::login::error net6::login::ERROR_MAX = 0xff; std::string net6::login::errstring(error err) { switch(err) { case net6::login::ERROR_NAME_INVALID: return _("Invalid name"); case net6::login::ERROR_NAME_IN_USE: return _("Name is already in use"); default: return _("An unknown login error occured"); } } namespace { /** Translates a message without being in the net6 namespace. */ const char* _(const char* msgid) { return net6::_(msgid); } /** Translates a system dependant error value to net6 error codes. */ net6::error::code system_to_net6(int error_code) { switch(error_code) { #ifdef WIN32 case WSAEINTR: return net6::error::INTERRUPTED; case WSAEACCES: return net6::error::ACCESS_DENIED; case WSAEFAULT: return net6::error::BAD_ADDRESS; case WSAEINVAL: return net6::error::INVALID_ARGUMENT; case WSAEMFILE: return net6::error::TOO_MANY_FILES; case WSAEWOULDBLOCK: return net6::error::WOULD_BLOCK; case WSAEALREADY: return net6::error::OPERATION_IN_PROGRESS; case WSAENOTSOCK: return net6::error::NOT_SOCKET; case WSAEDESTADDRREQ: return net6::error::DESTINATION_ADDRESS_REQUIRED; case WSAEMSGSIZE: return net6::error::MESSAGE_TOO_LONG; case WSAEPROTOTYPE: return net6::error::WRONG_PROTOCOL_TYPE; case WSAENOPROTOOPT: return net6::error::BAD_PROTOCOL_OPTION; case WSAEPROTONOSUPPORT: return net6::error::PROTOCOL_NOT_SUPPORTED; case WSAESOCKTNOSUPPORT: return net6::error::SOCKET_NOT_SUPPORTED; case WSAEOPNOTSUPP: return net6::error::OPERATION_NOT_SUPPORTED; case WSAEPFNOSUPPORT: return net6::error::PROTOCOL_FAMILY_NOT_SUPPORTED; case WSAEAFNOSUPPORT: return net6::error::ADDRESS_FAMILY_NOT_SUPPORTED; case WSAEADDRINUSE: return net6::error::ADDRESS_IN_USE; case WSAEADDRNOTAVAIL: return net6::error::ADDRESS_UNAVAILABLE; case WSAENETDOWN: return net6::error::NETWORK_DOWN; case WSAENETUNREACH: return net6::error::NETWORK_UNREACHABLE; case WSAENETRESET: return net6::error::NETWORK_RESET; case WSAECONNABORTED: return net6::error::CONNECTION_ABORTED; case WSAECONNRESET: return net6::error::CONNECTION_RESET; case WSAENOBUFS: return net6::error::NO_BUFFER_SPACE; case WSAEISCONN: return net6::error::SOCKET_IS_CONNECTED; case WSAENOTCONN: return net6::error::SOCKET_NOT_CONNECTED; case WSAESHUTDOWN: return net6::error::SOCKET_SHUTDOWN; case WSAETIMEDOUT: return net6::error::CONNECTION_TIMEOUT; case WSAECONNREFUSED: return net6::error::CONNECTION_REFUSED; case WSAEHOSTDOWN: return net6::error::HOST_DOWN; case WSAEHOSTUNREACH: return net6::error::HOST_UNREACHABLE; case WSAEPROCLIM: return net6::error::TOO_MANY_PROCESSES; case WSASYSNOTREADY: return net6::error::SYSTEM_NOT_READY; case WSAVERNOTSUPPORTED: return net6::error::VERSION_NOT_SUPPORTED; case WSANOTINITIALISED: return net6::error::NOT_INITIALISED; case WSAEDISCON: return net6::error::DISCONNECTED; case WSATYPE_NOT_FOUND: return net6::error::TYPE_NOT_FOUND; case WSAHOST_NOT_FOUND: return net6::error::HOSTNAME_NOT_FOUND; case WSATRY_AGAIN: return net6::error::TEMPORARY_FAILURE; case WSANO_DATA: return net6::error::NO_DATA_RECORD; case WSA_INVALID_HANDLE: return net6::error::INVALID_HANDLE; case WSA_INVALID_PARAMETER: return net6::error::INVALID_PARAMETER; #else case EACCES: return net6::error::ACCESS_DENIED; case EADDRINUSE: return net6::error::ADDRESS_IN_USE; case EADDRNOTAVAIL: return net6::error::ADDRESS_UNAVAILABLE; case EAFNOSUPPORT: return net6::error::ADDRESS_FAMILY_NOT_SUPPORTED; case EAGAIN: return net6::error::WOULD_BLOCK; case EALREADY: return net6::error::OPERATION_IN_PROGRESS; case EBADF: return net6::error::NOT_SOCKET; // TODO: What is bad message..? // deactivated 2005-04-15 by phil: not BSD-compatible // case EBADMSG: // return net6::error::MESSAGE_TOO_LONG; case ECONNABORTED: return net6::error::CONNECTION_ABORTED; case ECONNREFUSED: return net6::error::CONNECTION_REFUSED; case ECONNRESET: return net6::error::CONNECTION_RESET; case EDESTADDRREQ: return net6::error::DESTINATION_ADDRESS_REQUIRED; case EFAULT: return net6::error::BAD_ADDRESS; case EHOSTUNREACH: return net6::error::HOST_UNREACHABLE; case EINPROGRESS: return net6::error::OPERATION_IN_PROGRESS; case EINTR: return net6::error::INTERRUPTED; case EINVAL: return net6::error::INVALID_ARGUMENT; case EISCONN: return net6::error::SOCKET_IS_CONNECTED; case EMFILE: return net6::error::TOO_MANY_FILES; case EMSGSIZE: return net6::error::MESSAGE_TOO_LONG; case ENETDOWN: return net6::error::NETWORK_DOWN; case ENETRESET: return net6::error::NETWORK_RESET; case ENETUNREACH: return net6::error::NETWORK_UNREACHABLE; case ENFILE: return net6::error::TOO_MANY_FILES; case ENOBUFS: return net6::error::NO_BUFFER_SPACE; // deactivated 2005-04-15 by phil: not BSD-compatible // case ENODATA: // return net6::error::NO_DATA_RECORD; case ENODEV: return net6::error::NO_DEVICE; case ENOMEM: return net6::error::NO_MEMORY; case ENOPROTOOPT: return net6::error::BAD_PROTOCOL_OPTION; case ENOTCONN: return net6::error::SOCKET_NOT_CONNECTED; case ENOTSOCK: return net6::error::NOT_SOCKET; case EOPNOTSUPP: return net6::error::OPERATION_NOT_SUPPORTED; case EPERM: return net6::error::ACCESS_DENIED; case EPIPE: return net6::error::BROKEN_PIPE; case EPROTONOSUPPORT: return net6::error::PROTOCOL_NOT_SUPPORTED; case EPROTOTYPE: return net6::error::WRONG_PROTOCOL_TYPE; case ETIMEDOUT: return net6::error::CONNECTION_TIMEOUT; // case EWOULDBLOCK: // Same as EAGAIN // return net6::error::WOULD_BLOCK; #endif default: return net6::error::UNKNOWN; } } /** Translates an error code reported by getaddrinfo to a net6 error * code. */ net6::error::code gai_to_net6(int code) { using net6::error; switch(code) { case EAI_FAMILY: return net6::error::ADDRESS_FAMILY_NOT_SUPPORTED; case EAI_SOCKTYPE: return net6::error::SOCKET_NOT_SUPPORTED; case EAI_BADFLAGS: return net6::error::INVALID_ARGUMENT; case EAI_NONAME: return net6::error::HOSTNAME_NOT_FOUND; case EAI_SERVICE: return net6::error::TYPE_NOT_FOUND; // These #ifdef'd values seem not to exist on all systems. #ifdef EAI_ADDRFAMILY case EAI_ADDRFAMILY: // TODO: Do we want HOST_NOT_FOUND here? return net6::error::ADDRESS_UNAVAILABLE; #endif #if EAI_NODATA != EAI_NONAME #ifdef EAI_NODATA case EAI_NODATA: return net6::error::NO_DATA_RECORD; #endif #endif case EAI_MEMORY: return net6::error::NO_MEMORY; case EAI_AGAIN: return net6::error::TEMPORARY_FAILURE; #ifdef EAI_SYSTEM case EAI_SYSTEM: return system_to_net6(errno); #endif default: return net6::error::UNKNOWN; } } /** Translates an error code reported by gethostbyname into a net6 * error code. */ net6::error::code ghbn_to_net6(int code) { #ifdef WIN32 return system_to_net6(code); #else switch(code) { case HOST_NOT_FOUND: return net6::error::HOSTNAME_NOT_FOUND; case NO_ADDRESS: //case NO_DATA: // same value as NO_ADDRESS return net6::error::NO_DATA_RECORD; case TRY_AGAIN: return net6::error::TEMPORARY_FAILURE; default: return net6::error::UNKNOWN; } #endif } net6::error::code tls_to_net6(int code) { // TODO: Add more, or, better, remove error code and replace // by gnutls_strerror(). switch(code) { case GNUTLS_E_AGAIN: return net6::error::WOULD_BLOCK; case GNUTLS_E_DECRYPTION_FAILED: return net6::error::DECRYPTION_FAILED; case GNUTLS_E_DH_PRIME_UNACCEPTABLE: return net6::error::PRIME_UNACCEPTABLE; case GNUTLS_E_ENCRYPTION_FAILED: return net6::error::ENCRYPTION_FAILED; case GNUTLS_E_GOT_APPLICATION_DATA: return net6::error::GOT_APPLICATION_DATA; case GNUTLS_E_INSUFFICIENT_CREDENTIALS: return net6::error::INSUFFICIENT_CREDENTIALS; case GNUTLS_E_INTERRUPTED: return net6::error::INTERRUPTED; case GNUTLS_E_INVALID_REQUEST: return net6::error::INVALID_REQUEST; case GNUTLS_E_KEY_USAGE_VIOLATION: return net6::error::KEY_USAGE_VIOLATION; case GNUTLS_E_MAC_VERIFY_FAILED: return net6::error::MAC_VERIFY_FAILED; case GNUTLS_E_NO_CERTIFICATE_FOUND: return net6::error::NO_CERTIFICATE; case GNUTLS_E_NO_TEMPORARY_DH_PARAMS: return net6::error::NO_TEMPORARY_DH_PARAMS; case GNUTLS_E_NO_TEMPORARY_RSA_PARAMS: return net6::error::NO_TEMPORARY_RSA_PARAMS; case GNUTLS_E_PK_DECRYPTION_FAILED: return net6::error::DECRYPTION_FAILED; case GNUTLS_E_PK_ENCRYPTION_FAILED: return net6::error::ENCRYPTION_FAILED; case GNUTLS_E_PULL_ERROR: return net6::error::PULL_ERROR; case GNUTLS_E_PUSH_ERROR: return net6::error::PUSH_ERROR; #ifdef GNUTLS_E_RANDOM_FAILED case GNUTLS_E_RANDOM_FAILED: return net6::error::RANDOM_FAILED; #endif case GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER: return net6::error::INVALID_ARGUMENT; case GNUTLS_E_REHANDSHAKE: return net6::error::REHANDSHAKE; case GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET: return net6::error::UNEXPECTED_HANDSHAKE; case GNUTLS_E_UNEXPECTED_PACKET: return net6::error::UNEXPECTED_PACKET; case GNUTLS_E_UNEXPECTED_PACKET_LENGTH: return net6::error::UNEXPECTED_PACKET_LENGTH; default: return net6::error::UNKNOWN; } } /** Translates a system dependant error value from a given domain * into a net6 error code */ net6::error::code domain_to_net6(net6::error::domain error_domain, int error_code) { switch(error_domain) { case net6::error::SYSTEM: return system_to_net6(error_code); case net6::error::GETADDRINFO: return gai_to_net6(error_code); case net6::error::GETHOSTBYNAME: return ghbn_to_net6(error_code); case net6::error::GNUTLS: return tls_to_net6(error_code); default: throw std::logic_error( "domain_to_net6:\n" "Unknown error domain" ); } } /** Translates an error code into a human-readable error message */ const char* net6_strerror(net6::error::code error_code) { using net6::error; switch(error_code) { case net6::error::INTERRUPTED: return _("Interrupted function call"); case net6::error::ACCESS_DENIED: return _("Access denied"); case net6::error::BAD_ADDRESS: return _("Bad address"); case net6::error::INVALID_ARGUMENT: return _("Invalid argument"); case net6::error::TOO_MANY_FILES: return _("Too many open files"); case net6::error::WOULD_BLOCK: return _("Resource temporarily unavailable"); case net6::error::OPERATION_IN_PROGRESS: return _("Operation already in progress"); case net6::error::NOT_SOCKET: return _("Socket operation on non-socket"); case net6::error::DESTINATION_ADDRESS_REQUIRED: return _("Destination address required"); case net6::error::MESSAGE_TOO_LONG: return _("Message too long"); case net6::error::WRONG_PROTOCOL_TYPE: return _("Protocol wrong type for socket"); case net6::error::BAD_PROTOCOL_OPTION: return _("Bad protocol option"); case net6::error::PROTOCOL_NOT_SUPPORTED: return _("Protocol not supported"); case net6::error::SOCKET_NOT_SUPPORTED: return _("Socket type not supported"); case net6::error::OPERATION_NOT_SUPPORTED: return _("Operation not supported"); case net6::error::PROTOCOL_FAMILY_NOT_SUPPORTED: return _("Protocol family not supported"); case net6::error::ADDRESS_FAMILY_NOT_SUPPORTED: return _("Address family not supported"); case net6::error::ADDRESS_IN_USE: return _("Address is already in use"); case net6::error::ADDRESS_UNAVAILABLE: return _("Cannot assign requested address"); case net6::error::NETWORK_DOWN: return _("Network is down"); case net6::error::NETWORK_UNREACHABLE: return _("Network is unreachable"); case net6::error::NETWORK_RESET: return _("Network dropped connection on reset"); case net6::error::CONNECTION_ABORTED: return _("Software caused connection abort"); case net6::error::CONNECTION_RESET: return _("Connection reset by peer"); case net6::error::NO_BUFFER_SPACE: return _("No buffer space available"); case net6::error::SOCKET_IS_CONNECTED: return _("Socket is already connected"); case net6::error::SOCKET_NOT_CONNECTED: return _("Socket is not connected"); case net6::error::SOCKET_SHUTDOWN: return _("Cannot send after socket shutdown"); case net6::error::CONNECTION_TIMEOUT: return _("Connection timed out"); case net6::error::CONNECTION_REFUSED: return _("Connection refused"); case net6::error::HOST_DOWN: return _("Host is down"); case net6::error::HOST_UNREACHABLE: return _("No route to host"); case net6::error::TOO_MANY_PROCESSES: return _("Too many processes"); case net6::error::SYSTEM_NOT_READY: return _("Network subsystem is unavailable"); case net6::error::VERSION_NOT_SUPPORTED: return _("Winsock.dll version out of range"); case net6::error::NOT_INITIALISED: return _("Successful WSAStartup not yet performed"); case net6::error::DISCONNECTED: return _("Graceful shutdown in progress"); case net6::error::TYPE_NOT_FOUND: return _("Class type not found"); case net6::error::HOSTNAME_NOT_FOUND: return _("Host not found"); case net6::error::TEMPORARY_FAILURE: return _("Nonauthoritative host not found"); case net6::error::NO_DATA_RECORD: return _("No data record of requested type"); case net6::error::INVALID_HANDLE: return _("Specified event object handle is invalid"); case net6::error::INVALID_PARAMETER: return _("One or more parameters are invalid"); case net6::error::NO_MEMORY: return _("No more memory is available"); case net6::error::BROKEN_PIPE: return _("Broken pipe"); case net6::error::NO_DEVICE: return _("No such device"); case net6::error::DECRYPTION_FAILED: return _("Decryption has failed"); case net6::error::PRIME_UNACCEPTABLE: return _("The Diffie Hellman prime sent by the server " "is not acceptable (not long enough)"); case net6::error::ENCRYPTION_FAILED: return _("Encryption has failed"); case net6::error::GOT_APPLICATION_DATA: return _("TLS Application data were received, while " "expecting handshake data"); case net6::error::INSUFFICIENT_CREDENTIALS: return _("Insufficient credentials for that request"); case net6::error::INVALID_REQUEST: return _("The request is invalid"); case net6::error::KEY_USAGE_VIOLATION: return _("Key usage violation in certificate has " "been detected"); case net6::error::MAC_VERIFY_FAILED: return _("The Message Authentication Code " "verification failed"); case net6::error::NO_CERTIFICATE: return _("The peer did not send any certificate"); case net6::error::NO_TEMPORARY_DH_PARAMS: return _("No temporary DH parameters were found"); case net6::error::NO_TEMPORARY_RSA_PARAMS: return _("No temporary RSA parameters were found"); case net6::error::PULL_ERROR: return _("Error in the pull function"); case net6::error::PUSH_ERROR: return _("Error in the push function"); case net6::error::RANDOM_FAILED: return _("Failed to acquire random data"); case net6::error::REHANDSHAKE: return _("Rehandshake was requested by the peer"); case net6::error::UNEXPECTED_HANDSHAKE: return _("An unexpected TLS handshake packet " "was received"); case net6::error::UNEXPECTED_PACKET: return _("An unexpected TLS packet was received"); case net6::error::UNEXPECTED_PACKET_LENGTH: return _("A TLS packet with unexpected length " "was received."); case net6::error::UNKNOWN: return _("A nonrecoverable error has occured"); default: throw std::logic_error( "net6_strerror:\n" "Unknown error code" ); } } int last_error(net6::error::domain error_domain) { switch(error_domain) { case net6::error::SYSTEM: #ifdef WIN32 return WSAGetLastError(); #else return errno; #endif default: return -1; } } } net6::error::error(domain error_domain, int error_code) : std::runtime_error(net6_strerror(domain_to_net6(error_domain, error_code)) ), errcode(domain_to_net6(error_domain, error_code) ) { } net6::error::error(domain error_domain): std::runtime_error( net6_strerror( errcode = domain_to_net6( error_domain, last_error(error_domain) ) ) ) { } net6::error::error(code error_code) : std::runtime_error(net6_strerror(error_code) ), errcode(error_code) { } net6::error::code net6::error::get_code() const { return errcode; }