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)
{
hostent *hent;
sockaddr_in sin;
m_Role = RoleOutbound;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
stringstream s;
s << port;
string strPort = s.str();
hent = gethostbyname(hostname.c_str());
addrinfo hints;
addrinfo *result;
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());
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
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 && WSAGetLastError() != WSAEWOULDBLOCK) {
#else /* _WIN32 */
if (rc < 0 && errno != EINPROGRESS) {
#endif /* _WIN32 */
if (rc < 0) {
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)

View 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);

View 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)
{
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
const int optTrue = 1;
setsockopt(GetFD(), SOL_SOCKET, SO_REUSEADDR, (char *)&optTrue, sizeof(optTrue));
const int optTrue = 1;
setsockopt(GetFD(), SOL_SOCKET, SO_REUSEADDR, (char *)&optTrue, sizeof(optTrue));
#endif /* _WIN32 */
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);
if (::bind(GetFD(), (sockaddr *)&sin, sizeof(sin)) < 0)
HandleSocketError();
}
string TCPSocket::GetAddressFromSockaddr(sockaddr *address)
{
static char buffer[256];
int rc = ::bind(fd, info->ai_addr, info->ai_addrlen);
#ifdef _WIN32
DWORD BufferLength = sizeof(buffer);
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();
if (rc < 0 && WSAGetLastError() != WSAEWOULDBLOCK)
#else /* _WIN32 */
void *IpAddress;
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();
if (rc < 0 && errno != EINPROGRESS)
#endif /* _WIN32 */
continue;
return buffer;
}
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;
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);
char host[NI_MAXHOST];
char service[NI_MAXSERV];
if (getpeername(GetFD(), (sockaddr *)address, &len) < 0) {
HandleSocketError();
if (getnameinfo(address, len, host, sizeof(host), service, sizeof(service), NI_NUMERICHOST | NI_NUMERICSERV) < 0)
throw InvalidArgumentException(); /* TODO: throw proper exception */
return false;
}
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 GetAddressFromSockaddr((sockaddr *)&sin);
return string();
}
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 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
{
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);

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

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