Reputation: 308
I am maintaining an old system which runs fine on IPv4 format and i found out that the listener did not trigger when the requestor is coming from IPv6. I have the following line of code
SOCKADDR_IN SocketAddr;
INT nBufferSize=sizeof(SocketAddr);
hConnectSocket=WSAAccept(m_hListenSocket,(SOCKADDR *)&SocketAddr,&nBufferSize,NULL,NULL);
if (hConnectSocket==INVALID_SOCKET) return false;
I also googled and i know i should be using SOCKADDR_IN6 for IPv6. Is it possible to convert SOCKADDR_IN6 to SOCKADDR_IN format so that the rest of the application will work?
Thanks.
Upvotes: 1
Views: 1653
Reputation: 15277
I implemented some time ago a solution that can work with IPV4 and IPV6 addresses. I did even encapsulate that property from the outside world.
The rest of the program should only know about sockets. And if your code accepts an address in the IPV6 or IPV4 format does not really matter /after accepting).
The important point is that you need to specify the ai_family
with AF_UNSPEC
. Then it will handle both address families. And for the accept function, you can handover a parameter big enough to hold both address types.
I am not sure, but maybe that could help you.
Please see the following code snippet that I developed some years ago in C++98.
// The following structures are used in order to be independent from the internet address families
// e.g. IPV4 or IPV6. The basic original functions have been designed for IPV4 only.
// But now we are in the age of IPV6. And we need to have means to deal with both address types
// So we have one Data type, that can hold both IPV4 and IPV6 (because it has the length of the
// larger IPV6 address). The pointer of this structure can be casted to the original data type
// that the functions always expected.
// The first field in the structures denotes the IP Address Family
// This is the big storage that can hold either a IPV4 or a IPV6 address
typedef struct sockaddr_storage SocketAddressStorage;
// This Type can hold the length of the IP Address container
typedef socklen_t SocketAddressStorageLength;
// This type is the Socket Address that OS function expect. We will cast the pointer of the big
// data type to this one
typedef struct sockaddr SocketAddress;
// The next 2 are specific address containers for either IPV4 or IPV6.
// One of them will be a part of the big "struct sockaddr_storage"
typedef struct sockaddr_in SocketAddressInternetIPV4;
typedef struct sockaddr_in6 SocketAddressInternetIPV6;
// We use the big structure that can hold an IPV4 and IPV6 address
// because we do not know, who is contacting this node
SocketAddressStorage addressOfCommunicationPartner;
// Get the length of the above define data structure
SocketAddressStorageLength socketAddressStorageLength = sizeof(addressOfCommunicationPartner);
// Accept the connection request from a client
// handle is the filedescriptor bound to this node and listening for connection requests
// The function will return a new file descriptor for the connected socket. This is a specific socket
// for the just established connection. The handle will continue to listen for more connection requests
// So this is a factory. We are listening for connection requests and if we get one, we create a new
// file descriptor for the specific communication purposes
// The information of the foreign node will be put in the "addressOfCommunicationPartner"
// Accept the connection request from a client
//lint -e{740,929,1924}
const Handle connectionHandle = accept(handle, reinterpret_cast<SocketAddress *>(&addressOfCommunicationPartner), &socketAddressStorageLength);
// Check, if connection could be established and we have a valid file descriptor
if (connectionHandle > null<Handle>())
{
// Now we want to get the IP address of the partner. Can be IPv4 or IPv6
// The following old style C String can hold both IPv4 and IPv6 address strings
mchar ipAddressCString[INET6_ADDRSTRLEN+1];
// This is a pointer into the address structure of the communication partner
// It points either to sin_addr for IPv4 or sin6_addr for IPv6
const void *ipAddressPEitherV4orV6;
// This will contain the IP Version as a string
std::string ipVersion;
// Now check, what family, what type of IP adress we have
//lint -e{911,1960}
if (AF_INET == addressOfCommunicationPartner.ss_family)
{
// So, it is IPv4. Remember that
ipVersion = "IPv4";
// Get a pointer to the appropriate element of the struct, which contains IP address info. And this depending on the IP Family/Type
//lint --e{740,925,929} Yes indeed, an unusual pointer cast
ipAddressPEitherV4orV6 = static_cast<const void *>( &((reinterpret_cast<const SocketAddressInternetIPV4 *const>(&addressOfCommunicationPartner))->sin_addr) );
}
else
{
// It is IPv6. Remember that
ipVersion = "IPv6";
// Get a pointer to the appropriate element of the struct, which contains IP address info. And this depending on the IP Family/Type
//lint --e{740,925,929} Yes indeed, an unusual pointer cast
ipAddressPEitherV4orV6 = static_cast<const void *>( &((reinterpret_cast<const SocketAddressInternetIPV6 *const>(&addressOfCommunicationPartner))->sin6_addr) );
}
// Convert native IP address format to readable C-String
//lint -e{917,1960}
if (null<mchar *>() == inet_ntop(addressOfCommunicationPartner.ss_family, ipAddressPEitherV4orV6, ipAddressCString, sizeof(ipAddressCString)))
{
// If this did not work then we will not show any IP Address. We can live with that
ipAddressCString[0] = '\x0';
}
// Debug Output
{
static long i=1;
ui << "Connection accepted " << i << " " << ipVersion << " " << ipAddressCString << " " << machineNetworkAddressInfo.portNumberString << std::endl;
i++;
}
// So. The connection request was established. We gathered all information
// Create a new TCP connection
TcpConnectionBase *tcpConnectionBase =tcpConnectionFactory->createInstance(machineNetworkAddressInfo.portNumberString, connectionHandle);
// And put a pointer to it in our internal list of Tcp Connection
tcpConnection.push_back(tcpConnectionBase);
You may find the rest here
Upvotes: 0
Reputation: 65
You can't convert all IPv6 addresses to IPv4 - there are more IPv6 addresses than IPv4 addresses. The best way to tackle this issue is to update/upgrade your application so it understand and store IPv6 addresses. This thread might be useful.
Upvotes: 3