]> granicus.if.org Git - icinga2/commitdiff
Cleaned up socket error handling.
authorGunnar Beutner <gunnar.beutner@netways.de>
Sat, 26 May 2012 18:00:03 +0000 (20:00 +0200)
committerGunnar Beutner <gunnar.beutner@netways.de>
Sat, 26 May 2012 18:01:00 +0000 (20:01 +0200)
12 files changed:
base/exception.cpp
base/exception.h
base/observable.h
base/socket.cpp
base/socket.h
base/tcpclient.cpp
base/tcpserver.cpp
base/tcpsocket.cpp
base/tlsclient.cpp
base/variant.cpp
base/variant.h
icinga/jsonrpcendpoint.cpp

index bdc0e82ac217bcf64fc20517d52a71fbedab98ff..5a6dcc95b03b1bbc09b8c112c97bbb6d2db1cd9b 100644 (file)
@@ -26,6 +26,7 @@ using namespace icinga;
  */
 Exception::Exception(void)
 {
+       m_Code = 0;
        m_Message = NULL;
 }
 
@@ -36,6 +37,7 @@ Exception::Exception(void)
  */
 Exception::Exception(const char *message)
 {
+       m_Code = 0;
        m_Message = NULL;
        SetMessage(message);
 }
@@ -48,6 +50,26 @@ Exception::~Exception(void) throw()
        Memory::Free(m_Message);
 }
 
+/**
+ * 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.
  *
index b47b3bdce84a9ad5a3766d005dc547ac72d436a4..3ab702e64e6217d6ca020b50df56a76b21a3ab8b 100644 (file)
@@ -35,15 +35,18 @@ public:
        Exception(const char *message);
        virtual ~Exception(void) throw();
 
+       int GetCode(void) const;
        const char *GetMessage(void) const;
 
        virtual const char *what(void) const throw();
 
 protected:
+       void SetCode(int code);
        void SetMessage(const char *message);
 
 private:
        char *m_Message;
+       int m_Code;
 };
 
 #define DEFINE_EXCEPTION_CLASS(klass)                                  \
@@ -101,6 +104,7 @@ public:
        {
                string msg = message + ": " + FormatErrorCode(errorCode);
                SetMessage(msg.c_str());
+               SetCode(errorCode);
        }
 
        /**
@@ -129,6 +133,7 @@ public:
        {
                string msg = message + ": " + FormatErrorCode(errorCode);
                SetMessage(msg.c_str());
+               SetCode(errorCode);
        }
 
        /**
index 2fb0b7bfd3b7e9118338cd0744e025417b2a55e4..26721895a6090b78cf6b2bf14c8a2ecb28f5a9cc 100644 (file)
@@ -86,6 +86,16 @@ public:
                }
        }
 
+       /**
+        * Checks whether there's at least one observer.
+        *
+        * @returns true if there are one or more observers, false otherwise.
+        */
+       bool HasObservers(void) const
+       {
+               return !m_Observers.empty();
+       }
+
 private:
        vector<ObserverType> m_Observers;
 };
index e5b697cc8f9815d9ab5177afa5783ad60fcab671..a876b3dcbda4c947f336e04a64d21ee7bb5388b4 100644 (file)
@@ -132,28 +132,53 @@ void Socket::CloseInternal(bool from_dtor)
 }
 
 /**
- * Handles a socket error by calling the OnError event.
+ * Retrieves the last error that occured for the socket.
+ *
+ * @returns An error code.
  */
-void Socket::HandleSocketError(void)
+int Socket::GetError(void) const
 {
        int opt;
        socklen_t optlen = sizeof(opt);
 
        int rc = getsockopt(GetFD(), SOL_SOCKET, SO_ERROR, (char *)&opt, &optlen);
 
-       if (rc >= 0 && opt != 0) {
-               SocketErrorEventArgs sea;
-               sea.Code = opt;
+       if (rc >= 0)
+               return opt;
+
+       return 0;
+}
+
+/**
+ * Retrieves the last socket error.
+ *
+ * @returns An error code.
+ */
+int Socket::GetLastSocketError(void)
+{
 #ifdef _WIN32
-               sea.Message = Win32Exception::FormatErrorCode(sea.Code);
+       return WSAGetLastError();
 #else /* _WIN32 */
-               sea.Message = PosixException::FormatErrorCode(sea.Code);
+       return errno;
 #endif /* _WIN32 */
+}
+
+/**
+ * Handles a socket error by calling the OnError event or throwing an exception
+ * when there are no observers for the OnError event.
+ *
+ * @param exception An exception.
+ */
+void Socket::HandleSocketError(const Exception& exception)
+{
+       if (OnError.HasObservers()) {
+               SocketErrorEventArgs sea(exception);
                OnError(sea);
-       }
 
-       Close();
-       return;
+               Close();
+       } else {
+               throw exception;
+       }
 }
 
 /**
@@ -164,7 +189,8 @@ void Socket::HandleSocketError(void)
  */
 int Socket::ExceptionEventHandler(const EventArgs&)
 {
-       HandleSocketError();
+       HandleSocketError(SocketException(
+           "select() returned fd in except fdset", GetError()));
 
        return 0;
 }
