0
votes

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 :)

2
What antivirus app is running on the laptops? - Martin James
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
Can you please show the client code? How is it determining which IP/Port to connect to? - Remy Lebeau

2 Answers

2
votes

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.

0
votes

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();
}