2012-03-28 13:24:49 +02:00
|
|
|
#include "i2-base.h"
|
|
|
|
|
|
|
|
using namespace icinga;
|
|
|
|
|
2012-04-19 08:46:41 +02:00
|
|
|
Socket::CollectionType Socket::Sockets;
|
2012-03-28 13:24:49 +02:00
|
|
|
|
|
|
|
Socket::Socket(void)
|
|
|
|
{
|
|
|
|
m_FD = INVALID_SOCKET;
|
|
|
|
}
|
|
|
|
|
|
|
|
Socket::~Socket(void)
|
|
|
|
{
|
2012-04-24 14:02:15 +02:00
|
|
|
CloseInternal(true);
|
2012-03-28 13:24:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void Socket::Start(void)
|
|
|
|
{
|
2012-04-18 15:22:25 +02:00
|
|
|
assert(m_FD != INVALID_SOCKET);
|
|
|
|
|
2012-04-04 12:22:46 +02:00
|
|
|
OnException += bind_weak(&Socket::ExceptionEventHandler, shared_from_this());
|
|
|
|
|
2012-04-23 09:48:20 +02:00
|
|
|
Sockets.push_back(static_pointer_cast<Socket>(shared_from_this()));
|
2012-03-28 13:24:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void Socket::Stop(void)
|
|
|
|
{
|
2012-04-23 09:48:20 +02:00
|
|
|
Sockets.remove_if(weak_ptr_eq_raw<Socket>(this));
|
2012-03-28 13:24:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void Socket::SetFD(SOCKET fd)
|
|
|
|
{
|
2012-03-29 13:15:54 +02:00
|
|
|
unsigned long lTrue = 1;
|
|
|
|
|
|
|
|
if (fd != INVALID_SOCKET)
|
|
|
|
ioctlsocket(fd, FIONBIO, &lTrue);
|
|
|
|
|
2012-03-28 13:24:49 +02:00
|
|
|
m_FD = fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
SOCKET Socket::GetFD(void) const
|
|
|
|
{
|
|
|
|
return m_FD;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Socket::Close(void)
|
|
|
|
{
|
2012-04-24 14:02:15 +02:00
|
|
|
CloseInternal(false);
|
2012-03-28 13:24:49 +02:00
|
|
|
}
|
|
|
|
|
2012-04-24 14:02:15 +02:00
|
|
|
void Socket::CloseInternal(bool from_dtor)
|
2012-03-28 13:24:49 +02:00
|
|
|
{
|
2012-04-27 13:44:53 +02:00
|
|
|
if (m_FD == INVALID_SOCKET)
|
|
|
|
return;
|
|
|
|
|
|
|
|
closesocket(m_FD);
|
|
|
|
m_FD = INVALID_SOCKET;
|
2012-03-28 13:24:49 +02:00
|
|
|
|
2012-04-27 13:44:53 +02:00
|
|
|
/* nobody can possibly have a valid event subscription when the
|
|
|
|
destructor has been called */
|
|
|
|
if (!from_dtor) {
|
2012-03-28 13:24:49 +02:00
|
|
|
Stop();
|
2012-04-27 13:44:53 +02:00
|
|
|
|
|
|
|
EventArgs ea;
|
|
|
|
ea.Source = shared_from_this();
|
|
|
|
OnClosed(ea);
|
|
|
|
}
|
2012-03-28 13:24:49 +02:00
|
|
|
}
|
|
|
|
|
2012-04-22 16:45:31 +02:00
|
|
|
void Socket::HandleSocketError(void)
|
2012-04-04 12:22:46 +02:00
|
|
|
{
|
|
|
|
int opt;
|
|
|
|
socklen_t optlen = sizeof(opt);
|
|
|
|
|
|
|
|
int rc = getsockopt(GetFD(), SOL_SOCKET, SO_ERROR, (char *)&opt, &optlen);
|
|
|
|
|
2012-04-22 16:45:31 +02:00
|
|
|
if (rc >= 0 && opt != 0) {
|
2012-04-18 15:22:25 +02:00
|
|
|
SocketErrorEventArgs sea;
|
|
|
|
sea.Code = opt;
|
2012-04-22 16:45:31 +02:00
|
|
|
#ifdef _WIN32
|
|
|
|
sea.Message = Win32Exception::FormatErrorCode(sea.Code);
|
|
|
|
#else /* _WIN32 */
|
|
|
|
sea.Message = PosixException::FormatErrorCode(sea.Code);
|
|
|
|
#endif /* _WIN32 */
|
2012-04-18 15:22:25 +02:00
|
|
|
OnError(sea);
|
2012-04-04 12:22:46 +02:00
|
|
|
}
|
|
|
|
|
2012-04-22 16:45:31 +02:00
|
|
|
Close();
|
|
|
|
return;
|
2012-04-04 12:22:46 +02:00
|
|
|
}
|
|
|
|
|
2012-04-22 16:45:31 +02:00
|
|
|
int Socket::ExceptionEventHandler(const EventArgs& ea)
|
2012-03-28 13:24:49 +02:00
|
|
|
{
|
2012-04-22 16:45:31 +02:00
|
|
|
HandleSocketError();
|
2012-03-28 13:24:49 +02:00
|
|
|
|
2012-04-22 16:45:31 +02:00
|
|
|
return 0;
|
2012-03-28 13:24:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Socket::WantsToRead(void) const
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Socket::WantsToWrite(void) const
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2012-04-27 11:44:05 +02:00
|
|
|
|
|
|
|
string Socket::GetAddressFromSockaddr(sockaddr *address, socklen_t len)
|
|
|
|
{
|
|
|
|
char host[NI_MAXHOST];
|
|
|
|
char service[NI_MAXSERV];
|
|
|
|
|
|
|
|
if (getnameinfo(address, len, host, sizeof(host), service, sizeof(service), NI_NUMERICHOST | NI_NUMERICSERV) < 0)
|
|
|
|
throw InvalidArgumentException(); /* TODO: throw proper exception */
|
|
|
|
|
|
|
|
stringstream s;
|
|
|
|
s << "[" << host << "]:" << service;
|
|
|
|
return s.str();
|
|
|
|
}
|
|
|
|
|
|
|
|
string Socket::GetClientAddress(void)
|
|
|
|
{
|
|
|
|
sockaddr_storage sin;
|
|
|
|
socklen_t len = sizeof(sin);
|
|
|
|
|
|
|
|
if (getsockname(GetFD(), (sockaddr *)&sin, &len) < 0) {
|
|
|
|
HandleSocketError();
|
|
|
|
|
|
|
|
return string();
|
|
|
|
}
|
|
|
|
|
|
|
|
return GetAddressFromSockaddr((sockaddr *)&sin, len);
|
|
|
|
}
|
|
|
|
|
|
|
|
string Socket::GetPeerAddress(void)
|
|
|
|
{
|
|
|
|
sockaddr_storage sin;
|
|
|
|
socklen_t len = sizeof(sin);
|
|
|
|
|
|
|
|
if (getpeername(GetFD(), (sockaddr *)&sin, &len) < 0) {
|
|
|
|
HandleSocketError();
|
|
|
|
|
|
|
|
return string();
|
|
|
|
}
|
|
|
|
|
|
|
|
return GetAddressFromSockaddr((sockaddr *)&sin, len);
|
|
|
|
}
|