mirror of https://github.com/Icinga/icinga2.git
Cleaned up socket error handling.
This commit is contained in:
parent
4819449efb
commit
5dfb1cc4b4
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
#ifdef _WIN32
|
||||
sea.Message = Win32Exception::FormatErrorCode(sea.Code);
|
||||
#else /* _WIN32 */
|
||||
sea.Message = PosixException::FormatErrorCode(sea.Code);
|
||||
#endif /* _WIN32 */
|
||||
OnError(sea);
|
||||
}
|
||||
if (rc >= 0)
|
||||
return opt;
|
||||
|
||||
Close();
|
||||
return;
|
||||
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 */
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
} 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());
|
||||
}
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue