Implemented IPv6 support.

This commit is contained in:
Gunnar Beutner 2012-04-27 09:54:07 +02:00
parent 3825e2902f
commit c1a8576c5c
6 changed files with 117 additions and 109 deletions

View File

@ -25,31 +25,54 @@ void TCPClient::Start(void)
void TCPClient::Connect(const string& hostname, unsigned short port) void TCPClient::Connect(const string& hostname, unsigned short port)
{ {
hostent *hent; m_Role = RoleOutbound;
sockaddr_in sin;
memset(&sin, 0, sizeof(sin)); stringstream s;
sin.sin_family = AF_INET; s << port;
sin.sin_port = htons(port); string strPort = s.str();
hent = gethostbyname(hostname.c_str()); addrinfo hints;
addrinfo *result;
if (hent != NULL) memset(&hints, 0, sizeof(hints));
sin.sin_addr.s_addr = ((in_addr *)hent->h_addr_list[0])->s_addr; hints.ai_family = AF_UNSPEC;
else hints.ai_socktype = SOCK_STREAM;
sin.sin_addr.s_addr = inet_addr(hostname.c_str()); hints.ai_protocol = IPPROTO_TCP;
int rc = connect(GetFD(), (sockaddr *)&sin, sizeof(sin)); int rc = getaddrinfo(hostname.c_str(), strPort.c_str(), &hints, &result);
#ifdef _WIN32 if (rc < 0) {
if (rc < 0 && WSAGetLastError() != WSAEWOULDBLOCK) {
#else /* _WIN32 */
if (rc < 0 && errno != EINPROGRESS) {
#endif /* _WIN32 */
HandleSocketError(); HandleSocketError();
return;
} }
m_Role = RoleOutbound; int fd = INVALID_SOCKET;
for (addrinfo *info = result; info != NULL; info = info->ai_next) {
fd = socket(info->ai_family, info->ai_socktype, info->ai_protocol);
if (fd == INVALID_SOCKET)
continue;
SetFD(fd);
rc = connect(fd, info->ai_addr, info->ai_addrlen);
#ifdef _WIN32
if (rc < 0 && WSAGetLastError() != WSAEWOULDBLOCK)
#else /* _WIN32 */
if (rc < 0 && errno != EINPROGRESS)
#endif /* _WIN32 */
continue;
break;
}
if (fd == INVALID_SOCKET)
HandleSocketError();
freeaddrinfo(result);
} }
FIFO::Ptr TCPClient::GetSendQueue(void) FIFO::Ptr TCPClient::GetSendQueue(void)

View File

@ -37,7 +37,7 @@ void TCPServer::Listen(void)
int TCPServer::ReadableEventHandler(const EventArgs& ea) int TCPServer::ReadableEventHandler(const EventArgs& ea)
{ {
int fd; int fd;
sockaddr_in addr; sockaddr_storage addr;
socklen_t addrlen = sizeof(addr); socklen_t addrlen = sizeof(addr);
fd = accept(GetFD(), (sockaddr *)&addr, &addrlen); fd = accept(GetFD(), (sockaddr *)&addr, &addrlen);

View File

@ -2,11 +2,11 @@
using namespace icinga; using namespace icinga;
void TCPSocket::MakeSocket(void) void TCPSocket::MakeSocket(int family)
{ {
assert(GetFD() == INVALID_SOCKET); assert(GetFD() == INVALID_SOCKET);
int fd = socket(AF_INET, SOCK_STREAM, 0); int fd = socket(family, SOCK_STREAM, 0);
if (fd == INVALID_SOCKET) { if (fd == INVALID_SOCKET) {
HandleSocketError(); HandleSocketError();
@ -17,118 +17,106 @@ void TCPSocket::MakeSocket(void)
SetFD(fd); 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)
{ {
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;
hints.ai_flags = AI_PASSIVE;
if (getaddrinfo(hostname, strPort.c_str(), &hints, &result) < 0) {
HandleSocketError();
return;
}
int fd = INVALID_SOCKET;
for (addrinfo *info = result; info != NULL; info = info->ai_next) {
fd = socket(info->ai_family, info->ai_socktype, info->ai_protocol);
if (fd == INVALID_SOCKET)
continue;
SetFD(fd);
const int optFalse = 0;
setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&optFalse, sizeof(optFalse));
#ifndef _WIN32 #ifndef _WIN32
const int optTrue = 1; const int optTrue = 1;
setsockopt(GetFD(), SOL_SOCKET, SO_REUSEADDR, (char *)&optTrue, sizeof(optTrue)); setsockopt(GetFD(), SOL_SOCKET, SO_REUSEADDR, (char *)&optTrue, sizeof(optTrue));
#endif /* _WIN32 */ #endif /* _WIN32 */
sockaddr_in sin; int rc = ::bind(fd, info->ai_addr, info->ai_addrlen);
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);
if (::bind(GetFD(), (sockaddr *)&sin, sizeof(sin)) < 0)
HandleSocketError();
}
string TCPSocket::GetAddressFromSockaddr(sockaddr *address)
{
static char buffer[256];
#ifdef _WIN32 #ifdef _WIN32
DWORD BufferLength = sizeof(buffer); if (rc < 0 && WSAGetLastError() != WSAEWOULDBLOCK)
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);
return "";
}
if (WSAAddressToString(address, len, NULL, buffer, &BufferLength) != 0)
return string();
#else /* _WIN32 */ #else /* _WIN32 */
void *IpAddress; if (rc < 0 && errno != EINPROGRESS)
if (address->sa_family == AF_INET)
IpAddress = &(((sockaddr_in *)address)->sin_addr);
else
IpAddress = &(((sockaddr_in6 *)address)->sin6_addr);
if (inet_ntop(address->sa_family, IpAddress, buffer, sizeof(buffer)) == NULL)
return string();
#endif /* _WIN32 */ #endif /* _WIN32 */
continue;
return buffer; break;
}
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;
} }
}
bool TCPSocket::GetClientSockaddr(sockaddr_storage *address) if (fd == INVALID_SOCKET)
{
socklen_t len = sizeof(*address);
if (getsockname(GetFD(), (sockaddr *)address, &len) < 0) {
HandleSocketError(); HandleSocketError();
return false; freeaddrinfo(result);
}
return true;
} }
bool TCPSocket::GetPeerSockaddr(sockaddr_storage *address)
string TCPSocket::GetAddressFromSockaddr(sockaddr *address, socklen_t len)
{ {
socklen_t len = sizeof(*address); char host[NI_MAXHOST];
char service[NI_MAXSERV];
if (getpeername(GetFD(), (sockaddr *)address, &len) < 0) { if (getnameinfo(address, len, host, sizeof(host), service, sizeof(service), NI_NUMERICHOST | NI_NUMERICSERV) < 0)
HandleSocketError(); throw InvalidArgumentException(); /* TODO: throw proper exception */
return false; stringstream s;
} s << "[" << host << "]:" << service;
return s.str();
return true;
} }
string TCPSocket::GetClientAddress(void) string TCPSocket::GetClientAddress(void)
{ {
sockaddr_storage sin; sockaddr_storage sin;
socklen_t len = sizeof(sin);
if (!GetClientSockaddr(&sin)) if (getsockname(GetFD(), (sockaddr *)&sin, &len) < 0) {
return ""; HandleSocketError();
return GetAddressFromSockaddr((sockaddr *)&sin); return string();
}
return GetAddressFromSockaddr((sockaddr *)&sin, len);
} }
string TCPSocket::GetPeerAddress(void) string TCPSocket::GetPeerAddress(void)
{ {
sockaddr_storage sin; sockaddr_storage sin;
socklen_t len = sizeof(sin);
if (!GetPeerSockaddr(&sin)) if (getpeername(GetFD(), (sockaddr *)&sin, &len) < 0) {
return ""; HandleSocketError();
return GetAddressFromSockaddr((sockaddr *)&sin); return string();
}
return GetAddressFromSockaddr((sockaddr *)&sin, len);
} }

View File

@ -7,17 +7,16 @@ namespace icinga
class I2_BASE_API TCPSocket : public Socket class I2_BASE_API TCPSocket : public Socket
{ {
private: private:
static string GetAddressFromSockaddr(sockaddr *address); static string GetAddressFromSockaddr(sockaddr *address, socklen_t len);
static unsigned short GetPortFromSockaddr(sockaddr *address);
void MakeSocket(int family);
public: public:
typedef shared_ptr<TCPSocket> Ptr; typedef shared_ptr<TCPSocket> Ptr;
typedef weak_ptr<TCPSocket> WeakPtr; typedef weak_ptr<TCPSocket> WeakPtr;
void MakeSocket(void); void Bind(unsigned short port, int family);
void Bind(const char *hostname, unsigned short port, int family);
void Bind(unsigned short port);
void Bind(const char *hostname, unsigned short port);
bool GetClientSockaddr(sockaddr_storage *address); bool GetClientSockaddr(sockaddr_storage *address);
bool GetPeerSockaddr(sockaddr_storage *address); bool GetPeerSockaddr(sockaddr_storage *address);

View File

@ -16,8 +16,7 @@ void EndpointManager::AddListener(unsigned short port)
JsonRpcServer::Ptr server = make_shared<JsonRpcServer>(m_SSLContext); JsonRpcServer::Ptr server = make_shared<JsonRpcServer>(m_SSLContext);
RegisterServer(server); RegisterServer(server);
server->MakeSocket(); server->Bind(port, AF_INET6);
server->Bind(port);
server->Listen(); server->Listen();
server->Start(); server->Start();
} }
@ -25,7 +24,7 @@ void EndpointManager::AddListener(unsigned short port)
void EndpointManager::AddConnection(string host, unsigned short port) void EndpointManager::AddConnection(string host, unsigned short port)
{ {
stringstream s; stringstream s;
s << "Adding new endpoint: " << host << ":" << port; s << "Adding new endpoint: [" << host << "]:" << port;
Application::Log(s.str()); Application::Log(s.str());
JsonRpcEndpoint::Ptr endpoint = make_shared<JsonRpcEndpoint>(); JsonRpcEndpoint::Ptr endpoint = make_shared<JsonRpcEndpoint>();

View File

@ -63,7 +63,6 @@ void JsonRpcEndpoint::Connect(string host, unsigned short port, shared_ptr<SSL_C
m_PeerPort = port; m_PeerPort = port;
JsonRpcClient::Ptr client = make_shared<JsonRpcClient>(RoleOutbound, sslContext); JsonRpcClient::Ptr client = make_shared<JsonRpcClient>(RoleOutbound, sslContext);
client->MakeSocket();
client->Connect(host, port); client->Connect(host, port);
client->Start(); client->Start();