diff --git a/src/exception.cpp b/src/exception.cpp index 5090e4fe..a8479b82 100644 --- a/src/exception.cpp +++ b/src/exception.cpp @@ -328,13 +328,27 @@ exception* net_exception::clone() const { return new net_exception(*this); } const char* net_exception::name() const throw() { return "net_exception"; } +// +// socket_exception +// + +socket_exception::~socket_exception() throw() {} +socket_exception::socket_exception(const string& what, const exception& other) + : net_exception(what.empty() + ? "Socket error." + : "Socket error: '" + what + "'.", other) {} + +exception* socket_exception::clone() const { return new socket_exception(*this); } +const char* socket_exception::name() const throw() { return "socket_exception"; } + + // // connection_error // connection_error::~connection_error() throw() {} connection_error::connection_error(const string& what, const exception& other) - : net_exception(what.empty() + : socket_exception(what.empty() ? "Connection error." : "Connection error: '" + what + "'.", other) {} diff --git a/src/platforms/posix/posixSocket.cpp b/src/platforms/posix/posixSocket.cpp index 8a042950..32b657fd 100644 --- a/src/platforms/posix/posixSocket.cpp +++ b/src/platforms/posix/posixSocket.cpp @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include "vmime/exception.hpp" @@ -90,16 +92,34 @@ void posixSocket::connect(const vmime::string& address, const vmime::port_t port m_desc = ::socket(AF_INET, SOCK_STREAM, 0); if (m_desc == -1) - throw vmime::exceptions::connection_error("Error while creating socket."); + { + try + { + throwSocketError(errno); + } + catch (exceptions::socket_exception& e) + { + throw vmime::exceptions::connection_error + ("Error while creating socket.", e); + } + } // Start connection if (::connect(m_desc, reinterpret_cast (&addr), sizeof(addr)) == -1) { - ::close(m_desc); - m_desc = -1; + try + { + throwSocketError(errno); + } + catch (exceptions::socket_exception& e) + { + ::close(m_desc); + m_desc = -1; - // Error - throw vmime::exceptions::connection_error("Error while connecting socket."); + // Error + throw vmime::exceptions::connection_error + ("Error while connecting socket.", e); + } } } @@ -156,16 +176,53 @@ const int posixSocket::receiveRaw(char* buffer, const int count) void posixSocket::send(const vmime::string& buffer) { - ::send(m_desc, buffer.data(), buffer.length(), 0); + if (::send(m_desc, buffer.data(), buffer.length(), 0) == -1) + throwSocketError(errno); } void posixSocket::sendRaw(const char* buffer, const int count) { - ::send(m_desc, buffer, count, 0); + if (::send(m_desc, buffer, count, 0) == -1) + throwSocketError(errno); } +void posixSocket::throwSocketError(const int err) +{ + string msg; + + switch (err) + { + case EACCES: msg = "EACCES: permission denied"; break; + case EAFNOSUPPORT: msg = "EAFNOSUPPORT: address family not supported"; break; + case EMFILE: msg = "EMFILE: process file table overflow"; break; + case ENFILE: msg = "ENFILE: system limit reached"; break; + case EPROTONOSUPPORT: msg = "EPROTONOSUPPORT: protocol not supported"; break; + case EAGAIN: msg = "EGAIN: blocking operation"; break; + case EBADF: msg = "EBADF: invalid descriptor"; break; + case ECONNRESET: msg = "ECONNRESET: connection reset by peer"; break; + case EFAULT: msg = "EFAULT: bad user space address"; break; + case EINTR: msg = "EINTR: signal occured before transmission"; break; + case EINVAL: msg = "EINVAL: invalid argument"; break; + case EMSGSIZE: msg = "EMSGSIZE: message cannot be sent atomically"; break; + case ENOBUFS: msg = "ENOBUFS: output queue is full"; break; + case ENOMEM: msg = "ENOMEM: out of memory"; break; + case EPIPE: + case ENOTCONN: msg = "ENOTCONN: not connected"; break; + case ECONNREFUSED: msg = "ECONNREFUSED: connection refused"; break; + default: + + std::ostringstream oss; + oss << ::strerror(err); + + msg = oss.str(); + break; + } + + throw exceptions::socket_exception(msg); +} + // diff --git a/vmime/exception.hpp b/vmime/exception.hpp index c09e8919..55d4c480 100644 --- a/vmime/exception.hpp +++ b/vmime/exception.hpp @@ -359,11 +359,27 @@ public: typedef net_exception messaging_exception; +/** Socket error. + */ + +class socket_exception : public net_exception +{ +public: + + socket_exception(const string& what = "", const exception& other = NO_EXCEPTION); + ~socket_exception() throw(); + + exception* clone() const; + const char* name() const throw(); + +}; + + /** Error while connecting to the server: this may be a DNS resolution error * or a connection error (for example, time-out while connecting). */ -class connection_error : public net_exception +class connection_error : public socket_exception { public: diff --git a/vmime/platforms/posix/posixSocket.hpp b/vmime/platforms/posix/posixSocket.hpp index 93315cf9..fea46abd 100644 --- a/vmime/platforms/posix/posixSocket.hpp +++ b/vmime/platforms/posix/posixSocket.hpp @@ -49,6 +49,10 @@ public: void send(const vmime::string& buffer); void sendRaw(const char* buffer, const int count); +protected: + + static void throwSocketError(const int err); + private: char m_buffer[65536];