@@ -218,7 +244,8 @@ string Socket::GetClientAddress(void)
        socklen_t len = sizeof(sin);
 
        if (getsockname(GetFD(), (sockaddr *)&sin, &len) < 0) {
-               HandleSocketError();
+               HandleSocketError(SocketException(
+                   "getsockname() failed", GetError()));
 
                return string();
        }
@@ -237,10 +264,29 @@ string Socket::GetPeerAddress(void)
        socklen_t len = sizeof(sin);
 
        if (getpeername(GetFD(), (sockaddr *)&sin, &len) < 0) {
-               HandleSocketError();
+               HandleSocketError(SocketException(
+                   "getpeername() failed", GetError()));
 
                return string();
        }
 
        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.c_str());
+}
\ No newline at end of file
index e52e16833df65f56278f359dbd9081615e310779..1d56c23d75eda4805c93ebf3d8df92b804e7b412 100644 (file)
@@ -29,8 +29,10 @@ namespace icinga {
  */
 struct I2_BASE_API SocketErrorEventArgs : public EventArgs
 {
-       int Code; /**< The error code. */
-       string Message; /**< A message describing the error. */
+       const Exception& Error;
+
+       SocketErrorEventArgs(const Exception& exception)
+           : Error(exception) { }
 };
 
 /**
@@ -74,7 +76,10 @@ public:
 protected:
        Socket(void);
 
-       void HandleSocketError(void);
+       int GetError(void) const;
+       static int GetLastSocketError(void);
+       void HandleSocketError(const Exception& exception);
+
        virtual void CloseInternal(bool from_dtor);
 
 private:
@@ -85,6 +90,15 @@ private:
        static string GetAddressFromSockaddr(sockaddr *address, socklen_t len);
 };
 
+/**
+ * A socket exception.
+ */
+class SocketException : public Exception
+{
+public:
+       SocketException(const string& message, int errorCode);
+};
+
 }
 
 #endif /* SOCKET_H */
index 83d04f6b873033c25651178f1085f5ed3aba8b9b..0045cff5ade171b2f53c4c4cb772f0d07a2e2334 100644 (file)
@@ -76,8 +76,8 @@ void TcpClient::Connect(const string& node, const string& service)
        int rc = getaddrinfo(node.c_str(), service.c_str(), &hints, &result);
 
        if (rc < 0) {
-               HandleSocketError();
-
+               HandleSocketError(SocketException(
+                   "getaddrinfo() failed", GetLastSocketError()));
                return;
        }
 
@@ -94,19 +94,23 @@ void TcpClient::Connect(const string& node, const string& service)
                rc = connect(fd, info->ai_addr, info->ai_addrlen);
 
 #ifdef _WIN32
-       if (rc < 0 && WSAGetLastError() != WSAEWOULDBLOCK)
+               if (rc < 0 && WSAGetLastError() != WSAEWOULDBLOCK) {
 #else /* _WIN32 */
-       if (rc < 0 && errno != EINPROGRESS)
+               if (rc < 0 && errno != EINPROGRESS) {
 #endif /* _WIN32 */
+                       closesocket(fd);
+                       SetFD(INVALID_SOCKET);
+
                        continue;
+               }
 
                break;
        }
 
-       if (fd == INVALID_SOCKET)
-               HandleSocketError();
-
        freeaddrinfo(result);
