News: Help with WSock2 & Event objects

From Web (01.07.1997)

Question

From dschwamm@www.henrys.de Tue Jul 01 18:07:21 1997
Path: inf2hro!fu-berlin.de!nntprelay.mathworks.com!howland.erols.net!
  ais.net!newsfeed.direct.ca!news.he.net!news.pagesat.net!skypoint.com!
  not-for-mail
From: "T. Barlow" <tbarlow@skypoint.com>
Newsgroups: comp.os.ms-windows.programmer.tools.winsock,
  comp.os.ms-windows.programmer.networks,comp.os.ms-windows.programmer.win32
Subject: Help with WSock2 & Event objects
Date: Fri, 27 Jun 1997 22:13:52 -0500
Organization: SkyPoint Communications, Inc.
Lines: 124
Message-ID: <33B4816F.C0F20FA6@skypoint.com>
NNTP-Posting-Host: dial067.skypoint.net
Mime-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
X-Mailer: Mozilla 4.0b5 [en] (Win95; I)
X-Priority: 3 (Normal)
Xref: inf2hro comp.os.ms-windows.programmer.tools.winsock:6954
  comp.os.ms-windows.programmer.networks:10124
  comp.os.ms-windows.programmer.win32:68800

HI,

  I'm working on a MUD server and started looking into
using event objects along with a worker thread to manage
both the listening and connected sockets.

  The code is for WSock2,  and I'm having a problem.
I'm able to connect a few times, but once I close all
connections via telnet, the code breaks on my DebugBreak()
line in the server thread. I get an error 6 (invalid
handle), but only after I get all the FD_CLOSE signals
and have no sockets left but the listener.  BTW, I'm
connecting with telnet using "localhost" (127.0.0.1).

  Anyone have a clue what I'm doing wrong? And, is there
a better way to monitor the main socket and all connecting
sockets without polling? It seems like a waste of time
having to call WSAEnumNetworkEvents() for every socket
whenever I get a signal!

  Please help.

  Here are parts of the code I'm using (no error checks):

// Terminate & socket event handles
ghEvents[EVENT_TERMINATE] = CreateEvent( NULL, TRUE, FALSE, NULL );
ghEvents[EVENT_SERVER] =  (HANDLE)WSACreateEvent();

WSAStartup( MAKEWORD( 2, 0 ), &m_wsaData );
gdcMaster = WSASocket(AF_INET,SOCK_STREAM,IPPROTO_IP,NULL,0,0);

bOption = TRUE;
setsockopt(gdcMaster, SOL_SOCKET, SO_DONTLINGER, &bOption,
sizeof(bOption));

sa.sin_family = AF_INET;
sa.sin_port = htons(4242);
sa.sin_addr.s_addr = htonl(INADDR_ANY);
bind(gdcMaster, &sa, sizeof(sa));

WSAEventSelect(gdcMaster,ghEvents[1],FD_ACCEPT|FD_READ|FD_WRITE|FD_CLOSE);

listen(gdcMaster, 5);

ghServerThread = _beginthreadex(
  NULL,0,ServerThread,ghEvents,0,&guiThreadID
);

// Here is the cut down thread code .....
unsigned int __stdcall ServerThread( void *pvContext )
{
  HANDLE *phEvents = (HANDLE *)pvContext;
  WSANETWORKEVENTS EventInfo;
  DWORD dwSignal;
  while ( 1 )
  {
    dwSignal = WaitForMultipleObjects(
      NUM_EVENTS,phEvents,FALSE,INFINITE
    );
    if ( dwSignal - WAIT_OBJECT_0 == EVENT_TERMINATE )
      return 0;

    if ( dwSignal == WAIT_FAILED )
    {
      DWORD dwErr = GetLastError();
      DebugBreak();
    }

    if ( dwSignal - WAIT_OBJECT_0 == EVENT_SERVER )
    {
       DESCRIPTOR *pPrev = NULL, *pDel, *p = gpdcConnections;

       // Check listener...
       WSAEnumNetworkEvents(gdcMaster,NULL,&EventInfo);
       if ( EventInfo.lNetworkEvents & FD_ACCEPT )
       {
          DESCRIPTOR *pNew = (DESCRIPTOR *)calloc(1,sizeof(DESCRIPTOR));
          struct sockaddr addr;
          int len = sizeof(addr);
          pNew->dc = accept(gdcMaster,&addr,&len);
          if ( !gpdcConnections )
            gpdcConnections = pNew;
          else
          {
            DESCRIPTOR *p = gpdcConnections;
            while ( p->pNext ) p = p->pNext;
            p->pNext = pNew;
          }
          giNumConnections++;
          ResetEvent(phEvents[EVENT_SERVER]);
          continue;
        }

        // Check all connections
        while ( p )
        {
          WSAEnumNetworkEvents(p->dc,NULL,&EventInfo);
          if ( EventInfo.lNetworkEvents & FD_CLOSE )
          {
            pDel = p;
            p = p->pNext;
            closesocket(pDel->dc);
            free( pDel );
            if ( pPrev )
              pPrev->pNext = p;
            else
              gpdcConnections = p;
            giNumConnections--;
          }
          else
          {
            // Read data...
            if ( EventInfo.lNetworkEvents & FD_READ )
              recv(p->dc,....) etc...
            // Write possible...
            if ( EventInfo.lNetworkEvents & FD_WRITE )
              write queued data....
            pPrev = p;
            p = p->pNext;
          }
        }
        ResetEvent(phEvents[EVENT_SERVER]);
     }
   }
   return 0;
}