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)
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();
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);
}