Search code examples
c++windowssocketstcp

What can cause ERROR_CONNECTION_ABORTED when calling GetQueuedCompletionStatus


I have inherited some Windows TCP server code, only to find it does not work.

I call GetQueuedCompletionStatus() and this generates the ERROR_CONNECTION_ABORTED error.

Code that calls it:

unsigned int WinTCPServer::runWorker()
{
   unsigned int returnValue = 0U;

   bool bStayAlive = true;
   while (bStayAlive)
   {
      // Wait for IOCP events.
      DWORD bytesTransferred = 0U;
      ULONG_PTR completionKey = 0U;
      LPOVERLAPPED pOverlapped = NULL;
      BOOL bResult = GetQueuedCompletionStatus(_hIOCP, &bytesTransferred, &completionKey, &pOverlapped, INFINITE);

      if (FALSE == bResult)
      {
         // If pOverlapped == NULL then no packet was dequeued, the other parameters contain
         // undefined values, and we can't tell which socket it was. If pOverlapped != NULL,
         // the function has dequeued a failed completion packet.
         if (pOverlapped == NULL)
         {
            std::string error = "GetQueuedCompletionStatus failed, unknown context, interface id: " + std::to_string(_interfaceID);
            _consoleLog.AppError(__FILE__, __LINE__, error);
         }
         else
         {
            // If the completion key is zero, this was a shut-down post that failed
            // (PostQueuedCompletionStatus with zero). This shouldn't happen! No real
            // way of handling this gracefully.
            if (0U == completionKey)
            {
               _consoleLog.PlatformError(__FILE__, __LINE__, "GetQueuedCompletionStatus failed", GetLastError());
               std::string error = "TCP server shut down error, interface ID " + std::to_string(_interfaceID);
               _consoleLog.AppError(__FILE__, __LINE__, error);
            }
            else
            {
               // Don't report client disconnections as errors.
               DWORD lastError = GetLastError();
               if ((ERROR_NETNAME_DELETED != lastError) && (ERROR_OPERATION_ABORTED != lastError))
               {
                  _consoleLog.PlatformError(__FILE__, __LINE__, "GetQueuedCompletionStatus failed", lastError);
               }

               // Perform any outstanding actions on the overlapped operation.
               WinTCPClientContext* pClientContext = reinterpret_cast<WinTCPClientContext*>(completionKey);
               pClientContext->ProcessIncompleteOverlapped(pOverlapped);

               // We don't want to use this client any more.
               removeClient(*pClientContext);
            }
         }
      }
      else
      {
         // A null client context means the server is shutting down (i.e. has called
         // PostQueuedCompletionStatus with a NULL value).
         if (0U == completionKey)
         {
            bStayAlive = false;
         }
         else
         {
            // Convert the completion key into the client context.
            WinTCPClientContext* pClientContext = reinterpret_cast<WinTCPClientContext*>(completionKey);
            if (0U == bytesTransferred)
            {
               // This means a gracefull disconnection of the client. 
               // We should get this for every outstanding post (i.e. 
               // outstanding reads and writes).
               pClientContext->ProcessIncompleteOverlapped(pOverlapped);

               // We don't want to use this client any more.
               removeClient(*pClientContext);
            }
            else
            {
               // Process the overlapped result
               try
               {
                  // Process the post.
                  pClientContext->ProcessOverlapped(pOverlapped, bytesTransferred);
               }
               catch (utility::CommsException& ex)
               {
                  _consoleLog.PlatformError(ex.Filename(), ex.Line(), ex.Error(), ex.ErrorCode());
                  _consoleLog.StatusInfo(__FILE__, __LINE__, "client error, disconnecting");

                  // We don't want to use this client any more.
                  removeClient(*pClientContext);
               }
               catch (utility::Exception& ex)
               {
                  _consoleLog.AppError(ex.Filename(), ex.Line(), ex.Error());
                  _consoleLog.StatusInfo(__FILE__, __LINE__, "client error, disconnecting");

                  // We don't want to use this client any more.
                  removeClient(*pClientContext);
               }
            }
         }
      }
   }

   return returnValue;
}

The server connects to a client and some message between the 2 are processed correctly. There are however, a couple of messages that cause this error and I have no idea why.

What are the causes of this error, and how can debug them?


Solution

  • This problem was actually nothing to do with the tcp comms. The application was throwing a deeply buried unhandled exception causing strange behavior.