So, I am on Windows 10, and using latest MINGW64 from MSYS2:
$ uname -a
MINGW64_NT-10.0-19043 DESKTOP-XXXXXXX 3.2.0-340.x86_64 2021-08-02 16:30 UTC x86_64 Msys
I have experiencing something strange with Winsock bind, which I can now reconstruct on a minimal working example, which is a basic server code from Winsock Server And Client Example: "getaddrinfo" was not declared in this scope , that I saved as test.cpp
(EDIT: code is now with printout, EDIT2: and with input argument):
#undef UNICODE
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
// Need to link with Ws2_32.lib
#pragma comment (lib, "Ws2_32.lib")
// #pragma comment (lib, "Mswsock.lib")
#define DEFAULT_BUFLEN 512
//~ #define DEFAULT_PORT "27015"
#define DEFAULT_PORT "9010"
void print_getaddrinfo_response(struct addrinfo *result);
int __cdecl main(int argc, char **argv)
{
WSADATA wsaData;
int iResult;
SOCKET ListenSocket = INVALID_SOCKET;
SOCKET ClientSocket = INVALID_SOCKET;
struct addrinfo *result = NULL;
struct addrinfo hints;
char defaultport[8];
int iSendResult;
char recvbuf[DEFAULT_BUFLEN];
int recvbuflen = DEFAULT_BUFLEN;
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed with error: %d\n", iResult);
return 1;
}
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
// here, argc==1 for no arguments
if (argc==2) {
snprintf( defaultport, 8, "%s", argv[1] );
} else {
snprintf( defaultport, 8, "%s", DEFAULT_PORT );
}
printf("Listening on port: %s ...", defaultport);
// Resolve the server address and port
iResult = getaddrinfo(NULL, defaultport, &hints, &result);
if ( iResult != 0 ) {
printf("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
return 1;
}
//print_getaddrinfo_response(result);
// Create a SOCKET for connecting to server
ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (ListenSocket == INVALID_SOCKET) {
printf("socket failed with error: %ld\n", WSAGetLastError());
freeaddrinfo(result);
WSACleanup();
return 1;
}
// Setup the TCP listening socket
iResult = bind( ListenSocket, result->ai_addr, (int)result->ai_addrlen);
if (iResult == SOCKET_ERROR) {
printf("bind failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
WSACleanup();
return 1;
}
freeaddrinfo(result);
iResult = listen(ListenSocket, SOMAXCONN);
if (iResult == SOCKET_ERROR) {
printf("listen failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
if (argc==2) { // exit immediately
printf(" exiting\n");
closesocket(ListenSocket);
WSACleanup();
return 0;
}
// Accept a client socket
ClientSocket = accept(ListenSocket, NULL, NULL);
if (ClientSocket == INVALID_SOCKET) {
printf("accept failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
// No longer need server socket
closesocket(ListenSocket);
// Receive until the peer shuts down the connection
do {
iResult = recv(ClientSocket, recvbuf, recvbuflen, 0);
if (iResult > 0) {
printf("Bytes received: %d\n", iResult);
// Echo the buffer back to the sender
iSendResult = send( ClientSocket, recvbuf, iResult, 0 );
if (iSendResult == SOCKET_ERROR) {
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
printf("Bytes sent: %d\n", iSendResult);
}
else if (iResult == 0)
printf("Connection closing...\n");
else {
printf("recv failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
} while (iResult > 0);
// shutdown the connection since we're done
iResult = shutdown(ClientSocket, SD_SEND);
if (iResult == SOCKET_ERROR) {
printf("shutdown failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
// cleanup
closesocket(ClientSocket);
WSACleanup();
return 0;
}
void print_getaddrinfo_response(struct addrinfo *result) {
// from https://learn.microsoft.com/en-us/windows/win32/api/ws2def/ns-ws2def-addrinfoa
INT iRetval;
int i = 1;
struct addrinfo *ptr = NULL;
struct sockaddr_in *sockaddr_ipv4;
LPSOCKADDR sockaddr_ip;
char ipstringbuffer[46];
DWORD ipbufferlength = 46;
// Retrieve each address and print out the hex bytes
for(ptr=result; ptr != NULL ;ptr=ptr->ai_next) {
printf("getaddrinfo response %d\n", i++);
printf("\tFlags: 0x%x\n", ptr->ai_flags);
printf("\tFamily: ");
switch (ptr->ai_family) {
case AF_UNSPEC:
printf("Unspecified\n");
break;
case AF_INET:
printf("AF_INET (IPv4)\n");
sockaddr_ipv4 = (struct sockaddr_in *) ptr->ai_addr;
printf("\tIPv4 address %s\n",
inet_ntoa(sockaddr_ipv4->sin_addr) );
break;
case AF_INET6:
printf("AF_INET6 (IPv6)\n");
// the InetNtop function is available on Windows Vista and later
// sockaddr_ipv6 = (struct sockaddr_in6 *) ptr->ai_addr;
// printf("\tIPv6 address %s\n",
// InetNtop(AF_INET6, &sockaddr_ipv6->sin6_addr, ipstringbuffer, 46) );
// We use WSAAddressToString since it is supported on Windows XP and later
sockaddr_ip = (LPSOCKADDR) ptr->ai_addr;
// The buffer length is changed by each call to WSAAddresstoString
// So we need to set it for each iteration through the loop for safety
ipbufferlength = 46;
iRetval = WSAAddressToString(sockaddr_ip, (DWORD) ptr->ai_addrlen, NULL,
ipstringbuffer, &ipbufferlength );
if (iRetval)
printf("WSAAddressToString failed with %u\n", WSAGetLastError() );
else
printf("\tIPv6 address %s\n", ipstringbuffer);
break;
case AF_NETBIOS:
printf("AF_NETBIOS (NetBIOS)\n");
break;
default:
printf("Other %ld\n", ptr->ai_family);
break;
}
printf("\tSocket type: ");
switch (ptr->ai_socktype) {
case 0:
printf("Unspecified\n");
break;
case SOCK_STREAM:
printf("SOCK_STREAM (stream)\n");
break;
case SOCK_DGRAM:
printf("SOCK_DGRAM (datagram) \n");
break;
case SOCK_RAW:
printf("SOCK_RAW (raw) \n");
break;
case SOCK_RDM:
printf("SOCK_RDM (reliable message datagram)\n");
break;
case SOCK_SEQPACKET:
printf("SOCK_SEQPACKET (pseudo-stream packet)\n");
break;
default:
printf("Other %ld\n", ptr->ai_socktype);
break;
}
printf("\tProtocol: ");
switch (ptr->ai_protocol) {
case 0:
printf("Unspecified\n");
break;
case IPPROTO_TCP:
printf("IPPROTO_TCP (TCP)\n");
break;
case IPPROTO_UDP:
printf("IPPROTO_UDP (UDP) \n");
break;
default:
printf("Other %ld\n", ptr->ai_protocol);
break;
}
printf("\tLength of this sockaddr: %d\n", ptr->ai_addrlen);
printf("\tCanonical name: %s\n", ptr->ai_canonname);
}
}
This I compile in MINGW64:
$ g++ test.cpp -g -o test.exe -lws2_32
... and as far as building goes, it compiles without a problem. But when running:
- When you have the code as in the original linked post, with
#define DEFAULT_PORT "27015"
, then there is no problem, and code works - I'm running it fromcmd.exe
:
D:\>test.exe
getaddrinfo response 1
Flags: 0x0
Family: AF_INET (IPv4)
IPv4 address 0.0.0.0
Socket type: SOCK_STREAM (stream)
Protocol: IPPROTO_TCP (TCP)
Length of this sockaddr: 16
Canonical name: (null)
Bytes received: 7
Bytes sent: 7
Connection closing...
... and the above happens in response to triggering it with telnet (which I call from the MINGW64 bash
shell):
$ telnet 127.0.0.1 27015
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
hello
hello
↔
telnet> q
Connection closed.
- When you have the code as in this post, that is, with
#define DEFAULT_PORT "9010"
, it compiles fine; but then when I try to run it,it exits immediately:
D:\>test.exe
getaddrinfo response 1
Flags: 0x0
Family: AF_INET (IPv4)
IPv4 address 0.0.0.0
Socket type: SOCK_STREAM (stream)
Protocol: IPPROTO_TCP (TCP)
Length of this sockaddr: 16
Canonical name: (null)
bind failed with error: 10013
Now, Socket error 10013 is a message which implies that a port is blocked and/or unreachable - which I guess means, port 9010 is blocked somehow?!
But, so far, I cannot confirm that this port is blocked in any way:
Querying the firewall (in administrative command prompt) on the test.exe
program gives me:
D:\>netsh firewall show config | findstr test
Enable Inbound test / D:\test.exe
... which I guess means, it is allowed to have incoming connections?
D:\>netsh firewall show config | findstr 9010
D:\>
The above returns nothing, so port 9010 seems to be not explicitly mentioned in firewall.
And querying for open listening port 9010 (as in, if there is a hanging process in the background, preventing test.exe to start up), also returns nothing:
D:\>netstat -a -n | findstr 9010
D:\>
So, how in the world can I debug, and find out/confirm, why is port 9010 in this application inaccessible - but port 27015 works fine ?!
EDIT: I've added printouts in response to comment:
The
getaddrinfo
function can return a list of results
... and here, it seems, it returns only one - for address 0.0.0.0
Also, I agree with:
you are using a port that someone doesn't want you using.
... and, in essence, I'd like to find out what is that someone that doesn't want me using port 9010 - especially since when I try the above commands, I do not get any message, that anything is using port 9010.
EDIT2: The code can now accept the port via input argument, and if that is the case, it exits immediately (so, all the notes about recompiling and calling, still work).
That means, now I can call a loop like this:
$ for i in $(seq 8080 11000); do ./test.exe $i; done
Listening on port: 8080 ... exiting
Listening on port: 8081 ... exiting
Listening on port: 8082 ... exiting
...
Listening on port: 8818 ... exiting
Listening on port: 8819 ... exiting
Listening on port: 8820 ...bind failed with error: 10013
Listening on port: 8821 ...bind failed with error: 10013
...
Using this technique, I have so far found, that this program cannot bind to ports 8820:9519 [diff 700], 9676:9875 [diff 200] ... and probably others.
The question is: why exactly these ranges fail and not others, and how can I confirm that using any Windows application (GUI or command line?)