Question

I am trying to code a small test-server for completion ports. But when I try to call AcceptEx... it always returns WSAEINVAL as the winsock error code... I don´t really get what was my mistake

http://codepad.org/NEXG3Ssh <- code on codepad

and

StartWinsock();
 cout << "Winsock initiated\n";
 //Get the number of processors
 DWORD ulProcessors = GetNumberOfProcessors();
 cout << "Number of Processors/Threads, that will be used: " << ulProcessors << endl;
 //Create an completion port
 hCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, ulProcessors);
 if(hCompletionPort == NULL)
  ErrorAbort("Could not create completion port");
 cout << "Completion Port created\n";

 //Create threads
 CreateThreads(ulProcessors);
 cout << "Threads created\n";

 //Create socket
 AcceptorSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
 addrinfo *final, hints;
 memset(&hints, 0, sizeof(hints));
 hints.ai_family = AF_INET;
 hints.ai_flags = AI_PASSIVE;
 if(getaddrinfo(NULL,"12345", &hints, &final))
  ErrorAbort("Could not retrieve address information");
 if(bind(AcceptorSock,final->ai_addr, final->ai_addrlen))
  ErrorAbort("Could not bind socket");
 freeaddrinfo(final);
 cout << "Acceptor socket created and bound\nStarting to listen on the acceptor socket\n";
 if(listen(AcceptorSock, 2))
  ErrorAbort("Can´t listen on the socket");

 //Add acceptor socket file handle to be observed by the completion port
 if(CreateIoCompletionPort((HANDLE)AcceptorSock, hCompletionPort, NEW_CONNECTION, 0) != hCompletionPort)
  ErrorAbort("A new completion port has been created instead of using the existing one");
 cout << "Acceptor socket associated with the completion port\n";

 ResumeThreads(2);
 char lpOutputBuf[1024];
 int outBufLen = 1024;
 DWORD dwBytes;
 OVERLAPPED over;
 SOCKET newSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);


 while(true)
 {
  memset(&over, 0, sizeof(over));
  if(AcceptEx(AcceptorSock, newSock, lpOutputBuf, outBufLen - ((sizeof(sockaddr_in) + 16) * 2), sizeof(sockaddr_in)+16, sizeof(sockaddr_in)+16, &dwBytes, &over) == FALSE)
  {
   int x = WSAGetLastError();
   if( x != WSA_IO_PENDING)
    ErrorAbort("Could not acceptex a new connection");
  }
 }
Was it helpful?

Solution

Te problem in your code is this:

while(true)
{
  memset(&over, 0, sizeof(over));
  if(AcceptEx(AcceptorSock, newSock, lpOutputBuf, outBufLen - ((sizeof(sockaddr_in) + 16) * 2), sizeof(sockaddr_in)+16, sizeof(sockaddr_in)+16, &dwBytes, &over) == FALSE)
  {
    int x = WSAGetLastError();
    if( x != WSA_IO_PENDING)
    ErrorAbort("Could not acceptex a new connection");
  }
}

The second parameter of the AcceptEx Function (in this case newSock) must be a unconnected and unbound socket, then when a new connection arrives the newSock parameter will be an invalid parameter (because now is connected), to avoid this a New Socket Handle must be created, but the loop must wait until the new connection arrives, to do this a WSAEVENT must be use. The first the function WSAEventSelect must be used to associate the FD_ACCEPT Network event with the WSAEVENT, this mus be done before the creation of the AcceptThread:

g_ev = WSACreateEvent();
if (WSA_INVALID_EVENT == g_ev)
  ErrorAbort("Error occurred while WSACreateEvent()";
if (SOCKET_ERROR == WSAEventSelect(AcceptorSock, g_ev, FD_ACCEPT))
{
  WSACloseEvent(g_ev);
  ErrorAbort("Error occurred while WSAEventSelect().");
}

The AcceptThread Then Call The AcceptEx Function and Wait for a New Connection, when a new connection arrives the newSock is Added to the Completion port and a new Socket is created, this thread have only the elements required to accept connections:

DWORD WINAPI AcceptThread(LPVOID lParam)
{
  SOCKET AcceptorSock = (SOCKET)lParam, new;
  SOCKET newSock; 
  OVERLAPPED over;    
  DWORD wr;

  memset(&over, 0, sizeof(over));
  do
  {
    newSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if(AcceptEx(AcceptorSock, newSock, lpOutputBuf, outBufLen - ((sizeof(sockaddr_in) + 16) * 2), sizeof(sockaddr_in)+16, sizeof(sockaddr_in)+16, &dwBytes, &over) == FALSE)
    {
      int x = WSAGetLastError();
      if (x != ERROR_IO_PENDING)
      {
        cout << "Could not acceptex a new connection" << endl;
        return 1;
      }
      else
      {
        if (WSA_WAIT_TIMEOUT != (wr = WSAWaitForMultipleEvents(1,  &g_ev, FALSE, INFINITE, FALSE)))
        {
          WSAEnumNetworkEvents(AcceptorSock, g_ev, &WSAEvents);
          if ((WSAEvents.lNetworkEvents & FD_ACCEPT) &&  (0 == WSAEvents.iErrorCode[FD_ACCEPT_BIT]))
          {
            if (CreateIoCompletionPort(newSock, hCompletionPort, 0, 0) == NULL)
            {
              cout << "Error CreateIoCompletionPort" << endl;
              return 2;
            }
            WSAResetEvent(g_ev);
          }
        }
      }
    }
  }while(wr != WSA_WAIT_EVENT_0);
}

If any body needs more information this links could be useful: http://www.winsocketdotnetworkprogramming.com/winsock2programming/winsock2advancedscalableapp6b.html http://www.codeproject.com/KB/IP/SimpleIOCPApp.aspx http://msdn.microsoft.com/en-us/magazine/cc302334.aspx

OTHER TIPS

SOCKET newSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

should use WSASocket rather than socket and you should pass the WSA_FLAG_OVERLAPPED flag when creating the socket.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top