/* 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 <winsock2.h>
#include <ws2tcpip.h>
#else
#include <errno.h>
#include <netdb.h>
#endif
#include <gnutls/gnutls.h>
#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;
}
syntax highlighted by Code2HTML, v. 0.9.1