2025-11-28 00:35:46 +09:00

174 lines
6.6 KiB
C++

// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (C) 2002 Microsoft Corporation. All Rights Reserved.
//
// Module Name: NBAccept.cpp
//
// Description:
// This file contains the functions for implementing the
// non-blocking version of the accept. It uses many of the common functions
// defined in Common.cpp.
#pragma warning (disable: 4127)
#include "common.h"
/*
This function is the entry point for the Non-blocking Accept implementation.
It waits on select for each of the listening/accepted sockets until any
event is signalled. If a listening socket gets signalled, it performs
accept. If an accepted socket gets signalled, it performs read and echoes
back the data.
*/
void NonBlockingAcceptMain()
{
// prints a "i am still awake" message every few seconds.
const long HEART_BEAT_INTERVAL = 30;
PSOCK_INFO pSockInfo,
pNextSock;
FD_SET readFDSet;
struct timeval interval;
int nReady;
BOOL bSocketError;
int nSocksInFDSet;
printf("Entering NonBlockingAcceptMain()\n");
// process the available sockets in the global socket list.
while(g_AcceptContext.pSockList)
{
// first, prepare the FD_SET for passing to select.
// initialize the FD_SET
FD_ZERO(&readFDSet);
nSocksInFDSet = 0;
// include each socket in the FD_SET. For listening sockets,
// read means a new connection is available.
for(pSockInfo = g_AcceptContext.pSockList; pSockInfo != NULL;
pSockInfo = pSockInfo->next)
{
// the FD_SET will take only upto FD_SETSIZE number of sockets.
// so, we signal an error if we exceed the MAX_CLIENTS which is
// less than or equal to FD_SETSIZE. If more clients need to be
// supported, then FD_SETSIZE can be redefined before including
// winsock2.h
if (nSocksInFDSet < MAX_CLIENTS)
{
FD_SET(pSockInfo->sock, &readFDSet);
nSocksInFDSet++;
}
else
{
printf("ERROR: Number of sockets in FD Set exceeds MAX_CLIENTS (%d)\n", MAX_CLIENTS);
break;
}
}
printf("Num sockets in FD_SET: %d\n", nSocksInFDSet);
// wait on select for HEART_BEAT_INTEVAL seconds to see if any of
// the sockets are signalled.
interval.tv_sec = HEART_BEAT_INTERVAL;
interval.tv_usec = 0;
printf("Waiting in select for data/connections ...\n");
// currently we use only the read set, which signals all the
// three events required:
// accept for listening sockets,
// read for connected sockets and
// close for both type of sockets on error.
nReady = select(0, &readFDSet, NULL, NULL, &interval);
if (nReady == SOCKET_ERROR)
{
printf("ERROR: select failed. Error = %d\n", WSAGetLastError());
// pause so as not to output frequently in case of repeated errors.
Sleep(3000);
continue;
}
// check if some socket was signalled.
if (nReady == 0)
{
printf("No connections/data in the last %d seconds. \n",
HEART_BEAT_INTERVAL);
continue;
}
// find out which socket was signalled and process that socket.
// since nReady indicates how many sockets are in the signalled
// state, we don't need to loop if we have already processed that
// many sockets.
pSockInfo = g_AcceptContext.pSockList;
while (pSockInfo != NULL && nReady > 0)
{
// check if this socket is set.
if (FD_ISSET(pSockInfo->sock, &readFDSet))
{
nReady--;
// for listening sockets, signalling on a read set means
// a new connection is available.
if (pSockInfo->isSocketListening)
{
// accept the connection and add the new socket to the
// beginning of the list (not the end, so that we won't
// come across the newly added sockets before they are
// included in the next select call later).
ProcessAcceptEvent(pSockInfo);
}
else
{
// this read event for a connected socket means data
// is available or socket is closed.
// read data if available and if we have buffer space.
bSocketError = ProcessReadEvent(pSockInfo);
// if we already found that the socket is closed due to
// some errors, we don't need to send the data
if (!bSocketError)
{
// so far no error, so try echoing the data back.
bSocketError = SendData(pSockInfo);
}
// if there was an error in recv/send, close the
// socket.
if (bSocketError)
{
// close the socket
closesocket(pSockInfo->sock);
printf("Closed socket %d. "
"Total Bytes Recd = %d, "
"Total Bytes Sent = %d\n",
pSockInfo->sock,
pSockInfo->nTotalRecd,
pSockInfo->nTotalSent);
// delete the SockInfo structure and free the memory.
pNextSock = pSockInfo->next;
DeleteSockInfoFromList(&g_AcceptContext.pSockList,
pSockInfo);
pSockInfo = pNextSock;
continue;
}
}
}
// move on to the next socket. as mentioned earlier, since
// new sockets are added only in the beginning of the list
// we won't be processing them until they are included in the
// next select call.
pSockInfo = pSockInfo->next;
}
}
printf("Exiting NonBlockingAcceptMain()\n");
return;
}