*/
Exception::Exception(void)
{
+ m_Code = 0;
m_Message = NULL;
}
*/
Exception::Exception(const char *message)
{
+ m_Code = 0;
m_Message = NULL;
SetMessage(message);
}
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.
*
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) \
{
string msg = message + ": " + FormatErrorCode(errorCode);
SetMessage(msg.c_str());
+ SetCode(errorCode);
}
/**
{
string msg = message + ": " + FormatErrorCode(errorCode);
SetMessage(msg.c_str());
+ SetCode(errorCode);
}
/**
}
}
+ /**
+ * 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;
};
}
/**
- * 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;
+ }
}
/**
*/
int Socket::ExceptionEventHandler(const EventArgs&)
{
- HandleSocketError();
+ HandleSocketError(SocketException(
+ "select() returned fd in except fdset", GetError()));
return 0;
}
socklen_t len = sizeof(sin);
if (getsockname(GetFD(), (sockaddr *)&sin, &len) < 0) {
- HandleSocketError();
+ HandleSocketError(SocketException(
+ "getsockname() failed", GetError()));
return string();
}
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
*/
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) { }
};
/**
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:
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 */
int rc = getaddrinfo(node.c_str(), service.c_str(), &hints, &result);
if (rc < 0) {
- HandleSocketError();
-
+ HandleSocketError(SocketException(
+ "getaddrinfo() failed", GetLastSocketError()));
return;
}
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());
}
/**
return 0;
if (rc <= 0) {
- HandleSocketError();
+ HandleSocketError(SocketException("recv() failed", GetError()));
return 0;
}
rc = send(GetFD(), (const char *)m_SendQueue->GetReadBuffer(), m_SendQueue->GetSize(), 0);
if (rc <= 0) {
- HandleSocketError();
+ HandleSocketError(SocketException("send() failed", GetError()));
return 0;
}
int rc = listen(GetFD(), SOMAXCONN);
if (rc < 0) {
- HandleSocketError();
+ HandleSocketError(SocketException(
+ "listen() failed", GetError()));
return;
}
}
fd = accept(GetFD(), (sockaddr *)&addr, &addrlen);
if (fd < 0) {
- HandleSocketError();
+ HandleSocketError(SocketException(
+ "accept() failed", GetError()));
return 0;
}
int fd = socket(family, SOCK_STREAM, 0);
if (fd == INVALID_SOCKET) {
- HandleSocketError();
+ HandleSocketError(SocketException(
+ "socket() failed", GetLastSocketError()));
return;
}
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;
}
break;
}
- if (fd == INVALID_SOCKET)
- HandleSocketError();
-
freeaddrinfo(result);
+
+ if (fd == INVALID_SOCKET)
+ HandleSocketError(InvalidArgumentException());
}
return 0;
default:
- HandleSSLError();
+ HandleSocketError(OpenSSLException(
+ "SSL_read failed", ERR_get_error()));
return 0;
}
return 0;
default:
- HandleSSLError();
+ HandleSocketError(OpenSSLException(
+ "SSL_write failed", ERR_get_error()));
return 0;
}
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.
*
*
* @returns The variant's value as a bool.
*/
-long Variant::GetBool(void) const
+bool Variant::GetBool(void) const
{
Convert(VariantInteger);
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;
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;
}