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