Search code examples
c++tcpportwinsock

Winsock program causing port exhaustion


Going off a different post that helped explain the source of the symptoms of my issue: https://superuser.com/questions/1348102/windows-10-ephemeral-port-exhaustion-but-netstat-says-otherwise

I am having a very similar issue - except the problem is the program eating up all the ports is one I created myself.

See the top 2 results

See the top 2 results - 6072 ports used by one instance and 545 by the other - if I understand that result set correctly.

There are 2 instances listed as there are 2 instances running - this is a program that connects to a machine every 60 seconds, asks if it has information, retrieves it if it does, and then closes the connection.

It was written in C++ using winsock TCP connections.

Is there anything someone could suggest I modify to prevent this from happening?

Currently, after about a month and a half of the program running, we run into the issue of not being able to RDC into the server "due to a time and date difference" even though the time and date are perfectly in sync with the NTP server and the rest of the computers, and of course it will seize being able to connect to anything.

We can still connect to the server directly through IP address, but not hostname.

I haven't yet found any solutions to this other than rebooting the server.

The mechanism for connecting is a simple and primitive:

void Connect(string ipA)
{
    // Initialize Winsock
    Debug("Connecting to socket...");
    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != NO_ERROR)
    {
        Debug("Client: Error at WSAStartup().");
    }
    else
    {
        Debug("Client: WSAStartup() is OK.");
    }
    // Create a SOCKET for connecting to server
    u_long mode = (u_long)0;

    ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    GPT_ATTRIBUTE_NO_BLOCK_IO_PROTOCOL;
    if (ConnectSocket == INVALID_SOCKET)
    {
        printf("Client: Error at socket(): %ld.\n", WSAGetLastError());
        WSACleanup();
        return;
    }

    iResult = ioctlsocket(ConnectSocket, FIONBIO, &mode);
    if (iResult != NO_ERROR)
        printf("ioctlsocket failed with error: %ld\n", iResult);

    sockaddr_in clientService;
    clientService.sin_family = AF_INET;
    clientService.sin_addr.s_addr = inet_addr(ipA.c_str());
    clientService.sin_port = htons(port);

    // Connect to server.
    if (connect(ConnectSocket, (SOCKADDR*)&clientService, sizeof(clientService)) == SOCKET_ERROR)
    {
        Debug("Connection failed...");
        WSACleanup();
        return;
    }
    else
        Debug("Connection successful.");
}

This method is called with the IP address supplied as a parameter and results in a successful connection.

After that, several request-response packets are sent using these:

void SendPacket(int iResult, SOCKET ConnectSocket, const char* a)
{
    Debug("Sending message to CW: " + (string)a);
    iResult = send(ConnectSocket, a, strlen(a), 0);
    if (iResult == SOCKET_ERROR) {
        Debug("Send failed");
        closesocket(ConnectSocket);
        WSACleanup();
    }
    else
        Debug("Send successful.");
}

And

iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);

And once we're done with the particular session, we close the connection:

void ShutDown(int iResult, SOCKET ConnectSocket)
{
    iResult = shutdown(ConnectSocket, SD_SEND);
    Debug("Shutting down socket...");
    if (iResult == SOCKET_ERROR) {
        Debug("Shutdown failed");
        closesocket(ConnectSocket);
        WSACleanup();
    }
    else
        Debug("Shutdown successful.");
}

There are a couple hundred lines of code that handles the data received, but those won't be relevant as they don't deal with any sort of network connection.

To say I have no experience with C++ would be an understatement, I simply slapped this together using basic MS templates until it worked exactly as we needed it and haven't touched it since.

So if there is anything someone can point out that I could change to avoid port exhaustion, I would be very grateful.

Just to add a bit of clarity - the program will ALWAYS connect to the machine on the same port. I have tried to bind the outgoing connection (from Windows) port to the same one also, but I have been unsuccessful - wasted many hours trying to get this 1 simple thing right, but I presume that would resolve my issues.


Solution

  • I see that you are calling shutdown when you are done with a connection and if we consult the documentation for that we see:

    The shutdown function does not close the socket. Any resources attached to the socket will not be freed until closesocket is invoked.

    Which I take to mean that any ports associated with the socket remain in use.

    Further down that page, we also read:

    An application should not rely on being able to reuse a socket after it has been shut down. In particular, a Windows Sockets provider is not required to support the use of connect on a socket that has been shut down.

    So, all-in-all, I would call closesocket instead of shutdown and then request a new socket from Winsock when you need one.