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.

1004 lines
25 KiB

  1. /*++
  2. Copyright (c) 1999-2000 Microsoft Corporation
  3. File Name:
  4. server.c
  5. Abstract:
  6. This file contains code which implements rpc server start and stop.
  7. Author: Ting Cai
  8. Created: 07/10/1999
  9. --*/
  10. #include <pch.h>
  11. #include "ssdp.h"
  12. #include "status.h"
  13. #include "ssdpfunc.h"
  14. #include "ssdptypes.h"
  15. #include "ssdpnetwork.h"
  16. #include "ncbase.h"
  17. #include "event.h"
  18. #include "ncinet.h"
  19. #include "eventsrv.h"
  20. #include "iphlpapi.h"
  21. #include "announce.h"
  22. #include "notify.h"
  23. #include "search.h"
  24. #include "cache.h"
  25. #include "ReceiveData.h"
  26. #include "InterfaceList.h"
  27. #include "ReceiveData.h"
  28. #include "InterfaceHelper.h"
  29. #define SSDP_MSG_MAX_THROTTLE_SIZE 16384
  30. /*********************************************************************/
  31. /* Global vars for debugging */
  32. /*********************************************************************/
  33. // To-Do: Auto-restart the ssdpsrv.exe.
  34. // Updated through interlocked exchange
  35. static LONG bRegisteredIf = 0;
  36. // static long bRegisteredEp = 0;
  37. LONG bShutdown = 0;
  38. HANDLE ShutDownEvent = NULL;
  39. HWND hWnd = NULL;
  40. SOCKET g_socketTcp;
  41. HANDLE g_hAddrChange = NULL;
  42. OVERLAPPED g_ovAddrChange = {0};
  43. HANDLE g_hEventAddrChange = NULL;
  44. HANDLE g_hAddrChangeWait = NULL;
  45. static const CHAR c_szWindowClassName[] = "SSDP Server Window";
  46. HWND SsdpCreateWindow();
  47. LRESULT CALLBACK SsdpWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
  48. VOID RunMessageLoop();
  49. VOID NTAPI InterfaceChange(PVOID pvContext, BOOLEAN fFlag)
  50. {
  51. DWORD dwStatus;
  52. HWND hwnd = (HWND)pvContext;
  53. TraceTag(ttidSsdpNetwork, "InterfaceChange called!!!!!!!");
  54. ResetNetworkList(hwnd);
  55. dwStatus = NotifyAddrChange(&g_hAddrChange, &g_ovAddrChange);
  56. if (dwStatus != ERROR_SUCCESS && dwStatus != ERROR_IO_PENDING)
  57. {
  58. TraceTag(ttidSsdpNetwork, "NotifyAddrChange returned %d",
  59. dwStatus);
  60. }
  61. }
  62. BOOL FRegisterAddrChange(HWND hwnd)
  63. {
  64. DWORD dwStatus;
  65. BOOL fResult = FALSE;
  66. TraceTag(ttidSsdpNetwork, "RegisterAddrChange() entered...");
  67. g_hEventAddrChange = CreateEvent(NULL, FALSE, FALSE, NULL);
  68. if (g_hEventAddrChange)
  69. {
  70. if (RegisterWaitForSingleObject(&g_hAddrChangeWait, g_hEventAddrChange,
  71. InterfaceChange, (LPVOID)hwnd, INFINITE, 0))
  72. {
  73. TraceTag(ttidSsdpNetwork, "RegisterWaitForSingleObject() "
  74. "succeeded...");
  75. g_ovAddrChange.hEvent = g_hEventAddrChange;
  76. dwStatus = NotifyAddrChange(&g_hAddrChange, &g_ovAddrChange);
  77. if (dwStatus != ERROR_SUCCESS && dwStatus != ERROR_IO_PENDING)
  78. {
  79. TraceTag(ttidSsdpNetwork, "NotifyAddrChange returned %d",
  80. dwStatus);
  81. }
  82. else
  83. {
  84. fResult = TRUE;
  85. TraceTag(ttidSsdpNetwork, "NotifyAddrChange succeeded",
  86. dwStatus);
  87. }
  88. }
  89. }
  90. return fResult;
  91. }
  92. VOID UnregisterAddrChange()
  93. {
  94. if (g_hAddrChangeWait)
  95. {
  96. UnregisterWait(g_hAddrChangeWait);
  97. }
  98. if (g_hEventAddrChange)
  99. {
  100. CloseHandle(g_hEventAddrChange);
  101. }
  102. }
  103. INT SsdpMain(SERVICE_STATUS_HANDLE ssHandle, LPSERVICE_STATUS pStatus)
  104. {
  105. TraceTag(ttidSsdpRpcIf, "SsdpMain - Enter");
  106. unsigned long hThread;
  107. #ifdef DBG
  108. InitializeDebugging();
  109. #endif
  110. // Initialize data structures
  111. HRESULT hr = S_OK;
  112. InitializeListNetwork();
  113. InitializeListOpenConn();
  114. hr = CTimerQueue::Instance().HrInitialize();
  115. if(FAILED(hr))
  116. {
  117. TraceHr(ttidSsdpRpcIf, FAL, hr, FALSE, "SsdpMain - CTimerQueue::Instance().HrInitialize failed");
  118. goto cleanup;
  119. }
  120. hr = CInterfaceHelper::Instance().HrInitialize();
  121. if(FAILED(hr))
  122. {
  123. goto cleanup;
  124. }
  125. hr = CUPnPInterfaceList::Instance().HrInitialize();
  126. if(FAILED(hr))
  127. {
  128. goto cleanup;
  129. TraceHr(ttidSsdpRpcIf, FAL, hr, FALSE, "SsdpMain - CUPnPInterfaceList::Instance().HrInitialize failed");
  130. }
  131. // SSDP socket initialization
  132. if (SocketInit() != 0)
  133. {
  134. TraceTag(ttidError, "SsdpMain - SocketInit failed");
  135. goto cleanup;
  136. }
  137. g_socketTcp = CreateHttpSocket();
  138. if (g_socketTcp == INVALID_SOCKET)
  139. {
  140. TraceTag(ttidError, "SsdpMain - CreateHttpSocket failed");
  141. // Should we continue without eventing?
  142. goto cleanup;
  143. }
  144. if (RpcServerStart() != 0)
  145. {
  146. TraceTag(ttidError, "SsdpMain - RpcServerStart failed");
  147. goto cleanup;
  148. }
  149. hr = CReceiveDataManager::Instance().HrInitialize();
  150. if(FAILED(hr))
  151. {
  152. TraceHr(ttidSsdpRpcIf, FAL, hr, FALSE, "SsdpMain - CReceiveDataManager::Instance().HrInitialize failed");
  153. RpcServerStop();
  154. goto cleanup;
  155. }
  156. // Initializes Max Cache Entries
  157. hr = CSsdpCacheEntryManager::Instance().HrInitialize();
  158. if(FAILED(hr))
  159. {
  160. TraceHr(ttidSsdpRpcIf, FAL, hr, FALSE, "SsdpMain - CSsdpCacheEntryManager::Instance().HrInitialize failed");
  161. RpcServerStop();
  162. goto cleanup;
  163. }
  164. hWnd = SsdpCreateWindow();
  165. if (hWnd == NULL)
  166. {
  167. TraceTag(ttidError, "SsdpMain - SsdpCreateWindow failed");
  168. RpcServerStop();
  169. goto cleanup;
  170. }
  171. if (ListenOnAllNetworks(hWnd) != 0)
  172. {
  173. TraceTag(ttidError, "SsdpMain - ListenOnAllNetworks failed");
  174. RpcServerStop();
  175. goto cleanup;
  176. }
  177. if (StartHttpServer(g_socketTcp, hWnd, SM_TCP) != 0)
  178. {
  179. TraceTag(ttidError, "SsdpMain - StartHttpServer failed");
  180. RpcServerStop();
  181. goto cleanup;
  182. }
  183. if (!FRegisterAddrChange(hWnd))
  184. {
  185. TraceTag(ttidError, "SsdpMain - FRegisterAddrChange failed");
  186. RpcServerStop();
  187. goto cleanup;
  188. }
  189. TraceTag(ttidSsdpRpcIf, "SsdpMain - Performed initialization");
  190. pStatus->dwCurrentState = SERVICE_RUNNING;
  191. if (SetServiceStatus(ssHandle, pStatus) == FALSE)
  192. {
  193. TraceTag(ttidError, "SsdpMain - SetServiceStatus failed");
  194. RpcServerStop();
  195. goto cleanup;
  196. }
  197. TraceTag(ttidSsdpRpcIf, "SSDPSRV service is now started");
  198. RunMessageLoop();
  199. TraceTag(ttidSsdpRpcIf, "SsdpMain - Doing shutdown");
  200. RpcServerStop();
  201. UnregisterAddrChange();
  202. TraceTag(ttidSsdpRpcIf, "Waiting for the shut down event.");
  203. if (ShutDownEvent)
  204. {
  205. WaitForSingleObject(ShutDownEvent,INFINITE);
  206. }
  207. TraceTag(ttidSsdpRpcIf, "Shut down event signaled.");
  208. cleanup:
  209. TraceTag(ttidSsdpRpcIf, "SsdpMain - Doing cleanup");
  210. CReceiveDataManager::Instance().HrShutdown();
  211. CleanupHttpSocket();
  212. CleanupListOpenConn();
  213. CSsdpCacheEntryManager::Instance().HrShutdown();
  214. CTimerQueue::Instance().HrShutdown(INVALID_HANDLE_VALUE);
  215. CUPnPInterfaceList::Instance().HrShutdown();
  216. CInterfaceHelper::Instance().HrShutdown();
  217. CleanupListNetwork(FALSE);
  218. SocketFinish();
  219. TraceTag(ttidSsdpRpcIf, "Finished shutdown cleanup.");
  220. #ifdef DBG
  221. // CloseLogFileHandle(fileLog);
  222. UnInitializeDebugging();
  223. #endif // DBG
  224. if (ShutDownEvent)
  225. {
  226. CloseHandle(ShutDownEvent);
  227. ShutDownEvent = NULL;
  228. }
  229. #ifdef NEVER
  230. if (g_hInetSess)
  231. {
  232. InternetCloseHandle(g_hInetSess);
  233. }
  234. #endif
  235. if (hWnd)
  236. {
  237. DestroyWindow(hWnd);
  238. hWnd = NULL;
  239. }
  240. UnregisterClass(c_szWindowClassName, NULL);
  241. return 0;
  242. }
  243. /*********************************************************************/
  244. /* MIDL allocate and free */
  245. /*********************************************************************/
  246. VOID __RPC_FAR * __RPC_USER midl_user_allocate(size_t len)
  247. {
  248. return(malloc(len));
  249. }
  250. VOID __RPC_USER midl_user_free(VOID __RPC_FAR * ptr)
  251. {
  252. free(ptr);
  253. }
  254. BOOL
  255. IsAuthenticatedUser()
  256. {
  257. BOOL fAuthenticated = FALSE;
  258. DWORD dwSidSize = SECURITY_MAX_SID_SIZE;
  259. SID* pSidAuthenticated = (SID*)midl_user_allocate(dwSidSize);
  260. if (NULL == pSidAuthenticated)
  261. {
  262. goto Cleanup;
  263. }
  264. //
  265. // create SID for the authenticated users
  266. //
  267. if (!CreateWellKnownSid(WinAuthenticatedUserSid,
  268. NULL, // not a domain sid
  269. pSidAuthenticated,
  270. &dwSidSize))
  271. {
  272. // check the error for debug builds, normally we don't care about the error
  273. // because all we can do is to fail the call :)
  274. #ifdef DBG
  275. HRESULT hr = (HRESULT)GetLastError();
  276. #endif
  277. goto Cleanup;
  278. }
  279. //
  280. // check whether current client token has this sid
  281. //
  282. if (!CheckTokenMembership(NULL, //current token
  283. pSidAuthenticated, // sid for the authenticated user
  284. &fAuthenticated))
  285. {
  286. // check the error for debug builds, normally we don't care about the error
  287. // because all we can do is to fail the call :)
  288. #ifdef DBG
  289. HRESULT hr = (HRESULT)GetLastError();
  290. #endif
  291. // just to be on the safe side (as we don't know that CheckTokenMembership
  292. // does not modify fAuthenticated in case of error)
  293. fAuthenticated = FALSE;
  294. goto Cleanup;
  295. }
  296. Cleanup:
  297. if (pSidAuthenticated)
  298. midl_user_free(pSidAuthenticated);
  299. return fAuthenticated;
  300. }
  301. BOOL
  302. IsAnonymousUser()
  303. {
  304. BOOL fAnonymous = FALSE;
  305. DWORD dwSidSize = SECURITY_MAX_SID_SIZE;
  306. SID* pSidAnonymous= (SID*)midl_user_allocate(dwSidSize);
  307. if (NULL == pSidAnonymous)
  308. {
  309. goto Cleanup;
  310. }
  311. //
  312. // create SID for the authenticated users
  313. //
  314. if (!CreateWellKnownSid(WinAnonymousSid,
  315. NULL, // not a domain sid
  316. pSidAnonymous,
  317. &dwSidSize))
  318. {
  319. // check the error for debug builds, normally we don't care about the error
  320. // because all we can do is to fail the call :)
  321. #ifdef DBG
  322. HRESULT hr = (HRESULT)GetLastError();
  323. #endif
  324. goto Cleanup;
  325. }
  326. //
  327. // check whether current client token has this sid
  328. //
  329. if (!CheckTokenMembership(NULL, //current token
  330. pSidAnonymous, // sid for the authenticated user
  331. &fAnonymous))
  332. {
  333. // check the error for debug builds, normally we don't care about the error
  334. // because all we can do is to fail the call :)
  335. #ifdef DBG
  336. HRESULT hr = (HRESULT)GetLastError();
  337. #endif
  338. // just to be on the safe side (as we don't know that CheckTokenMembership
  339. // does not modify fAnonymous in case of error)
  340. fAnonymous = FALSE;
  341. goto Cleanup;
  342. }
  343. Cleanup:
  344. if (pSidAnonymous)
  345. midl_user_free(pSidAnonymous);
  346. return fAnonymous;
  347. }
  348. RPC_STATUS RPC_ENTRY
  349. RpcSecurityCallback( RPC_IF_HANDLE* handle, void* pCtx)
  350. {
  351. RPC_STATUS status = RPC_S_OK;
  352. UINT uiTransportType = 0;
  353. ULONG ulAuthLevel = 0;
  354. ULONG ulAuthSvc = 0;
  355. BOOL fImpersonated = FALSE;
  356. //
  357. // check to make sure incoming call comes through LRPC
  358. //
  359. status = I_RpcBindingInqTransportType(NULL, // current caller
  360. &uiTransportType);
  361. if (status)
  362. goto Cleanup;
  363. if (TRANSPORT_TYPE_LPC != uiTransportType)
  364. {
  365. status = RPC_S_ACCESS_DENIED;
  366. goto Cleanup;
  367. }
  368. //
  369. // retrieve client's authentication information
  370. //
  371. status = RpcBindingInqAuthClient(NULL, // current call
  372. NULL, // don't care about authz handle
  373. NULL, // don't need client' principal name, as he is local
  374. &ulAuthLevel,
  375. &ulAuthSvc,
  376. NULL);
  377. if (status)
  378. goto Cleanup;
  379. //
  380. // we require packet privacy (encryption and signing). with lrpc
  381. // it is set by default, but still, the check is simple
  382. //
  383. if (!(RPC_C_AUTHN_LEVEL_PKT_PRIVACY & ulAuthLevel))
  384. {
  385. status = RPC_S_ACCESS_DENIED;
  386. goto Cleanup;
  387. }
  388. //
  389. // client used some kind of authentication service
  390. //
  391. if (RPC_C_AUTHN_NONE == ulAuthSvc)
  392. {
  393. status = RPC_S_ACCESS_DENIED;
  394. goto Cleanup;
  395. }
  396. //
  397. // impersonate, in order to check caller's token
  398. //
  399. status = RpcImpersonateClient(NULL);
  400. if (status)
  401. goto Cleanup;
  402. fImpersonated = TRUE;
  403. //
  404. // check whether this is an authenticated user (client)
  405. //
  406. if (!IsAuthenticatedUser())
  407. {
  408. status = RPC_S_ACCESS_DENIED;
  409. goto Cleanup;
  410. }
  411. //
  412. // do a separate check for the anonymous user
  413. // (even though i am not sure whether it is applicable for LRPC)
  414. //
  415. if (IsAnonymousUser())
  416. {
  417. status = RPC_S_ACCESS_DENIED;
  418. goto Cleanup;
  419. }
  420. Cleanup:
  421. if (fImpersonated)
  422. RpcRevertToSelf();
  423. //
  424. // this routine is expected to return either success (RPC_S_OK) or
  425. // RPC_S_ACCESS_DENIED, so all other erros should be masked
  426. //
  427. if (status != RPC_S_OK)
  428. status = RPC_S_ACCESS_DENIED;
  429. return status;
  430. }
  431. INT RpcServerStart()
  432. {
  433. RPC_STATUS status = RPC_S_OK;
  434. BOOL fRegisteredRpc = FALSE;
  435. RPC_BINDING_VECTOR* pBindingVector = NULL;
  436. //
  437. // analyze all existing networks available.
  438. //
  439. status = GetNetworks();
  440. if (status)
  441. goto Error;
  442. //
  443. // create the event, to be used to synchronize shutdown
  444. //
  445. ShutDownEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  446. if (ShutDownEvent == NULL)
  447. {
  448. TraceTag(ttidSsdpRpcInit, "Failed to create shut down event (%d)",
  449. GetLastError());
  450. goto Error;
  451. }
  452. //
  453. // now, start the RPC interface
  454. //
  455. //
  456. // Use LPC protocol sequence
  457. //
  458. status = RpcServerUseProtseq((unsigned char*)"ncalrpc",
  459. RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
  460. NULL);
  461. if (status)
  462. goto Error;
  463. //
  464. // use NTLM or kerberos
  465. //
  466. status = RpcServerRegisterAuthInfo(NULL,
  467. RPC_C_AUTHN_GSS_NEGOTIATE,
  468. NULL,
  469. NULL);
  470. if (status)
  471. goto Error;
  472. //
  473. // register our interface,
  474. // RPC_IF_ALLOW_SECURE_ONLY - to allow only users with authentication level higher than
  475. // RPC_C_AUTHN_LEVEL_NONE, even though it is
  476. // unnecessary, as it is superceeded by the security callback
  477. // RPC_IF_AUTOLISTEN - start listening on the interface as soon as interface is registred and
  478. // and stops listening as soon as interface is unregistered
  479. //
  480. status = RpcServerRegisterIfEx(_ssdpsrv_v1_0_s_ifspec,
  481. NULL, // MgrTypeUuid
  482. NULL, // MgrEpv; null means use default
  483. RPC_IF_ALLOW_SECURE_ONLY | RPC_IF_AUTOLISTEN,
  484. RPC_C_LISTEN_MAX_CALLS_DEFAULT,
  485. (RPC_IF_CALLBACK_FN*)RpcSecurityCallback);
  486. if (status)
  487. goto Error;
  488. //
  489. // get the list of available bindings
  490. //
  491. status = RpcServerInqBindings(&pBindingVector);
  492. if (status)
  493. goto Error;
  494. //
  495. // register all the endpoints with the map database
  496. //
  497. status = RpcEpRegister(_ssdpsrv_v1_0_s_ifspec,
  498. pBindingVector,
  499. NULL,
  500. NULL); // no annotation
  501. if (status)
  502. goto Error;
  503. // if we reached this point, everything must have registered successfully
  504. // so we should mark that
  505. fRegisteredRpc = TRUE;
  506. TraceTag(ttidSsdpRpcInit, "RPC server is started");
  507. Cleanup:
  508. if (pBindingVector)
  509. RpcBindingVectorFree(&pBindingVector);
  510. return status;
  511. Error:
  512. TraceTag(ttidSsdpRpcInit, "StartRpcServer failed (%x)", status);
  513. //
  514. // don't cleanup everything, as all this globl stuff, like ShutdownEvent
  515. // is expected to be cleaned from the SsdpMain.
  516. // Rpc is the only stuff that needs to be cleaned up
  517. //
  518. if (fRegisteredRpc)
  519. {
  520. RpcServerStop();
  521. }
  522. goto Cleanup;
  523. }
  524. // Unregister RPC interface, endpoint and close the file if necessary.
  525. INT RpcServerStop()
  526. {
  527. RPC_STATUS status = RPC_S_OK;
  528. status = RpcServerUnregisterIfEx(_ssdpsrv_v1_0_s_ifspec,
  529. NULL, // MgrTypeUuid
  530. 1); // call rundown now
  531. TraceTag(ttidSsdpRpcStop, "Leaving RpcServerStop");
  532. return status;
  533. }
  534. VOID ProcessSsdpRequest(PSSDP_REQUEST pSsdpRequest, RECEIVE_DATA *pData)
  535. {
  536. // Ensure that the socket is in the network list before attempting to
  537. // get its name
  538. //
  539. if (pData->fIsTcpSocket || FReferenceSocket(pData->socket))
  540. {
  541. sockaddr_in addr;
  542. int nSize = sizeof(addr);
  543. getsockname(pData->socket, reinterpret_cast<sockaddr*>(&addr), &nSize);
  544. CInterfaceHelper::Instance().HrResolveAddress(addr.sin_addr.S_un.S_addr,
  545. pSsdpRequest->guidInterface);
  546. if (!pData->fIsTcpSocket)
  547. {
  548. UnreferenceSocket(pData->socket);
  549. }
  550. }
  551. else
  552. {
  553. FreeSsdpRequest(pSsdpRequest);
  554. return;
  555. }
  556. if (!pData->fIsTcpSocket && !pData->fMCast && pSsdpRequest->Method != SSDP_M_SEARCH)
  557. {
  558. FreeSsdpRequest(pSsdpRequest);
  559. return;
  560. }
  561. if (pSsdpRequest->Method == SSDP_M_SEARCH)
  562. {
  563. if (0 == lstrcmpA(pSsdpRequest->RequestUri, "*"))
  564. {
  565. TraceTag(ttidSsdpSocket, "Searching for ST (%s)",
  566. pSsdpRequest->Headers[SSDP_ST]);
  567. CSsdpServiceManager::Instance().HrAddSearchResponse(pSsdpRequest,
  568. &pData->socket,
  569. &pData->RemoteSocket);
  570. }
  571. else
  572. {
  573. TraceTag(ttidSsdpSocket, "Not searching for ST, since URI != '*' (URI='%s')",
  574. pSsdpRequest->RequestUri);
  575. }
  576. }
  577. else if (pSsdpRequest->Method == SSDP_NOTIFY)
  578. {
  579. TraceTag(ttidSsdpSocket, "Receive notification of type (%s)",
  580. pSsdpRequest->Headers[SSDP_NT]);
  581. if (!lstrcmpi(pSsdpRequest->Headers[SSDP_NTS], "upnp:propchange"))
  582. {
  583. if(pSsdpRequest->Headers[GENA_SID])
  584. {
  585. TraceTag(ttidEvents, "ProcessSsdpRequest - upnp:propchange - SID:%s", pSsdpRequest->Headers[GENA_SID]);
  586. }
  587. CSsdpNotifyRequestManager::Instance().HrCheckListNotifyForEvent(pSsdpRequest);
  588. if (pData->fIsTcpSocket || FReferenceSocket(pData->socket))
  589. {
  590. SocketSend(OKResponseHeader, pData->socket, NULL);
  591. if (!pData->fIsTcpSocket)
  592. {
  593. UnreferenceSocket(pData->socket);
  594. }
  595. }
  596. }
  597. else if (!lstrcmpi(pSsdpRequest->Headers[SSDP_NTS], "ssdp:alive") ||
  598. !lstrcmpi(pSsdpRequest->Headers[SSDP_NTS], "ssdp:byebye"))
  599. {
  600. BOOL IsSubscribed;
  601. // preserve source address if possible.
  602. // hack here where we use szSID to hold address
  603. // this should not be used for alive normally.
  604. if (pSsdpRequest->Headers[GENA_SID] == NULL)
  605. {
  606. char* pszIp = GetSourceAddress(pData->RemoteSocket);
  607. pSsdpRequest->Headers[GENA_SID] = (CHAR *) midl_user_allocate(
  608. sizeof(CHAR) * (strlen(pszIp) + 1));
  609. if (pSsdpRequest->Headers[GENA_SID])
  610. {
  611. strcpy(pSsdpRequest->Headers[GENA_SID], pszIp);
  612. }
  613. }
  614. // We only cache notification that clients has subscribed.
  615. IsSubscribed = CSsdpNotifyRequestManager::Instance().FIsAliveOrByebyeInListNotify(pSsdpRequest);
  616. CSsdpCacheEntryManager::Instance().HrUpdateCacheList(pSsdpRequest, IsSubscribed);
  617. }
  618. else
  619. {
  620. // unrecognized NTS type
  621. }
  622. // SsdpMessage fields are freed when clean up cache entry.
  623. // FreeSsdpRequest(pSsdpRequest);
  624. }
  625. else
  626. {
  627. TraceTag(ttidSsdpSocket, "Unrecognized SSDP request.");
  628. }
  629. FreeSsdpRequest(pSsdpRequest);
  630. }
  631. VOID RunMessageLoop()
  632. {
  633. MSG msg;
  634. while (GetMessage(&msg, 0, 0, 0))
  635. {
  636. TranslateMessage(&msg);
  637. DispatchMessage(&msg);
  638. }
  639. TraceTag(ttidSsdpRpcInit, "Message loop is done");
  640. }
  641. HWND SsdpCreateWindow()
  642. {
  643. WNDCLASS WndClass;
  644. HWND hwnd;
  645. //
  646. // Register the window class.
  647. //
  648. WndClass.style = 0;
  649. WndClass.lpfnWndProc = SsdpWindowProc;
  650. WndClass.cbClsExtra = 0;
  651. WndClass.cbWndExtra = 0;
  652. WndClass.hInstance = NULL;
  653. WndClass.hIcon = NULL;
  654. WndClass.hCursor = NULL;
  655. WndClass.hbrBackground = NULL;
  656. WndClass.lpszMenuName = NULL;
  657. WndClass.lpszClassName = c_szWindowClassName;
  658. if (!RegisterClass(&WndClass))
  659. {
  660. TraceTag(ttidSsdpRpcInit, "RegisterClassEx failed.");
  661. return NULL;
  662. }
  663. //
  664. // Create the window.
  665. //
  666. hwnd = CreateWindow(
  667. c_szWindowClassName,
  668. "",
  669. WS_OVERLAPPEDWINDOW,
  670. CW_USEDEFAULT,
  671. CW_USEDEFAULT,
  672. CW_USEDEFAULT,
  673. CW_USEDEFAULT,
  674. NULL,
  675. NULL,
  676. NULL,
  677. NULL
  678. );
  679. if (hwnd == NULL)
  680. {
  681. TraceTag(ttidSsdpRpcInit, "CreateWindow failed.");
  682. return NULL;
  683. }
  684. TraceTag(ttidSsdpRpcInit, "Created window %x", hwnd);
  685. ShowWindow(hwnd, SW_HIDE);
  686. UpdateWindow(hwnd);
  687. return hwnd;
  688. }
  689. LRESULT CALLBACK SsdpWindowProc(
  690. HWND hwnd,
  691. UINT msg,
  692. WPARAM wParam,
  693. LPARAM lParam
  694. )
  695. /*++
  696. Routine Description:
  697. Window message dispatch procedure for our hidden window.
  698. Arguments:
  699. hwnd - The target window handle.
  700. msg - The current message.
  701. wParam - WPARAM value.
  702. lParam - LPARAM value.
  703. Return Value:
  704. LRESULT - The result of the message.
  705. --*/
  706. {
  707. LRESULT Result = 0;
  708. INT EventCode;
  709. INT ErrorCode;
  710. SOCKET Socket;
  711. CHAR * szData;
  712. CHAR * szTcpData;
  713. SOCKADDR_IN RemoteSocket;
  714. DWORD cbBuffSize = 0;
  715. BOOL bMCast;
  716. switch (msg)
  717. {
  718. case SM_SSDP:
  719. Socket = (SOCKET) wParam;
  720. EventCode = WSAGETSELECTEVENT(lParam);
  721. ErrorCode = WSAGETSELECTERROR(lParam);
  722. switch (EventCode)
  723. {
  724. case FD_READ:
  725. if (FReferenceSocket(Socket))
  726. {
  727. cbBuffSize = 0;
  728. if (SocketReceive(Socket, &szData, &cbBuffSize, &RemoteSocket, TRUE, &bMCast) == TRUE)
  729. {
  730. if(cbBuffSize <= SSDP_MSG_MAX_THROTTLE_SIZE )
  731. {
  732. CReceiveDataManager::Instance().HrAddData(
  733. szData,
  734. Socket,
  735. bMCast,
  736. reinterpret_cast<SOCKADDR_IN*>(&RemoteSocket));
  737. }
  738. else
  739. {
  740. // Typical SSDP MSG is less than 1K. If its greater than 16K we suspect a Buffer flood attack.
  741. free(szData);
  742. TraceTag(ttidSsdpRpcInit, "Received SSDP Msg more than 16k");
  743. }
  744. }
  745. UnreferenceSocket(Socket);
  746. }
  747. break;
  748. }
  749. break;
  750. case SM_TCP:
  751. Socket = (SOCKET) wParam;
  752. EventCode = WSAGETSELECTEVENT(lParam);
  753. ErrorCode = WSAGETSELECTERROR(lParam);
  754. switch (EventCode)
  755. {
  756. case FD_READ:
  757. DWORD cbBuffer;
  758. if (SocketReceive(Socket, &szTcpData, &cbBuffer,
  759. &RemoteSocket, FALSE, &bMCast) == TRUE)
  760. {
  761. RECEIVE_DATA * pData = NULL;
  762. pData = (RECEIVE_DATA *)malloc(sizeof(RECEIVE_DATA));
  763. if (pData)
  764. {
  765. CopyMemory(&pData->RemoteSocket, &RemoteSocket,
  766. sizeof(SOCKADDR_IN));
  767. pData->socket = Socket;
  768. pData->szBuffer = szTcpData;
  769. pData->cbBuffer = cbBuffer;
  770. pData->fIsTcpSocket = TRUE;
  771. pData->fMCast = FALSE;
  772. QueueUserWorkItem(LookupListOpenConn, pData, 0);
  773. }
  774. else
  775. {
  776. TraceError("Couldn't allocate sufficient memory!",
  777. E_OUTOFMEMORY);
  778. }
  779. }
  780. break;
  781. case FD_ACCEPT:
  782. TraceTag(ttidSsdpRpcInit, "Ready to accept connection");
  783. HandleAccept(Socket);
  784. break;
  785. case FD_CLOSE:
  786. // To-Do: Do I need to call recv to make sure all available data are read?
  787. TraceTag(ttidSsdpRpcInit, "Closing socket %d", Socket);
  788. closesocket(Socket);
  789. RemoveOpenConn(Socket);
  790. }
  791. break;
  792. case WM_QUERYENDSESSION:
  793. TraceTag(ttidSsdpRpcInit, "Received WM_QUERYENDSESSION message");
  794. if (!(lParam & ENDSESSION_LOGOFF))
  795. {
  796. TraceTag(ttidSsdpRpcInit, "System is shutting down");
  797. }
  798. Result = TRUE;
  799. break;
  800. default:
  801. //
  802. // Pass it through.
  803. //
  804. Result = DefWindowProc( hwnd, msg, wParam, lParam );
  805. break;
  806. }
  807. return Result;
  808. }