#include #include #include #define DEFAULT_PORT "33123" #define MAX_THREADS 16 #define WINSOCK_INIT_ERROR 1 #define GETADDRINFO_ERROR 2 #define SOCKET_CREATE_ERROR 4 #define BIND_SOCKET_ERROR 8 #define LISTEN_SOCKET_ERROR 16 #define CLIENT_CONNECT_ERROR 32 int sockInit(void); int sockListen(void); int mainLoop(void); DWORD WINAPI clientWork(LPVOID); CRITICAL_SECTION CriticalSection; int numClients = 0; SOCKET ListenSocket = INVALID_SOCKET; int main(int argc, char *argv[]) { int returnValue = 0; returnValue += sockInit(); returnValue += sockListen(); if (returnValue) { return returnValue; } InitializeCriticalSection(&CriticalSection); // never returns returnValue += mainLoop(); DeleteCriticalSection(&CriticalSection); return returnValue; } int sockInit(void) { int returnValue = 0; int iResult; WSADATA wsaData; struct addrinfo *result = NULL, *ptr = NULL, hints; // Initialize Winsock iResult = WSAStartup(MAKEWORD(2,2), &wsaData); if (iResult != 0) { printf("WSAStartup failed: %d\n", iResult); returnValue += WINSOCK_INIT_ERROR; } ZeroMemory(&hints, sizeof(hints)); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; hints.ai_flags = AI_PASSIVE; // Resolve the local address and port to be used by the server iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result); if (iResult != 0) { printf("getaddrinfo failed: %d\n", iResult); WSACleanup(); returnValue += GETADDRINFO_ERROR; } // Create a SOCKET for the server to listen for client connections ListenSocket = socket(result->ai_family, result->ai_socktype, \ result->ai_protocol); if (ListenSocket == INVALID_SOCKET) { printf("Error at socket(): %ld\n", WSAGetLastError()); freeaddrinfo(result); WSACleanup(); returnValue += SOCKET_CREATE_ERROR; } // Setup the TCP listening socket iResult = bind(ListenSocket, result->ai_addr, (int)result->ai_addrlen); if (iResult == SOCKET_ERROR) { printf("bind failed: %d\n", WSAGetLastError()); freeaddrinfo(result); closesocket(ListenSocket); WSACleanup(); returnValue += BIND_SOCKET_ERROR; } return returnValue; } int sockListen(void) { if (listen(ListenSocket, SOMAXCONN ) == SOCKET_ERROR) { printf("Error at bind(): %ld\n", WSAGetLastError()); closesocket(ListenSocket); WSACleanup(); return LISTEN_SOCKET_ERROR; } return 0; } int mainLoop(void) { int returnValue = 0; SOCKET ClientSocket = INVALID_SOCKET; DWORD dwThreadId[MAX_THREADS]; HANDLE hThread[MAX_THREADS]; while(true) { if (numClients >= MAX_THREADS) continue; // Accept a client socket ClientSocket = accept(ListenSocket, NULL, NULL); if (ClientSocket == INVALID_SOCKET) { printf("accept failed: %d\n", WSAGetLastError()); closesocket(ListenSocket); WSACleanup(); returnValue += CLIENT_CONNECT_ERROR; break; } EnterCriticalSection(&CriticalSection); numClients++; LeaveCriticalSection(&CriticalSection); hThread[numClients] = CreateThread( NULL, 0, clientWork, &ClientSocket, 0, &dwThreadId[numClients]); if (hThread[numClients] == NULL) ExitProcess(numClients); } return returnValue; } DWORD WINAPI clientWork(LPVOID lpParam) { SOCKET *lSock; lSock = (SOCKET *) lpParam; EnterCriticalSection(&CriticalSection); numClients--; LeaveCriticalSection(&CriticalSection); return 0; }