experimental IPv6 implementation (patch 1771429)

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@50061 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2007-11-18 20:53:33 +00:00
parent 559843f078
commit 8575ff507f
19 changed files with 797 additions and 173 deletions

View File

@@ -237,7 +237,7 @@ wxIPV6address::wxIPV6address()
}
wxIPV6address::wxIPV6address(const wxIPV6address& other)
: wxIPaddress(other)
: wxIPaddress(other), m_origHostname(other.m_origHostname)
{
}
@@ -252,68 +252,119 @@ bool wxIPV6address::Hostname(const wxString& name)
wxLogWarning( _("Trying to solve a NULL hostname: giving up") );
return false;
}
return (GAddress_INET_SetHostName(m_address, name.mb_str()) == GSOCK_NOERROR);
m_origHostname = name;
return (GAddress_INET6_SetHostName(m_address, name.mb_str()) == GSOCK_NOERROR);
}
bool wxIPV6address::Hostname(unsigned char[16] WXUNUSED(addr))
bool wxIPV6address::Hostname(unsigned char addr[16])
{
return true;
wxString name;
unsigned short wk[8];
for ( int i = 0; i < 8; ++i )
{
wk[i] = addr[2*i];
wk[i] <<= 8;
wk[i] |= addr[2*i+1];
}
name.Printf("%x:%x:%x:%x:%x:%x:%x:%x",
wk[0], wk[1], wk[2], wk[3], wk[4], wk[5], wk[6], wk[7]);
return Hostname(name);
}
bool wxIPV6address::Service(const wxString& name)
{
return (GAddress_INET_SetPortName(m_address, name.mb_str(), "tcp") == GSOCK_NOERROR);
return (GAddress_INET6_SetPortName(m_address, name.mb_str(), "tcp") == GSOCK_NOERROR);
}
bool wxIPV6address::Service(unsigned short port)
{
return (GAddress_INET_SetPort(m_address, port) == GSOCK_NOERROR);
return (GAddress_INET6_SetPort(m_address, port) == GSOCK_NOERROR);
}
bool wxIPV6address::LocalHost()
{
return (GAddress_INET_SetHostName(m_address, "localhost") == GSOCK_NOERROR);
return (GAddress_INET6_SetHostName(m_address, "localhost") == GSOCK_NOERROR);
}
bool wxIPV6address::IsLocalHost() const
{
return (Hostname() == wxT("localhost") || IPAddress() == wxT("127.0.0.1"));
if ( Hostname() == "localhost" )
return true;
wxString addr = IPAddress();
return addr == wxT("::1") ||
addr == wxT("0:0:0:0:0:0:0:1") ||
addr == wxT("::ffff:127.0.0.1");
}
bool wxIPV6address::BroadcastAddress()
{
return (GAddress_INET_SetBroadcastAddress(m_address) == GSOCK_NOERROR);
wxFAIL_MSG( "not implemented" );
return false;
}
bool wxIPV6address::AnyAddress()
{
return (GAddress_INET_SetAnyAddress(m_address) == GSOCK_NOERROR);
return (GAddress_INET6_SetAnyAddress(m_address) == GSOCK_NOERROR);
}
wxString wxIPV6address::IPAddress() const
{
unsigned long raw = GAddress_INET_GetHostAddress(m_address);
return wxString::Format(
_T("%u.%u.%u.%u"),
(unsigned char)((raw>>24) & 0xff),
(unsigned char)((raw>>16) & 0xff),
(unsigned char)((raw>>8) & 0xff),
(unsigned char)(raw & 0xff)
);
unsigned char addr[16];
GAddress_INET6_GetHostAddress(m_address,(in6_addr*)addr);
wxUint16 words[8];
int i,
prefix_zero_count = 0;
for ( i = 0; i < 8; ++i )
{
words[i] = addr[i*2];
words[i] <<= 8;
words[i] |= addr[i*2+1];
if ( i == prefix_zero_count && words[i] == 0 )
++prefix_zero_count;
}
wxString result;
if ( prefix_zero_count == 8 )
{
result = wxT( "::" );
}
else if ( prefix_zero_count == 6 && words[5] == 0xFFFF )
{
// IPv4 mapped
result.Printf("::ffff:%d.%d.%d.%d",
addr[12], addr[13], addr[14], addr[15]);
}
else // general case
{
result = ":";
for ( i = prefix_zero_count; i < 8; ++i )
{
result += wxString::Format(":%x", words[i]);
}
}
return result;
}
wxString wxIPV6address::Hostname() const
{
char hostname[1024];
hostname[0] = 0;
GAddress_INET_GetHostName(m_address, hostname, 1024);
if ( GAddress_INET6_GetHostName(m_address,
hostname,
WXSIZEOF(hostname)) != GSOCK_NOERROR )
return wxEmptyString;
return wxString::FromAscii(hostname);
}
unsigned short wxIPV6address::Service() const
{
return GAddress_INET_GetPort(m_address);
return GAddress_INET6_GetPort(m_address);
}
#endif // wxUSE_IPV6

