1 /* 2 * PROJECT: ReactOS simple TCP/IP services 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: base/services/tcpsvcs/skelserver.c 5 * PURPOSE: Sets up a server and listens for connections 6 * COPYRIGHT: Copyright 2005 - 2008 Ged Murphy <gedmurphy@gmail.com> 7 * 8 */ 9 10 #include "tcpsvcs.h" 11 12 #define BUF 1024 13 14 static SOCKET 15 SetUpListener(USHORT Port) 16 { 17 SOCKET sock; 18 SOCKADDR_IN server; 19 BOOL bSetup = FALSE; 20 21 sock = socket(AF_INET, SOCK_STREAM, 0); 22 if (sock != INVALID_SOCKET) 23 { 24 ZeroMemory(&server, sizeof(SOCKADDR_IN)); 25 server.sin_family = AF_INET; 26 server.sin_addr.s_addr = htonl(INADDR_ANY); 27 server.sin_port = Port; 28 29 if (bind(sock, (SOCKADDR*)&server, sizeof(SOCKADDR_IN)) != SOCKET_ERROR) 30 { 31 if (listen(sock, SOMAXCONN) != SOCKET_ERROR) 32 { 33 bSetup = TRUE; 34 } 35 else 36 { 37 LogEvent(L"listen() failed", WSAGetLastError(), 0, LOG_ERROR); 38 } 39 } 40 else 41 { 42 LogEvent(L"bind() failed", WSAGetLastError(), 0, LOG_ERROR); 43 } 44 } 45 else 46 { 47 LogEvent(L"socket() failed", WSAGetLastError(), 0, LOG_ERROR); 48 } 49 50 return bSetup ? sock : INVALID_SOCKET; 51 } 52 53 54 static VOID 55 AcceptConnections(SOCKET listeningSocket, 56 LPTHREAD_START_ROUTINE lpService, 57 LPWSTR lpName) 58 { 59 SOCKADDR_IN client; 60 SOCKET sock; 61 HANDLE hThread; 62 TIMEVAL timeVal; 63 FD_SET readFD; 64 WCHAR logBuf[256]; 65 INT timeOut = 2000; 66 67 timeVal.tv_sec = timeOut / 1000; 68 timeVal.tv_usec = timeOut % 1000; 69 70 while (!bShutdown) 71 { 72 INT selRet = 0; 73 74 FD_ZERO(&readFD); 75 FD_SET(listeningSocket, &readFD); 76 77 selRet = select(0, &readFD, NULL, NULL, &timeVal); 78 if (selRet > 0) 79 { 80 if (!bShutdown || FD_ISSET(listeningSocket, &readFD)) 81 { 82 INT addrSize = sizeof(SOCKADDR_IN); 83 84 sock = accept(listeningSocket, (SOCKADDR*)&client, &addrSize); 85 if (sock != INVALID_SOCKET) 86 { 87 swprintf(logBuf, 88 L"Accepted connection to %s server from %S:%d", 89 lpName, 90 inet_ntoa(client.sin_addr), 91 ntohs(client.sin_port)); 92 LogEvent(logBuf, 0, 0, LOG_FILE); 93 94 swprintf(logBuf, L"Creating worker thread for %s", lpName); 95 LogEvent(logBuf, 0, 0, LOG_FILE); 96 97 if (!bShutdown) 98 { 99 hThread = CreateThread(0, 0, lpService, (void*)sock, 0, NULL); 100 if (hThread != NULL) 101 { 102 CloseHandle(hThread); 103 } 104 else 105 { 106 swprintf(logBuf, L"Failed to start worker thread for the %s server", 107 lpName); 108 LogEvent(logBuf, 0, 0, LOG_FILE); 109 } 110 } 111 } 112 else 113 { 114 LogEvent(L"accept failed", WSAGetLastError(), 0, LOG_ERROR); 115 } 116 } 117 } 118 else if (selRet == SOCKET_ERROR) 119 { 120 LogEvent(L"select failed", WSAGetLastError(), 0, LOG_ERROR); 121 } 122 } 123 } 124 125 BOOL 126 ShutdownConnection(SOCKET sock, 127 BOOL bRec) 128 { 129 WCHAR logBuf[256]; 130 131 /* Disallow any further data sends. This will tell the other side 132 that we want to go away now. If we skip this step, we don't 133 shut the connection down nicely. */ 134 if (shutdown(sock, SD_SEND) == SOCKET_ERROR) 135 { 136 LogEvent(L"Error in shutdown()", WSAGetLastError(), 0, LOG_ERROR); 137 return FALSE; 138 } 139 140 /* Receive any extra data still sitting on the socket 141 before we close it */ 142 if (bRec) 143 { 144 CHAR readBuffer[BUF]; 145 INT ret; 146 147 do 148 { 149 ret = recv(sock, readBuffer, BUF, 0); 150 if (ret >= 0) 151 { 152 swprintf(logBuf, L"FYI, received %d unexpected bytes during shutdown", ret); 153 LogEvent(logBuf, 0, 0, LOG_FILE); 154 } 155 } while (ret > 0); 156 } 157 158 closesocket(sock); 159 160 return TRUE; 161 } 162 163 164 DWORD WINAPI 165 StartServer(LPVOID lpParam) 166 { 167 SOCKET listeningSocket; 168 PSERVICES pServices; 169 TCHAR logBuf[256]; 170 171 pServices = (PSERVICES)lpParam; 172 173 swprintf(logBuf, L"Starting %s server", pServices->lpName); 174 LogEvent(logBuf, 0, 0, LOG_FILE); 175 176 if (!bShutdown) 177 { 178 listeningSocket = SetUpListener(htons(pServices->Port)); 179 if (!bShutdown && listeningSocket != INVALID_SOCKET) 180 { 181 swprintf(logBuf, 182 L"%s is waiting for connections on port %d", 183 pServices->lpName, 184 pServices->Port); 185 LogEvent(logBuf, 0, 0, LOG_FILE); 186 187 AcceptConnections(listeningSocket, pServices->lpService, pServices->lpName); 188 } 189 else 190 { 191 LogEvent(L"Socket error when setting up listener", 0, 0, LOG_FILE); 192 } 193 } 194 195 swprintf(logBuf, L"Exiting %s thread", pServices->lpName); 196 LogEvent(logBuf, 0, 0, LOG_FILE); 197 ExitThread(0); 198 } 199