]> granicus.if.org Git - icinga2/commitdiff
Implemented IPv6 support.
authorGunnar Beutner <gunnar.beutner@netways.de>
Fri, 27 Apr 2012 07:54:07 +0000 (09:54 +0200)
committerGunnar Beutner <gunnar.beutner@netways.de>
Fri, 27 Apr 2012 07:54:07 +0000 (09:54 +0200)
base/tcpclient.cpp
base/tcpserver.cpp
base/tcpsocket.cpp
base/tcpsocket.h
icinga/endpointmanager.cpp
icinga/jsonrpcendpoint.cpp

index e609e5116894fc0c8bd64aa49322687303509cde..93e3229d93674149ff17f86e3da7ed2aacace199 100644 (file)
@@ -25,31 +25,54 @@ void TCPClient::Start(void)
 
 void TCPClient::Connect(const string& hostname, unsigned short port)
 {
-       hostent *hent;
-       sockaddr_in sin;
+       m_Role = RoleOutbound;
+
+       stringstream s;
+       s << port;
+       string strPort = s.str();
+
+       addrinfo hints;
+       addrinfo *result;
+
+       memset(&hints, 0, sizeof(hints));
+       hints.ai_family = AF_UNSPEC;
+       hints.ai_socktype = SOCK_STREAM;
+       hints.ai_protocol = IPPROTO_TCP;
 
-       memset(&sin, 0, sizeof(sin));
-       sin.sin_family = AF_INET;
-       sin.sin_port = htons(port);
+       int rc = getaddrinfo(hostname.c_str(), strPort.c_str(), &hints, &result);
+
+       if (rc < 0) {
+               HandleSocketError();
+
+               return;
+       }
 
-       hent = gethostbyname(hostname.c_str());
+       int fd = INVALID_SOCKET;
 
-       if (hent != NULL)
-               sin.sin_addr.s_addr = ((in_addr *)hent->h_addr_list[0])->s_addr;
-       else
-               sin.sin_addr.s_addr = inet_addr(hostname.c_str());
+       for (addrinfo *info = result; info != NULL; info = info->ai_next) {
+               fd = socket(info->ai_family, info->ai_socktype, info->ai_protocol);
 
-       int rc = connect(GetFD(), (sockaddr *)&sin, sizeof(sin));
+               if (fd == INVALID_SOCKET)
+                       continue;
+
+               SetFD(fd);
+
+               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 */
-               HandleSocketError();
+                       continue;
+
+               break;
        }
 
-       m_Role = RoleOutbound;
+       if (fd == INVALID_SOCKET)
+               HandleSocketError();
+
+       freeaddrinfo(result);
 }
 
 FIFO::Ptr TCPClient::GetSendQueue(void)
