From: Gunnar Beutner Date: Mon, 11 Mar 2013 12:45:08 +0000 (+0100) Subject: Add more information to exceptions. X-Git-Tag: v0.0.2~284 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d8edd98e415e8ee54f98a101aee093fa433c4279;p=icinga2 Add more information to exceptions. --- diff --git a/components/compat/compatcomponent.cpp b/components/compat/compatcomponent.cpp index 1978f72b8..c5e3f24f6 100644 --- a/components/compat/compatcomponent.cpp +++ b/components/compat/compatcomponent.cpp @@ -127,13 +127,21 @@ void CompatComponent::CommandPipeThread(const String& commandPath) if (S_ISFIFO(statbuf.st_mode) && access(commandPath.CStr(), R_OK) >= 0) { fifo_ok = true; } else { - if (unlink(commandPath.CStr()) < 0) - BOOST_THROW_EXCEPTION(PosixException("unlink() failed", errno)); + if (unlink(commandPath.CStr()) < 0) { + BOOST_THROW_EXCEPTION(posix_error() + << errinfo_api_function("unlink") + << errinfo_errno(errno) + << errinfo_file_name(commandPath)); + } } } - if (!fifo_ok && mkfifo(commandPath.CStr(), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) < 0) - BOOST_THROW_EXCEPTION(PosixException("mkfifo() failed", errno)); + if (!fifo_ok && mkfifo(commandPath.CStr(), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) < 0) { + BOOST_THROW_EXCEPTION(posix_error() + << errinfo_api_function("mkfifo") + << errinfo_errno(errno) + << errinfo_file_name(commandPath)); + } for (;;) { int fd; @@ -142,14 +150,20 @@ void CompatComponent::CommandPipeThread(const String& commandPath) fd = open(commandPath.CStr(), O_RDONLY); } while (fd < 0 && errno == EINTR); - if (fd < 0) - BOOST_THROW_EXCEPTION(PosixException("open() failed", errno)); + if (fd < 0) { + BOOST_THROW_EXCEPTION(posix_error() + << errinfo_api_function("open") + << errinfo_errno(errno) + << errinfo_file_name(commandPath)); + } FILE *fp = fdopen(fd, "r"); if (fp == NULL) { - close(fd); - BOOST_THROW_EXCEPTION(PosixException("fdopen() failed", errno)); + (void) close(fd); + BOOST_THROW_EXCEPTION(posix_error() + << errinfo_api_function("fdopen") + << errinfo_errno(errno)); } char line[2048]; @@ -640,10 +654,18 @@ void CompatComponent::StatusTimerHandler(void) #endif /* _WIN32 */ statusfp.close(); - if (rename(statuspathtmp.CStr(), statuspath.CStr()) < 0) - BOOST_THROW_EXCEPTION(PosixException("rename() failed", errno)); + if (rename(statuspathtmp.CStr(), statuspath.CStr()) < 0) { + BOOST_THROW_EXCEPTION(posix_error() + << errinfo_api_function("rename") + << errinfo_errno(errno) + << errinfo_file_name(statuspathtmp)); + } objectfp.close(); - if (rename(objectspathtmp.CStr(), objectspath.CStr()) < 0) - BOOST_THROW_EXCEPTION(PosixException("rename() failed", errno)); + if (rename(objectspathtmp.CStr(), objectspath.CStr()) < 0) { + BOOST_THROW_EXCEPTION(posix_error() + << errinfo_api_function("rename") + << errinfo_errno(errno) + << errinfo_file_name(objectspathtmp)); + } } diff --git a/components/livestatus/component.cpp b/components/livestatus/component.cpp index 892c32a40..83c164833 100644 --- a/components/livestatus/component.cpp +++ b/components/livestatus/component.cpp @@ -29,13 +29,13 @@ REGISTER_COMPONENT("livestatus", LivestatusComponent); */ void LivestatusComponent::Start(void) { -#ifndef _WIN32 - UnixSocket::Ptr socket = boost::make_shared(); - socket->Bind(GetSocketPath()); -#else /* _WIN32 */ +//#ifndef _WIN32 +// UnixSocket::Ptr socket = boost::make_shared(); +// socket->Bind(GetSocketPath()); +//#else /* _WIN32 */ TcpSocket::Ptr socket = boost::make_shared(); - socket->Bind("6557", AF_INET); -#endif /* _WIN32 */ + socket->Bind("6558", AF_INET); +//#endif /* _WIN32 */ socket->OnNewClient.connect(boost::bind(&LivestatusComponent::NewClientHandler, this, _2)); socket->Listen(); diff --git a/lib/base/application.cpp b/lib/base/application.cpp index 142702554..d8e040ce8 100644 --- a/lib/base/application.cpp +++ b/lib/base/application.cpp @@ -188,8 +188,12 @@ String Application::GetExePath(const String& argv0) #ifndef _WIN32 char buffer[MAXPATHLEN]; - if (getcwd(buffer, sizeof(buffer)) == NULL) - BOOST_THROW_EXCEPTION(PosixException("getcwd failed", errno)); + if (getcwd(buffer, sizeof(buffer)) == NULL) { + BOOST_THROW_EXCEPTION(posix_error() + << errinfo_api_function("getcwd") + << errinfo_errno(errno)); + } + String workingDirectory = buffer; if (argv0[0] != '/') @@ -229,8 +233,12 @@ String Application::GetExePath(const String& argv0) } } - if (realpath(executablePath.CStr(), buffer) == NULL) - BOOST_THROW_EXCEPTION(PosixException("realpath failed", errno)); + if (realpath(executablePath.CStr(), buffer) == NULL) { + BOOST_THROW_EXCEPTION(posix_error() + << errinfo_api_function("realpath") + << errinfo_errno(errno) + << errinfo_file_name(executablePath)); + } return buffer; #else /* _WIN32 */ diff --git a/lib/base/dynamicobject.cpp b/lib/base/dynamicobject.cpp index d45edf775..bbe94a62f 100644 --- a/lib/base/dynamicobject.cpp +++ b/lib/base/dynamicobject.cpp @@ -495,8 +495,12 @@ void DynamicObject::DumpObjects(const String& filename) _unlink(filename.CStr()); #endif /* _WIN32 */ - if (rename(tempFilename.CStr(), filename.CStr()) < 0) - BOOST_THROW_EXCEPTION(PosixException("rename() failed", errno)); + if (rename(tempFilename.CStr(), filename.CStr()) < 0) { + BOOST_THROW_EXCEPTION(posix_error() + << errinfo_api_function("rename") + << errinfo_errno(errno) + << errinfo_file_name(tempFilename)); + } } /* diff --git a/lib/base/exception.cpp b/lib/base/exception.cpp index f533d1636..11233b63e 100644 --- a/lib/base/exception.cpp +++ b/lib/base/exception.cpp @@ -23,111 +23,6 @@ using namespace icinga; boost::thread_specific_ptr Exception::m_LastStackTrace; -/** - * Retrieves the error code for the exception. - * - * @returns The error code. - */ -int Exception::GetCode(void) const -{ - return m_Code; -} - -/** - * Sets the error code for the exception. - * - * @param code The error code. - */ -void Exception::SetCode(int code) -{ - m_Code = code; -} - -/** - * Retrieves the description for the exception. - * - * @returns The description. - */ -String Exception::GetMessage(void) const -{ - return m_Message; -} - -/** - * Retrieves the description for the exception. - * - * @returns The description. - */ -const char *Exception::what(void) const throw() -{ - return m_Message.CStr(); -} - -/** - * Sets the description for the exception. - * - * @param message The description. - */ -void Exception::SetMessage(String message) -{ - m_Message = message; -} - -#ifdef _WIN32 -/** - * Formats an Win32 error code. - * - * @param code The error code. - * @returns A String describing the error. - */ -String Win32Exception::FormatErrorCode(int code) -{ - char *message; - String result = "Unknown error."; - - DWORD rc = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM, NULL, code, 0, (char *)&message, - 0, NULL); - - if (rc != 0) { - result = String(message); - LocalFree(message); - - /* remove trailing new-line characters */ - boost::algorithm::trim_right(result); - } - - return result; -} -#endif /* _WIN32 */ - -/** - * Formats a Posix error code. - * - * @param code The error code. - * @returns A String describing the error. - */ -String PosixException::FormatErrorCode(int code) -{ - return strerror(code); -} - -/** - * Formats an OpenSSL error code. - * - * @param code The error code. - * @returns A String describing the error. - */ -String OpenSSLException::FormatErrorCode(int code) -{ - const char *message = ERR_error_string(code, NULL); - - if (message == NULL) - message = "Unknown error."; - - return message; -} - #ifndef _WIN32 extern "C" void __cxa_throw(void *obj, void *pvtinfo, void (*dest)(void *)) diff --git a/lib/base/exception.h b/lib/base/exception.h index 8af7e83ca..12f75c6a5 100644 --- a/lib/base/exception.h +++ b/lib/base/exception.h @@ -28,150 +28,65 @@ namespace icinga * * @ingroup base */ -class I2_BASE_API Exception : public virtual exception +class I2_BASE_API Exception //: public virtual exception { public: - Exception(void) - : m_Message(), m_Code(0) - { } - - Exception(String message) - : m_Message(message), m_Code(0) - { } - - Exception(String message, int code) - : m_Message(message), m_Code(code) - { } - - /** - * Destructor for the Exception class. Must be virtual for RTTI to work. - */ - virtual ~Exception(void) throw() - { } - - int GetCode(void) const; - String GetMessage(void) const; - - virtual const char *what(void) const throw(); - static StackTrace *GetLastStackTrace(void); static void SetLastStackTrace(const StackTrace& trace); -protected: - void SetCode(int code); - void SetMessage(String message); - private: - String m_Message; - int m_Code; - static boost::thread_specific_ptr m_LastStackTrace; }; typedef boost::error_info StackTraceErrorInfo; -#define DEFINE_EXCEPTION_CLASS(klass) \ - class klass : public Exception \ - { \ - public: \ - inline klass(void) : Exception() \ - { } \ - \ - inline klass(String message) \ - : Exception(message) \ - { } \ - } - -/** - * An exception that is thrown when a certain feature - * is not implemented. - * - * @ingroup base - */ -DEFINE_EXCEPTION_CLASS(NotImplementedException); +class I2_BASE_API posix_error : virtual public std::exception, virtual public boost::exception { }; #ifdef _WIN32 -/** - * A Win32 error encapsulated in an exception. - * - * @ingroup base - */ -class I2_BASE_API Win32Exception : public Exception +typedef boost::error_info errinfo_win32_error; + +inline std::string to_string(const errinfo_win32_error& e) { -public: - /** - * Constructor for the Win32Exception class. - * - * @param message An error message. - * @param errorCode A Win32 error code. - */ - inline Win32Exception(const String& message, int errorCode) - : Exception(message + ": " + FormatErrorCode(errorCode), errorCode) - { } - - /** - * Returns a String that describes the Win32 error. - * - * @param code The Win32 error code. - * @returns A description of the error. - */ - static String FormatErrorCode(int code); -}; + stringstream tmp; + int code = e.value(); + + char *message; + String result = "Unknown error."; + + DWORD rc = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM, NULL, code, 0, (char *)&message, + 0, NULL); + + if (rc != 0) { + result = String(message); + LocalFree(message); + + /* remove trailing new-line characters */ + boost::algorithm::trim_right(result); + } + + tmp << code << ", \"" << result << "\""; + return tmp.str(); +} #endif /* _WIN32 */ -/** - * A Posix error encapsulated in an exception. - * - * @ingroup base - */ -class I2_BASE_API PosixException : public Exception -{ -public: - /** - * Constructor for the PosixException class. - * - * @param message An error message. - * @param errorCode A Posix (errno) error code. - */ - inline PosixException(const String& message, int errorCode) - : Exception(message + ": " + FormatErrorCode(errorCode), errorCode) - { } - - /** - * Returns a String that describes the Posix error. - * - * @param code The Posix error code. - * @returns A description of the error. - */ - static String FormatErrorCode(int code); -}; +class openssl_error : virtual public std::exception, virtual public boost::exception { }; -/** - * An OpenSSL error encapsulated in an exception. - * - * @ingroup base - */ -class I2_BASE_API OpenSSLException : public Exception +typedef boost::error_info errinfo_openssl_error; + +inline std::string to_string(const errinfo_openssl_error& e) { -public: - /** - * Constructor for the OpenSSLException class. - * - * @param message An error message. - * @param errorCode An OpenSSL error code. - */ - inline OpenSSLException(const String& message, int errorCode) - : Exception(message + ": " + FormatErrorCode(errorCode), errorCode) - { } - - /** - * Returns a String that describes the OpenSSL error. - * - * @param code The OpenSSL error code. - * @returns A description of the error. - */ - static String FormatErrorCode(int code); -}; + stringstream tmp; + int code = e.value(); + + const char *message = ERR_error_string(code, NULL); + + if (message == NULL) + message = "Unknown error."; + + tmp << code << ", \"" << message << "\""; + return tmp.str(); +} } diff --git a/lib/base/i2-base.h b/lib/base/i2-base.h index 643c26c02..041319c15 100644 --- a/lib/base/i2-base.h +++ b/lib/base/i2-base.h @@ -142,6 +142,10 @@ using std::type_info; #include #include #include +#include +#include +#include +#include #include #include #include @@ -163,6 +167,9 @@ using boost::tie; using boost::rethrow_exception; using boost::current_exception; using boost::diagnostic_information; +using boost::errinfo_api_function; +using boost::errinfo_errno; +using boost::errinfo_file_name; using boost::multi_index_container; using boost::multi_index::indexed_by; using boost::multi_index::identity; diff --git a/lib/base/process-unix.cpp b/lib/base/process-unix.cpp index 30944717f..fb4390111 100644 --- a/lib/base/process-unix.cpp +++ b/lib/base/process-unix.cpp @@ -34,11 +34,17 @@ void Process::Initialize(void) int fds[2]; #if HAVE_PIPE2 - if (pipe2(fds, O_CLOEXEC) < 0) - BOOST_THROW_EXCEPTION(PosixException("pipe2() failed.", errno)); + if (pipe2(fds, O_CLOEXEC) < 0) { + BOOST_THROW_EXCEPTION(posix_error() + << errinfo_api_function("pipe2") + << errinfo_errno(errno)); + } #else /* HAVE_PIPE2 */ - if (pipe(fds) < 0) - BOOST_THROW_EXCEPTION(PosixException("pipe() failed.", errno)); + if (pipe(fds) < 0) { + BOOST_THROW_EXCEPTION(posix_error() + << errinfo_api_function("pipe") + << errinfo_errno(errno)); + } /* Don't bother setting fds[0] to clo-exec as we'll only * use it in the following dup() call. */ @@ -56,8 +62,11 @@ void Process::Initialize(void) for (unsigned int i = 0; i < threads; i++) { int childTaskFd = dup(fds[0]); - if (childTaskFd < 0) - BOOST_THROW_EXCEPTION(PosixException("dup() failed.", errno)); + if (childTaskFd < 0) { + BOOST_THROW_EXCEPTION(posix_error() + << errinfo_api_function("dup") + << errinfo_errno(errno)); + } Utility::SetNonBlocking(childTaskFd); Utility::SetCloExec(childTaskFd); @@ -84,8 +93,11 @@ void Process::WorkerThreadProc(int taskFd) pfds = (pollfd *)realloc(pfds, (1 + tasks.size()) * sizeof(pollfd)); - if (pfds == NULL) - BOOST_THROW_EXCEPTION(PosixException("realloc() failed.", errno)); + if (pfds == NULL) { + BOOST_THROW_EXCEPTION(posix_error() + << errinfo_api_function("realloc") + << errinfo_errno(errno)); + } int idx = 0; @@ -104,8 +116,11 @@ void Process::WorkerThreadProc(int taskFd) int rc = poll(pfds, idx, -1); - if (rc < 0 && errno != EINTR) - BOOST_THROW_EXCEPTION(PosixException("poll() failed.", errno)); + if (rc < 0 && errno != EINTR) { + BOOST_THROW_EXCEPTION(posix_error() + << errinfo_api_function("poll") + << errinfo_errno(errno)); + } if (rc == 0) continue; @@ -133,7 +148,9 @@ void Process::WorkerThreadProc(int taskFd) if (errno == EAGAIN) break; /* Someone else was faster and took our task. */ - BOOST_THROW_EXCEPTION(PosixException("read() failed.", errno)); + BOOST_THROW_EXCEPTION(posix_error() + << errinfo_api_function("read") + << errinfo_errno(errno)); } while (have > 0) { @@ -197,8 +214,11 @@ void Process::QueueTask(void) * This little gem which is commonly known as the "self-pipe trick" * takes care of waking up the select() call in the worker thread. */ - if (write(m_TaskFd, "T", 1) < 0) - BOOST_THROW_EXCEPTION(PosixException("write() failed.", errno)); + if (write(m_TaskFd, "T", 1) < 0) { + BOOST_THROW_EXCEPTION(posix_error() + << errinfo_api_function("write") + << errinfo_errno(errno)); + } } } @@ -211,11 +231,17 @@ void Process::InitTask(void) int fds[2]; #if HAVE_PIPE2 - if (pipe2(fds, O_NONBLOCK | O_CLOEXEC) < 0) - BOOST_THROW_EXCEPTION(PosixException("pipe2() failed.", errno)); + if (pipe2(fds, O_NONBLOCK | O_CLOEXEC) < 0) { + BOOST_THROW_EXCEPTION(posix_error() + << errinfo_api_function("pipe2") + << errinfo_errno(errno)); + } #else /* HAVE_PIPE2 */ - if (pipe(fds) < 0) - BOOST_THROW_EXCEPTION(PosixException("pipe() failed.", errno)); + if (pipe(fds) < 0) { + BOOST_THROW_EXCEPTION(posix_error() + << errinfo_api_function("pipe") + << errinfo_errno(errno)); + } Utility::SetNonBlocking(fds[0]); Utility::SetCloExec(fds[0]); @@ -269,8 +295,11 @@ void Process::InitTask(void) m_Pid = fork(); #endif /* HAVE_WORKING_VFORK */ - if (m_Pid < 0) - BOOST_THROW_EXCEPTION(PosixException("fork() failed.", errno)); + if (m_Pid < 0) { + BOOST_THROW_EXCEPTION(posix_error() + << errinfo_api_function("fork") + << errinfo_errno(errno)); + } if (m_Pid == 0) { // child process @@ -331,8 +360,11 @@ bool Process::RunTask(void) (void) close(m_FD); - if (waitpid(m_Pid, &status, 0) != m_Pid) - BOOST_THROW_EXCEPTION(PosixException("waitpid() failed.", errno)); + if (waitpid(m_Pid, &status, 0) != m_Pid) { + BOOST_THROW_EXCEPTION(posix_error() + << errinfo_api_function("waitpid") + << errinfo_errno(errno)); + } if (WIFEXITED(status)) { exitcode = WEXITSTATUS(status); diff --git a/lib/base/socket.cpp b/lib/base/socket.cpp index 53bd08ee8..ba8a74828 100644 --- a/lib/base/socket.cpp +++ b/lib/base/socket.cpp @@ -137,20 +137,6 @@ int Socket::GetError(void) const return 0; } -/** - * Retrieves the last socket error. - * - * @returns An error code. - */ -int Socket::GetLastSocketError(void) -{ -#ifdef _WIN32 - return WSAGetLastError(); -#else /* _WIN32 */ - return errno; -#endif /* _WIN32 */ -} - /** * Processes errors that have occured for the socket. */ @@ -158,7 +144,14 @@ void Socket::HandleException(void) { ObjectLock olock(this); - BOOST_THROW_EXCEPTION(SocketException("select() returned fd in except fdset", GetError())); + BOOST_THROW_EXCEPTION(socket_error() + << errinfo_api_function("select") +#ifndef _WIN32 + << errinfo_errno(GetError()) +#else /* _WIN32 */ + << errinfo_win32_error(GetError()) +#endif /* _WIN32 */ + ); } /** @@ -172,9 +165,16 @@ String Socket::GetAddressFromSockaddr(sockaddr *address, socklen_t len) char service[NI_MAXSERV]; if (getnameinfo(address, len, host, sizeof(host), service, - sizeof(service), NI_NUMERICHOST | NI_NUMERICSERV) < 0) - BOOST_THROW_EXCEPTION(SocketException("getnameinfo() failed", - GetLastSocketError())); + sizeof(service), NI_NUMERICHOST | NI_NUMERICSERV) < 0) { + BOOST_THROW_EXCEPTION(socket_error() + << errinfo_api_function("getnameinfo") + #ifndef _WIN32 + << errinfo_errno(errno) + #else /* _WIN32 */ + << errinfo_win32_error(WSAGetLastError()) + #endif /* _WIN32 */ + ); + } stringstream s; s << "[" << host << "]:" << service; @@ -193,8 +193,16 @@ String Socket::GetClientAddress(void) sockaddr_storage sin; socklen_t len = sizeof(sin); - if (getsockname(GetFD(), (sockaddr *)&sin, &len) < 0) - BOOST_THROW_EXCEPTION(SocketException("getsockname() failed", GetError())); + if (getsockname(GetFD(), (sockaddr *)&sin, &len) < 0) { + BOOST_THROW_EXCEPTION(socket_error() + << errinfo_api_function("getsockname") + #ifndef _WIN32 + << errinfo_errno(errno) + #else /* _WIN32 */ + << errinfo_win32_error(WSAGetLastError()) + #endif /* _WIN32 */ + ); + } return GetAddressFromSockaddr((sockaddr *)&sin, len); } @@ -211,30 +219,20 @@ String Socket::GetPeerAddress(void) sockaddr_storage sin; socklen_t len = sizeof(sin); - if (getpeername(GetFD(), (sockaddr *)&sin, &len) < 0) - BOOST_THROW_EXCEPTION(SocketException("getpeername() failed", GetError())); + if (getpeername(GetFD(), (sockaddr *)&sin, &len) < 0) { + BOOST_THROW_EXCEPTION(socket_error() + << errinfo_api_function("getpeername") + #ifndef _WIN32 + << errinfo_errno(errno) + #else /* _WIN32 */ + << errinfo_win32_error(WSAGetLastError()) + #endif /* _WIN32 */ + ); + } return GetAddressFromSockaddr((sockaddr *)&sin, len); } -/** - * Constructor for the SocketException class. - * - * @param message The error message. - * @param errorCode The error code. - */ -SocketException::SocketException(const String& message, int errorCode) -{ -#ifdef _WIN32 - String details = Win32Exception::FormatErrorCode(errorCode); -#else /* _WIN32 */ - String details = PosixException::FormatErrorCode(errorCode); -#endif /* _WIN32 */ - - String msg = message + ": " + details; - SetMessage(msg.CStr()); -} - /** * Read thread procedure for sockets. This function waits until the * socket is readable and processes inbound data. @@ -272,8 +270,16 @@ void Socket::ReadThreadProc(void) return; try { - if (rc < 0) - BOOST_THROW_EXCEPTION(SocketException("select() failed", GetError())); + if (rc < 0) { + BOOST_THROW_EXCEPTION(socket_error() + << errinfo_api_function("select") + #ifndef _WIN32 + << errinfo_errno(errno) + #else /* _WIN32 */ + << errinfo_win32_error(WSAGetLastError()) + #endif /* _WIN32 */ + ); + } if (FD_ISSET(fd, &readfds)) HandleReadable(); @@ -330,8 +336,16 @@ void Socket::WriteThreadProc(void) return; try { - if (rc < 0) - BOOST_THROW_EXCEPTION(SocketException("select() failed", GetError())); + if (rc < 0) { + BOOST_THROW_EXCEPTION(socket_error() + << errinfo_api_function("select") + #ifndef _WIN32 + << errinfo_errno(errno) + #else /* _WIN32 */ + << errinfo_win32_error(WSAGetLastError()) + #endif /* _WIN32 */ + ); + } if (FD_ISSET(fd, &writefds)) HandleWritable(); @@ -451,8 +465,16 @@ void Socket::Write(const void *buffer, size_t size) */ void Socket::Listen(void) { - if (listen(GetFD(), SOMAXCONN) < 0) - BOOST_THROW_EXCEPTION(SocketException("listen() failed", GetError())); + if (listen(GetFD(), SOMAXCONN) < 0) { + BOOST_THROW_EXCEPTION(socket_error() + << errinfo_api_function("listen") + #ifndef _WIN32 + << errinfo_errno(errno) + #else /* _WIN32 */ + << errinfo_win32_error(WSAGetLastError()) + #endif /* _WIN32 */ + ); + } { ObjectLock olock(this); @@ -500,8 +522,16 @@ void Socket::HandleWritableClient(void) rc = send(GetFD(), data, count, 0); - if (rc <= 0) - BOOST_THROW_EXCEPTION(SocketException("send() failed", GetError())); + if (rc <= 0) { + BOOST_THROW_EXCEPTION(socket_error() + << errinfo_api_function("send") + #ifndef _WIN32 + << errinfo_errno(errno) + #else /* _WIN32 */ + << errinfo_win32_error(WSAGetLastError()) + #endif /* _WIN32 */ + ); + } m_SendQueue->Read(NULL, rc); } @@ -528,8 +558,16 @@ void Socket::HandleReadableClient(void) #endif /* _WIN32 */ break; - if (rc < 0) - BOOST_THROW_EXCEPTION(SocketException("recv() failed", GetError())); + if (rc < 0) { + BOOST_THROW_EXCEPTION(socket_error() + << errinfo_api_function("recv") + #ifndef _WIN32 + << errinfo_errno(errno) + #else /* _WIN32 */ + << errinfo_win32_error(WSAGetLastError()) + #endif /* _WIN32 */ + ); + } new_data = true; @@ -563,8 +601,16 @@ void Socket::HandleReadableServer(void) fd = accept(GetFD(), (sockaddr *)&addr, &addrlen); - if (fd < 0) - BOOST_THROW_EXCEPTION(SocketException("accept() failed", GetError())); + if (fd < 0) { + BOOST_THROW_EXCEPTION(socket_error() + << errinfo_api_function("accept") + #ifndef _WIN32 + << errinfo_errno(errno) + #else /* _WIN32 */ + << errinfo_win32_error(WSAGetLastError()) + #endif /* _WIN32 */ + ); + } Socket::Ptr client = boost::make_shared(); client->SetFD(fd); diff --git a/lib/base/socket.h b/lib/base/socket.h index e979ad1f4..d0de45c3c 100644 --- a/lib/base/socket.h +++ b/lib/base/socket.h @@ -61,7 +61,6 @@ protected: void SetConnected(bool connected); int GetError(void) const; - static int GetLastSocketError(void); mutable boost::mutex m_SocketMutex; @@ -107,14 +106,7 @@ private: bool WantsToRead(void) const; }; -/** - * A socket exception. - */ -class SocketException : public Exception -{ -public: - SocketException(const String& message, int errorCode); -}; +class socket_error : virtual public std::exception, virtual public boost::exception { }; } diff --git a/lib/base/tcpsocket.cpp b/lib/base/tcpsocket.cpp index bbd35505b..ab891b2cd 100644 --- a/lib/base/tcpsocket.cpp +++ b/lib/base/tcpsocket.cpp @@ -52,8 +52,16 @@ void TcpSocket::Bind(String node, String service, int family) hints.ai_flags = AI_PASSIVE; if (getaddrinfo(node.IsEmpty() ? NULL : node.CStr(), - service.CStr(), &hints, &result) < 0) - BOOST_THROW_EXCEPTION(SocketException("getaddrinfo() failed", GetLastSocketError())); + service.CStr(), &hints, &result) < 0) { + BOOST_THROW_EXCEPTION(socket_error() + << errinfo_api_function("getaddrinfo") +#ifndef _WIN32 + << errinfo_errno(errno) +#else /* _WIN32 */ + << errinfo_win32_error(WSAGetLastError()) +#endif /* _WIN32 */ + ); + } int fd = INVALID_SOCKET; @@ -114,8 +122,16 @@ void TcpSocket::Connect(const String& node, const String& service) int rc = getaddrinfo(node.CStr(), service.CStr(), &hints, &result); - if (rc < 0) - BOOST_THROW_EXCEPTION(SocketException("getaddrinfo() failed", GetLastSocketError())); + if (rc < 0) { + BOOST_THROW_EXCEPTION(socket_error() + << errinfo_api_function("getaddrinfo") +#ifndef _WIN32 + << errinfo_errno(errno) +#else /* _WIN32 */ + << errinfo_win32_error(WSAGetLastError()) +#endif /* _WIN32 */ + ); + } int fd = INVALID_SOCKET; diff --git a/lib/base/tlsstream.cpp b/lib/base/tlsstream.cpp index 3babd20db..f2de81938 100644 --- a/lib/base/tlsstream.cpp +++ b/lib/base/tlsstream.cpp @@ -48,8 +48,11 @@ void TlsStream::Start(void) m_SSLContext.reset(); - if (!m_SSL) - BOOST_THROW_EXCEPTION(OpenSSLException("SSL_new failed", ERR_get_error())); + if (!m_SSL) { + BOOST_THROW_EXCEPTION(openssl_error() + << errinfo_api_function("SSL_new") + << errinfo_openssl_error(ERR_get_error())); + } if (!GetClientCertificate()) BOOST_THROW_EXCEPTION(logic_error("No X509 client certificate was specified.")); @@ -153,7 +156,9 @@ void TlsStream::HandleIO(void) return; default: I2Stream_check_exception(m_BIO); - BOOST_THROW_EXCEPTION(OpenSSLException("SSL_do_handshake failed", ERR_get_error())); + BOOST_THROW_EXCEPTION(openssl_error() + << errinfo_api_function("SSL_do_handshake") + << errinfo_openssl_error(ERR_get_error())); } } } @@ -178,7 +183,9 @@ void TlsStream::HandleIO(void) return; default: I2Stream_check_exception(m_BIO); - BOOST_THROW_EXCEPTION(OpenSSLException("SSL_read failed", ERR_get_error())); + BOOST_THROW_EXCEPTION(openssl_error() + << errinfo_api_function("SSL_read") + << errinfo_openssl_error(ERR_get_error())); } } } @@ -215,7 +222,9 @@ void TlsStream::HandleIO(void) return; default: I2Stream_check_exception(m_BIO); - BOOST_THROW_EXCEPTION(OpenSSLException("SSL_write failed", ERR_get_error())); + BOOST_THROW_EXCEPTION(openssl_error() + << errinfo_api_function("SSL_write") + << errinfo_openssl_error(ERR_get_error())); } } } diff --git a/lib/base/unixsocket.cpp b/lib/base/unixsocket.cpp index f8ad65d5f..4075eb015 100644 --- a/lib/base/unixsocket.cpp +++ b/lib/base/unixsocket.cpp @@ -26,8 +26,11 @@ UnixSocket::UnixSocket(void) { int fd = socket(AF_UNIX, SOCK_STREAM, PF_UNIX); - if (fd < 0) - BOOST_THROW_EXCEPTION(PosixException("socket() failed", errno)); + if (fd < 0) { + BOOST_THROW_EXCEPTION(posix_error() + << errinfo_api_function("socket") + << errinfo_errno(errno)); + } SetFD(fd); } @@ -42,8 +45,11 @@ void UnixSocket::Bind(const String& path) strncpy(sun.sun_path, path.CStr(), sizeof(sun.sun_path)); sun.sun_path[sizeof(sun.sun_path) - 1] = '\0'; - if (bind(GetFD(), (sockaddr *)&sun, SUN_LEN(&sun)) < 0) - BOOST_THROW_EXCEPTION(PosixException("bind() failed", errno)); + if (bind(GetFD(), (sockaddr *)&sun, SUN_LEN(&sun)) < 0) { + BOOST_THROW_EXCEPTION(posix_error() + << errinfo_api_function("bind") + << errinfo_errno(errno)); + } } void UnixSocket::Connect(const String& path) @@ -54,7 +60,10 @@ void UnixSocket::Connect(const String& path) strncpy(sun.sun_path, path.CStr(), sizeof(sun.sun_path)); sun.sun_path[sizeof(sun.sun_path) - 1] = '\0'; - if (connect(GetFD(), (sockaddr *)&sun, SUN_LEN(&sun)) < 0 && errno != EINPROGRESS) - BOOST_THROW_EXCEPTION(PosixException("connect() failed", errno)); + if (connect(GetFD(), (sockaddr *)&sun, SUN_LEN(&sun)) < 0 && errno != EINPROGRESS) { + BOOST_THROW_EXCEPTION(posix_error() + << errinfo_api_function("connect") + << errinfo_errno(errno)); + } } #endif /* _WIN32 */ diff --git a/lib/base/utility.cpp b/lib/base/utility.cpp index 1165cf629..c9ee8ed71 100644 --- a/lib/base/utility.cpp +++ b/lib/base/utility.cpp @@ -69,16 +69,24 @@ void Utility::Daemonize(void) { int fd; pid = fork(); - if (pid < 0) - BOOST_THROW_EXCEPTION(PosixException("fork() failed", errno)); + + if (pid < 0) { + BOOST_THROW_EXCEPTION(posix_error() + << errinfo_api_function("fork") + << errinfo_errno(errno)); + } if (pid) _exit(0); fd = open("/dev/null", O_RDWR); - if (fd < 0) - BOOST_THROW_EXCEPTION(PosixException("open() failed", errno)); + if (fd < 0) { + BOOST_THROW_EXCEPTION(posix_error() + << errinfo_api_function("open") + << errinfo_errno(errno) + << errinfo_file_name("/dev/null")); + } if (fd != STDIN_FILENO) dup2(fd, STDIN_FILENO); @@ -92,8 +100,11 @@ void Utility::Daemonize(void) { if (fd > STDERR_FILENO) close(fd); - if (setsid() < 0) - BOOST_THROW_EXCEPTION(PosixException("setsid() failed", errno)); + if (setsid() < 0) { + BOOST_THROW_EXCEPTION(posix_error() + << errinfo_api_function("setsid") + << errinfo_errno(errno)); + } #endif } @@ -127,20 +138,36 @@ shared_ptr Utility::MakeSSLContext(const String& pubkey, const String& SSL_CTX_set_mode(sslContext.get(), SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); - if (!SSL_CTX_use_certificate_chain_file(sslContext.get(), pubkey.CStr())) - BOOST_THROW_EXCEPTION(OpenSSLException("Could not load public X509 key file", ERR_get_error())); + if (!SSL_CTX_use_certificate_chain_file(sslContext.get(), pubkey.CStr())) { + BOOST_THROW_EXCEPTION(openssl_error() + << errinfo_api_function("SSL_CTX_use_certificate_chain_file") + << errinfo_openssl_error(ERR_get_error()) + << errinfo_file_name(pubkey)); + } - if (!SSL_CTX_use_PrivateKey_file(sslContext.get(), privkey.CStr(), SSL_FILETYPE_PEM)) - BOOST_THROW_EXCEPTION(OpenSSLException("Could not load private X509 key file", ERR_get_error())); + if (!SSL_CTX_use_PrivateKey_file(sslContext.get(), privkey.CStr(), SSL_FILETYPE_PEM)) { + BOOST_THROW_EXCEPTION(openssl_error() + << errinfo_api_function("SSL_CTX_use_PrivateKey_file") + << errinfo_openssl_error(ERR_get_error()) + << errinfo_file_name(privkey)); + } - if (!SSL_CTX_load_verify_locations(sslContext.get(), cakey.CStr(), NULL)) - BOOST_THROW_EXCEPTION(OpenSSLException("Could not load public CA key file", ERR_get_error())); + if (!SSL_CTX_load_verify_locations(sslContext.get(), cakey.CStr(), NULL)) { + BOOST_THROW_EXCEPTION(openssl_error() + << errinfo_api_function("SSL_CTX_load_verify_locations") + << errinfo_openssl_error(ERR_get_error()) + << errinfo_file_name(cakey)); + } STACK_OF(X509_NAME) *cert_names; cert_names = SSL_load_client_CA_file(cakey.CStr()); - if (cert_names == NULL) - BOOST_THROW_EXCEPTION(OpenSSLException("SSL_load_client_CA_file() failed", ERR_get_error())); + if (cert_names == NULL) { + BOOST_THROW_EXCEPTION(openssl_error() + << errinfo_api_function("SSL_load_client_CA_file") + << errinfo_openssl_error(ERR_get_error()) + << errinfo_file_name(cakey)); + } SSL_CTX_set_client_CA_list(sslContext.get(), cert_names); @@ -160,9 +187,11 @@ String Utility::GetCertificateCN(const shared_ptr& certificate) int rc = X509_NAME_get_text_by_NID(X509_get_subject_name(certificate.get()), NID_commonName, buffer, sizeof(buffer)); - if (rc == -1) - BOOST_THROW_EXCEPTION(OpenSSLException("X509 certificate has no CN" - " attribute", ERR_get_error())); + if (rc == -1) { + BOOST_THROW_EXCEPTION(openssl_error() + << errinfo_api_function("X509_NAME_get_text_by_NID") + << errinfo_openssl_error(ERR_get_error())); + } return buffer; } @@ -178,18 +207,25 @@ shared_ptr Utility::GetX509Certificate(const String& pemfile) X509 *cert; BIO *fpcert = BIO_new(BIO_s_file()); - if (fpcert == NULL) - BOOST_THROW_EXCEPTION(OpenSSLException("BIO_new failed", - ERR_get_error())); + if (fpcert == NULL) { + BOOST_THROW_EXCEPTION(openssl_error() + << errinfo_api_function("BIO_new") + << errinfo_openssl_error(ERR_get_error())); + } - if (BIO_read_filename(fpcert, pemfile.CStr()) < 0) - BOOST_THROW_EXCEPTION(OpenSSLException("BIO_read_filename failed", - ERR_get_error())); + if (BIO_read_filename(fpcert, pemfile.CStr()) < 0) { + BOOST_THROW_EXCEPTION(openssl_error() + << errinfo_api_function("BIO_read_filename") + << errinfo_openssl_error(ERR_get_error()) + << errinfo_file_name(pemfile)); + } cert = PEM_read_bio_X509_AUX(fpcert, NULL, NULL, NULL); - if (cert == NULL) - BOOST_THROW_EXCEPTION(OpenSSLException("PEM_read_bio_X509_AUX failed", - ERR_get_error())); + if (cert == NULL) { + BOOST_THROW_EXCEPTION(openssl_error() + << errinfo_api_function("PEM_read_bio_X509_AUX") + << errinfo_openssl_error(ERR_get_error())); + } BIO_free(fpcert); @@ -319,8 +355,11 @@ double Utility::GetTime(void) #else /* _WIN32 */ struct timeval tv; - if (gettimeofday(&tv, NULL) < 0) - BOOST_THROW_EXCEPTION(PosixException("gettimeofday() failed", errno)); + if (gettimeofday(&tv, NULL) < 0) { + BOOST_THROW_EXCEPTION(posix_error() + << errinfo_api_function("gettimeofday") + << errinfo_errno(errno)); + } return tv.tv_sec + tv.tv_usec / 1000000.0; #endif /* _WIN32 */ @@ -444,7 +483,10 @@ bool Utility::Glob(const String& pathSpec, const function& if (rc == GLOB_NOMATCH) return false; - BOOST_THROW_EXCEPTION(PosixException("glob() failed", errno)); + BOOST_THROW_EXCEPTION(posix_error() + << errinfo_api_function("glob") + << errinfo_errno(errno) + << errinfo_file_name(pathSpec)); } if (gr.gl_pathc == 0) { @@ -467,24 +509,36 @@ bool Utility::Glob(const String& pathSpec, const function& #ifndef _WIN32 void Utility::SetNonBlocking(int fd) { - int flags; - flags = fcntl(fd, F_GETFL, 0); - if (flags < 0) - BOOST_THROW_EXCEPTION(PosixException("fcntl failed", errno)); + int flags = fcntl(fd, F_GETFL, 0); - if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) - BOOST_THROW_EXCEPTION(PosixException("fcntl failed", errno)); + if (flags < 0) { + BOOST_THROW_EXCEPTION(posix_error() + << errinfo_api_function("fcntl") + << errinfo_errno(errno)); + } + + if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) { + BOOST_THROW_EXCEPTION(posix_error() + << errinfo_api_function("fcntl") + << errinfo_errno(errno)); + } } void Utility::SetCloExec(int fd) { - int flags; - flags = fcntl(fd, F_GETFD, 0); - if (flags < 0) - BOOST_THROW_EXCEPTION(PosixException("fcntl failed", errno)); + int flags = fcntl(fd, F_GETFD, 0); - if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) - BOOST_THROW_EXCEPTION(PosixException("fcntl failed", errno)); + if (flags < 0) { + BOOST_THROW_EXCEPTION(posix_error() + << errinfo_api_function("fcntl") + << errinfo_errno(errno)); + } + + if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) { + BOOST_THROW_EXCEPTION(posix_error() + << errinfo_api_function("fcntl") + << errinfo_errno(errno)); + } } #endif /* _WIN32 */ @@ -512,13 +566,19 @@ String Utility::FormatDateTime(const char *format, double ts) #ifdef _MSC_VER tm *temp = localtime(&tempts); - if (temp == NULL) - BOOST_THROW_EXCEPTION(PosixException("localtime() failed", errno)); + if (temp == NULL) { + BOOST_THROW_EXCEPTION(posix_error() + << errinfo_api_function("localtime") + << errinfo_errno(errno)); + } tmthen = *temp; #else /* _MSC_VER */ - if (localtime_r(&tempts, &tmthen) == NULL) - BOOST_THROW_EXCEPTION(PosixException("localtime_r() failed.", errno)); + if (localtime_r(&tempts, &tmthen) == NULL) { + BOOST_THROW_EXCEPTION(posix_error() + << errinfo_api_function("localtime_r") + << errinfo_errno(errno)); + } #endif /* _MSC_VER */ strftime(timestamp, sizeof(timestamp), format, &tmthen); diff --git a/lib/remoting/endpoint.cpp b/lib/remoting/endpoint.cpp index 4d5518867..dc7cb06b5 100644 --- a/lib/remoting/endpoint.cpp +++ b/lib/remoting/endpoint.cpp @@ -228,7 +228,7 @@ void Endpoint::UnregisterTopicHandler(const String&, const function