I am learning how to use Winsock. I am programming a server that listens for a connection. Everything worked fine until I wanted to change the whole code over to IPv6.
I've gone through every question and website related to this topic, but no solution suited me... :/
Background: Windows, using Visual Studio 2019, IPv6 is activated and working all fine otherwise (I can ping my phone in IPv6 for example).
Every time I get error 10049. This one tells me that the given IP is invalid. I tried every one I could find in ipconfig and ::1.
int slisten;
long res;
SOCKET client;
WSADATA wsaData;
res = WSAStartup(MAKEWORD(2, 1), &wsaData);
if (res == 0)
cout << "WSAStartup()\t\t successful" << endl;
else
cout << "error WSAStartup(): " << WSAGetLastError() << endl;
slisten = socket(PF_INET6, SOCK_STREAM, 0);
if (slisten != INVALID_SOCKET)
cout << "socket() \t\t successful" << endl;
else
cout << "error socket(): " << WSAGetLastError() << endl;
//IPv6
struct sockaddr_in6 ip6addr;
ip6addr.sin6_family = AF_INET6;
ip6addr.sin6_port = htons(55339);
inet_pton(AF_INET6, "::1", &ip6addr.sin6_addr);
res = bind(slisten, (struct sockaddr*) & ip6addr, sizeof ip6addr);
if (res == SOCKET_ERROR)
{
wprintf(L"bind function failed with error: %d\n", WSAGetLastError());
}
/* IPv4, not in use
struct sockaddr_in ip4addr;
ip4addr.sin_family = AF_INET;
ip4addr.sin_port = htons(3490);
inet_pton(AF_INET, "127.0.0.1", &ip4addr.sin_addr);
res = bind(slisten, (struct sockaddr*) & ip4addr, sizeof ip4addr);
if (res == SOCKET_ERROR)
{
wprintf(L"bind function failed with error: %d\n", WSAGetLastError());
}
*/
The IPv4 method works, but the IPv6 doesn't.
WSAStartup() = Success
socket() = Success
bind() = Error 10049
If I comment out the IPv6 part and uncomment the IPv4 part, and change PF_INET6 to PF_INET in slisten = socket(), there is no bind() error.
Tell me if you need more code or something, but I mean, if the program throws in an error at that specific function, everything until then must work fine because there are no errors (?).
Some parts of the code belong to s41b0tproductions on YouTube. You can find him at https://www.youtube.com/user/s41b0tproductions/videos.
-
Read the documentation carefully, it tells you how to check for errors and how to retrieve further error info. This error code can also be mapped to a string, both with a utility or programmatically. With that in mind, extract a minimal reproducible example from your code for posting here. As a new user, also take the tour and read How to Ask.Ulrich Eckhardt– Ulrich Eckhardt2019年10月02日 17:20:35 +00:00Commented Oct 2, 2019 at 17:20
1 Answer 1
When calling socket(), PF_INET/PF_INET6 should be AF_INET/AF_INET6 instead. But this generally doesn't matter as the PF_... and AF_... macros usually map to the same numeric values.
But, more importantly, you are not zeroing out the sockaddr_in/sockadr_in6 structs before filling them in. You should always zero out Win32 API structs before using them. For AF_INET, you are not populating the sockaddr_in::sin_zero field with zeros, so it will contain random bytes from the call stack. Which is usually OK since that field is generally ignored. But for AF_INET6, you are not populating the sockaddr_in6::sin6_flowinfo and sockaddr_in6::sin6_scope_id fields, which do have meaning, and is likely the root cause of your WSAEADDRNOTAVAIL error when they contain random values.
Use this instead:
struct sockaddr_in6 ip6addr = {};
struct sockaddr_in ip4addr = {};
Or:
struct sockaddr_in6 ip6addr;
ZeroMemory(&ip6addr, sizeof ip6addr);
struct sockaddr_in ip4addr;
ZeroMemory(&ip4addr, sizeof ip4addr);
However, a better way to create properly filled sockaddr_in/sockaddr_in6 structs for bind() (and connect()) is to use getaddrinfo() instead of filling them manually:
const char szHost = "::1"; // or "127.0.0.1"
const char *szPort = "55339";
addrinfo hint = {};
hint.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
hint.ai_family = AF_INET6; // or AF_INET
hint.ai_socktype = SOCK_STREAM;
hint.ai_protocol = IPPROTO_TCP;
addrinfo *addr = NULL;
res = getaddrinfo(szHost, szPort, &hint, &addr);
if (res != 0)
{
wprintf(L"getaddrinfo function failed with error: %d\n", res);
}
else
{
res = bind(slisten, addr->ai_addr, addr->ai_addrlen);
if (res == SOCKET_ERROR)
{
wprintf(L"bind function failed with error: %d\n", WSAGetLastError());
}
freeaddrinfo(addr);
}