+
+       if (fd == INVALID_SOCKET)
+               HandleSocketError(InvalidArgumentException());
 }
 
 /**
@@ -151,7 +155,7 @@ int TcpClient::ReadableEventHandler(const EventArgs&)
                return 0;
 
        if (rc <= 0) {
-               HandleSocketError();
+               HandleSocketError(SocketException("recv() failed", GetError()));
                return 0;
        }
 
@@ -177,7 +181,7 @@ int TcpClient::WritableEventHandler(const EventArgs&)
        rc = send(GetFD(), (const char *)m_SendQueue->GetReadBuffer(), m_SendQueue->GetSize(), 0);
 
        if (rc <= 0) {
-               HandleSocketError();
+               HandleSocketError(SocketException("send() failed", GetError()));
                return 0;
        }
 
index de6c4a642d16c43a088a8169afeeea01d74f8769..a5c3d6dcdcb9339ece80710241bd1e8c735bacce 100644 (file)
@@ -67,7 +67,8 @@ void TcpServer::Listen(void)
        int rc = listen(GetFD(), SOMAXCONN);
 
        if (rc < 0) {
-               HandleSocketError();
+               HandleSocketError(SocketException(
+                   "listen() failed", GetError()));
                return;
        }
 }
@@ -88,7 +89,8 @@ int TcpServer::ReadableEventHandler(const EventArgs&)
        fd = accept(GetFD(), (sockaddr *)&addr, &addrlen);
 
        if (fd < 0) {
-               HandleSocketError();
+               HandleSocketError(SocketException(
+                   "accept() failed", GetError()));
                return 0;
        }
 
index 97733e977a303921a8cd8997fa74630bce75b86c..2cce586d1e8886dbfcf573d5be86f18822e059af 100644 (file)
@@ -33,7 +33,8 @@ void TcpSocket::MakeSocket(int family)
        int fd = socket(family, SOCK_STREAM, 0);
 
        if (fd == INVALID_SOCKET) {
-               HandleSocketError();
+               HandleSocketError(SocketException(
+                   "socket() failed", GetLastSocketError()));
 
                return;
        }
@@ -70,8 +71,10 @@ void TcpSocket::Bind(string node, string service, int family)
        hints.ai_protocol = IPPROTO_TCP;
        hints.ai_flags = AI_PASSIVE;
 
-       if (getaddrinfo(node.empty() ? NULL : node.c_str(), service.c_str(), &hints, &result) < 0) {
-               HandleSocketError();
+       if (getaddrinfo(node.empty() ? NULL : node.c_str(),
+           service.c_str(), &hints, &result) < 0) {
+               HandleSocketError(SocketException(
+                   "getaddrinfo() failed", GetLastSocketError()));
 
                return;
        }
@@ -110,8 +113,8 @@ void TcpSocket::Bind(string node, string service, int family)
                break;
        }
 
-       if (fd == INVALID_SOCKET)
-               HandleSocketError();
-
        freeaddrinfo(result);
+
+       if (fd == INVALID_SOCKET)
+               HandleSocketError(InvalidArgumentException());
 }
index bba6d40d65c62fbce7c00480ce03c69ce342b530..a9e1ebc807bc794450a889170618ff5e77240370 100644 (file)
@@ -132,7 +132,8 @@ int TlsClient::ReadableEventHandler(const EventArgs&)
 
                                return 0;
                        default:
-                               HandleSSLError();
+                               HandleSocketError(OpenSSLException(
+                                   "SSL_read failed", ERR_get_error()));
 
                                return 0;
                }
@@ -174,7 +175,8 @@ int TlsClient::WritableEventHandler(const EventArgs&)
 
                                return 0;
                        default:
-                               HandleSSLError();
+                               HandleSocketError(OpenSSLException(
+                                   "SSL_write failed", ERR_get_error()));
 
                                return 0;
                }
@@ -229,24 +231,6 @@ void TlsClient::CloseInternal(bool from_dtor)
        TcpClient::CloseInternal(from_dtor);
 }
 
-/**
- * Handles an OpenSSL error.
- */
-void TlsClient::HandleSSLError(void)
-{
-       int code = ERR_get_error();
-
-       if (code != 0) {
-               SocketErrorEventArgs sea;
-               sea.Code = code;
-               sea.Message = OpenSSLException::FormatErrorCode(sea.Code);
-               OnError(sea);
-       }
-
-       Close();
-       return;
-}
-
 /**
  * Factory function for the TlsClient class.
  *
index b41f0b0c9615e775699884b19f18769496175f1d..3c906df27499cb3d71e6b2463cbab76d9922eda0 100644 (file)
@@ -69,7 +69,7 @@ long Variant::GetInteger(void) const
  *
  * @returns The variant's value as a bool.
  */
-long Variant::GetBool(void) const
+bool Variant::GetBool(void) const
 {
        Convert(VariantInteger);
 
index b2e24382e4b5a740e1b91413b65e000b637253e9..19db37a76508fe02775e4ec425d898bc4d917bfb 100644 (file)
@@ -69,7 +69,7 @@ public:
        VariantType GetType(void) const;
 
        long GetInteger(void) const;
-       long GetBool(void) const;
+       bool GetBool(void) const;
        string GetString(void) const;
        Object::Ptr GetObject(void) const;
 
index 6608bed7ef9b8b9df0269f35598eb0a565297399..81ce236c0d4787462a2196530324cc843b441553 100644 (file)
@@ -132,7 +132,7 @@ int JsonRpcEndpoint::ClientClosedHandler(const EventArgs&)
 
 int JsonRpcEndpoint::ClientErrorHandler(const SocketErrorEventArgs& ea)
 {
-       cerr << "Error occured for JSON-RPC socket: Code=" << ea.Code << "; Message=" << ea.Message << endl;
+       cerr << "Error occured for JSON-RPC socket: Code=" << ea.Error.GetCode() << "; Message=" << ea.Error.GetMessage() << endl;
 
        return 0;
 }