View File

@@ -88,6 +88,13 @@
# define WX_SOCKLEN_T int
#endif
#if wxUSE_IPV6
typedef struct sockaddr_storage wxSockAddr;
#else
typedef struct sockaddr wxSockAddr;
#endif
/* Table of GUI-related functions. We must call them indirectly because
* of wxBase and GUI separation: */
@@ -181,7 +188,7 @@ GSocket::GSocket()
m_dobind = true;
m_initialRecvBufferSize = -1;
m_initialSendBufferSize = -1;
assert(gs_gui_functions);
/* Per-socket GUI-specific initialization */
m_ok = gs_gui_functions->Init_Socket(this);
@@ -301,7 +308,7 @@ GSocketError GSocket::SetPeer(GAddress *address)
GAddress *GSocket::GetLocal()
{
GAddress *address;
struct sockaddr addr;
wxSockAddr addr;
WX_SOCKLEN_T size = sizeof(addr);
GSocketError err;
@@ -318,7 +325,7 @@ GAddress *GSocket::GetLocal()
return NULL;
}
if (getsockname(m_fd, &addr, &size) == SOCKET_ERROR)
if (getsockname(m_fd, (sockaddr*)&addr, &size) == SOCKET_ERROR)
{
m_error = GSOCK_IOERR;
return NULL;
@@ -331,7 +338,7 @@ GAddress *GSocket::GetLocal()
return NULL;
}
if ((err = _GAddress_translate_from(address, &addr, size)) != GSOCK_NOERROR)
if ((err = _GAddress_translate_from(address, (sockaddr*)&addr, size)) != GSOCK_NOERROR)
{
GAddress_destroy(address);
m_error = err;
@@ -441,7 +448,7 @@ GSocketError GSocket::SetServer()
GSocket *GSocket::WaitConnection()
{
GSocket *connection;
struct sockaddr from;
wxSockAddr from;
WX_SOCKLEN_T fromlen = sizeof(from);
GSocketError err;
u_long arg = 1;
@@ -475,7 +482,7 @@ GSocket *GSocket::WaitConnection()
return NULL;
}
connection->m_fd = accept(m_fd, &from, &fromlen);
connection->m_fd = accept(m_fd, (sockaddr*)&from, &fromlen);
if (connection->m_fd == INVALID_SOCKET)
{
@@ -500,7 +507,7 @@ GSocket *GSocket::WaitConnection()
m_error = GSOCK_MEMERR;
return NULL;
}
err = _GAddress_translate_from(connection->m_peer, &from, fromlen);
err = _GAddress_translate_from(connection->m_peer, (sockaddr*)&from, fromlen);
if (err != GSOCK_NOERROR)
{
GAddress_destroy(connection->m_peer);
@@ -1164,12 +1171,12 @@ int GSocket::Recv_Stream(char *buffer, int size)
int GSocket::Recv_Dgram(char *buffer, int size)
{
struct sockaddr from;
wxSockAddr from;
WX_SOCKLEN_T fromlen = sizeof(from);
int ret;
GSocketError err;
ret = recvfrom(m_fd, buffer, size, 0, &from, &fromlen);
ret = recvfrom(m_fd, buffer, size, 0, (sockaddr*)&from, &fromlen);
if (ret == SOCKET_ERROR)
return SOCKET_ERROR;
@@ -1184,7 +1191,7 @@ int GSocket::Recv_Dgram(char *buffer, int size)
return -1;
}
}
err = _GAddress_translate_from(m_peer, &from, fromlen);
err = _GAddress_translate_from(m_peer, (sockaddr*)&from, fromlen);
if (err != GSOCK_NOERROR)
{
GAddress_destroy(m_peer);
@@ -1352,7 +1359,7 @@ GSocketError _GAddress_translate_from(GAddress *address,
case AF_UNIX:
address->m_family = GSOCK_UNIX;
break;
#ifdef AF_INET6
#if wxUSE_IPV6
case AF_INET6:
address->m_family = GSOCK_INET6;
break;
@@ -1579,6 +1586,175 @@ unsigned short GAddress_INET_GetPort(GAddress *address)
return ntohs(addr->sin_port);
}
#if wxUSE_IPV6
/*
* -------------------------------------------------------------------------
* Internet IPv6 address family
* -------------------------------------------------------------------------
*/
#include "ws2tcpip.h"
#ifdef __VISUALC__
#pragma comment(lib,"ws2_32")
#endif // __VISUALC__
GSocketError _GAddress_Init_INET6(GAddress *address)
{
struct in6_addr any_address = IN6ADDR_ANY_INIT;
address->m_len = sizeof(struct sockaddr_in6);
address->m_addr = (struct sockaddr *) malloc(address->m_len);
if (address->m_addr == NULL)
{
address->m_error = GSOCK_MEMERR;
return GSOCK_MEMERR;
}
memset(address->m_addr,0,address->m_len);
address->m_family = GSOCK_INET6;
address->m_realfamily = AF_INET6;
((struct sockaddr_in6 *)address->m_addr)->sin6_family = AF_INET6;
((struct sockaddr_in6 *)address->m_addr)->sin6_addr = any_address;
return GSOCK_NOERROR;
}
GSocketError GAddress_INET6_SetHostName(GAddress *address, const char *hostname)
{
assert(address != NULL);
CHECK_ADDRESS(address, INET6);
addrinfo hints;
memset( & hints, 0, sizeof( hints ) );
hints.ai_family = AF_INET6;
addrinfo * info = 0;
if ( getaddrinfo( hostname, "0", & hints, & info ) || ! info )
{
address->m_error = GSOCK_NOHOST;
return GSOCK_NOHOST;
}
memcpy( address->m_addr, info->ai_addr, info->ai_addrlen );
freeaddrinfo( info );
return GSOCK_NOERROR;
}
GSocketError GAddress_INET6_SetAnyAddress(GAddress *address)
{
assert(address != NULL);
CHECK_ADDRESS(address, INET6);
struct in6_addr addr;
memset( & addr, 0, sizeof( addr ) );
return GAddress_INET6_SetHostAddress(address, addr);
}
GSocketError GAddress_INET6_SetHostAddress(GAddress *address,
struct in6_addr hostaddr)
{
assert(address != NULL);
CHECK_ADDRESS(address, INET6);
((struct sockaddr_in6 *)address->m_addr)->sin6_addr = hostaddr;
return GSOCK_NOERROR;
}
GSocketError GAddress_INET6_SetPortName(GAddress *address, const char *port,
const char *protocol)
{
struct servent *se;
struct sockaddr_in6 *addr;
assert(address != NULL);
CHECK_ADDRESS(address, INET6);
if (!port)
{
address->m_error = GSOCK_INVPORT;
return GSOCK_INVPORT;
}
se = getservbyname(port, protocol);
if (!se)
{
if (isdigit(port[0]))
{
int port_int;
port_int = atoi(port);
addr = (struct sockaddr_in6 *)address->m_addr;
addr->sin6_port = htons((u_short) port_int);
return GSOCK_NOERROR;
}
address->m_error = GSOCK_INVPORT;
return GSOCK_INVPORT;
}
addr = (struct sockaddr_in6 *)address->m_addr;
addr->sin6_port = se->s_port;
return GSOCK_NOERROR;
}
GSocketError GAddress_INET6_SetPort(GAddress *address, unsigned short port)
{
struct sockaddr_in6 *addr;
assert(address != NULL);
CHECK_ADDRESS(address, INET6);
addr = (struct sockaddr_in6 *)address->m_addr;
addr->sin6_port = htons(port);
return GSOCK_NOERROR;
}
GSocketError GAddress_INET6_GetHostName(GAddress *address, char *hostname, size_t sbuf)
{
struct hostent *he;
char *addr_buf;
struct sockaddr_in6 *addr;
assert(address != NULL);
CHECK_ADDRESS(address, INET6);
addr = (struct sockaddr_in6 *)address->m_addr;
addr_buf = (char *)&(addr->sin6_addr);
he = gethostbyaddr(addr_buf, sizeof(addr->sin6_addr), AF_INET6);
if (he == NULL)
{
address->m_error = GSOCK_NOHOST;
return GSOCK_NOHOST;
}
strncpy(hostname, he->h_name, sbuf);
return GSOCK_NOERROR;
}
GSocketError GAddress_INET6_GetHostAddress(GAddress *address,struct in6_addr *hostaddr)
{
assert(address != NULL);
assert(hostaddr != NULL);
CHECK_ADDRESS_RETVAL(address, INET6, GSOCK_INVADDR);
*hostaddr = ( (struct sockaddr_in6 *)address->m_addr )->sin6_addr;
return GSOCK_NOERROR;
}
unsigned short GAddress_INET6_GetPort(GAddress *address)
{
assert(address != NULL);
CHECK_ADDRESS_RETVAL(address, INET6, 0);
return ntohs( ((struct sockaddr_in6 *)address->m_addr)->sin6_port );
}
#endif // wxUSE_IPV6
/*
* -------------------------------------------------------------------------
* Unix address family

View File

@@ -450,6 +450,12 @@ struct servent *wxGetservbyname_r(const char *port, const char *protocol,
# define GSocket_Debug(args)
#endif /* __GSOCKET_DEBUG__ */
#if wxUSE_IPV6
typedef struct sockaddr_storage wxSockAddr;
#else
typedef struct sockaddr wxSockAddr;
#endif
/* Table of GUI-related functions. We must call them indirectly because
* of wxBase and GUI separation: */
@@ -678,7 +684,7 @@ GSocketError GSocket::SetPeer(GAddress *address)
GAddress *GSocket::GetLocal()
{
GAddress *address;
struct sockaddr addr;
wxSockAddr addr;
WX_SOCKLEN_T size = sizeof(addr);
GSocketError err;
@@ -695,7 +701,7 @@ GAddress *GSocket::GetLocal()
return NULL;
}
if (getsockname(m_fd, &addr, (WX_SOCKLEN_T *) &size) < 0)
if (getsockname(m_fd, (sockaddr*)&addr, (WX_SOCKLEN_T *) &size) < 0)
{
m_error = GSOCK_IOERR;
return NULL;
@@ -709,7 +715,7 @@ GAddress *GSocket::GetLocal()
return NULL;
}
err = _GAddress_translate_from(address, &addr, size);
err = _GAddress_translate_from(address, (sockaddr*)&addr, size);
if (err != GSOCK_NOERROR)
{
GAddress_destroy(address);
@@ -827,7 +833,7 @@ GSocketError GSocket::SetServer()
*/
GSocket *GSocket::WaitConnection()
{
struct sockaddr from;
wxSockAddr from;
WX_SOCKLEN_T fromlen = sizeof(from);
GSocket *connection;
GSocketError err;
@@ -859,7 +865,7 @@ GSocket *GSocket::WaitConnection()
return NULL;
}
connection->m_fd = accept(m_fd, &from, (WX_SOCKLEN_T *) &fromlen);
connection->m_fd = accept(m_fd, (sockaddr*)&from, (WX_SOCKLEN_T *) &fromlen);
/* Reenable CONNECTION events */
Enable(GSOCK_CONNECTION);
@@ -888,7 +894,7 @@ GSocket *GSocket::WaitConnection()
return NULL;
}
err = _GAddress_translate_from(connection->m_peer, &from, fromlen);
err = _GAddress_translate_from(connection->m_peer, (sockaddr*)&from, fromlen);
if (err != GSOCK_NOERROR)
{
delete connection;
@@ -1673,7 +1679,7 @@ int GSocket::Recv_Stream(char *buffer, int size)
int GSocket::Recv_Dgram(char *buffer, int size)
{
struct sockaddr from;
wxSockAddr from;
WX_SOCKLEN_T fromlen = sizeof(from);
int ret;
GSocketError err;
@@ -1682,7 +1688,7 @@ int GSocket::Recv_Dgram(char *buffer, int size)
do
{
ret = recvfrom(m_fd, buffer, size, 0, &from, (WX_SOCKLEN_T *) &fromlen);
ret = recvfrom(m_fd, buffer, size, 0, (sockaddr*)&from, (WX_SOCKLEN_T *) &fromlen);
}
while (ret == -1 && errno == EINTR); /* Loop until not interrupted */
@@ -1700,7 +1706,7 @@ int GSocket::Recv_Dgram(char *buffer, int size)
}
}
err = _GAddress_translate_from(m_peer, &from, fromlen);
err = _GAddress_translate_from(m_peer, (sockaddr*)&from, fromlen);
if (err != GSOCK_NOERROR)
{
GAddress_destroy(m_peer);
@@ -1989,11 +1995,11 @@ GSocketError _GAddress_translate_from(GAddress *address,
case AF_UNIX:
address->m_family = GSOCK_UNIX;
break;
#ifdef AF_INET6
#if wxUSE_IPV6
case AF_INET6:
address->m_family = GSOCK_INET6;
break;
#endif
#endif // wxUSE_IPV6
default:
{
address->m_error = GSOCK_INVOP;
@@ -2256,6 +2262,169 @@ unsigned short GAddress_INET_GetPort(GAddress *address)
return ntohs(addr->sin_port);
}
#if wxUSE_IPV6
/*
* -------------------------------------------------------------------------
* Internet IPv6 address family
* -------------------------------------------------------------------------
*/
GSocketError _GAddress_Init_INET6(GAddress *address)
{
struct in6_addr any_address = IN6ADDR_ANY_INIT;
address->m_len = sizeof(struct sockaddr_in6);
address->m_addr = (struct sockaddr *) malloc(address->m_len);
if (address->m_addr == NULL)
{
address->m_error = GSOCK_MEMERR;
return GSOCK_MEMERR;
}
memset(address->m_addr,0,address->m_len);
address->m_family = GSOCK_INET6;
address->m_realfamily = AF_INET6;
((struct sockaddr_in6 *)address->m_addr)->sin6_family = AF_INET6;
((struct sockaddr_in6 *)address->m_addr)->sin6_addr = any_address;
return GSOCK_NOERROR;
}
GSocketError GAddress_INET6_SetHostName(GAddress *address, const char *hostname)
{
assert(address != NULL);
CHECK_ADDRESS(address, INET6);
addrinfo hints;
memset( & hints, 0, sizeof( hints ) );
hints.ai_family = AF_INET6;
addrinfo * info = 0;
if ( getaddrinfo( hostname, "0", & hints, & info ) || ! info )
{
address->m_error = GSOCK_NOHOST;
return GSOCK_NOHOST;
}
memcpy( address->m_addr, info->ai_addr, info->ai_addrlen );
freeaddrinfo( info );
return GSOCK_NOERROR;
}
GSocketError GAddress_INET6_SetAnyAddress(GAddress *address)
{
assert(address != NULL);
CHECK_ADDRESS(address, INET6);
struct in6_addr addr;
memset( & addr, 0, sizeof( addr ) );
return GAddress_INET6_SetHostAddress(address, addr);
}
GSocketError GAddress_INET6_SetHostAddress(GAddress *address,
struct in6_addr hostaddr)
{
assert(address != NULL);
CHECK_ADDRESS(address, INET6);
((struct sockaddr_in6 *)address->m_addr)->sin6_addr = hostaddr;
return GSOCK_NOERROR;
}
GSocketError GAddress_INET6_SetPortName(GAddress *address, const char *port,
const char *protocol)
{
struct servent *se;
struct sockaddr_in6 *addr;
assert(address != NULL);
CHECK_ADDRESS(address, INET6);
if (!port)
{
address->m_error = GSOCK_INVPORT;
return GSOCK_INVPORT;
}
se = getservbyname(port, protocol);
if (!se)
{
if (isdigit(port[0]))
{
int port_int;
port_int = atoi(port);
addr = (struct sockaddr_in6 *)address->m_addr;
addr->sin6_port = htons((u_short) port_int);
return GSOCK_NOERROR;
}
address->m_error = GSOCK_INVPORT;
return GSOCK_INVPORT;
}
addr = (struct sockaddr_in6 *)address->m_addr;
addr->sin6_port = se->s_port;
return GSOCK_NOERROR;
}
GSocketError GAddress_INET6_SetPort(GAddress *address, unsigned short port)
{
struct sockaddr_in6 *addr;
assert(address != NULL);
CHECK_ADDRESS(address, INET6);
addr = (struct sockaddr_in6 *)address->m_addr;
addr->sin6_port = htons(port);
return GSOCK_NOERROR;
}
GSocketError GAddress_INET6_GetHostName(GAddress *address, char *hostname, size_t sbuf)
{
struct hostent *he;
char *addr_buf;
struct sockaddr_in6 *addr;
assert(address != NULL);
CHECK_ADDRESS(address, INET6);
addr = (struct sockaddr_in6 *)address->m_addr;
addr_buf = (char *)&(addr->sin6_addr);
he = gethostbyaddr(addr_buf, sizeof(addr->sin6_addr), AF_INET6);
if (he == NULL)
{
address->m_error = GSOCK_NOHOST;
return GSOCK_NOHOST;
}
strncpy(hostname, he->h_name, sbuf);
return GSOCK_NOERROR;
}
GSocketError GAddress_INET6_GetHostAddress(GAddress *address,struct in6_addr *hostaddr)
{
assert(address != NULL);
assert(hostaddr != NULL);
CHECK_ADDRESS_RETVAL(address, INET6, GSOCK_INVADDR);
*hostaddr = ( (struct sockaddr_in6 *)address->m_addr )->sin6_addr;
return GSOCK_NOERROR;
}
unsigned short GAddress_INET6_GetPort(GAddress *address)
{
assert(address != NULL);
CHECK_ADDRESS_RETVAL(address, INET6, 0);
return ntohs( ((struct sockaddr_in6 *)address->m_addr)->sin6_port );
}
#endif // wxUSE_IPV6
/*
* -------------------------------------------------------------------------
* Unix address family