Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

612 lines
17 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Copyright (C) Microsoft Corporation, 1999.
  4. //
  5. // File: E V E N T S R V . C P P
  6. //
  7. // Contents: UPnP GENA server.
  8. //
  9. // Notes:
  10. //
  11. // Author: Ting Cai Dec. 1999
  12. //
  13. // Email: [email protected]
  14. //
  15. //----------------------------------------------------------------------------
  16. #include <pch.h>
  17. #pragma hdrstop
  18. #include <winsock2.h>
  19. #include "wininet.h"
  20. #include "eventsrv.h"
  21. #include "ssdpfunc.h"
  22. #include "ssdptypes.h"
  23. #include "ssdpnetwork.h"
  24. #include "ncbase.h"
  25. #define LISTEN_BACKLOG 5
  26. VOID ProcessSsdpRequest(PSSDP_REQUEST pSsdpRequest, RECEIVE_DATA *pData);
  27. static LIST_ENTRY g_listOpenConn;
  28. static CRITICAL_SECTION g_csListOpenConn;
  29. static int g_cOpenConnections;
  30. static long g_cMaxOpenConnections = 150;
  31. static const long c_cMaxOpenDefault = 150; // default maximum
  32. static const long c_cMaxOpenMin = 5; // absolute minimum
  33. static const long c_cMaxOpenMax = 1500; // absolute maximum
  34. static long cQueuedAccepts = 0;
  35. static SOCKET HttpSocket;
  36. LONG bCreated = 0;
  37. VOID InitializeListOpenConn()
  38. {
  39. HKEY hkey;
  40. DWORD dwMaxConns = c_cMaxOpenDefault;
  41. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  42. "SYSTEM\\CurrentControlSet\\Services"
  43. "\\SSDPSRV\\Parameters", 0,
  44. KEY_READ, &hkey))
  45. {
  46. DWORD cbSize = sizeof(DWORD);
  47. // ignore failure. In that case, we'll use default
  48. (VOID) RegQueryValueEx(hkey, "MaxEventConnects", NULL, NULL, (BYTE *)&dwMaxConns, &cbSize);
  49. RegCloseKey(hkey);
  50. }
  51. dwMaxConns = max(dwMaxConns, c_cMaxOpenMin);
  52. dwMaxConns = min(dwMaxConns, c_cMaxOpenMax);
  53. g_cMaxOpenConnections = dwMaxConns;
  54. InitializeCriticalSection(&g_csListOpenConn);
  55. EnterCriticalSection(&g_csListOpenConn);
  56. InitializeListHead(&g_listOpenConn);
  57. g_cOpenConnections = 0;
  58. LeaveCriticalSection(&g_csListOpenConn);
  59. TraceTag(ttidEventServer, "Initializing Max Connections %d ", g_cOpenConnections);
  60. }
  61. VOID FreeOpenConnection(POPEN_TCP_CONN pOpenConn)
  62. {
  63. Assert(OPEN_TCP_CONN_SIGNATURE == (pOpenConn->iType));
  64. FreeSsdpRequest(&pOpenConn->ssdpRequest);
  65. free(pOpenConn->szData);
  66. pOpenConn->szData = NULL;
  67. pOpenConn->state = CONNECTION_INIT;
  68. pOpenConn->cbData = 0;
  69. pOpenConn->cbHeaders = 0;
  70. }
  71. VOID CloseOpenConnection(SOCKET socketPeer)
  72. {
  73. closesocket(socketPeer);
  74. RemoveOpenConn(socketPeer);
  75. }
  76. POPEN_TCP_CONN CreateOpenConnection(SOCKET socketPeer)
  77. {
  78. POPEN_TCP_CONN pOpenConn = (POPEN_TCP_CONN) malloc(sizeof(OPEN_TCP_CONN));
  79. if (pOpenConn == NULL)
  80. {
  81. TraceTag(ttidEventServer, "Couldn't allocate memory for %d", socketPeer);
  82. return NULL;
  83. }
  84. pOpenConn->iType = OPEN_TCP_CONN_SIGNATURE;
  85. pOpenConn->socketPeer = socketPeer;
  86. pOpenConn->szData = NULL;
  87. pOpenConn->state = CONNECTION_INIT;
  88. pOpenConn->cbData = 0;
  89. pOpenConn->cbHeaders = 0;
  90. InitializeSsdpRequest(&pOpenConn->ssdpRequest);
  91. return pOpenConn;
  92. }
  93. VOID AddToListOpenConn(POPEN_TCP_CONN pOpenConn)
  94. {
  95. EnterCriticalSection(&g_csListOpenConn);
  96. InsertHeadList(&g_listOpenConn, &(pOpenConn->linkage));
  97. g_cOpenConnections++;
  98. LeaveCriticalSection(&g_csListOpenConn);
  99. TraceTag(ttidEventServer, "AddToListOpenConn - Connections %d ", g_cOpenConnections);
  100. }
  101. VOID CleanupListOpenConn()
  102. {
  103. PLIST_ENTRY p;
  104. PLIST_ENTRY pListHead = &g_listOpenConn;
  105. TraceTag(ttidEventServer, "----- Cleanup Open Connection List -----");
  106. EnterCriticalSection(&g_csListOpenConn);
  107. for (p = pListHead->Flink; p != pListHead;)
  108. {
  109. POPEN_TCP_CONN pOpenConn;
  110. pOpenConn = CONTAINING_RECORD (p, OPEN_TCP_CONN, linkage);
  111. p = p->Flink;
  112. TraceTag(ttidEventServer, "Removing Open Conn %x -----", pOpenConn);
  113. RemoveEntryList(&(pOpenConn->linkage));
  114. g_cOpenConnections--;
  115. TraceTag(ttidEventServer, "CleanupListOpenConn - Connections %d ", g_cOpenConnections);
  116. closesocket(pOpenConn->socketPeer);
  117. FreeOpenConnection(pOpenConn);
  118. // just to be sure we don't use this again
  119. pOpenConn->iType = -1;
  120. free(pOpenConn);
  121. }
  122. LeaveCriticalSection(&g_csListOpenConn);
  123. DeleteCriticalSection(&g_csListOpenConn);
  124. TraceTag(ttidEventServer, "----- Finished Cleanup Open Connection List -----");
  125. }
  126. // Pre-condition: WSAStartup was successful.
  127. // Post-Condtion: HttpSocket is created. GetNetworks can proceed.
  128. SOCKET CreateHttpSocket()
  129. {
  130. SOCKADDR_IN sockaddrLocal;
  131. int iRet;
  132. HttpSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  133. if (HttpSocket == INVALID_SOCKET)
  134. {
  135. TraceTag(ttidEventServer, "Failed to create http socket. Error code (%d).", GetLastError());
  136. return INVALID_SOCKET;
  137. }
  138. // Bind
  139. sockaddrLocal.sin_family = AF_INET;
  140. sockaddrLocal.sin_addr.s_addr = INADDR_ANY;
  141. sockaddrLocal.sin_port = htons(EVENT_PORT);
  142. iRet = bind(HttpSocket, (struct sockaddr *)&sockaddrLocal, sizeof(sockaddrLocal));
  143. if (iRet == SOCKET_ERROR)
  144. {
  145. TraceTag(ttidEventServer, "Failed to bind http socket. Error code (%d).", GetLastError());
  146. closesocket(HttpSocket);
  147. HttpSocket = INVALID_SOCKET;
  148. return INVALID_SOCKET;
  149. }
  150. InterlockedIncrement(&bCreated);
  151. return HttpSocket;
  152. }
  153. INT StartHttpServer(SOCKET HttpSocket, HWND hWnd, u_int wMsg)
  154. {
  155. INT iRet;
  156. iRet = listen(HttpSocket, LISTEN_BACKLOG);
  157. if (iRet == SOCKET_ERROR)
  158. {
  159. iRet = GetLastError();
  160. closesocket(HttpSocket);
  161. HttpSocket = INVALID_SOCKET;
  162. TraceTag(ttidEventServer, "Failed to listen on http socket. Error code (%d).", iRet);
  163. return iRet;
  164. }
  165. iRet = WSAAsyncSelect(HttpSocket, hWnd, wMsg, FD_ACCEPT | FD_CONNECT | FD_READ | FD_CLOSE);
  166. if (iRet == SOCKET_ERROR)
  167. {
  168. iRet = GetLastError();
  169. closesocket(HttpSocket);
  170. HttpSocket = INVALID_SOCKET;
  171. TraceTag(ttidEventServer, "----- select failed with error code %d -----", iRet);
  172. return iRet;
  173. }
  174. else
  175. {
  176. TraceTag(ttidEventServer, "Ready to accept tcp connections.");
  177. return 0;
  178. }
  179. }
  180. VOID CleanupHttpSocket()
  181. {
  182. if (InterlockedExchange(&bCreated, bCreated) != 0)
  183. {
  184. if (HttpSocket != INVALID_SOCKET)
  185. {
  186. closesocket(HttpSocket);
  187. }
  188. }
  189. }
  190. VOID DoAccept(SOCKET socket)
  191. {
  192. SOCKADDR_IN sockaddrFrom;
  193. SOCKET socketPeer;
  194. int iLen;
  195. POPEN_TCP_CONN pOpenTcpConn;
  196. iLen = sizeof(SOCKADDR_IN);
  197. Assert(socket == HttpSocket);
  198. // AcceptEx
  199. socketPeer = accept(socket, (LPSOCKADDR)&sockaddrFrom, &iLen);
  200. TraceTag(ttidEventServer, "DoAccept - Before Adding to List Connections %d ", g_cOpenConnections);
  201. if (socketPeer == SOCKET_ERROR)
  202. {
  203. TraceTag(ttidEventServer, "----- accept failed with error code %d -----", GetLastError());
  204. return;
  205. }
  206. pOpenTcpConn = CreateOpenConnection(socketPeer);
  207. if (pOpenTcpConn)
  208. {
  209. AddToListOpenConn(pOpenTcpConn);
  210. }
  211. else
  212. {
  213. TraceError("Couldn't add new connection. Out of memory!",
  214. E_OUTOFMEMORY);
  215. }
  216. }
  217. VOID DelayAccept()
  218. {
  219. InterlockedIncrement(&cQueuedAccepts);
  220. TraceTag(ttidEventServer, "----- DelayAccept %d -----", cQueuedAccepts);
  221. }
  222. VOID DoDelayedAccept()
  223. {
  224. InterlockedDecrement(&cQueuedAccepts);
  225. TraceTag(ttidEventServer, "----- DoDelayedAccept %d -----", cQueuedAccepts);
  226. DoAccept(HttpSocket);
  227. }
  228. VOID HandleAccept(SOCKET socket)
  229. {
  230. if ((g_cOpenConnections > g_cMaxOpenConnections) && (socket == HttpSocket))
  231. {
  232. DelayAccept();
  233. }
  234. else
  235. {
  236. DoAccept(socket);
  237. }
  238. }
  239. // Pre-Condition:
  240. // The cs for open connection list is held
  241. BOOL FProcessTcpReceiveBuffer(POPEN_TCP_CONN pOpenConn, RECEIVE_DATA *pData)
  242. {
  243. Assert(pOpenConn);
  244. Assert(pData);
  245. Assert(pData->szBuffer);
  246. Assert(OPEN_TCP_CONN_SIGNATURE == (pOpenConn->iType));
  247. int iLen = 1;
  248. CHAR *szBuf = NULL;
  249. CHAR *pCurrent;
  250. CHAR *szHeaders;
  251. BOOL fNeedToLeave = TRUE;
  252. TraceTag(ttidEventServer, "Partying on pOpenConn 0x%08X, pData->szBuffer='%s'", pOpenConn, pData->szBuffer);
  253. if ( pOpenConn->cbData > MAX_EVENT_BUF_THROTTLE_SIZE ) {
  254. pOpenConn->state = CONNECTION_ERROR_FORCED_CLOSE;
  255. SocketSendErrorResponse(pData->socket, HTTP_STATUS_BAD_REQUEST);
  256. // Gracefully shutdown. Open Conn will be removed in FD_CLOSe
  257. shutdown(pData->socket, SD_SEND);
  258. TraceTag(ttidEventServer, "FProcessTcpReceiveBuffer - Exceeds MAX_EVENT_BUF_THROTTLE_SIZE");
  259. // Try to tear down the connection..
  260. }
  261. else {
  262. // Accumulate data
  263. iLen += strlen(pData->szBuffer);
  264. if (pOpenConn->szData != NULL)
  265. {
  266. iLen += strlen(pOpenConn->szData);
  267. }
  268. szBuf = (CHAR *) malloc(iLen * sizeof(CHAR));
  269. if (!szBuf)
  270. {
  271. TraceError("FProcessTcpReceiveBuffer", E_OUTOFMEMORY);
  272. return FALSE;
  273. }
  274. szBuf[0] = '\0';
  275. if (pOpenConn->szData)
  276. {
  277. strcpy(szBuf, pOpenConn->szData);
  278. free(pOpenConn->szData);
  279. }
  280. strcat(szBuf, pData->szBuffer);
  281. pOpenConn->cbData += pData->cbBuffer;
  282. pOpenConn->szData = szBuf;
  283. }
  284. TraceTag(ttidEventServer, "FProcessTcpReceiveBuffer - Buff Recv %d",pOpenConn->cbData);
  285. switch (pOpenConn->state)
  286. {
  287. case CONNECTION_INIT:
  288. pCurrent = IsHeadersComplete(pOpenConn->szData);
  289. if((pCurrent == NULL) && pOpenConn->cbData > MAX_EVENT_NOTIFY_HEADER_THROTTLE_SIZE )
  290. {
  291. pOpenConn->state = CONNECTION_ERROR_FORCED_CLOSE;
  292. SocketSendErrorResponse(pData->socket, HTTP_STATUS_BAD_REQUEST);
  293. // Gracefully shutdown. Open Conn will be removed in FD_CLOSe
  294. shutdown(pData->socket, SD_SEND);
  295. TraceTag(ttidEventServer, "FProcessTcpReceiveBuffer - Exceeds MAX_EVENT_NOTIFY_HEADER_THROTTLE_SIZE");
  296. // Try to tear down the connection..
  297. }
  298. if ( pCurrent != NULL)
  299. {
  300. pOpenConn->cbHeaders = (DWORD)(pCurrent - (pOpenConn->szData)) + 4;
  301. szHeaders = ParseRequestLine(pOpenConn->szData, &(pOpenConn->ssdpRequest));
  302. if ((szHeaders != NULL) && ( pOpenConn->ssdpRequest.Method == SSDP_NOTIFY ))
  303. {
  304. CHAR *szContent;
  305. szContent = ParseHeaders(szHeaders, &(pOpenConn->ssdpRequest));
  306. if (szContent == NULL)
  307. {
  308. TraceTag(ttidEventServer, "ParseHeaders returned NULL for socket %d",
  309. pOpenConn->socketPeer);
  310. // We've reached a terminal error. Since there might be
  311. // other received data for this connection already in the
  312. // queue, transition to this error state, so that we know
  313. // not to process any more data.
  314. pOpenConn->state = CONNECTION_ERROR_CLOSING;
  315. FreeOpenConnection(pOpenConn);
  316. SocketSendErrorResponse(pData->socket, HTTP_STATUS_BAD_REQUEST);
  317. // Gracefully shutdown. Open Conn will be removed in FD_CLOSe
  318. shutdown(pData->socket, SD_SEND);
  319. }
  320. else
  321. {
  322. if (VerifySsdpHeaders(&(pOpenConn->ssdpRequest)) == FALSE)
  323. {
  324. TraceTag(ttidEventServer, "Verified headers returned false for %d",
  325. pOpenConn->socketPeer);
  326. pOpenConn->state = CONNECTION_ERROR_CLOSING;
  327. SocketSendErrorResponse(pData->socket, HTTP_STATUS_BAD_REQUEST);
  328. // Gracefully shutdown. Open Conn will be removed in FD_CLOSe
  329. shutdown(pData->socket, SD_SEND);
  330. return TRUE;
  331. }
  332. // else
  333. if (ParseContent(szContent,
  334. (pOpenConn->cbData - pOpenConn->cbHeaders),
  335. &(pOpenConn->ssdpRequest)) == TRUE)
  336. {
  337. PSSDP_REQUEST pRequest;
  338. pRequest = (PSSDP_REQUEST) malloc(sizeof(SSDP_REQUEST));
  339. if (pRequest != NULL &&
  340. CopySsdpRequest(pRequest, &(pOpenConn->ssdpRequest)) != FALSE)
  341. {
  342. fNeedToLeave = FALSE;
  343. FreeOpenConnection(pOpenConn);
  344. LeaveCriticalSection(&g_csListOpenConn);
  345. ProcessSsdpRequest(pRequest, pData);
  346. free(pRequest);
  347. }
  348. else
  349. {
  350. FreeOpenConnection(pOpenConn);
  351. if (pRequest)
  352. {
  353. FreeSsdpRequest(pRequest);
  354. free(pRequest);
  355. }
  356. }
  357. }
  358. else
  359. {
  360. // HTTP request not complete
  361. CHAR *szTemp;
  362. szTemp = SzaDupSza(szContent);
  363. free(pOpenConn->szData);
  364. pOpenConn->szData = szTemp;
  365. pOpenConn->state = CONNECTION_HEADERS_READY;
  366. // Done for now, wait for more data
  367. }
  368. }
  369. }
  370. else
  371. {
  372. pOpenConn->state = CONNECTION_ERROR_FORCED_CLOSE;
  373. SocketSendErrorResponse(pData->socket, HTTP_STATUS_BAD_REQUEST);
  374. // Gracefully shutdown. Open Conn will be removed in FD_CLOSe
  375. shutdown(pData->socket, SD_SEND);
  376. }
  377. }
  378. break;
  379. case CONNECTION_HEADERS_READY:
  380. if (ParseContent(pOpenConn->szData,
  381. (pOpenConn->cbData - pOpenConn->cbHeaders),
  382. &(pOpenConn->ssdpRequest)) == TRUE)
  383. {
  384. SSDP_REQUEST ssdpRequest;
  385. if (CopySsdpRequest(&ssdpRequest, &(pOpenConn->ssdpRequest)) != FALSE)
  386. {
  387. fNeedToLeave = FALSE;
  388. FreeOpenConnection(pOpenConn);
  389. LeaveCriticalSection(&g_csListOpenConn);
  390. ProcessSsdpRequest(&ssdpRequest, pData);
  391. }
  392. else
  393. {
  394. FreeOpenConnection(pOpenConn);
  395. FreeSsdpRequest(&ssdpRequest);
  396. }
  397. }
  398. else
  399. {
  400. TraceTag(ttidEventServer, "ParseContent failed!");
  401. }
  402. break;
  403. case CONNECTION_ERROR_CLOSING:
  404. // we've already failed to process this socket but it hasn't yet
  405. // been closed. Don't do anything here.
  406. //
  407. TraceTag(ttidEventServer,
  408. "FProcessTcpReceiveBuffer: "
  409. "connection closing from error, ignoring pData->szBuffer");
  410. break;
  411. }
  412. TraceTag(ttidEventServer, "Done partying on pOpenConn 0x%08X", pOpenConn);
  413. return fNeedToLeave;
  414. }
  415. DWORD LookupListOpenConn(LPVOID pvData)
  416. {
  417. PLIST_ENTRY p;
  418. PLIST_ENTRY pListHead = &g_listOpenConn;
  419. BOOL fLeave = TRUE;
  420. BOOL fCloseConn = FALSE;
  421. RECEIVE_DATA * pData = (RECEIVE_DATA *)pvData;
  422. Assert(pData);
  423. TraceTag(ttidEventServer, "----- Search Open Connections List -----");
  424. AssertSz(pData->szBuffer != NULL, "SocketReceive should have allocated the buffer");
  425. EnterCriticalSection(&g_csListOpenConn);
  426. for (p = pListHead->Flink; p != pListHead;)
  427. {
  428. POPEN_TCP_CONN pOpenConn;
  429. pOpenConn = CONTAINING_RECORD (p, OPEN_TCP_CONN, linkage);
  430. p = p->Flink;
  431. if (pOpenConn->socketPeer == pData->socket)
  432. {
  433. fLeave = FProcessTcpReceiveBuffer(pOpenConn, pData);
  434. fCloseConn = (pOpenConn->state == CONNECTION_ERROR_FORCED_CLOSE)?TRUE:FALSE;
  435. break;
  436. }
  437. }
  438. if (fLeave)
  439. {
  440. LeaveCriticalSection(&g_csListOpenConn);
  441. }
  442. if(fCloseConn)
  443. {
  444. CloseOpenConnection(pData->socket);
  445. }
  446. free(pData->szBuffer);
  447. free(pData);
  448. return 0;
  449. }
  450. VOID RemoveOpenConn(SOCKET socket)
  451. {
  452. PLIST_ENTRY p;
  453. PLIST_ENTRY pListHead = &g_listOpenConn;
  454. int cFound = 0;
  455. TraceTag(ttidEventServer, "----- Search Open Connections List to remove -----");
  456. EnterCriticalSection(&g_csListOpenConn);
  457. for (p = pListHead->Flink; p != pListHead;)
  458. {
  459. POPEN_TCP_CONN pOpenConn;
  460. pOpenConn = CONTAINING_RECORD (p, OPEN_TCP_CONN, linkage);
  461. p = p->Flink;
  462. if (pOpenConn->socketPeer == socket)
  463. {
  464. RemoveEntryList(&pOpenConn->linkage);
  465. g_cOpenConnections--;
  466. FreeOpenConnection(pOpenConn);
  467. free(pOpenConn);
  468. cFound++;
  469. }
  470. }
  471. LeaveCriticalSection(&g_csListOpenConn);
  472. TraceTag(ttidEventServer, "RemoveOpenConn - Found %d",cFound);
  473. while (cFound > 0)
  474. {
  475. if (InterlockedExchange(&cQueuedAccepts, cQueuedAccepts) > 0)
  476. {
  477. DoDelayedAccept();
  478. }
  479. cFound--;
  480. }
  481. TraceTag(ttidEventServer, "RemoveOpenConn - Num of Connections %d",g_cOpenConnections);
  482. }