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.

1404 lines
41 KiB

  1. #include <pch.h>
  2. #pragma hdrstop
  3. #include <wininet.h>
  4. #include "ssdptypes.h"
  5. #include "notify.h"
  6. #include "ssdpnetwork.h"
  7. #include "ssdpfunc.h"
  8. #include "ssdpsrv.h"
  9. #include "event.h"
  10. #include "ncinet.h"
  11. #include "ncbase.h"
  12. #include "upthread.h"
  13. #include "rundown.h"
  14. #define NOTIFY_RESULT_SIZE 2
  15. static const CHAR c_szDeadNts[] = "upnp:dead";
  16. #if DBG
  17. const DWORD c_csecTimeout = 60 * 3; // 3 minute timeout (debug)
  18. #else
  19. const DWORD c_csecTimeout = 60 * 30; // 30 minute timeout
  20. #endif
  21. const TCHAR c_szSubscribe[] = TEXT("SUBSCRIBE");
  22. const TCHAR c_szUnSubscribe[] = TEXT("UNSUBSCRIBE");
  23. extern const TCHAR c_szHttpVersion[] = TEXT("HTTP/1.1");
  24. const TCHAR c_szSubsHeaderFmt[] = TEXT("NT: upnp:event\r\n"
  25. "Callback: <http://%s:%d/%s>\r\n"
  26. "Timeout: Second-%d\r\n\r\n");
  27. const TCHAR c_szReSubsHeaderFmt[] = TEXT("SID: %s\r\nTimeout: Second-%d\r\n");
  28. const TCHAR c_szUnSubsHeaderFmt[] = TEXT("SID: %s\r\n");
  29. const TCHAR c_szServer[] = TEXT("Server");
  30. const TCHAR c_szTimeout[] = TEXT("Timeout");
  31. const TCHAR c_szSid[] = TEXT("SID");
  32. // URI and port of our listener
  33. const TCHAR c_szNotifyUri[] = TEXT("notify");
  34. const DWORD c_nPort = 5000;
  35. #if DBG
  36. const DWORD c_csecDefaultTimeout = 60 * 1; // 1 minute is default
  37. // subscription timeout (debug)
  38. #else
  39. const DWORD c_csecDefaultTimeout = 60 * 10; // 10 minutes is default
  40. // subscription timeout
  41. #endif
  42. HRESULT HrSendSubscriptionRequest(HINTERNET hin,
  43. LPCTSTR szUrl,
  44. LPCTSTR szSid,
  45. DWORD *pcsecTimeout,
  46. LPTSTR *pszSidOut,
  47. ESSR_TYPE essrt);
  48. CSsdpPendingNotification::CSsdpPendingNotification()
  49. {
  50. ZeroMemory(&m_ssdpRequest, sizeof(m_ssdpRequest));
  51. }
  52. CSsdpPendingNotification::~CSsdpPendingNotification()
  53. {
  54. FreeSsdpRequest(&m_ssdpRequest);
  55. }
  56. HRESULT CSsdpPendingNotification::HrInitialize(const SSDP_REQUEST * pRequest)
  57. {
  58. HRESULT hr = S_OK;
  59. if(!CopySsdpRequest(&m_ssdpRequest, pRequest))
  60. {
  61. hr = E_OUTOFMEMORY;
  62. }
  63. TraceHr(ttidEvents, FAL, hr, FALSE, "CSsdpPendingNotification::HrInitialize");
  64. return hr;
  65. }
  66. HRESULT CSsdpPendingNotification::HrGetRequest(SSDP_REQUEST * pRequest)
  67. {
  68. HRESULT hr = S_OK;
  69. if(!CopySsdpRequest(pRequest, &m_ssdpRequest))
  70. {
  71. hr = E_FAIL;
  72. }
  73. TraceHr(ttidEvents, FAL, hr, FALSE, "CSsdpPendingNotification::HrGetRequest");
  74. return hr;
  75. }
  76. CSsdpNotifyRequest::CSsdpNotifyRequest() : m_timer(*this), m_hNotifySemaphore(INVALID_HANDLE_VALUE)
  77. {
  78. }
  79. CSsdpNotifyRequest::~CSsdpNotifyRequest()
  80. {
  81. }
  82. void CSsdpNotifyRequest::OnRundown(CSsdpNotifyRequest * pNotify)
  83. {
  84. CSsdpNotifyRequestManager::Instance().OnRundown(pNotify);
  85. }
  86. class CNotifyRequestTimerAction : public CWorkItem
  87. {
  88. public:
  89. static HRESULT HrCreate(
  90. CSsdpNotifyRequest * pRequest,
  91. DWORD dwSecTimeout,
  92. const CUString & strSid,
  93. const CUString & strUrl);
  94. private:
  95. CNotifyRequestTimerAction(CSsdpNotifyRequest * pRequest, DWORD dwSecTimeout);
  96. ~CNotifyRequestTimerAction();
  97. CNotifyRequestTimerAction(const CNotifyRequestTimerAction &);
  98. CNotifyRequestTimerAction & operator=(const CNotifyRequestTimerAction &);
  99. DWORD DwRun();
  100. HRESULT HrIntialize(
  101. const CUString & strSid,
  102. const CUString & strUrl);
  103. CSsdpNotifyRequest * m_pRequest;
  104. DWORD m_dwSecTimeout;
  105. CUString m_strSid;
  106. CUString m_strUrl;
  107. };
  108. CNotifyRequestTimerAction::CNotifyRequestTimerAction(CSsdpNotifyRequest * pRequest, DWORD dwSecTimeout)
  109. : m_pRequest(pRequest), m_dwSecTimeout(dwSecTimeout)
  110. {
  111. }
  112. CNotifyRequestTimerAction::~CNotifyRequestTimerAction()
  113. {
  114. }
  115. HRESULT CNotifyRequestTimerAction::HrCreate(
  116. CSsdpNotifyRequest * pRequest,
  117. DWORD dwSecTimeout,
  118. const CUString & strSid,
  119. const CUString & strUrl)
  120. {
  121. HRESULT hr = S_OK;
  122. CNotifyRequestTimerAction * pAction = new CNotifyRequestTimerAction(pRequest, dwSecTimeout);
  123. if(!pAction)
  124. {
  125. hr = E_OUTOFMEMORY;
  126. }
  127. if(SUCCEEDED(hr))
  128. {
  129. hr = pAction->HrIntialize(strSid, strUrl);
  130. if(SUCCEEDED(hr))
  131. {
  132. hr = pAction->HrStart(TRUE);
  133. }
  134. if(FAILED(hr))
  135. {
  136. delete pAction;
  137. }
  138. }
  139. TraceHr(ttidEvents, FAL, hr, FALSE, "CNotifyRequestTimerAction::HrCreate");
  140. return hr;
  141. }
  142. DWORD CNotifyRequestTimerAction::DwRun()
  143. {
  144. HRESULT hr = S_OK;
  145. char * szSid = NULL;
  146. char * szUrl = NULL;
  147. hr = m_strSid.HrGetMultiByteWithAlloc(&szSid);
  148. if(SUCCEEDED(hr))
  149. {
  150. hr = m_strUrl.HrGetMultiByteWithAlloc(&szUrl);
  151. if(SUCCEEDED(hr))
  152. {
  153. hr = HrSendSubscriptionRequest(g_hInetSess, szUrl, szSid, &m_dwSecTimeout,
  154. NULL, SSR_RESUBSCRIBE);
  155. }
  156. }
  157. if(SUCCEEDED(hr))
  158. {
  159. hr = CSsdpNotifyRequestManager::Instance().HrRestartClientResubscribeTimer(
  160. m_pRequest, m_dwSecTimeout);
  161. }
  162. else
  163. {
  164. // Failed to send a re-subscribe. We now need to notify clients that
  165. // a subscription has been lost. Compose a pending notification to
  166. // let them know this fact.
  167. //
  168. SSDP_REQUEST ssdpRequest;
  169. ZeroMemory(&ssdpRequest, sizeof(ssdpRequest));
  170. InitializeSsdpRequest(&ssdpRequest);
  171. ssdpRequest.Headers[GENA_SID] = szSid;
  172. szSid = NULL;
  173. hr = HrCopyString(c_szDeadNts, &ssdpRequest.Headers[SSDP_NTS]);
  174. if(SUCCEEDED(hr))
  175. {
  176. hr = CSsdpNotifyRequestManager::Instance().HrCheckListNotifyForEvent(&ssdpRequest);
  177. }
  178. FreeSsdpRequest(&ssdpRequest);
  179. }
  180. delete [] szSid;
  181. delete [] szUrl;
  182. TraceHr(ttidEvents, FAL, hr, FALSE, "CNotifyRequestTimerAction::DwRun");
  183. return 0;
  184. }
  185. HRESULT CNotifyRequestTimerAction::HrIntialize(
  186. const CUString & strSid,
  187. const CUString & strUrl)
  188. {
  189. HRESULT hr = S_OK;
  190. hr = m_strSid.HrAssign(strSid);
  191. if(SUCCEEDED(hr))
  192. {
  193. hr = m_strUrl.HrAssign(strUrl);
  194. }
  195. TraceHr(ttidEvents, FAL, hr, FALSE, "CNotifyRequestTimerAction::HrIntialize");
  196. return hr;
  197. }
  198. void CSsdpNotifyRequest::TimerFired()
  199. {
  200. HRESULT hr = S_OK;
  201. hr = CNotifyRequestTimerAction::HrCreate(this, this->m_dwSecTimeout, this->m_strSid, this->m_strUrl);
  202. TraceHr(ttidEvents, FAL, hr, FALSE, "CSsdpNotifyRequest::TimerFired");
  203. }
  204. BOOL CSsdpNotifyRequest::TimerTryToLock()
  205. {
  206. return m_critSec.FTryEnter();
  207. }
  208. void CSsdpNotifyRequest::TimerUnlock()
  209. {
  210. m_critSec.Leave();
  211. }
  212. HRESULT CSsdpNotifyRequest::HrRestartClientResubscribeTimer(
  213. DWORD dwSecTimeout)
  214. {
  215. HRESULT hr = S_OK;
  216. CLock lock(m_critSec);
  217. m_dwSecTimeout = dwSecTimeout;
  218. // Do 65% of timeout in milliseconds
  219. DWORD dwTimeoutInMillis = (dwSecTimeout * 65 * 1000) / 100;
  220. hr = m_timer.HrResetTimer(dwTimeoutInMillis);
  221. TraceHr(ttidEvents, FAL, hr, FALSE, "CSsdpNotifyRequest::HrRestartClientResubscribeTimer");
  222. return hr;
  223. }
  224. HRESULT CSsdpNotifyRequest::HrInitializeAlive(
  225. const char * szNT,
  226. HANDLE hNotifySemaphore)
  227. {
  228. if(!szNT)
  229. {
  230. return E_POINTER;
  231. }
  232. HRESULT hr = S_OK;
  233. m_nt = NOTIFY_ALIVE;
  234. hr = m_strNT.HrAssign(szNT);
  235. if(SUCCEEDED(hr))
  236. {
  237. m_hNotifySemaphore = hNotifySemaphore;
  238. m_dwSecTimeout = 0;
  239. }
  240. TraceHr(ttidEvents, FAL, hr, FALSE, "CSsdpNotifyRequest::HrInitializeAlive");
  241. return hr;
  242. }
  243. HRESULT CSsdpNotifyRequest::HrInitializePropChange(
  244. const char * szUrl,
  245. HANDLE hNotifySemaphore)
  246. {
  247. if(!szUrl || !*szUrl)
  248. {
  249. return E_POINTER;
  250. }
  251. HRESULT hr = S_OK;
  252. m_nt = NOTIFY_PROP_CHANGE;
  253. hr = m_strUrl.HrAssign(szUrl);
  254. if(SUCCEEDED(hr))
  255. {
  256. m_hNotifySemaphore = hNotifySemaphore;
  257. m_dwSecTimeout = 0;
  258. }
  259. TraceHr(ttidEvents, FAL, hr, FALSE, "CSsdpNotifyRequest::HrInitializePropChange");
  260. return hr;
  261. }
  262. HRESULT CSsdpNotifyRequest::HrSendPropChangeSubscription(SSDP_REGISTER_INFO ** ppRegisterInfo)
  263. {
  264. HRESULT hr = S_OK;
  265. *ppRegisterInfo = NULL;
  266. char * szUrl = NULL;
  267. char * szSid = NULL;
  268. hr = m_strUrl.HrGetMultiByteWithAlloc(&szUrl);
  269. if(SUCCEEDED(hr))
  270. {
  271. TraceTag(ttidEvents, "CSsdpNotifyRequest::HrSendPropChangeSubscription(this=%x) - About to call HrSendSubscriptionRequest", this);
  272. if (!g_hInetSess)
  273. {
  274. g_hInetSess = HinInternetOpenA("Mozilla/4.0 (compatible; UPnP/1.0; Windows NT/5.1)",
  275. INTERNET_OPEN_TYPE_DIRECT,
  276. NULL, NULL, 0);
  277. }
  278. if (g_hInetSess)
  279. {
  280. hr = HrSendSubscriptionRequest(g_hInetSess,
  281. szUrl,
  282. NULL,
  283. &m_dwSecTimeout,
  284. &szSid,
  285. SSR_SUBSCRIBE);
  286. }
  287. else
  288. {
  289. hr = E_UNEXPECTED;
  290. TraceTag(ttidEvents, "CSsdpNotifyRequest::HrSendPropChangeSubscription - HinInternetOpenA failed!");
  291. }
  292. if(SUCCEEDED(hr))
  293. {
  294. TraceTag(ttidEvents, "CSsdpNotifyRequest::HrSendPropChangeSubscription(this=%x) - Called HrSendSubscriptionRequest - SID:%s", this, szSid);
  295. hr = m_strSid.HrAssign(szSid);
  296. delete [] szSid;
  297. }
  298. delete [] szUrl;
  299. }
  300. if(SUCCEEDED(hr))
  301. {
  302. CLock lock(m_critSec);
  303. // Do 65% of timeout in milliseconds
  304. DWORD dwTimeoutInMillis = (m_dwSecTimeout * 65 * 1000) / 100;
  305. hr = m_timer.HrSetTimer(dwTimeoutInMillis);
  306. if(SUCCEEDED(hr))
  307. {
  308. SSDP_REGISTER_INFO * pRegisterInfo = new SSDP_REGISTER_INFO;
  309. if(!pRegisterInfo)
  310. {
  311. hr = E_OUTOFMEMORY;
  312. }
  313. if(SUCCEEDED(hr))
  314. {
  315. pRegisterInfo->csecTimeout = m_dwSecTimeout;
  316. hr = m_strSid.HrGetMultiByteWithAlloc(&pRegisterInfo->szSid);
  317. if(SUCCEEDED(hr))
  318. {
  319. *ppRegisterInfo = pRegisterInfo;
  320. }
  321. if(FAILED(hr))
  322. {
  323. delete pRegisterInfo;
  324. }
  325. }
  326. }
  327. }
  328. TraceHr(ttidEvents, FAL, hr, FALSE, "CSsdpNotifyRequest::HrSendPropChangeSubscription");
  329. return hr;
  330. }
  331. HRESULT CSsdpNotifyRequest::HrShutdown()
  332. {
  333. HRESULT hr = S_OK;
  334. CLock lock(m_critSec);
  335. if(NOTIFY_PROP_CHANGE == m_nt)
  336. {
  337. hr = m_timer.HrDelete(INVALID_HANDLE_VALUE);
  338. if(SUCCEEDED(hr))
  339. {
  340. char * szUrl = NULL;
  341. char * szSid = NULL;
  342. hr = m_strUrl.HrGetMultiByteWithAlloc(&szUrl);
  343. if(SUCCEEDED(hr))
  344. {
  345. hr = m_strSid.HrGetMultiByteWithAlloc(&szSid);
  346. if(SUCCEEDED(hr))
  347. {
  348. hr = HrSendSubscriptionRequest(g_hInetSess,
  349. szUrl,
  350. szSid,
  351. &m_dwSecTimeout,
  352. NULL,
  353. SSR_UNSUBSCRIBE);
  354. delete [] szSid;
  355. }
  356. delete [] szUrl;
  357. }
  358. }
  359. }
  360. TraceHr(ttidEvents, FAL, hr, FALSE, "CSsdpNotifyRequest::HrShutdown");
  361. return hr;
  362. }
  363. BOOL CSsdpNotifyRequest::FIsMatchBySemaphore(HANDLE hNotifySemaphore)
  364. {
  365. return m_hNotifySemaphore == hNotifySemaphore;
  366. }
  367. BOOL CSsdpNotifyRequest::FIsMatchingEvent(const SSDP_REQUEST * pRequest)
  368. {
  369. BOOL bMatch = FALSE;
  370. BOOL bIsPossibleMatch = pRequest->Headers[SSDP_NTS] &&
  371. !lstrcmpiA(pRequest->Headers[SSDP_NTS], "upnp:propchange");
  372. bIsPossibleMatch = bIsPossibleMatch && pRequest->Headers[CONTENT_TYPE] &&
  373. !_strnicmp(pRequest->Headers[CONTENT_TYPE], "text/xml", strlen("text/xml"));
  374. bIsPossibleMatch = bIsPossibleMatch && (NOTIFY_PROP_CHANGE == m_nt);
  375. if(bIsPossibleMatch)
  376. {
  377. // Ensure that we have a valid SID before letting this continue.
  378. // We enter this critsec so that we will wait until a potential
  379. // subscription has been sent and a SID received for it before this
  380. // code continues.
  381. //
  382. if(m_strSid.GetLength() && pRequest->Headers[GENA_SID])
  383. {
  384. char * szSid = NULL;
  385. HRESULT hr = m_strSid.HrGetMultiByteWithAlloc(&szSid);
  386. if(SUCCEEDED(hr))
  387. {
  388. bMatch = !lstrcmpiA(pRequest->Headers[GENA_SID], szSid);
  389. delete [] szSid;
  390. }
  391. }
  392. }
  393. return bMatch;
  394. }
  395. BOOL CSsdpNotifyRequest::FIsMatchingAliveOrByebye(const SSDP_REQUEST * pRequest)
  396. {
  397. BOOL bMatch = FALSE;
  398. Assert(!lstrcmpiA(pRequest->Headers[SSDP_NTS], "ssdp:alive") ||
  399. !lstrcmpiA(pRequest->Headers[SSDP_NTS], "ssdp:byebye"));
  400. if(NOTIFY_ALIVE == m_nt)
  401. {
  402. char * szNT = NULL;
  403. HRESULT hr = m_strNT.HrGetMultiByteWithAlloc(&szNT);
  404. if(SUCCEEDED(hr))
  405. {
  406. bMatch = !lstrcmpA(szNT, pRequest->Headers[SSDP_NT]);
  407. delete [] szNT;
  408. }
  409. }
  410. return bMatch;
  411. }
  412. HRESULT CSsdpNotifyRequest::HrQueuePendingNotification(const SSDP_REQUEST * pRequest)
  413. {
  414. HRESULT hr = S_OK;
  415. #if DBG
  416. if(SSDP_NOTIFY == pRequest->Method && pRequest->Headers[GENA_SID] && pRequest->Headers[GENA_SEQ])
  417. {
  418. TraceTag(ttidEvents,
  419. "CSsdpNotifyRequest::HrQueuePendingNotification - Event notification for SID:%s",
  420. pRequest->Headers[GENA_SID]);
  421. }
  422. #endif // DBG
  423. CLock lock(m_critSec);
  424. PendingNotificationList pendingNotificationList;
  425. hr = pendingNotificationList.HrPushFrontDefault();
  426. if(SUCCEEDED(hr))
  427. {
  428. hr = pendingNotificationList.Front().HrInitialize(pRequest);
  429. if(SUCCEEDED(hr))
  430. {
  431. m_pendingNotificationList.Append(pendingNotificationList);
  432. TraceTag(ttidEvents, "CSsdpNotifyRequest::HrQueuePendingNotification - releasing semaphore %x", m_hNotifySemaphore);
  433. if(!ReleaseSemaphore(m_hNotifySemaphore, 1, NULL))
  434. {
  435. hr = HrFromLastWin32Error();
  436. }
  437. }
  438. }
  439. TraceHr(ttidEvents, FAL, hr, FALSE, "CSsdpNotifyRequest::HrQueuePendingNotification");
  440. return hr;
  441. }
  442. BOOL CSsdpNotifyRequest::FIsPendingNotification()
  443. {
  444. CLock lock(m_critSec);
  445. return !m_pendingNotificationList.IsEmpty();
  446. }
  447. HRESULT CSsdpNotifyRequest::HrRetreivePendingNotification(MessageList ** ppSvcList)
  448. {
  449. HRESULT hr = S_OK;
  450. CLock lock(m_critSec);
  451. // I am just going to return one item
  452. MessageList * pSvcList = new MessageList;
  453. if(!pSvcList)
  454. {
  455. hr = E_OUTOFMEMORY;
  456. }
  457. if(SUCCEEDED(hr))
  458. {
  459. pSvcList->list = new SSDP_REQUEST;
  460. pSvcList->size = 1;
  461. if(!pSvcList->list)
  462. {
  463. hr = E_OUTOFMEMORY;
  464. }
  465. else
  466. {
  467. ZeroMemory(pSvcList->list, sizeof(SSDP_REQUEST));
  468. }
  469. }
  470. if(SUCCEEDED(hr))
  471. {
  472. if(m_pendingNotificationList.IsEmpty())
  473. {
  474. hr = S_FALSE;
  475. TraceTag(ttidEvents, "CSsdpNotifyRequest::HrRetreivePendingNotification - no pending notifications!");
  476. }
  477. if(S_OK == hr)
  478. {
  479. PendingNotificationList pendingNotificationList;
  480. PendingNotificationList::Iterator iter;
  481. if(S_OK == m_pendingNotificationList.GetIterator(iter))
  482. {
  483. iter.HrMoveToList(pendingNotificationList);
  484. hr = pendingNotificationList.Front().HrGetRequest(pSvcList->list);
  485. }
  486. }
  487. }
  488. if(FAILED(hr))
  489. {
  490. if(pSvcList)
  491. {
  492. delete pSvcList->list;
  493. pSvcList->list = NULL;
  494. pSvcList->size = 0;
  495. }
  496. }
  497. *ppSvcList = pSvcList;
  498. TraceHr(ttidEvents, FAL, hr, FALSE, "CSsdpNotifyRequest::HrRetreivePendingNotification");
  499. return hr;
  500. }
  501. CSsdpNotifyRequestManager CSsdpNotifyRequestManager::s_instance;
  502. CSsdpNotifyRequestManager::CSsdpNotifyRequestManager() : m_unTimestamp(0)
  503. {
  504. m_hEventTimestamp = CreateEvent(NULL, TRUE, FALSE, NULL);
  505. }
  506. CSsdpNotifyRequestManager::~CSsdpNotifyRequestManager()
  507. {
  508. CloseHandle(m_hEventTimestamp);
  509. }
  510. CSsdpNotifyRequestManager & CSsdpNotifyRequestManager::Instance()
  511. {
  512. return s_instance;
  513. }
  514. void CSsdpNotifyRequestManager::OnRundown(CSsdpNotifyRequest * pNotify)
  515. {
  516. HrRemoveInternal(TRUE, NULL, pNotify);
  517. }
  518. HRESULT CSsdpNotifyRequestManager::HrCreateAliveNotifyRequest(
  519. PCONTEXT_HANDLE_TYPE * ppContextHandle,
  520. const char * szNT,
  521. HANDLE hNotifySemaphore)
  522. {
  523. HRESULT hr = S_OK;
  524. CLock lock(m_critSecAliveList);
  525. *ppContextHandle = NULL;
  526. CSsdpNotifyRequest * pRequest = NULL;
  527. NotifyRequestList notifyRequestList;
  528. hr = notifyRequestList.HrPushFrontDefault();
  529. if(SUCCEEDED(hr))
  530. {
  531. hr = notifyRequestList.Front().HrInitializeAlive(szNT, hNotifySemaphore);
  532. if(SUCCEEDED(hr))
  533. {
  534. m_aliveList.Prepend(notifyRequestList);
  535. *ppContextHandle = &m_aliveList.Front();
  536. pRequest = &m_aliveList.Front();
  537. }
  538. }
  539. if(SUCCEEDED(hr) && pRequest)
  540. {
  541. hr = CSsdpRundownSupport::Instance().HrAddRundownItem(pRequest);
  542. }
  543. TraceHr(ttidEvents, FAL, hr, FALSE, "CSsdpNotifyRequestManager::HrCreateAliveNotifyRequest");
  544. return hr;
  545. }
  546. HRESULT CSsdpNotifyRequestManager::HrCreatePropChangeNotifyRequest(
  547. PCONTEXT_HANDLE_TYPE * ppContextHandle,
  548. const char * szUrl,
  549. HANDLE hNotifySemaphore,
  550. SSDP_REGISTER_INFO ** ppRegisterInfo)
  551. {
  552. HRESULT hr = S_OK;
  553. *ppContextHandle = NULL;
  554. CSsdpNotifyRequest * pRequest = NULL;
  555. NotifyRequestList notifyRequestList;
  556. hr = notifyRequestList.HrPushFrontDefault();
  557. if(SUCCEEDED(hr))
  558. {
  559. hr = notifyRequestList.Front().HrInitializePropChange(szUrl, hNotifySemaphore);
  560. if(SUCCEEDED(hr))
  561. {
  562. __int64 unTimestamp = 0;
  563. {
  564. CLock lock(m_critSecTimestampList);
  565. hr = m_timestampList.HrPushFront(m_unTimestamp);
  566. if(SUCCEEDED(hr))
  567. {
  568. unTimestamp = m_unTimestamp;
  569. ++m_unTimestamp;
  570. }
  571. }
  572. if(SUCCEEDED(hr))
  573. {
  574. hr = notifyRequestList.Front().HrSendPropChangeSubscription(ppRegisterInfo);
  575. if(SUCCEEDED(hr))
  576. {
  577. CLock lock(m_critSecPropChangeList);
  578. m_propChangeList.Prepend(notifyRequestList);
  579. *ppContextHandle = &m_propChangeList.Front();
  580. pRequest = &m_propChangeList.Front();
  581. }
  582. CLock lock(m_critSecTimestampList);
  583. TimestampList::Iterator iter;
  584. if(S_OK == m_timestampList.GetIterator(iter))
  585. {
  586. __int64 * pun = NULL;
  587. while(S_OK == iter.HrGetItem(&pun))
  588. {
  589. if(*pun == unTimestamp)
  590. {
  591. iter.HrErase();
  592. break;
  593. }
  594. if(S_OK != iter.HrNext())
  595. {
  596. break;
  597. }
  598. }
  599. }
  600. if(!PulseEvent(m_hEventTimestamp))
  601. {
  602. hr = HrFromLastWin32Error();
  603. TraceHr(ttidError, FAL, hr, FALSE, "CSsdpNotifyRequestManager::HrCreatePropChangeNotifyRequest - PulseEvent failed!");
  604. }
  605. }
  606. }
  607. }
  608. if(SUCCEEDED(hr) && pRequest)
  609. {
  610. hr = CSsdpRundownSupport::Instance().HrAddRundownItem(pRequest);
  611. }
  612. TraceHr(ttidEvents, FAL, hr, FALSE, "CSsdpNotifyRequestManager::HrCreatePropChangeNotifyRequest");
  613. return hr;
  614. }
  615. HRESULT CSsdpNotifyRequestManager::HrRemoveNotifyRequest(
  616. HANDLE hNotifySemaphore)
  617. {
  618. return HrRemoveInternal(FALSE, hNotifySemaphore, NULL);
  619. }
  620. HRESULT CSsdpNotifyRequestManager::HrRemoveNotifyRequestByPointer(
  621. CSsdpNotifyRequest * pRequest)
  622. {
  623. return HrRemoveInternal(FALSE, NULL, pRequest);
  624. }
  625. HRESULT CSsdpNotifyRequestManager::HrCheckListNotifyForEvent(const SSDP_REQUEST * pRequest)
  626. {
  627. HRESULT hr = S_OK;
  628. TraceTag(ttidEvents, "CSsdpNotifyRequestManager::HrCheckListNotifyForEvent");
  629. __int64 unTimestamp = 0;
  630. {
  631. CLock lock(m_critSecTimestampList);
  632. unTimestamp = m_unTimestamp;
  633. }
  634. bool bFound = FALSE;
  635. while(true)
  636. {
  637. {
  638. CLock lock(m_critSecPropChangeList);
  639. NotifyRequestList::Iterator iter;
  640. if(S_OK == m_propChangeList.GetIterator(iter))
  641. {
  642. CSsdpNotifyRequest * pNotifyIter = NULL;
  643. while(S_OK == iter.HrGetItem(&pNotifyIter))
  644. {
  645. if(pNotifyIter->FIsMatchingEvent(pRequest))
  646. {
  647. hr = pNotifyIter->HrQueuePendingNotification(pRequest);
  648. bFound = TRUE;
  649. break;
  650. }
  651. if(S_OK != iter.HrNext())
  652. {
  653. break;
  654. }
  655. }
  656. }
  657. }
  658. if(bFound)
  659. {
  660. break;
  661. }
  662. {
  663. BOOL bAllOlder = TRUE;
  664. CLock lock(m_critSecTimestampList);
  665. TimestampList::Iterator iter;
  666. if(S_OK == m_timestampList.GetIterator(iter))
  667. {
  668. __int64 * pun = NULL;
  669. while(S_OK == iter.HrGetItem(&pun))
  670. {
  671. if(*pun < unTimestamp)
  672. {
  673. bAllOlder = FALSE;
  674. break;
  675. }
  676. if(S_OK != iter.HrNext())
  677. {
  678. break;
  679. }
  680. }
  681. }
  682. if(bAllOlder)
  683. {
  684. break;
  685. }
  686. }
  687. WaitForSingleObject(m_hEventTimestamp, 2000);
  688. }
  689. #if DBG
  690. if(!bFound)
  691. {
  692. TraceTag(ttidEvents, "CSsdpNotifyRequestManager::HrCheckListNotifyForEvent - not found! SID:%s",
  693. pRequest->Headers[GENA_SID] ? pRequest->Headers[GENA_SID] : "<Unknown>");
  694. }
  695. #endif // DBG
  696. TraceHr(ttidEvents, FAL, hr, FALSE, "CSsdpNotifyRequestManager::HrCheckListNotifyForEvent");
  697. return hr;
  698. }
  699. HRESULT CSsdpNotifyRequestManager::HrCheckListNotifyForAliveOrByebye(const SSDP_REQUEST * pRequest)
  700. {
  701. HRESULT hr = S_OK;
  702. CLock lock(m_critSecAliveList);
  703. NotifyRequestList::Iterator iter;
  704. if(S_OK == m_aliveList.GetIterator(iter))
  705. {
  706. CSsdpNotifyRequest * pNotifyIter = NULL;
  707. while(S_OK == iter.HrGetItem(&pNotifyIter))
  708. {
  709. if(pNotifyIter->FIsMatchingAliveOrByebye(pRequest))
  710. {
  711. hr = pNotifyIter->HrQueuePendingNotification(pRequest);
  712. if(FAILED(hr))
  713. {
  714. break;
  715. }
  716. }
  717. if(S_OK != iter.HrNext())
  718. {
  719. break;
  720. }
  721. }
  722. }
  723. TraceHr(ttidEvents, FAL, hr, FALSE, "CSsdpNotifyRequestManager::HrCheckListNotifyForAliveOrByebye");
  724. return hr;
  725. }
  726. BOOL CSsdpNotifyRequestManager::FIsAliveOrByebyeInListNotify(const SSDP_REQUEST * pRequest)
  727. {
  728. HRESULT hr = S_OK;
  729. CLock lock(m_critSecAliveList);
  730. BOOL bRet = FALSE;
  731. NotifyRequestList::Iterator iter;
  732. if(S_OK == m_aliveList.GetIterator(iter))
  733. {
  734. CSsdpNotifyRequest * pNotifyIter = NULL;
  735. while(S_OK == iter.HrGetItem(&pNotifyIter))
  736. {
  737. if(pNotifyIter->FIsMatchingAliveOrByebye(pRequest))
  738. {
  739. bRet = TRUE;
  740. break;
  741. }
  742. if(S_OK != iter.HrNext())
  743. {
  744. break;
  745. }
  746. }
  747. }
  748. TraceHr(ttidEvents, FAL, hr, FALSE, "CSsdpNotifyRequestManager::FIsAliveOrByebyeInListNotify");
  749. return bRet;
  750. }
  751. HRESULT CSsdpNotifyRequestManager::HrRetreivePendingNotification(
  752. HANDLE hNotifySemaphore,
  753. MessageList ** ppSvcList)
  754. {
  755. HRESULT hr = S_OK;
  756. BOOL bFound = FALSE;
  757. {
  758. CLock lock(m_critSecAliveList);
  759. NotifyRequestList::Iterator iter;
  760. if(S_OK == m_aliveList.GetIterator(iter))
  761. {
  762. CSsdpNotifyRequest * pNotifyIter = NULL;
  763. while(S_OK == iter.HrGetItem(&pNotifyIter))
  764. {
  765. if(pNotifyIter->FIsMatchBySemaphore(hNotifySemaphore) && pNotifyIter->FIsPendingNotification())
  766. {
  767. hr = pNotifyIter->HrRetreivePendingNotification(ppSvcList);
  768. bFound = TRUE;
  769. break;
  770. }
  771. if(S_OK != iter.HrNext())
  772. {
  773. break;
  774. }
  775. }
  776. }
  777. }
  778. if(!bFound)
  779. {
  780. CLock lock(m_critSecPropChangeList);
  781. NotifyRequestList::Iterator iter;
  782. if(S_OK == m_propChangeList.GetIterator(iter))
  783. {
  784. CSsdpNotifyRequest * pNotifyIter = NULL;
  785. while(S_OK == iter.HrGetItem(&pNotifyIter))
  786. {
  787. if(pNotifyIter->FIsMatchBySemaphore(hNotifySemaphore) && pNotifyIter->FIsPendingNotification())
  788. {
  789. hr = pNotifyIter->HrRetreivePendingNotification(ppSvcList);
  790. bFound = TRUE;
  791. break;
  792. }
  793. if(S_OK != iter.HrNext())
  794. {
  795. break;
  796. }
  797. }
  798. }
  799. }
  800. // See if this is a bogus release
  801. if(!bFound)
  802. {
  803. *ppSvcList = new MessageList;
  804. if(!*ppSvcList)
  805. {
  806. hr = E_OUTOFMEMORY;
  807. }
  808. if(SUCCEEDED(hr))
  809. {
  810. (*ppSvcList)->size = 0;
  811. (*ppSvcList)->list = NULL;
  812. }
  813. }
  814. TraceHr(ttidEvents, FAL, hr, FALSE, "CSsdpNotifyRequestManager::HrRetreivePendingNotification");
  815. return hr;
  816. }
  817. HRESULT CSsdpNotifyRequestManager::HrRestartClientResubscribeTimer(
  818. CSsdpNotifyRequest * pRequest,
  819. DWORD dwSecTimeout)
  820. {
  821. HRESULT hr = S_OK;
  822. CLock lock(m_critSecPropChangeList);
  823. NotifyRequestList::Iterator iter;
  824. if(S_OK == m_propChangeList.GetIterator(iter))
  825. {
  826. CSsdpNotifyRequest * pNotifyIter = NULL;
  827. while(S_OK == iter.HrGetItem(&pNotifyIter))
  828. {
  829. if(pNotifyIter == pRequest)
  830. {
  831. hr = pNotifyIter->HrRestartClientResubscribeTimer(dwSecTimeout);
  832. break;
  833. }
  834. if(S_OK != iter.HrNext())
  835. {
  836. break;
  837. }
  838. }
  839. }
  840. TraceHr(ttidEvents, FAL, hr, FALSE, "CSsdpNotifyRequestManager::HrRestartClientResubscribeTimer");
  841. return hr;
  842. }
  843. HRESULT CSsdpNotifyRequestManager::HrRemoveInternal(BOOL bRundown, HANDLE hNotifySemaphore, CSsdpNotifyRequest * pRequest)
  844. {
  845. HRESULT hr = S_OK;
  846. NotifyRequestList notifyRequestListRemove;
  847. {
  848. CLock lock(m_critSecAliveList);
  849. NotifyRequestList::Iterator iter;
  850. if(S_OK == m_aliveList.GetIterator(iter))
  851. {
  852. CSsdpNotifyRequest * pNotifyIter = NULL;
  853. while(S_OK == iter.HrGetItem(&pNotifyIter))
  854. {
  855. Assert(!hNotifySemaphore == !!pRequest); // One or the other
  856. if((hNotifySemaphore && pNotifyIter->FIsMatchBySemaphore(hNotifySemaphore)) ||
  857. (pRequest && pNotifyIter == pRequest))
  858. {
  859. if(S_OK != iter.HrMoveToList(notifyRequestListRemove))
  860. {
  861. break;
  862. }
  863. }
  864. if(S_OK != iter.HrNext())
  865. {
  866. break;
  867. }
  868. }
  869. }
  870. }
  871. {
  872. CLock lock(m_critSecPropChangeList);
  873. NotifyRequestList::Iterator iter;
  874. if(S_OK == m_propChangeList.GetIterator(iter))
  875. {
  876. CSsdpNotifyRequest * pNotifyIter = NULL;
  877. while(S_OK == iter.HrGetItem(&pNotifyIter))
  878. {
  879. Assert(!hNotifySemaphore == !!pRequest); // One or the other
  880. if((hNotifySemaphore && pNotifyIter->FIsMatchBySemaphore(hNotifySemaphore)) ||
  881. (pRequest && pNotifyIter == pRequest))
  882. {
  883. if(S_OK != iter.HrMoveToList(notifyRequestListRemove))
  884. {
  885. break;
  886. }
  887. }
  888. if(S_OK != iter.HrNext())
  889. {
  890. break;
  891. }
  892. }
  893. }
  894. }
  895. // Delete the items outside of the lock
  896. {
  897. NotifyRequestList::Iterator iter;
  898. if(S_OK == notifyRequestListRemove.GetIterator(iter))
  899. {
  900. CSsdpNotifyRequest * pNotifyIter = NULL;
  901. while(S_OK == iter.HrGetItem(&pNotifyIter))
  902. {
  903. if(!bRundown)
  904. {
  905. CSsdpRundownSupport::Instance().RemoveRundownItem(pNotifyIter);
  906. }
  907. hr = pNotifyIter->HrShutdown();
  908. if(S_OK != iter.HrNext())
  909. {
  910. break;
  911. }
  912. }
  913. }
  914. }
  915. TraceHr(ttidEvents, FAL, hr, FALSE, "CSsdpNotifyRequestManager::HrRemoveInternal");
  916. return hr;
  917. }
  918. //+---------------------------------------------------------------------------
  919. //
  920. // Function: DwParseTime
  921. //
  922. // Purpose: Parses the Timeout header for a subscription
  923. //
  924. // Arguments:
  925. // szTime [in] Timeout value in the format defined by RFC2518
  926. //
  927. // Returns: Timeout value in SECONDS
  928. //
  929. // Author: danielwe 13 Oct 1999
  930. //
  931. // Notes: NYI
  932. //
  933. DWORD DwParseTime(LPCTSTR szTime)
  934. {
  935. TCHAR szDigits[64];
  936. const TCHAR c_szTimeout[] = TEXT("Second-");
  937. const INT c_cchTimeout = lstrlen(c_szTimeout);
  938. DWORD iDigit = 0;
  939. if (szTime && (lstrlen(szTime) > c_cchTimeout))
  940. {
  941. if (!_strnicmp(szTime, c_szTimeout, c_cchTimeout))
  942. {
  943. DWORD dwDigits;
  944. // Ok we know we have at least "Timeout-x" now
  945. szTime += c_cchTimeout;
  946. *szDigits = 0;
  947. while (isdigit(*szTime) && (iDigit < sizeof(szDigits) - 1))
  948. {
  949. // Copy the digits into the buffer
  950. szDigits[iDigit++] = *szTime++;
  951. }
  952. szDigits[iDigit] = TEXT('\0');
  953. dwDigits = _tcstoul(szDigits, NULL, 10);
  954. if (dwDigits)
  955. {
  956. return dwDigits;
  957. }
  958. else
  959. {
  960. return c_csecDefaultTimeout;
  961. }
  962. }
  963. }
  964. TraceTag(ttidEvents, "DwParseTime: Invalid timeout header %s. Returning "
  965. "default timeout of %d", szTime ? szTime : "<NULL>",
  966. c_csecDefaultTimeout);
  967. return c_csecDefaultTimeout;
  968. }
  969. //+---------------------------------------------------------------------------
  970. //
  971. // Function: HrQueryHeader
  972. //
  973. // Purpose: Helper function to query a header from an HTTP response
  974. //
  975. // Arguments:
  976. // hinR [in] Handle to request
  977. // szHeader [in] Header to query
  978. // pszValue [out] Returns header data
  979. //
  980. // Returns: S_OK if success, or ERROR_INTERNET_* error if failed
  981. //
  982. // Author: danielwe 18 Oct 1999
  983. //
  984. // Notes: Caller should free pszValue when done with it
  985. //
  986. HRESULT HrQueryHeader(HINTERNET hinR, LPCTSTR szHeader, LPTSTR *pszValue)
  987. {
  988. DWORD cbBuffer = 0;
  989. HRESULT hr = S_OK;
  990. // First get the header length
  991. //
  992. hr = HrHttpQueryInfo(hinR, HTTP_QUERY_CUSTOM, (LPTSTR)szHeader,
  993. &cbBuffer, 0);
  994. if (HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) == hr)
  995. {
  996. DWORD cbBuffLen = 0;
  997. cbBuffLen = _tcslen(szHeader);
  998. cbBuffer = ( cbBuffer > cbBuffLen ) ? cbBuffer : cbBuffLen ;
  999. *pszValue = (LPTSTR) malloc(cbBuffer + sizeof(TCHAR));
  1000. if (*pszValue)
  1001. {
  1002. lstrcpy(*pszValue, szHeader);
  1003. hr = HrHttpQueryInfo(hinR, HTTP_QUERY_CUSTOM, *pszValue, &cbBuffer, 0);
  1004. }
  1005. else
  1006. {
  1007. hr = E_OUTOFMEMORY;
  1008. }
  1009. }
  1010. else
  1011. {
  1012. AssertSz(FAILED(hr), "First call to HttpQueryInfo must fail!");
  1013. }
  1014. TraceError("HrQueryHeader", hr);
  1015. return hr;
  1016. }
  1017. HRESULT HrHttpQueryStatusCode(HINTERNET hinR, DWORD *pdwStatus)
  1018. {
  1019. HRESULT hr;
  1020. DWORD cbBuf = sizeof(*pdwStatus);
  1021. Assert(pdwStatus);
  1022. *pdwStatus = 0;
  1023. hr = HrHttpQueryInfo(hinR, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER,
  1024. pdwStatus, &cbBuf, NULL);
  1025. TraceError("HrHttpQueryStatusCode", hr);
  1026. return hr;
  1027. }
  1028. //+---------------------------------------------------------------------------
  1029. //
  1030. // Function: HrSendSubscriptionRequest
  1031. //
  1032. // Purpose: Sends a SUBSCRIBE request based on the data contained within
  1033. // pRequest.
  1034. //
  1035. // Arguments:
  1036. // hin [in] Handle to internet session returned from InternetOpen
  1037. // pRequest [in] Pointer to SSDP_NOTIFY_REQUEST containing information
  1038. // about the subscription that needs to be sent
  1039. // essrt [in] Can be one of:
  1040. // SSR_SUBSCRIBE - sends a subscription request
  1041. // SSR_RESUBSCRIBE - sends a re-subscription request
  1042. // SSR_UNSUBSCRIBE - sends an unsubscription request
  1043. //
  1044. // Returns: S_OK if success, or ERROR_INTERNET_* error if failed
  1045. //
  1046. // Author: danielwe 18 Oct 1999
  1047. //
  1048. // Notes:
  1049. //
  1050. HRESULT HrSendSubscriptionRequest(HINTERNET hin,
  1051. LPCTSTR szUrl,
  1052. LPCTSTR szSid,
  1053. DWORD *pcsecTimeout,
  1054. LPTSTR *pszSidOut,
  1055. ESSR_TYPE essrt)
  1056. {
  1057. HINTERNET hinC;
  1058. INTERNET_PORT ipPort;
  1059. URL_COMPONENTS urlComp = {0};
  1060. TCHAR szHostName[INTERNET_MAX_HOST_NAME_LENGTH];
  1061. TCHAR szUrlPath[INTERNET_MAX_URL_LENGTH];
  1062. HRESULT hr = S_OK;
  1063. Assert(pcsecTimeout);
  1064. // Parse the server name out of the URL
  1065. //
  1066. urlComp.dwStructSize = sizeof(URL_COMPONENTS);
  1067. urlComp.lpszHostName = (LPTSTR) &szHostName;
  1068. urlComp.dwHostNameLength = INTERNET_MAX_HOST_NAME_LENGTH;
  1069. urlComp.lpszUrlPath = (LPTSTR) &szUrlPath;
  1070. urlComp.dwUrlPathLength = INTERNET_MAX_URL_LENGTH;
  1071. hr = HrInternetCrackUrlA(szUrl, 0, 0, &urlComp);
  1072. if (SUCCEEDED(hr))
  1073. {
  1074. hinC = HinInternetConnectA(hin, szHostName, urlComp.nPort, NULL, NULL,
  1075. INTERNET_SERVICE_HTTP, 0, 0);
  1076. if (hinC)
  1077. {
  1078. HINTERNET hinR;
  1079. LPCTSTR szMethod = c_szSubscribe;
  1080. if (SSR_UNSUBSCRIBE == essrt)
  1081. {
  1082. szMethod = c_szUnSubscribe;
  1083. }
  1084. hinR = HinHttpOpenRequestA(hinC, szMethod, szUrlPath,
  1085. c_szHttpVersion, NULL, NULL, 0, 0);
  1086. if (hinR)
  1087. {
  1088. TCHAR szHeaders[1024];
  1089. if (SSR_RESUBSCRIBE == essrt)
  1090. {
  1091. wsprintf(szHeaders, c_szReSubsHeaderFmt, szSid,
  1092. *pcsecTimeout);
  1093. }
  1094. else if (SSR_SUBSCRIBE == essrt)
  1095. {
  1096. SOCKADDR_IN sockIn;
  1097. ULONG nAddr;
  1098. ZeroMemory(&sockIn, sizeof(SOCKADDR_IN));
  1099. hr = GetIpAddress(szHostName, &sockIn);
  1100. if (SUCCEEDED(hr))
  1101. {
  1102. nAddr = sockIn.sin_addr.s_addr;
  1103. wsprintf(szHeaders, c_szSubsHeaderFmt, INET_NTOA(nAddr),
  1104. c_nPort, c_szNotifyUri, c_csecTimeout);
  1105. }
  1106. }
  1107. else if (SSR_UNSUBSCRIBE == essrt)
  1108. {
  1109. wsprintf(szHeaders, c_szUnSubsHeaderFmt, szSid);
  1110. }
  1111. TraceTag(ttidEvents, "Sending request to %s/%s:%d",
  1112. szHostName, szUrlPath, urlComp.nPort);
  1113. TraceTag(ttidEvents, "Sending %s request:",
  1114. essrt == SSR_SUBSCRIBE ? "subscription" :
  1115. essrt == SSR_RESUBSCRIBE ? "re-subscription" :
  1116. essrt == SSR_UNSUBSCRIBE ? "unsubscribe" : "Unknown!");
  1117. TraceTag(ttidEvents, "-----------------------------");
  1118. TraceTag(ttidEvents, "%s", szHeaders);
  1119. TraceTag(ttidEvents, "-----------------------------");
  1120. if (SUCCEEDED(hr))
  1121. {
  1122. hr = HrHttpSendRequestA(hinR, szHeaders, -1, NULL, 0);
  1123. }
  1124. if (SUCCEEDED(hr))
  1125. {
  1126. LPTSTR szTimeout = NULL;
  1127. LPTSTR szServer = NULL;
  1128. DWORD dwStatus;
  1129. hr = HrHttpQueryStatusCode(hinR, &dwStatus);
  1130. if (SUCCEEDED(hr) &&
  1131. (dwStatus == HTTP_STATUS_OK) &&
  1132. (SSR_UNSUBSCRIBE != essrt))
  1133. {
  1134. // First get the server header. We don't care what's
  1135. // in it, just that it was present
  1136. //
  1137. hr = HrQueryHeader(hinR, c_szServer, &szServer);
  1138. if (SUCCEEDED(hr))
  1139. {
  1140. TraceTag(ttidEvents, "Server header contained: %s",
  1141. szServer);
  1142. // Get the SID and Timeout headers from the response
  1143. //
  1144. hr = HrQueryHeader(hinR, c_szTimeout, &szTimeout);
  1145. if (SUCCEEDED(hr))
  1146. {
  1147. *pcsecTimeout = DwParseTime(szTimeout);
  1148. TraceTag(ttidEvents, "Subscribe response has %d for "
  1149. "Timeout", *pcsecTimeout);
  1150. if (essrt == SSR_RESUBSCRIBE)
  1151. {
  1152. LPTSTR szSidNew = NULL;
  1153. Assert(szSid);
  1154. // Handle re-subscription response
  1155. hr = HrQueryHeader(hinR, c_szSid, &szSidNew);
  1156. if (SUCCEEDED(hr))
  1157. {
  1158. AssertSz(!lstrcmpi(szSidNew, szSid),
  1159. "SID from re-subscribe response isn't "
  1160. "the same!");
  1161. TraceTag(ttidEvents, "Resubscribe response has %s for "
  1162. "SID", szSidNew);
  1163. free(szSidNew);
  1164. }
  1165. }
  1166. else
  1167. {
  1168. // Handle subscription response
  1169. Assert(pszSidOut);
  1170. hr = HrQueryHeader(hinR, c_szSid, pszSidOut);
  1171. if (SUCCEEDED(hr))
  1172. {
  1173. TraceTag(ttidEvents, "Subscribe response has %s for "
  1174. "SID", *pszSidOut);
  1175. }
  1176. }
  1177. if (FAILED(hr))
  1178. {
  1179. TraceTag(ttidEvents, "Didn't get SID header from "
  1180. "subscription response!");
  1181. }
  1182. free(szTimeout);
  1183. }
  1184. free(szServer);
  1185. }
  1186. }
  1187. else
  1188. {
  1189. if (SUCCEEDED(hr) && dwStatus != HTTP_STATUS_OK)
  1190. {
  1191. TraceTag(ttidError, "HrSendSubscriptionRequest - Received the following error code (%d)", dwStatus);
  1192. hr = E_FAIL;
  1193. }
  1194. }
  1195. }
  1196. HrInternetCloseHandle(hinR);
  1197. }
  1198. HrInternetCloseHandle(hinC);
  1199. }
  1200. else
  1201. {
  1202. hr = HrFromLastWin32Error();
  1203. }
  1204. }
  1205. TraceError("HrSendSubscriptionRequest", hr);
  1206. return hr;
  1207. }