0

I have written a simple client/server application using winsock. The server and client connect and communicate over TCP port 76567 (just a random number I chose) on the localhost. I've tested it on three desktops, two running XP and the other running Win7, I've also tested it on four laptops, three running Win7 and one running XP. The application works fine on all the desktop machines and on the XP laptop, but on all three Win7 laptops I get Error 10061 when the client tries to connect to the server!

I've turned off the firewall but the problem persists, I've also looked around to see what causes this error and it looks like the client is trying to connect to a non-listening server. However, the server call to listen() returns succesfully! It's very odd that the problem only seems to happen on Win7 laptops, any ideas?

Here's my socket initialisation code:

// Initialise Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if(iResult != 0)
{
    printf("WSAStartup failed: %d\n", iResult);
}

// Create a server socket
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;

iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
if(iResult != 0)
{
    printf("getaddrinfo failed: %d\n", iResult);
    WSACleanup();
}

// Create a socket to listen for clients
listenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if(listenSocket == INVALID_SOCKET)
{
    printf("Error at socket(): %d\n", WSAGetLastError());

    freeaddrinfo(result);
    WSACleanup();
}

// Bind socket to ip address and port
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();
}
freeaddrinfo(result);

// Listen for connection requests
if(listen(listenSocket, SOMAXCONN) != 0)
{
    printf("Listen failed with error: %d\n", WSAGetLastError());

    closesocket(listenSocket);
    WSACleanup();
}

Many thanks :)

StackTrace
  • 41
  • 1
  • 2
  • 3
  • 1
    What antivirus app is running on the laptops? – Martin James Apr 27 '12 at 12:36
  • Just standard windows security stuff, although one of the laptops has Spybot on it. I don't think this is the problem though, because the desktops have Kaspersky or Norton running on them and I have no trouble with these machines. – StackTrace Apr 27 '12 at 15:03
  • Can you please show the client code? How is it determining which IP/Port to connect to? – Remy Lebeau Apr 28 '12 at 00:24

2 Answers2

2

IP port is 16-bit integer, therefore the maximum allowed port number is 0xFFFF (65535). What happens here is kind of integer overflow. Since your desired port number (76567) does not fit into 16 bits, the number is truncated and only lowest 16 bits are used. This gives you port number 11031. The line addr.sin_port = htons(76567); should give you a compiler warning since argument to htons() cannot fin into uint16_t.

Andrey
  • 1,561
  • 9
  • 12
0

getaddrinfo() returns a linked list of all available addresses for the given hints criteria. Even if the machine only has one network adapter, it could have multiple IP addresses assigned to it, even for localhost. You are binding the server socket to the first IP/Port pair that getaddrinfo() found, so it is possible that the client could be trying to connect to a different IP/Port that really is not listening on the server, for instance if the server bound to your LAN/Internet IP but the client is connecting to 127.0.0.1 instead. A client cannot connect to 127.0.0.1 unless the server is bound to 127.0.0.1.

In a multi-homed/multi-IP environment, you should use the wildcard 0.0.0.0 IP (aka INADDR_ANY) when calling bind(), instead of result->ai_addr. That will bind the socket to all available IPs of all installed network adapters. That way, the client can connect to any IP the server is bound to, including 127.0.0.1. In fact, given the code you have shown, you don't even need to use getaddrinfo() at all:

// Initialise Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if(iResult != 0)
{
    printf("WSAStartup failed: %d\n", iResult);
}

// Create an IPv4 server socket to listen for IPv4 clients
listenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(listenSocket == INVALID_SOCKET)
{
    printf("Error at socket(): %d\n", WSAGetLastError());
    WSACleanup();
}

// Bind socket to IPv4 address and port
sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(76567);
addr.sin_addr.s_addr = INADDR_ANY;

iResult = bind(listenSocket, (sockaddr*)&addr, sizeof(addr));
if(iResult == SOCKET_ERROR)
{
    printf("bind failed with error: %d\n", WSAGetLastError());
    closesocket(listenSocket);
    WSACleanup();
}

// Listen for IPv4 connection requests
if(listen(listenSocket, SOMAXCONN) != 0)
{
    printf("Listen failed with error: %d\n", WSAGetLastError());
    closesocket(listenSocket);
    WSACleanup();
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Good idea, I tried it but I get the same problem. Works fine on the desktop, but not on win7 laptops. Thanks for the suggestion Remy :) – StackTrace May 01 '12 at 10:53
  • Then use the command-line `netstat` tool, or SysInternal's TCPView tool, to verify that the server is actually listening on the IP/Port that the client is trying to connect to, and then make sure the client is actually trying to connect to the IP/Port you think it should be connecting to. – Remy Lebeau May 01 '12 at 22:35
  • Had a quick look on TCPView and it shows this: Protocol: TCP Local Address: Local Port: 11031 Remote Address: Remote Port: 0 Status: LISTENING The thing that confuses me is that I set the port to 76567. But neither the local or remote port is set to this. Thanks again Remy. – StackTrace May 08 '12 at 10:27
  • 11031 is 0x2B17 and 76567 is 0x12B17. Notice a similarity? Make sure you are assigning the port correctly. – Remy Lebeau May 08 '12 at 18:07
  • I think I'm assigning the port correctly `addr.sin_port = htons(76567);` However, I'm using MingGW, could this be some kind of cross-compiling problem, or even an incompatibility in MinGW's htons function? It's quite an annoying setup. I'm using Qt + MinGW for the server and Visual Studio for the clients (not my choice, I'm having to work with legacy code :( ) – StackTrace May 09 '12 at 10:42
  • OMG, what an idiot! 76567 > 65536!! Hence the truncation in Hex 0x12B17 to 0x2B17. Changed to port number 10000 but still get the same error! It works fine on desktops running XP and Win7 and works on laptops running XP but I get error 10061 on win7 laptops?!? I can confirm that the server connects and is listening on port 10000 and windows firewall is turned off. I'm so confused by this error! – StackTrace May 09 '12 at 15:14
  • If you run `netstat -a`, do you see Local Address `0.0.0.0:10000` listed and in a `LISTENING` state? – Remy Lebeau May 09 '12 at 18:21
  • If so, and you still cannot connect to it, then something other than the Windows Firewall is blocking the connection, such as an anti-virus/anti-malware app, or a bad networking driver, or something. – Remy Lebeau May 09 '12 at 18:29
  • `netstat -a` shows `Local Address 0.0.0.0:10000` and `State LISTENING`. Shouldn't it say `127.0.0.1:10000`? I'm going to find and turn off any security software to see if I can find whats blocking that port. Thanks for the help Remy, really appreciate it :) – StackTrace May 10 '12 at 08:51
  • No, it should say `0.0.0.0` and not `127.0.0.1`, because you actually are binding to `0.0.0.0`. That is the `INADDR_ANY` wildcard address, which allows you to connect to any IP on the machine, including `127.0.0.1`. – Remy Lebeau May 10 '12 at 16:40