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.

845 lines
24 KiB

  1. #include "nt.h"
  2. #include "ntrtl.h"
  3. #include "nturtl.h"
  4. #include "objbase.h"
  5. #include <rpcasync.h> // I_RpcExceptionFilter
  6. #include "ssdp.h"
  7. #include "status.h"
  8. #include "list.h"
  9. #include "ssdpapi.h"
  10. #include "common.h"
  11. #include "ncmem.h"
  12. #include "ncdefine.h"
  13. #include "ncdebug.h"
  14. #include "ssdpfuncc.h"
  15. #include "ssdpparser.h"
  16. #include "nccom.h"
  17. #include "ncstring.h"
  18. static LIST_ENTRY listNotify;
  19. PCONTEXT_HANDLE_TYPE g_pSyncContext = NULL;
  20. static HANDLE g_hListNotify = INVALID_HANDLE_VALUE;
  21. static long g_fExiting = 0; // set to 1 when get notification thread is exiting
  22. static long g_fSyncInited = FALSE; // TRUE if SyncHandle is initialized
  23. static HANDLE g_hThread = INVALID_HANDLE_VALUE;
  24. HANDLE g_hLaunchEvent = INVALID_HANDLE_VALUE;
  25. RTL_RESOURCE g_rsrcReg;
  26. static LONG g_lNotKey = 0;
  27. extern LONG cInitialized;
  28. // To-do: Rpc error server is too busy after GetNotificationRpc is in process.
  29. // signal the semaphore in rundown.
  30. VOID AddToListClientNotify(PSSDP_CLIENT_NOTIFY NotifyRequest);
  31. DWORD WINAPI GetNotificationLoop(LPVOID lpvThreadParam);
  32. VOID CallbackOnNotification(MessageList *list);
  33. // Purpose: takes the g_hListNotify mutex and returns
  34. // Note: This should be used only by code that lives on the Notify thread.
  35. // Code that can be executed when servicing an SSDP api call must use
  36. // MsgEnterListNotify instead. The purpose of having two functions
  37. // is to save the notify thread (which has no message loop) from
  38. // going through extra layers of method-call goop.
  39. VOID EnterListNotify()
  40. {
  41. DWORD dwResult;
  42. TraceTag(ttidSsdpCNotify, "Entering g_hListNotify...");
  43. dwResult = ::WaitForSingleObject(g_hListNotify, INFINITE);
  44. TraceTag(ttidSsdpCNotify, "...acquired g_hListNotify");
  45. AssertSz(WAIT_TIMEOUT != dwResult,
  46. "EnterListNotify: unexpected return value");
  47. AssertSz(WAIT_ABANDONED != dwResult,
  48. "EnterListNotify: invalid mutex state");
  49. AssertSz(WAIT_OBJECT_0 == dwResult,
  50. "EnterListNotify: unknown return value");
  51. }
  52. // Purpose: takes the g_hListNotify mutex and returns, servicing the message
  53. // pump while waiting
  54. // Note: This must be used instead of EnterListNotify by any code that
  55. // can be executed on the client thread. Code that lives exclusively
  56. // on the Notify thread should use EnterListNotify() instead.
  57. VOID MsgEnterListNotify()
  58. {
  59. HRESULT hr;
  60. DWORD dwResult;
  61. TraceTag(ttidSsdpCNotify, "Entering HrMyWaitForMultipleHandles");
  62. hr = HrMyWaitForMultipleHandles(0,
  63. INFINITE,
  64. 1,
  65. &g_hListNotify,
  66. &dwResult);
  67. // We shouldn't get RPC_S_CALLPENDING because we're waiting forever
  68. //
  69. Assert(SUCCEEDED(hr));
  70. }
  71. // Purpose: frees the g_hListNotify mutex and returns
  72. VOID LeaveListNotify()
  73. {
  74. BOOL fResult;
  75. TraceTag(ttidSsdpCNotify, "Releasing Mutex");
  76. fResult = ::ReleaseMutex(g_hListNotify);
  77. TraceTag(ttidSsdpCNotify, "Mutex is released");
  78. if (!fResult)
  79. {
  80. TraceLastWin32Error("LeaveListNotify");
  81. }
  82. }
  83. VOID FinishExitNotificationThread()
  84. {
  85. TraceTag(ttidSsdpCNotify, "Removing Sync Handle %x", g_pSyncContext);
  86. RpcTryExcept
  87. {
  88. RemoveSyncHandle(&g_pSyncContext);
  89. }
  90. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  91. {
  92. unsigned long ExceptionCode = RpcExceptionCode();
  93. TraceTag(ttidSsdpCNotify, "FinishExit... reported exception 0x%lx = %ld",
  94. ExceptionCode, ExceptionCode);
  95. }
  96. RpcEndExcept
  97. InterlockedExchange(&g_fSyncInited, 0);
  98. }
  99. VOID CleanupNotificationThread()
  100. {
  101. INT nStatus;
  102. TraceTag(ttidSsdpCNotify, "Cleaning up notif thread: %d", g_hThread);
  103. PLIST_ENTRY p;
  104. PLIST_ENTRY pListHead = &listNotify;
  105. TraceTag(ttidSsdpCNotify, "----- Cleanup SSDP Client Notify List -----");
  106. MsgEnterListNotify();
  107. p = pListHead->Flink;
  108. while (p != pListHead)
  109. {
  110. PSSDP_CLIENT_NOTIFY NotifyRequest;
  111. NotifyRequest = CONTAINING_RECORD (p, SSDP_CLIENT_NOTIFY, linkage);
  112. p = p->Flink;
  113. DeregisterNotification(NotifyRequest);
  114. }
  115. LeaveListNotify();
  116. if (g_hThread && g_hThread != INVALID_HANDLE_VALUE)
  117. {
  118. TraceTag(ttidSsdpCNotify, "Incrementing g_fExiting");
  119. InterlockedExchange(&g_fExiting, 1);
  120. RpcTryExcept
  121. {
  122. TraceTag(ttidSsdpCNotify, "Wakie wakie!");
  123. nStatus = WakeupGetNotificationRpc(g_pSyncContext);
  124. TraceTag(ttidSsdpCNotify, "Wake up returned status %x\n", nStatus);
  125. if (nStatus != 0 )
  126. {
  127. // Big problem, damage control
  128. FinishExitNotificationThread();
  129. }
  130. }
  131. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  132. {
  133. unsigned long ExceptionCode = RpcExceptionCode();
  134. SetLastError(ExceptionCode);
  135. TraceTag(ttidSsdpCNotify, "Wakeup: Runtime reported exception 0x%lx = %ld", ExceptionCode, ExceptionCode);
  136. FinishExitNotificationThread();
  137. }
  138. RpcEndExcept
  139. // note: we have to wait for our notify thread to exit _before_ we
  140. // destroy g_hListNotify, as the notify thread might be holding it
  141. // Wait for the thread to exit since we've just told it to wake up and die
  142. TraceTag(ttidSsdpCNotify, "Waiting for the notification loop thread to exit.\n");
  143. DWORD dwResult = 0;
  144. HrMyWaitForMultipleHandles(
  145. 0,
  146. INFINITE,
  147. 1,
  148. &g_hThread,
  149. &dwResult);
  150. CloseHandle(g_hThread);
  151. g_hThread = INVALID_HANDLE_VALUE;
  152. }
  153. {
  154. BOOL fResult;
  155. fResult = ::CloseHandle(g_hListNotify);
  156. AssertSz(fResult, "CleanupListNotify: CloseHandle(g_hListNotify) failed");
  157. g_hListNotify = INVALID_HANDLE_VALUE;
  158. }
  159. }
  160. HANDLE WINAPI RegisterNotification (NOTIFY_TYPE nt, CHAR * szType,
  161. CHAR *szEventUrl,
  162. SERVICE_CALLBACK_FUNC fnCallback,
  163. VOID *pContext)
  164. {
  165. PSSDP_CLIENT_NOTIFY ClientNotify = NULL;
  166. INT Size = sizeof(SSDP_CLIENT_NOTIFY);
  167. PCONTEXT_HANDLE_TYPE phContext;
  168. INT status;
  169. DWORD ThreadId;
  170. SSDP_REGISTER_INFO info = {0};
  171. SSDP_REGISTER_INFO *pinfo = &info;
  172. BOOL fHoldingListNotify = FALSE;
  173. BOOL bHoldingResource = FALSE;
  174. if (!cInitialized)
  175. {
  176. SetLastError(ERROR_NOT_READY);
  177. return INVALID_HANDLE_VALUE;
  178. }
  179. switch (nt)
  180. {
  181. case NOTIFY_PROP_CHANGE:
  182. if (szEventUrl == NULL || szType != NULL)
  183. {
  184. SetLastError(ERROR_INVALID_PARAMETER);
  185. return INVALID_HANDLE_VALUE;
  186. }
  187. break;
  188. case NOTIFY_ALIVE:
  189. if (szType == NULL || szEventUrl != NULL)
  190. {
  191. SetLastError(ERROR_INVALID_PARAMETER);
  192. return INVALID_HANDLE_VALUE;
  193. }
  194. break;
  195. default:
  196. SetLastError(ERROR_INVALID_PARAMETER);
  197. return INVALID_HANDLE_VALUE;
  198. }
  199. if (fnCallback == NULL)
  200. {
  201. SetLastError(ERROR_INVALID_PARAMETER);
  202. return INVALID_HANDLE_VALUE;
  203. }
  204. ClientNotify = (PSSDP_CLIENT_NOTIFY) malloc(Size);
  205. if (ClientNotify == NULL)
  206. {
  207. TraceTag(ttidSsdpCNotify, "Couldn't allocate memory for "
  208. "ClientNotifyRequest for %s", szType);
  209. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  210. return INVALID_HANDLE_VALUE;
  211. }
  212. ZeroMemory(ClientNotify, sizeof(SSDP_CLIENT_NOTIFY));
  213. switch (nt)
  214. {
  215. case NOTIFY_PROP_CHANGE:
  216. ClientNotify->Type = SSDP_CLIENT_EVENT_SIGNATURE;
  217. ClientNotify->szType = NULL;
  218. ClientNotify->szEventUrl = (CHAR *) malloc(strlen(szEventUrl)+1);
  219. if (ClientNotify->szEventUrl == NULL)
  220. {
  221. TraceTag(ttidSsdpCNotify, "Couldn't allocate memory for "
  222. "szEventUrl for %s", szEventUrl);
  223. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  224. free(ClientNotify);
  225. return INVALID_HANDLE_VALUE;
  226. }
  227. strcpy(ClientNotify->szEventUrl, szEventUrl);
  228. break;
  229. case NOTIFY_ALIVE:
  230. ClientNotify->Type = SSDP_CLIENT_NOTIFY_SIGNATURE;
  231. ClientNotify->szEventUrl = NULL;
  232. ClientNotify->szType = (CHAR *) malloc(strlen(szType)+1);
  233. if (ClientNotify->szType == NULL)
  234. {
  235. TraceTag(ttidSsdpCNotify, "Couldn't allocate memory for "
  236. "szType for %s", szType);
  237. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  238. free(ClientNotify);
  239. return INVALID_HANDLE_VALUE;
  240. }
  241. strcpy(ClientNotify->szType, szType);
  242. break;
  243. default:
  244. ASSERT(FALSE);
  245. return INVALID_HANDLE_VALUE;
  246. }
  247. if (InterlockedCompareExchange(&g_fSyncInited, 1, 0) == 0)
  248. {
  249. // First time ever going into this function
  250. Assert(IsListEmpty(&listNotify));
  251. RpcTryExcept
  252. {
  253. status = InitializeSyncHandle(&g_pSyncContext);
  254. TraceTag(ttidSsdpCNotify, "InitializeSyncHandler returned %d.",
  255. status);
  256. if (status)
  257. {
  258. SetLastError(status);
  259. InterlockedExchange(&g_fSyncInited, 0);
  260. SetEvent(g_hLaunchEvent);
  261. goto cleanup;
  262. }
  263. }
  264. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  265. {
  266. unsigned long ExceptionCode = RpcExceptionCode();
  267. SetLastError(ExceptionCode);
  268. TraceTag(ttidSsdpCNotify, "Runtime reported exception 0x%lx = %ld",
  269. ExceptionCode, ExceptionCode);
  270. InterlockedExchange(&g_fSyncInited, 0);
  271. SetEvent(g_hLaunchEvent);
  272. goto cleanup;
  273. }
  274. RpcEndExcept
  275. // create the thread to continuously get notifications
  276. g_hThread = (HANDLE) CreateThread(NULL, 0, GetNotificationLoop,
  277. (LPVOID) g_pSyncContext, 0, &ThreadId);
  278. if (!g_hThread || g_hThread == INVALID_HANDLE_VALUE)
  279. {
  280. FinishExitNotificationThread();
  281. InterlockedExchange(&g_fSyncInited, 0);
  282. SetLastError(ERROR_OUTOFMEMORY);
  283. }
  284. else
  285. {
  286. // reset this flag!
  287. InterlockedExchange(&g_fExiting, 0);
  288. }
  289. // Let other threads go
  290. SetEvent(g_hLaunchEvent);
  291. }
  292. else
  293. {
  294. DWORD dwResult;
  295. dwResult = WaitForSingleObject(g_hLaunchEvent, INFINITE);
  296. Assert(WAIT_OBJECT_0 == dwResult);
  297. }
  298. // Somehow the thread wasn't created
  299. if (!InterlockedExchange(&g_fSyncInited, g_fSyncInited))
  300. {
  301. TraceTag(ttidSsdpCNotify, "Thread wasn't created! Aborting...");
  302. SetLastError(ERROR_NOT_READY);
  303. goto cleanup;
  304. }
  305. bHoldingResource = RtlAcquireResourceShared(&g_rsrcReg, TRUE);
  306. if(bHoldingResource)
  307. {
  308. __try
  309. {
  310. RpcTryExcept
  311. {
  312. status = RegisterNotificationRpc(&(ClientNotify->HandleServer),
  313. g_pSyncContext, nt, szType,
  314. szEventUrl, &pinfo);
  315. if (status)
  316. {
  317. TraceTag(ttidError, "RegisterNotification: "
  318. "RegisterNotificationRpc failed! %d", status);
  319. SetLastError(status);
  320. goto cleanup;
  321. }
  322. }
  323. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  324. {
  325. unsigned long ExceptionCode = RpcExceptionCode();
  326. SetLastError(ExceptionCode);
  327. TraceTag(ttidSsdpCNotify, "Runtime reported exception 0x%lx = %ld", ExceptionCode, ExceptionCode);
  328. goto cleanup;
  329. }
  330. RpcEndExcept
  331. // add to the client notify request list
  332. ClientNotify->Size = Size;
  333. ClientNotify->Callback = fnCallback;
  334. ClientNotify->Context = pContext;
  335. if (pinfo)
  336. {
  337. Assert(pinfo->szSid);
  338. ClientNotify->szSid = SzaDupSza(pinfo->szSid);
  339. ClientNotify->csecTimeout = pinfo->csecTimeout;
  340. // Done with this
  341. midl_user_free(pinfo->szSid);
  342. }
  343. MsgEnterListNotify();
  344. TraceTag(ttidSsdpCNotify, "Adding %p to list", ClientNotify);
  345. InsertHeadList(&listNotify, &(ClientNotify->linkage));
  346. TraceTag(ttidSsdpCNotify, "Leaving mutex @382");
  347. LeaveListNotify();
  348. }
  349. __finally
  350. {
  351. RtlReleaseResource(&g_rsrcReg);
  352. }
  353. }
  354. TraceTag(ttidSsdpCNotify, "RegisterNotification returning %p", ClientNotify);
  355. return ClientNotify;
  356. cleanup:
  357. if (ClientNotify != NULL)
  358. {
  359. free(ClientNotify->szType);
  360. free(ClientNotify->szEventUrl);
  361. free(ClientNotify->szSid);
  362. free(ClientNotify);
  363. }
  364. return INVALID_HANDLE_VALUE;
  365. }
  366. BOOL WINAPI DeregisterNotification(HANDLE hNotification)
  367. {
  368. INT status = 0;
  369. BOOL fLast = FALSE;
  370. BOOL fRet = FALSE;
  371. PSSDP_CLIENT_NOTIFY ClientNotify = (PSSDP_CLIENT_NOTIFY) hNotification;
  372. if (!ClientNotify)
  373. {
  374. SetLastError(ERROR_INVALID_PARAMETER);
  375. return FALSE;
  376. }
  377. TraceTag(ttidSsdpCNotify, "DeregisterNotification was passed %p:%p",
  378. ClientNotify, &ClientNotify->HandleServer);
  379. if (!cInitialized)
  380. {
  381. SetLastError(ERROR_NOT_READY);
  382. return FALSE;
  383. }
  384. MsgEnterListNotify();
  385. _try
  386. {
  387. if ((ClientNotify->Type != SSDP_CLIENT_NOTIFY_SIGNATURE &&
  388. ClientNotify->Type != SSDP_CLIENT_EVENT_SIGNATURE) ||
  389. ClientNotify->Size != sizeof(SSDP_CLIENT_NOTIFY))
  390. {
  391. LeaveListNotify();
  392. SetLastError(ERROR_INVALID_PARAMETER);
  393. return FALSE;
  394. }
  395. }
  396. _except (1)
  397. {
  398. LeaveListNotify();
  399. unsigned long ExceptionCode = _exception_code();
  400. TraceTag(ttidSsdpCNotify, "Exception 0x%lx = %ld occurred in DeregisterNotification", ExceptionCode, ExceptionCode);
  401. SetLastError(ExceptionCode);
  402. return FALSE;
  403. }
  404. TraceTag(ttidSsdpCNotify, "Removing %p from list", ClientNotify);
  405. RemoveEntryList(&ClientNotify->linkage);
  406. LeaveListNotify();
  407. RpcTryExcept
  408. {
  409. status = DeregisterNotificationRpc(&ClientNotify->HandleServer, fLast);
  410. if (status != 0)
  411. {
  412. TraceTag(ttidSsdpCNotify, "Deregister returned %d", status);
  413. }
  414. ABORT_ON_FAILURE(status);
  415. }
  416. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  417. {
  418. unsigned long ExceptionCode = RpcExceptionCode();
  419. SetLastError(ExceptionCode);
  420. TraceTag(ttidSsdpCNotify, "Runtime reported exception 0x%lx = %ld", ExceptionCode, ExceptionCode);
  421. goto cleanup;
  422. }
  423. RpcEndExcept
  424. TraceTag(ttidSsdpCNotify, "Checking if listNotify is empty\n");
  425. fRet = TRUE;
  426. cleanup:
  427. free(ClientNotify->szType);
  428. free(ClientNotify->szSid);
  429. free(ClientNotify->szEventUrl);
  430. free(ClientNotify);
  431. return fRet;
  432. }
  433. VOID FreeMessageList(MessageList *list)
  434. {
  435. INT i;
  436. if (list != NULL)
  437. {
  438. for (i = 0; i < list->size; i++)
  439. {
  440. SSDP_REQUEST *pSsdpRequest;
  441. pSsdpRequest = list->list+i;
  442. FreeSsdpRequest(pSsdpRequest);
  443. }
  444. free(list->list);
  445. free(list);
  446. }
  447. }
  448. const DWORD c_cRetryMax = 3;
  449. DWORD WINAPI GetNotificationLoop(LPVOID lpvThreadParam)
  450. {
  451. DWORD cRetries = c_cRetryMax;
  452. ULONG ulExceptionCode = 0;
  453. while (1)
  454. {
  455. MessageList *list = NULL;
  456. PCONTEXT_HANDLE_TYPE pSemaphore = (PCONTEXT_HANDLE_TYPE) lpvThreadParam;
  457. if (!cRetries)
  458. {
  459. break;
  460. }
  461. // reset this to make sure
  462. ulExceptionCode = 0;
  463. // To-do: Check if we are exiting?
  464. // To-do: Check memory leak.
  465. RpcTryExcept
  466. {
  467. TraceTag(ttidSsdpCNotify, "Calling GetNotificationRpc...");
  468. GetNotificationRpc(pSemaphore, &list);
  469. }
  470. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  471. {
  472. ulExceptionCode = RpcExceptionCode();
  473. TraceTag(ttidSsdpCNotify, "GetNotif: Runtime reported exception "
  474. "0x%lx = %ld", ulExceptionCode, ulExceptionCode);
  475. }
  476. RpcEndExcept
  477. if (InterlockedExchange(&g_fExiting, g_fExiting) != 0)
  478. {
  479. TraceTag(ttidSsdpCNotify, "GetNotif is exiting.");
  480. FreeMessageList(list);
  481. break;
  482. }
  483. if (list != 0)
  484. {
  485. PrintSsdpMessageList(list);
  486. CallbackOnNotification(list);
  487. }
  488. // Decrement the retry count if there is an error
  489. //
  490. if (NOERROR != ulExceptionCode)
  491. {
  492. cRetries--;
  493. }
  494. else
  495. {
  496. cRetries = c_cRetryMax;
  497. }
  498. }
  499. FinishExitNotificationThread();
  500. TraceTag(ttidSsdpCNotify, "Thread is exiting");
  501. return 0;
  502. }
  503. BOOL InitializeListNotify()
  504. {
  505. Assert(INVALID_HANDLE_VALUE == g_hListNotify);
  506. g_hListNotify = ::CreateMutex(NULL, TRUE, NULL);
  507. if (!g_hListNotify)
  508. {
  509. return FALSE;
  510. }
  511. // note: we don't need to call EnterListNotify() since we passed
  512. // bInitialOwner == TRUE above
  513. //
  514. InitializeListHead(&listNotify);
  515. LeaveListNotify();
  516. return TRUE;
  517. }
  518. BOOL IsInListNotify(CHAR *szType)
  519. {
  520. PLIST_ENTRY p;
  521. PLIST_ENTRY pListHead = &listNotify;
  522. MsgEnterListNotify();
  523. p = pListHead->Flink;
  524. while (p != pListHead)
  525. {
  526. PSSDP_CLIENT_NOTIFY NotifyRequest;
  527. NotifyRequest = CONTAINING_RECORD (p, SSDP_CLIENT_NOTIFY, linkage);
  528. p = p->Flink;
  529. if (NotifyRequest->szType && !lstrcmpi(NotifyRequest->szType, szType))
  530. {
  531. LeaveListNotify();
  532. return TRUE;
  533. }
  534. }
  535. LeaveListNotify();
  536. return FALSE;
  537. }
  538. VOID CallbackOnNotification(MessageList *list)
  539. {
  540. INT i;
  541. PLIST_ENTRY p;
  542. PLIST_ENTRY pListHead = &listNotify;
  543. TraceTag(ttidSsdpCNotify, "Callback on notification list.");
  544. TraceTag(ttidSsdpCNotify, "Trying to get the exclusive lock...");
  545. // Yeah this is a big hack, but it should work. If this is triggered by a call
  546. // to RegisterNotificationRpc then we want to wait before that call has
  547. // finished before allowing this guy to start. We just want to wait, not to
  548. // synchronize access (which the list notify already does).
  549. RtlAcquireResourceExclusive(&g_rsrcReg, TRUE);
  550. TraceTag(ttidSsdpCNotify, "...got it!");
  551. RtlReleaseResource(&g_rsrcReg);
  552. TraceTag(ttidSsdpCNotify, "Released it!");
  553. struct CallbackInfo
  554. {
  555. SERVICE_CALLBACK_FUNC m_pfnCallback;
  556. SSDP_CALLBACK_TYPE m_ssdpCallbackType;
  557. PSSDP_MESSAGE m_pssdpMessage;
  558. void * m_pvContext;
  559. };
  560. long nCallbackCount = 0;
  561. EnterListNotify();
  562. // Go through list once to get a count of items
  563. for (i = 0; i < list->size; i++)
  564. {
  565. SSDP_REQUEST *pSsdpRequest;
  566. pSsdpRequest = list->list+i;
  567. p = pListHead->Flink;
  568. TraceTag(ttidSsdpCNotify, "Searching list to callback...");
  569. while (p != pListHead)
  570. {
  571. TraceTag(ttidSsdpCNotify, "Found an item to check...");
  572. PSSDP_CLIENT_NOTIFY NotifyRequest;
  573. BOOL fShouldCallback;
  574. NotifyRequest = CONTAINING_RECORD (p, SSDP_CLIENT_NOTIFY, linkage);
  575. if (NotifyRequest->Type == SSDP_CLIENT_EVENT_SIGNATURE)
  576. {
  577. // Match the SID in the NOTIFY to the SID in any local
  578. // subscribers
  579. //
  580. fShouldCallback = (pSsdpRequest->Headers[GENA_SID] &&
  581. !lstrcmp(pSsdpRequest->Headers[GENA_SID], NotifyRequest->szSid));
  582. }
  583. else
  584. {
  585. fShouldCallback = (pSsdpRequest->Headers[SSDP_NT] &&
  586. !lstrcmp(pSsdpRequest->Headers[SSDP_NT], NotifyRequest->szType)) ||
  587. (pSsdpRequest->Headers[SSDP_ST] &&
  588. !lstrcmp(pSsdpRequest->Headers[SSDP_ST], NotifyRequest->szType));
  589. }
  590. if (fShouldCallback)
  591. {
  592. ++nCallbackCount;
  593. }
  594. p = p->Flink;
  595. }
  596. }
  597. CallbackInfo * arCallbackInfo = NULL;
  598. if(nCallbackCount)
  599. {
  600. arCallbackInfo = reinterpret_cast<CallbackInfo*>(malloc(nCallbackCount * sizeof(CallbackInfo)));
  601. }
  602. long nCallback = 0;
  603. // Go through list again to store callback info
  604. for (i = 0; i < list->size && arCallbackInfo && nCallback < nCallbackCount; i++)
  605. {
  606. SSDP_REQUEST *pSsdpRequest;
  607. pSsdpRequest = list->list+i;
  608. p = pListHead->Flink;
  609. TraceTag(ttidSsdpCNotify, "Searching list to callback...");
  610. while (p != pListHead)
  611. {
  612. TraceTag(ttidSsdpCNotify, "Found an item to check...");
  613. PSSDP_CLIENT_NOTIFY NotifyRequest;
  614. BOOL fShouldCallback;
  615. NotifyRequest = CONTAINING_RECORD (p, SSDP_CLIENT_NOTIFY, linkage);
  616. if (NotifyRequest->Type == SSDP_CLIENT_EVENT_SIGNATURE)
  617. {
  618. // Match the SID in the NOTIFY to the SID in any local
  619. // subscribers
  620. //
  621. fShouldCallback = (pSsdpRequest->Headers[GENA_SID] &&
  622. !lstrcmp(pSsdpRequest->Headers[GENA_SID], NotifyRequest->szSid));
  623. }
  624. else
  625. {
  626. fShouldCallback = (pSsdpRequest->Headers[SSDP_NT] &&
  627. !lstrcmp(pSsdpRequest->Headers[SSDP_NT], NotifyRequest->szType)) ||
  628. (pSsdpRequest->Headers[SSDP_ST] &&
  629. !lstrcmp(pSsdpRequest->Headers[SSDP_ST], NotifyRequest->szType));
  630. }
  631. if (fShouldCallback)
  632. {
  633. PSSDP_MESSAGE pSsdpMessage;
  634. pSsdpMessage = (PSSDP_MESSAGE) malloc(sizeof(SSDP_MESSAGE));
  635. if (pSsdpMessage != NULL)
  636. {
  637. if (InitializeSsdpMessageFromRequest(pSsdpMessage,
  638. pSsdpRequest) == TRUE)
  639. {
  640. SSDP_CALLBACK_TYPE CallbackType = SSDP_ALIVE;
  641. if (!lstrcmpi(pSsdpRequest->Headers[SSDP_NTS],
  642. "ssdp:byebye"))
  643. {
  644. CallbackType = SSDP_BYEBYE;
  645. }
  646. else if (!lstrcmpi(pSsdpRequest->Headers[SSDP_NTS],
  647. "upnp:propchange"))
  648. {
  649. CallbackType = SSDP_EVENT;
  650. }
  651. else if (!lstrcmpi(pSsdpRequest->Headers[SSDP_NTS],
  652. "upnp:dead"))
  653. {
  654. CallbackType = SSDP_DEAD;
  655. }
  656. arCallbackInfo[nCallback].m_pfnCallback = NotifyRequest->Callback;
  657. arCallbackInfo[nCallback].m_ssdpCallbackType = CallbackType;
  658. arCallbackInfo[nCallback].m_pssdpMessage = pSsdpMessage;
  659. arCallbackInfo[nCallback].m_pvContext = NotifyRequest->Context;
  660. ++nCallback;
  661. }
  662. }
  663. else
  664. {
  665. --nCallbackCount;
  666. TraceTag(ttidSsdpNotify, "Failed to allocate memory for "
  667. "SsdpMessage.");
  668. }
  669. }
  670. p = p->Flink;
  671. }
  672. }
  673. LeaveListNotify();
  674. FreeMessageList(list);
  675. // Make calls without list locked
  676. for(long n = 0; n < nCallbackCount; ++n)
  677. {
  678. arCallbackInfo[n].m_pfnCallback(
  679. arCallbackInfo[n].m_ssdpCallbackType,
  680. arCallbackInfo[n].m_pssdpMessage,
  681. arCallbackInfo[n].m_pvContext);
  682. FreeSsdpMessage(arCallbackInfo[n].m_pssdpMessage);
  683. }
  684. free(arCallbackInfo);
  685. }