/* net6 - Library providing IPv4/IPv6 network access
* Copyright (C) 2005 Armin Burgmeier / 0x539 dev group
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef WIN32
#include <netdb.h>
#include <arpa/inet.h>
#endif
#include <sstream>
#include "common.hpp"
#include "config.hpp"
#include "error.hpp"
#include "address.hpp"
namespace
{
#ifdef WIN32
// We do not use getaddrinfo on WIN32
hostent* resolve_generic(const char* hostname, int family, int flags)
{
hostent* result = gethostbyname(hostname);
if(result == NULL)
throw net6::error(
net6::error::GETHOSTBYNAME,
WSAGetLastError()
);
// Check address type
if(result->h_addrtype != family)
throw net6::error(net6::error::GETHOSTBYNAME, NO_DATA);
return result;
}
#else
addrinfo* resolve_generic(const char* hostname, int family, int flags)
{
addrinfo hint;
hint.ai_family = family;
hint.ai_socktype = 0;
hint.ai_protocol = 0;
hint.ai_addrlen = 0;
hint.ai_addr = NULL;
hint.ai_canonname = NULL;
hint.ai_next = NULL;
hint.ai_flags = flags;
addrinfo* result;
int gai_error = getaddrinfo(hostname, NULL, &hint, &result);
if(gai_error != 0)
throw net6::error(net6::error::GETADDRINFO, gai_error);
return result;
}
#endif
#ifdef _WIN32
inline const char* inet_ntop4(int af, const void *__restrict src,
char *__restrict dest, socklen_t size)
{
// Format address
char* s = inet_ntoa(*reinterpret_cast<const in_addr*>(src));
if(s == NULL) return NULL;
// Copy to given buffer
socklen_t len = static_cast<socklen_t>(strlen(s) );
return strncpy(dest, s, size < (len + 1) ? size : (len + 1) );
}
// There is no inet_ntop on WIN32
inline const char *inet_ntop(int af, const void *__restrict src,
char *__restrict dest, socklen_t size)
{
switch(af)
{
case AF_INET:
return inet_ntop4(af, src, dest, size);
break;
default:
throw std::logic_error(
"inet_ntop is only implemented for "
"AF_INET address family on win32"
);
break;
}
}
#endif
}
net6::address::address()
{
}
net6::address::~address()
{
#ifdef DEBUG
if(addr)
std::cerr << "Warning: Unfreed address: " << addr << std::endl;
#endif
}
int net6::address::get_family() const
{
return addr->sa_family;
}
const uint32_t net6::ipv4_address::ANY = INADDR_ANY;
const uint32_t net6::ipv4_address::NONE = INADDR_NONE;
const uint32_t net6::ipv4_address::BROADCAST = INADDR_BROADCAST;
const uint32_t net6::ipv4_address::LOOPBACK = INADDR_LOOPBACK;
net6::ipv4_address::ipv4_address(unsigned int port)
{
addr = reinterpret_cast<sockaddr*>(new sockaddr_in);
cobj()->sin_family = AF_INET;
cobj()->sin_port = htons(port);
cobj()->sin_addr.s_addr = ANY;
}
net6::ipv4_address net6::ipv4_address::create_from_address(uint32_t ip_address,
unsigned int port)
{
ipv4_address addr;
addr.addr = reinterpret_cast<sockaddr*>(new sockaddr_in);
addr.cobj()->sin_family = AF_INET;
addr.cobj()->sin_port = htons(port);
addr.cobj()->sin_addr.s_addr = ip_address;
return addr;
}
net6::ipv4_address
net6::ipv4_address::create_from_hostname(const std::string& hostname,
unsigned int port)
{
ipv4_address addr;
addr.addr = reinterpret_cast<sockaddr*>(new sockaddr_in);
#ifdef WIN32
hostent* info = resolve_generic(hostname.c_str(), AF_INET, 0);
#else
#ifdef HAVE_AI_ADDRCONFIG
addrinfo* info = resolve_generic(hostname.c_str(), AF_INET, AI_ADDRCONFIG);
#else
addrinfo* info = resolve_generic(hostname.c_str(), AF_INET, 0);
#endif
sockaddr_in* ai_addr = reinterpret_cast<sockaddr_in*>(info->ai_addr);
#endif
addr.cobj()->sin_family = AF_INET;
addr.cobj()->sin_port = htons(port);
#ifdef WIN32
addr.cobj()->sin_addr.s_addr = *((uint32_t*)info->h_addr_list[0]);
#else
addr.cobj()->sin_addr.s_addr = ai_addr->sin_addr.s_addr;
freeaddrinfo(info);
#endif
return addr;
}
net6::ipv4_address::ipv4_address(const sockaddr_in* other)
: address()
{
sockaddr_in* my_addr = new sockaddr_in;
my_addr->sin_family = other->sin_family;
my_addr->sin_port = other->sin_port;
my_addr->sin_addr.s_addr = other->sin_addr.s_addr;
addr = reinterpret_cast<sockaddr*>(my_addr);
}
net6::ipv4_address::ipv4_address(const ipv4_address& other)
: address()
{
sockaddr_in* my_addr = new sockaddr_in;
sockaddr_in* other_addr = reinterpret_cast<sockaddr_in*>(other.addr);
my_addr->sin_family = other_addr->sin_family;
my_addr->sin_port = other_addr->sin_port;
my_addr->sin_addr.s_addr = other_addr->sin_addr.s_addr;
addr = reinterpret_cast<sockaddr*>(my_addr);
}
net6::ipv4_address::~ipv4_address()
{
if(addr)
{
delete addr;
addr = NULL;
}
}
std::list<net6::ipv4_address>
net6::ipv4_address::list(const std::string& hostname, unsigned int port)
{
std::list<ipv4_address> result;
#ifdef WIN32
hostent* info = resolve_generic(hostname.c_str(), AF_INET, 0);
#else
#ifdef HAVE_AI_ADDRCONFIG
addrinfo* info = resolve_generic(hostname.c_str(), AF_INET, AI_ADDRCONFIG);
#else
addrinfo* info = resolve_generic(hostname.c_str(), AF_INET, 0);
#endif
#endif
#ifdef WIN32
for(int cur = 0; cur < info->h_length; ++ cur)
#else
for(addrinfo* cur = info; cur != NULL; cur = cur->ai_next)
#endif
{
#ifdef WIN32
result.push_back(
ipv4_address::create_from_address(
*((uint32_t*)info->h_addr_list[cur]),
port
)
);
#else
sockaddr_in* in = reinterpret_cast<sockaddr_in*>(cur->ai_addr);
in->sin_port = htons(port);
result.push_back(ipv4_address(in) );
#endif
}
#ifndef WIN32
freeaddrinfo(info);
#endif
return result;
}
net6::ipv4_address& net6::ipv4_address::operator=(const ipv4_address& other)
{
if(this == &other) return *this;
sockaddr_in* my_addr = reinterpret_cast<sockaddr_in*>(addr);
sockaddr_in* other_addr = reinterpret_cast<sockaddr_in*>(other.addr);
my_addr->sin_family = other_addr->sin_family;
my_addr->sin_port = other_addr->sin_port;
my_addr->sin_addr.s_addr = other_addr->sin_addr.s_addr;
return *this;
}
net6::ipv4_address& net6::ipv4_address::operator=(const sockaddr_in* other)
{
sockaddr_in* my_addr = reinterpret_cast<sockaddr_in*>(addr);
my_addr->sin_family = other->sin_family;
my_addr->sin_port = other->sin_port;
my_addr->sin_addr.s_addr = other->sin_addr.s_addr;
return *this;
}
net6::address* net6::ipv4_address::clone() const
{
return new ipv4_address(*this);
}
std::string net6::ipv4_address::get_name() const
{
const size_t len = INET_ADDRSTRLEN;
char buf[len];
inet_ntop(AF_INET, &((sockaddr_in*)addr)->sin_addr, buf, len);
return buf;
}
socklen_t net6::ipv4_address::get_size() const
{
return sizeof(sockaddr_in);
}
unsigned int net6::ipv4_address::get_port() const
{
return ntohs(cobj()->sin_port);
}
void net6::ipv4_address::set_port(unsigned int port)
{
cobj()->sin_port = htons(port);
}
const uint8_t net6::ipv6_address::ANY[16] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
const uint8_t net6::ipv6_address::LOOPBACK[16] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
};
net6::ipv6_address::ipv6_address(unsigned int port, unsigned int flowinfo,
unsigned int scope_id)
{
addr = reinterpret_cast<sockaddr*>(new sockaddr_in6);
cobj()->sin6_family = AF_INET6;
cobj()->sin6_port = htons(port);
cobj()->sin6_flowinfo = flowinfo;
std::copy(ANY, ANY + 16, cobj()->sin6_addr.s6_addr);
cobj()->sin6_scope_id = scope_id;
}
net6::ipv6_address
net6::ipv6_address::create_from_address(const uint8_t ip_address[16],
unsigned int port,
unsigned int flowinfo,
unsigned int scope_id)
{
ipv6_address addr;
addr.addr = reinterpret_cast<sockaddr*>(new sockaddr_in6);
addr.cobj()->sin6_family = AF_INET6;
addr.cobj()->sin6_port = htons(port);
addr.cobj()->sin6_flowinfo = flowinfo;
std::copy(ip_address, ip_address + 16, addr.cobj()->sin6_addr.s6_addr);
addr.cobj()->sin6_scope_id = scope_id;
return addr;
}
net6::ipv6_address
net6::ipv6_address::create_from_hostname(const std::string& hostname,
unsigned int port,
unsigned int flowinfo,
unsigned int scope_id)
{
ipv6_address addr;
addr.addr = reinterpret_cast<sockaddr*>(new sockaddr_in6);
#ifdef WIN32
hostent* info = resolve_generic(hostname.c_str(), AF_INET6, 0);
#else
#ifdef HAVE_AI_ADDRCONFIG
addrinfo* info = resolve_generic(hostname.c_str(), AF_INET6, AI_ADDRCONFIG);
#else
addrinfo* info = resolve_generic(hostname.c_str(), AF_INET6, 0);
#endif
sockaddr_in6* ai_addr = reinterpret_cast<sockaddr_in6*>(info->ai_addr);
#endif
addr.cobj()->sin6_family = AF_INET6;
addr.cobj()->sin6_port = htons(port);
addr.cobj()->sin6_flowinfo = flowinfo;
#ifdef WIN32
std::copy(
info->h_addr_list[0],
info->h_addr_list[0] + 16,
addr.cobj()->sin6_addr.s6_addr
);
#else
std::copy(
ai_addr->sin6_addr.s6_addr,
ai_addr->sin6_addr.s6_addr + 16,
addr.cobj()->sin6_addr.s6_addr
);
#endif
addr.cobj()->sin6_scope_id = scope_id;
#ifndef WIN32
freeaddrinfo(info);
#endif
return addr;
}
net6::ipv6_address::ipv6_address(const sockaddr_in6* other)
: address()
{
sockaddr_in6* my_addr = new sockaddr_in6;
my_addr->sin6_family = other->sin6_family;
my_addr->sin6_port = other->sin6_port;
my_addr->sin6_flowinfo = other->sin6_flowinfo;
my_addr->sin6_scope_id = other->sin6_scope_id;
std::copy(
other->sin6_addr.s6_addr,
other->sin6_addr.s6_addr + 16,
my_addr->sin6_addr.s6_addr
);
addr = reinterpret_cast<sockaddr*>(my_addr);
}
net6::ipv6_address::ipv6_address(const ipv6_address& other)
: address()
{
sockaddr_in6* my_addr = new sockaddr_in6;
sockaddr_in6* other_addr = reinterpret_cast<sockaddr_in6*>(other.addr);
my_addr->sin6_family = other_addr->sin6_family;
my_addr->sin6_port = other_addr->sin6_port;
my_addr->sin6_flowinfo = other_addr->sin6_flowinfo;
my_addr->sin6_scope_id = other_addr->sin6_scope_id;
std::copy(
other_addr->sin6_addr.s6_addr,
other_addr->sin6_addr.s6_addr + 16,
my_addr->sin6_addr.s6_addr
);
addr = reinterpret_cast<sockaddr*>(my_addr);
}
net6::ipv6_address::~ipv6_address()
{
if(addr)
{
delete addr;
addr = NULL;
}
}
std::list<net6::ipv6_address>
net6::ipv6_address::list(const std::string& hostname, unsigned int port,
unsigned int flowinfo, unsigned int scope_id)
{
std::list<ipv6_address> result;
#ifdef WIN32
hostent* info = resolve_generic(hostname.c_str(), AF_INET6, 0);
#else
#ifdef HAVE_AI_ADDRCONFIG
addrinfo* info = resolve_generic(hostname.c_str(), AF_INET6, AI_ADDRCONFIG);
#else
addrinfo* info = resolve_generic(hostname.c_str(), AF_INET6, 0);
#endif
#endif
#ifdef WIN32
for(int cur = 0; cur < info->h_length; ++ cur)
#else
for(addrinfo* cur = info; cur != NULL; cur = cur->ai_next)
#endif
{
#ifdef WIN32
result.push_back(
ipv6_address::create_from_address(
reinterpret_cast<uint8_t*>(
info->h_addr_list[cur]
),
port,
flowinfo,
scope_id
)
);
#else
sockaddr_in6* in;
in = reinterpret_cast<sockaddr_in6*>(cur->ai_addr);
in->sin6_port = htons(port);
in->sin6_flowinfo = flowinfo;
in->sin6_scope_id = scope_id;
result.push_back(ipv6_address(in) );
#endif
}
#ifndef WIN32
freeaddrinfo(info);
#endif
return result;
}
net6::ipv6_address& net6::ipv6_address::operator=(const ipv6_address& other)
{
if(this == &other) return *this;
sockaddr_in6* my_addr = reinterpret_cast<sockaddr_in6*>(addr);
sockaddr_in6* other_addr = reinterpret_cast<sockaddr_in6*>(other.addr);
my_addr->sin6_family = other_addr->sin6_family;
my_addr->sin6_port = other_addr->sin6_port;
my_addr->sin6_flowinfo = other_addr->sin6_flowinfo;
my_addr->sin6_scope_id = other_addr->sin6_scope_id;
std::copy(
other_addr->sin6_addr.s6_addr,
other_addr->sin6_addr.s6_addr + 16,
my_addr->sin6_addr.s6_addr
);
return *this;
}
net6::ipv6_address& net6::ipv6_address::operator=(const sockaddr_in6* other)
{
sockaddr_in6* my_addr = reinterpret_cast<sockaddr_in6*>(addr);
my_addr->sin6_family = other->sin6_family;
my_addr->sin6_port = other->sin6_port;
my_addr->sin6_flowinfo = other->sin6_flowinfo;
my_addr->sin6_scope_id = other->sin6_scope_id;
std::copy(
other->sin6_addr.s6_addr,
other->sin6_addr.s6_addr + 16,
my_addr->sin6_addr.s6_addr
);
return *this;
}
net6::address* net6::ipv6_address::clone() const
{
return new ipv6_address(*this);
}
std::string net6::ipv6_address::get_name() const
{
#ifdef _WIN32
// No call to inet_ntop on WIN32 since inet_ntop is not defined
// on Win32. Use WSAAddressToString instead.
char destbuf[INET6_ADDRSTRLEN + 6];
DWORD len = INET6_ADDRSTRLEN + 6;
WSAAddressToStringA(
addr,
sizeof(sockaddr_in6),
NULL,
destbuf,
&len
);
char* sep = strrchr(destbuf, ':');
if(sep != NULL) *sep = '\0';
return destbuf;
#else
const size_t len = INET6_ADDRSTRLEN;
char buf[len];
inet_ntop(AF_INET6, &((sockaddr_in6*)addr)->sin6_addr, buf, len);
return buf;
#endif
}
socklen_t net6::ipv6_address::get_size() const
{
return sizeof(sockaddr_in6);
}
unsigned int net6::ipv6_address::get_port() const
{
return ntohs(cobj()->sin6_port);
}
unsigned int net6::ipv6_address::get_flowinfo() const
{
return cobj()->sin6_flowinfo;
}
unsigned int net6::ipv6_address::get_scope_id() const
{
return cobj()->sin6_scope_id;
}
void net6::ipv6_address::set_port(unsigned int port)
{
cobj()->sin6_port = htons(port);
}
void net6::ipv6_address::set_flowinfo(unsigned int flowinfo)
{
cobj()->sin6_flowinfo = flowinfo;
}
void net6::ipv6_address::set_scope_id(unsigned int scope_id)
{
cobj()->sin6_scope_id = scope_id;
}
syntax highlighted by Code2HTML, v. 0.9.1