index b857c96d0634f31816eb296e5e28776d0ec5e91d..b358170343fa2e44f811bfdfd5492e18fcdd52a8 100644 (file)
@@ -37,7 +37,7 @@ void TCPServer::Listen(void)
 int TCPServer::ReadableEventHandler(const EventArgs& ea)
 {
        int fd;
-       sockaddr_in addr;
+       sockaddr_storage addr;
        socklen_t addrlen = sizeof(addr);
 
        fd = accept(GetFD(), (sockaddr *)&addr, &addrlen);
index 82239ef58b5ca4473754c143252fe707d123baed..86d73afb53ff0ad0483073fdf3344abc5c282a50 100644 (file)
@@ -2,11 +2,11 @@
 
 using namespace icinga;
 
-void TCPSocket::MakeSocket(void)
+void TCPSocket::MakeSocket(int family)
 {
        assert(GetFD() == INVALID_SOCKET);
 
-       int fd = socket(AF_INET, SOCK_STREAM, 0);
+       int fd = socket(family, SOCK_STREAM, 0);
 
        if (fd == INVALID_SOCKET) {
                HandleSocketError();
@@ -17,118 +17,106 @@ void TCPSocket::MakeSocket(void)
        SetFD(fd);
 }
 
-void TCPSocket::Bind(unsigned short port)
+void TCPSocket::Bind(unsigned short port, int family)
 {
-       Bind(NULL, port);
+       Bind(NULL, port, family);
 }
 
-void TCPSocket::Bind(const char *hostname, unsigned short port)
+void TCPSocket::Bind(const char *hostname, unsigned short port, int family)
 {
-#ifndef _WIN32
-       const int optTrue = 1;
-       setsockopt(GetFD(), SOL_SOCKET, SO_REUSEADDR, (char *)&optTrue, sizeof(optTrue));
-#endif /* _WIN32 */
+       stringstream s;
+       s << port;
+       string strPort = s.str();
+
+       addrinfo hints;
+       addrinfo *result;
 
-       sockaddr_in sin;
-       memset(&sin, 0, sizeof(sin));
-       sin.sin_family = AF_INET;
-       sin.sin_addr.s_addr = hostname ? inet_addr(hostname) : htonl(INADDR_ANY);
-       sin.sin_port = htons(port);
+       memset(&hints, 0, sizeof(hints));
+       hints.ai_family = AF_UNSPEC;
+       hints.ai_socktype = SOCK_STREAM;
+       hints.ai_protocol = IPPROTO_TCP;
+       hints.ai_flags = AI_PASSIVE;
 
-       if (::bind(GetFD(), (sockaddr *)&sin, sizeof(sin)) < 0)
+       if (getaddrinfo(hostname, strPort.c_str(), &hints, &result) < 0) {
                HandleSocketError();
-}
 
-string TCPSocket::GetAddressFromSockaddr(sockaddr *address)
-{
-       static char buffer[256];
+               return;
+       }
 
-#ifdef _WIN32
-       DWORD BufferLength = sizeof(buffer);
+       int fd = INVALID_SOCKET;
 
-       socklen_t len;
-       if (address->sa_family == AF_INET)
-               len = sizeof(sockaddr_in);
-       else if (address->sa_family == AF_INET6)
-               len = sizeof(sockaddr_in6);
-       else {
-               assert(0);
+       for (addrinfo *info = result; info != NULL; info = info->ai_next) {
+               fd = socket(info->ai_family, info->ai_socktype, info->ai_protocol);
 
-               return "";
-       }
+               if (fd == INVALID_SOCKET)
+                       continue;
 
-       if (WSAAddressToString(address, len, NULL, buffer, &BufferLength) != 0)
-               return string();
-#else /* _WIN32 */
-       void *IpAddress;
+               SetFD(fd);
 
-       if (address->sa_family == AF_INET)
-               IpAddress = &(((sockaddr_in *)address)->sin_addr);
-       else
-               IpAddress = &(((sockaddr_in6 *)address)->sin6_addr);
+               const int optFalse = 0;
+               setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&optFalse, sizeof(optFalse));
 
-       if (inet_ntop(address->sa_family, IpAddress, buffer, sizeof(buffer)) == NULL)
-               return string();
+#ifndef _WIN32
+               const int optTrue = 1;
+               setsockopt(GetFD(), SOL_SOCKET, SO_REUSEADDR, (char *)&optTrue, sizeof(optTrue));
 #endif /* _WIN32 */
 
-       return buffer;
-}
+               int rc = ::bind(fd, info->ai_addr, info->ai_addrlen);
 
-unsigned short TCPSocket::GetPortFromSockaddr(sockaddr *address)
-{
-       if (address->sa_family == AF_INET)
-               return htons(((sockaddr_in *)address)->sin_port);
-       else if (address->sa_family == AF_INET6)
-               return htons(((sockaddr_in6 *)address)->sin6_port);
-       else {
-               assert(0);
-
-               return 0;
+#ifdef _WIN32
+       if (rc < 0 && WSAGetLastError() != WSAEWOULDBLOCK)
+#else /* _WIN32 */
+       if (rc < 0 && errno != EINPROGRESS)
+#endif /* _WIN32 */
+                       continue;
+
+               break;
        }
-}
 
-bool TCPSocket::GetClientSockaddr(sockaddr_storage *address)
-{
-       socklen_t len = sizeof(*address);
-       
-       if (getsockname(GetFD(), (sockaddr *)address, &len) < 0) {
+       if (fd == INVALID_SOCKET)
                HandleSocketError();
 
-               return false;
-       }
-
-       return true;
+       freeaddrinfo(result);
 }
 
-bool TCPSocket::GetPeerSockaddr(sockaddr_storage *address)
+
+string TCPSocket::GetAddressFromSockaddr(sockaddr *address, socklen_t len)
 {
-       socklen_t len = sizeof(*address);
-       
-       if (getpeername(GetFD(), (sockaddr *)address, &len) < 0) {
-               HandleSocketError();
+       char host[NI_MAXHOST];
+       char service[NI_MAXSERV];
 
-               return false;
-       }
+       if (getnameinfo(address, len, host, sizeof(host), service, sizeof(service), NI_NUMERICHOST | NI_NUMERICSERV) < 0)
+               throw InvalidArgumentException(); /* TODO: throw proper exception */
 
-       return true;
+       stringstream s;
+       s << "[" << host << "]:" << service;
+       return s.str();
 }
 
 string TCPSocket::GetClientAddress(void)
 {
        sockaddr_storage sin;
+       socklen_t len = sizeof(sin);
 
-       if (!GetClientSockaddr(&sin))
-               return "";
+       if (getsockname(GetFD(), (sockaddr *)&sin, &len) < 0) {
+               HandleSocketError();
+
+               return string();
+       }
 
-       return GetAddressFromSockaddr((sockaddr *)&sin);
+       return GetAddressFromSockaddr((sockaddr *)&sin, len);
 }
 
 string TCPSocket::GetPeerAddress(void)
 {
        sockaddr_storage sin;
+       socklen_t len = sizeof(sin);
 
-       if (!GetPeerSockaddr(&sin))
-               return "";
+       if (getpeername(GetFD(), (sockaddr *)&sin, &len) < 0) {
+               HandleSocketError();
+
+               return string();
+       }
 
-       return GetAddressFromSockaddr((sockaddr *)&sin);
+       return GetAddressFromSockaddr((sockaddr *)&sin, len);
 }
index 2373d2e1fb1617470c3814271a71bba1bcd9df9a..1545cc4ce2616f312a51524f9b42b6fe8da640b7 100644 (file)
@@ -7,17 +7,16 @@ namespace icinga
 class I2_BASE_API TCPSocket : public Socket
 {
 private:
-       static string GetAddressFromSockaddr(sockaddr *address);
-       static unsigned short GetPortFromSockaddr(sockaddr *address);
+       static string GetAddressFromSockaddr(sockaddr *address, socklen_t len);
+
+       void MakeSocket(int family);
 
 public:
        typedef shared_ptr<TCPSocket> Ptr;
        typedef weak_ptr<TCPSocket> WeakPtr;
 
-       void MakeSocket(void);
-
-       void Bind(unsigned short port);
-       void Bind(const char *hostname, unsigned short port);
+       void Bind(unsigned short port, int family);
+       void Bind(const char *hostname, unsigned short port, int family);
 
        bool GetClientSockaddr(sockaddr_storage *address);
        bool GetPeerSockaddr(sockaddr_storage *address);
index b9adab381cfaf958228581c942cab06c2820c57e..ae869ea8baa19bad0f20e013f32d358b04ce2f62 100644 (file)
@@ -16,8 +16,7 @@ void EndpointManager::AddListener(unsigned short port)
        JsonRpcServer::Ptr server = make_shared<JsonRpcServer>(m_SSLContext);
        RegisterServer(server);
 
-       server->MakeSocket();
-       server->Bind(port);
+       server->Bind(port, AF_INET6);
        server->Listen();
        server->Start();
 }
@@ -25,7 +24,7 @@ void EndpointManager::AddListener(unsigned short port)
 void EndpointManager::AddConnection(string host, unsigned short port)
 {
        stringstream s;
-       s << "Adding new endpoint: " << host << ":" << port;
+       s << "Adding new endpoint: [" << host << "]:" << port;
        Application::Log(s.str());
 
        JsonRpcEndpoint::Ptr endpoint = make_shared<JsonRpcEndpoint>();
index 2ec80924e3f0b5dbb819aa37d1007fce62d5e142..0fd58ae0a6e0013e4bd69045517fcec3dbd28e7f 100644 (file)
@@ -63,7 +63,6 @@ void JsonRpcEndpoint::Connect(string host, unsigned short port, shared_ptr<SSL_C
        m_PeerPort = port;
 
        JsonRpcClient::Ptr client = make_shared<JsonRpcClient>(RoleOutbound, sslContext);
-       client->MakeSocket();
        client->Connect(host, port);
        client->Start();