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.

1467 lines
42 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 2000.
  5. //
  6. // File: S E A R C H C . C P P
  7. //
  8. // Contents: Client side searching
  9. //
  10. // Notes:
  11. //
  12. // Author: mbend 2 Dec 2000
  13. //
  14. //----------------------------------------------------------------------------
  15. #include <pch.h>
  16. #pragma hdrstop
  17. #include <rpcasync.h> // I_RpcExceptionFilter
  18. #include "searchc.h"
  19. #include "list.h"
  20. #include "ssdpparser.h"
  21. #include "ssdpfuncc.h"
  22. #include "ssdpapi.h"
  23. #include "common.h"
  24. #include "ncbase.h"
  25. #include "ncdefine.h"
  26. #include "ncdebug.h"
  27. #include "nccom.h"
  28. #include "InterfaceTable.h"
  29. #include "iphlpapi.h"
  30. static CHAR *SearchHeader = "\"ssdp:discover\"";
  31. static CHAR *MulticastUri = "*";
  32. static CHAR *MX = "3";
  33. extern LONG cInitialized;
  34. #define MX_VALUE 3000
  35. #define SELECT_TIMEOUT 60
  36. #define NUM_OF_RETRY 2 // 3-1
  37. #define LOOPBACK_ADDR_TIMEOUT 120000 // 2 minutes
  38. CSsdpSearchThread::CSsdpSearchThread(CSsdpSearchRequest * pRequest) : m_pRequest(pRequest)
  39. {
  40. }
  41. CSsdpSearchThread::~CSsdpSearchThread()
  42. {
  43. }
  44. DWORD CSsdpSearchThread::DwRun()
  45. {
  46. return m_pRequest->DwThreadFunc();
  47. }
  48. CSsdpSearchRequest::CSsdpSearchRequest()
  49. : m_searchState(SEARCH_START), m_pfnCallback(NULL), m_pvContext(NULL),
  50. m_searchThread(this), m_nNumOfRetry(NUM_OF_RETRY), m_timer(*this),
  51. m_bHitWire(FALSE), m_hEventDone(NULL), m_bShutdown(FALSE),
  52. m_bOnlyLoopBack(TRUE), m_bDeletedTimer(FALSE)
  53. {
  54. }
  55. CSsdpSearchRequest::~CSsdpSearchRequest()
  56. {
  57. CloseHandle(m_hEventDone);
  58. long nCount = m_socketList.GetCount();
  59. for(long n = 0; n < nCount; ++n)
  60. {
  61. closesocket(m_socketList[n].m_socket);
  62. }
  63. m_socketList.Clear();
  64. ResponseMessageList::Iterator iter;
  65. if(S_OK == m_responseMessageList.GetIterator(iter))
  66. {
  67. SSDP_MESSAGE * pMsg = NULL;
  68. while(S_OK == iter.HrGetItem(&pMsg))
  69. {
  70. delete [] pMsg->szAltHeaders;
  71. delete [] pMsg->szContent;
  72. delete [] pMsg->szLocHeader;
  73. delete [] pMsg->szSid;
  74. delete [] pMsg->szType;
  75. delete [] pMsg->szUSN;
  76. if(S_OK != iter.HrNext())
  77. {
  78. break;
  79. }
  80. }
  81. }
  82. m_responseMessageList.Clear();
  83. }
  84. HRESULT CSsdpSearchRequest::HrInitialize(char * szType)
  85. {
  86. HRESULT hr = S_OK;
  87. if(!szType)
  88. {
  89. return E_INVALIDARG;
  90. }
  91. hr = m_strType.HrAssign(szType);
  92. if(SUCCEEDED(hr))
  93. {
  94. m_hEventDone = CreateEvent(NULL, TRUE, FALSE, NULL);
  95. if(!m_hEventDone)
  96. {
  97. hr = HrFromLastWin32Error();
  98. }
  99. if(SUCCEEDED(hr))
  100. {
  101. SSDP_REQUEST request;
  102. ZeroMemory(&request, sizeof(request));
  103. hr = HrInitializeSsdpSearchRequest(&request, szType);
  104. if(SUCCEEDED(hr))
  105. {
  106. char * szSearch = NULL;
  107. if(!ComposeSsdpRequest(&request, &szSearch))
  108. {
  109. hr = E_OUTOFMEMORY;
  110. }
  111. if(SUCCEEDED(hr))
  112. {
  113. hr = m_strSearch.HrAssign(szSearch);
  114. delete [] szSearch;
  115. }
  116. // Presumably these point to constants and should not be freed
  117. request.Headers[SSDP_MAN] = NULL;
  118. request.Headers[SSDP_MX] = NULL;
  119. request.RequestUri = NULL;
  120. FreeSsdpRequest(&request);
  121. }
  122. }
  123. }
  124. if(SUCCEEDED(hr))
  125. {
  126. hr = HrBuildSocketList();
  127. }
  128. TraceHr(ttidSsdpCNotify, FAL, hr, FALSE, "CSsdpSearchRequest::HrInitialize");
  129. return hr;
  130. }
  131. HRESULT CSsdpSearchRequest::HrBuildSocketList()
  132. {
  133. HRESULT hr = S_OK;
  134. CLock lock(m_critSec);
  135. SOCKET sockInfo = INVALID_SOCKET;
  136. SOCKADDR_IN sockAddrInfo;
  137. sockAddrInfo.sin_family = AF_INET;
  138. sockAddrInfo.sin_addr.s_addr = INADDR_ANY;
  139. sockAddrInfo.sin_port = 0;
  140. m_bOnlyLoopBack = TRUE ;
  141. // Open a socket to query interface list with
  142. sockInfo = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  143. if(INVALID_SOCKET == sockInfo)
  144. {
  145. hr = E_FAIL;
  146. TraceHr(ttidSsdpCNotify, FAL, hr, FALSE, "CSsdpSearchRequest::HrBuildSocketList - socket() failed");
  147. }
  148. if(SUCCEEDED(hr))
  149. {
  150. if(SOCKET_ERROR == bind(sockInfo, reinterpret_cast<sockaddr*>(&sockAddrInfo), sizeof(sockAddrInfo)))
  151. {
  152. hr = E_FAIL;
  153. TraceHr(ttidSsdpCNotify, FAL, hr, FALSE, "CSsdpSearchRequest::HrBuildSocketList - bind() failed");
  154. }
  155. }
  156. if(SUCCEEDED(hr))
  157. {
  158. DWORD cbSocketAddressList = 0;
  159. // Fetch size
  160. WSAIoctl(sockInfo, SIO_ADDRESS_LIST_QUERY, NULL, 0, NULL, 0, &cbSocketAddressList, NULL, NULL);
  161. if(cbSocketAddressList)
  162. {
  163. SOCKET_ADDRESS_LIST * pSocketAddressList = reinterpret_cast<SOCKET_ADDRESS_LIST*>(new char[cbSocketAddressList]);
  164. if(!pSocketAddressList)
  165. {
  166. hr = E_OUTOFMEMORY;
  167. }
  168. if(SUCCEEDED(hr))
  169. {
  170. // Fetch list of interfaces
  171. if(SOCKET_ERROR == WSAIoctl(sockInfo, SIO_ADDRESS_LIST_QUERY, NULL, 0, pSocketAddressList, cbSocketAddressList, &cbSocketAddressList, NULL, NULL))
  172. {
  173. hr = E_FAIL;
  174. TraceHr(ttidSsdpCNotify, FAL, hr, FALSE, "CSsdpSearchRequest::HrBuildSocketList - WSAIoctl() failed");
  175. }
  176. if(SUCCEEDED(hr))
  177. {
  178. GUID guidInterface;
  179. CInterfaceTable interfaceTable;
  180. hr = interfaceTable.HrInitialize();
  181. if(SUCCEEDED(hr))
  182. {
  183. TraceTag(ttidSsdpSearchResp, "CSsdpSearchRequest::BuildSocketList() No of Interface %d ",pSocketAddressList->iAddressCount);
  184. // Insert each interface into the list
  185. for(long n = 0; n < pSocketAddressList->iAddressCount && SUCCEEDED(hr); ++n)
  186. {
  187. SOCKET_ADDRESS * pSockAddr = &pSocketAddressList->Address[n];
  188. SOCKADDR_IN * pSockAddrIn = reinterpret_cast<SOCKADDR_IN*>(pSockAddr->lpSockaddr);
  189. BOOL bBad = pSockAddr->iSockaddrLength == 0 ||
  190. pSockAddr->lpSockaddr == NULL ||
  191. pSockAddr->lpSockaddr->sa_family != AF_INET ||
  192. pSockAddrIn->sin_addr.s_addr == 0;
  193. if(!bBad)
  194. {
  195. hr = interfaceTable.HrMapIpAddressToGuid(pSockAddrIn->sin_addr.S_un.S_addr, guidInterface);
  196. if(SUCCEEDED(hr))
  197. {
  198. SOCKET socket = INVALID_SOCKET;
  199. pSockAddrIn->sin_port = 0;
  200. if(!SocketOpen(&socket, pSockAddrIn, pSockAddrIn->sin_addr.S_un.S_addr, FALSE))
  201. {
  202. hr = E_FAIL;
  203. TraceHr(ttidSsdpCNotify, FAL, hr, FALSE, "CSsdpSearchRequest::HrBuildSocketList - SocketOpen() failed");
  204. }
  205. if(SUCCEEDED(hr))
  206. {
  207. SocketInfo socketInfo;
  208. socketInfo.m_socket = socket;
  209. socketInfo.m_guidInterface = guidInterface;
  210. hr = m_socketList.HrPushBack(socketInfo);
  211. m_bOnlyLoopBack = FALSE;
  212. TraceTag(ttidSsdpCSearch, "CSsdpSearchRequest::BuildSocketList() Loopbackonly(%d)", m_bOnlyLoopBack);
  213. }
  214. }
  215. }
  216. }
  217. }
  218. }
  219. delete [] reinterpret_cast<char*>(pSocketAddressList);
  220. }
  221. }
  222. }
  223. if(SUCCEEDED(hr))
  224. {
  225. // Bind to loopback address if nothing else
  226. SOCKADDR_IN sockAddrLoopback;
  227. sockAddrLoopback.sin_family = AF_INET;
  228. sockAddrLoopback.sin_addr.s_addr = inet_addr("127.0.0.1");
  229. sockAddrLoopback.sin_port = 0;
  230. SOCKET socketLoopback = INVALID_SOCKET;
  231. if(!SocketOpen(&socketLoopback, &sockAddrLoopback, sockAddrLoopback.sin_addr.s_addr, FALSE))
  232. {
  233. hr = E_FAIL;
  234. TraceHr(ttidSsdpCNotify, FAL, hr, FALSE, "CSsdpSearchRequest::HrBuildSocketList - SocketOpen() failed");
  235. }
  236. if(SUCCEEDED(hr))
  237. {
  238. SocketInfo socketInfo;
  239. socketInfo.m_socket = socketLoopback;
  240. ZeroMemory(&socketInfo.m_guidInterface, sizeof(socketInfo.m_guidInterface));
  241. hr = m_socketList.HrPushBack(socketInfo);
  242. }
  243. }
  244. if(FAILED(hr) && m_socketList.GetCount())
  245. {
  246. long nCount = m_socketList.GetCount();
  247. for(long n = 0; n < nCount; ++n)
  248. {
  249. closesocket(m_socketList[n].m_socket);
  250. }
  251. m_socketList.Clear();
  252. }
  253. if(INVALID_SOCKET != sockInfo)
  254. {
  255. closesocket(sockInfo);
  256. }
  257. TraceHr(ttidSsdpCNotify, FAL, hr, FALSE, "CSsdpSearchRequest::HrBuildSocketList");
  258. return hr;
  259. }
  260. HRESULT CSsdpSearchRequest::HrReBuildSocketList()
  261. {
  262. HRESULT hr = S_OK;
  263. {
  264. CLock lock(m_critSec);
  265. long nCount = m_socketList.GetCount();
  266. for(long n = 0; n < nCount; ++n)
  267. {
  268. closesocket(m_socketList[n].m_socket);
  269. }
  270. m_socketList.Clear();
  271. hr = HrBuildSocketList();
  272. }
  273. TraceHr(ttidSsdpCNotify, FAL, hr, FALSE, "CSsdpSearchRequest::HrReBuildSocketList");
  274. return hr;
  275. }
  276. HRESULT CSsdpSearchRequest::HrSocketSend(const char * szData)
  277. {
  278. HRESULT hr = S_OK;
  279. CLock lock(m_critSec);
  280. long nCount = m_socketList.GetCount();
  281. for(long n = 0; n < nCount; ++n)
  282. {
  283. SocketSend(szData, m_socketList[n].m_socket, NULL);
  284. }
  285. TraceHr(ttidSsdpCNotify, FAL, hr, FALSE, "CSsdpSearchRequest::HrSocketSend");
  286. return hr;
  287. }
  288. HRESULT CSsdpSearchRequest::HrProcessLoopbackAddrOnly()
  289. {
  290. HRESULT hr = S_OK;
  291. HANDLE hNotify = NULL;
  292. DWORD dwStatus;
  293. DWORD dwWaitStatus;
  294. HANDLE hInterfaceChangeEvent = NULL;
  295. ZeroMemory(&m_ovInterfaceChange, sizeof(m_ovInterfaceChange));
  296. hInterfaceChangeEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  297. if (hInterfaceChangeEvent)
  298. {
  299. m_ovInterfaceChange.hEvent = hInterfaceChangeEvent;
  300. // NotifyAddrChange will be cancelled when the calling thread dies
  301. // CSsdpSearchRequest, and therefore m_ovInterfaceChange, has a longer lifetime than the thread
  302. dwStatus = NotifyAddrChange(&hNotify, &m_ovInterfaceChange);
  303. if (dwStatus != ERROR_SUCCESS && dwStatus != ERROR_IO_PENDING)
  304. {
  305. TraceTag(ttidSsdpCSearch, "NotifyAddrChange returned %d",dwStatus);
  306. hr = E_FAIL;
  307. }
  308. else
  309. {
  310. TraceTag(ttidSsdpCSearch, "NotifyAddrChange succeeded",dwStatus);
  311. HANDLE hHandles[2] = {hInterfaceChangeEvent, m_hEventDone};
  312. dwWaitStatus = WaitForMultipleObjects(2, hHandles, FALSE, LOOPBACK_ADDR_TIMEOUT);
  313. switch(dwWaitStatus)
  314. {
  315. case WAIT_OBJECT_0:
  316. TraceTag(ttidSsdpCSearch, "Wait Object - IP Addr change notified");
  317. hr = HrReBuildSocketList();
  318. TraceTag(ttidSsdpCSearch, "Rebuilding Socket List - List Count - %d",m_socketList.GetCount());
  319. // falling through intentionally
  320. case WAIT_TIMEOUT:
  321. TraceTag(ttidSsdpCSearch, "AutoIP Time out");
  322. if(SUCCEEDED(hr))
  323. {
  324. char *szSearch = NULL;
  325. hr = m_strSearch.HrGetMultiByteWithAlloc(&szSearch);
  326. if(SUCCEEDED(hr))
  327. {
  328. hr = HrSocketSend(szSearch);
  329. delete [] szSearch;
  330. if(SUCCEEDED(hr))
  331. {
  332. hr = m_timer.HrSetTimer(MX_VALUE);
  333. }
  334. }
  335. }
  336. break;
  337. case WAIT_OBJECT_0 + 1:
  338. TraceTag(ttidSsdpCSearch, "Exiting");
  339. hr = E_FAIL;
  340. break;
  341. default:
  342. hr = E_FAIL;
  343. break;
  344. }
  345. }
  346. }
  347. else
  348. {
  349. hr = E_FAIL;
  350. }
  351. if(hInterfaceChangeEvent != NULL)
  352. CloseHandle(hInterfaceChangeEvent);
  353. TraceHr(ttidSsdpCNotify, FAL, hr, FALSE, "CSsdpSearchRequest::HrProcessLoopbackAddrOnly()");
  354. return hr ;
  355. }
  356. HRESULT CSsdpSearchRequest::HrStartAsync(
  357. BOOL bForceSearch,
  358. SERVICE_CALLBACK_FUNC pfnCallback,
  359. VOID * pvContext)
  360. {
  361. HRESULT hr = S_OK;
  362. SOCKADDR_IN sockAddrIn;
  363. int nSockAddrInSize = sizeof(sockAddrIn);
  364. if (!cInitialized)
  365. {
  366. return HRESULT_FROM_WIN32(ERROR_NOT_READY);
  367. }
  368. if(!pfnCallback)
  369. {
  370. return E_INVALIDARG;
  371. }
  372. m_pfnCallback = pfnCallback;
  373. m_pvContext = pvContext;
  374. m_searchState = SEARCH_DISCOVERING;
  375. if(!m_bOnlyLoopBack)
  376. hr = HrGetCacheResult();
  377. if(SUCCEEDED(hr))
  378. {
  379. if(bForceSearch || !FIsInListNotify(m_strType))
  380. {
  381. if(!m_bOnlyLoopBack)
  382. {
  383. m_bHitWire = TRUE;
  384. char * szSearch = NULL;
  385. hr = m_strSearch.HrGetMultiByteWithAlloc(&szSearch);
  386. if(SUCCEEDED(hr))
  387. {
  388. // Make sure we have some IO before we returned the handle, so getsockname will succeed.
  389. hr = HrSocketSend(szSearch);
  390. delete [] szSearch;
  391. if(SUCCEEDED(hr))
  392. {
  393. hr = m_timer.HrSetTimer(MX_VALUE);
  394. if(SUCCEEDED(hr))
  395. {
  396. {
  397. CLock lock(m_critSec);
  398. hr = m_searchThread.HrStart(FALSE, FALSE);
  399. }
  400. if(FAILED(hr))
  401. {
  402. HrDeleteTimer();
  403. }
  404. }
  405. }
  406. }
  407. }
  408. else
  409. {
  410. hr = m_searchThread.HrStart(FALSE, FALSE);
  411. }
  412. }
  413. }
  414. if(FAILED(hr))
  415. {
  416. (*pfnCallback)(SSDP_DONE, NULL, pvContext);
  417. }
  418. TraceHr(ttidSsdpCNotify, FAL, hr, FALSE, "CSsdpSearchRequest::HrStartAsync");
  419. return hr;
  420. }
  421. HRESULT CSsdpSearchRequest::HrStartSync(BOOL bForceSearch)
  422. {
  423. HRESULT hr = S_OK;
  424. if (!cInitialized)
  425. {
  426. return HRESULT_FROM_WIN32(ERROR_NOT_READY);
  427. }
  428. m_searchState = SEARCH_DISCOVERING;
  429. hr = HrGetCacheResult();
  430. if(SUCCEEDED(hr))
  431. {
  432. if(bForceSearch || !FIsInListNotify(m_strType))
  433. {
  434. m_bHitWire = TRUE;
  435. char * szSearch = NULL;
  436. hr = m_strSearch.HrGetMultiByteWithAlloc(&szSearch);
  437. if(SUCCEEDED(hr))
  438. {
  439. hr = HrSocketSend(szSearch);
  440. delete [] szSearch;
  441. if(SUCCEEDED(hr))
  442. {
  443. hr = m_timer.HrSetTimer(MX_VALUE);
  444. if(SUCCEEDED(hr))
  445. {
  446. hr = DwThreadFunc();
  447. if(SUCCEEDED(hr))
  448. {
  449. if(m_responseMessageList.IsEmpty())
  450. {
  451. hr = HRESULT_FROM_WIN32(ERROR_NO_MORE_SERVICES);
  452. }
  453. }
  454. HrDeleteTimer();
  455. }
  456. }
  457. }
  458. }
  459. }
  460. TraceHr(ttidSsdpCNotify, FAL, hr, FALSE, "CSsdpSearchRequest::HrStartSync");
  461. return hr;
  462. }
  463. HRESULT CSsdpSearchRequest::HrShutdown()
  464. {
  465. HRESULT hr = S_OK;
  466. {
  467. CLock lock(m_critSec);
  468. m_searchState = SEARCH_COMPLETED;
  469. }
  470. if(m_pfnCallback)
  471. {
  472. hr = HrCancelCallback();
  473. if(SUCCEEDED(hr))
  474. {
  475. DWORD dwResult;
  476. if (m_hEventDone)
  477. SetEvent(m_hEventDone);
  478. HANDLE h = m_searchThread.GetThreadHandle();
  479. hr = HrMyWaitForMultipleHandles(0,
  480. INFINITE,
  481. 1,
  482. &h,
  483. &dwResult);
  484. TraceError("CSsdpSearchRequest::HrShutdown: HrMyWaitForMultipleHandles", hr);
  485. }
  486. }
  487. TraceHr(ttidSsdpCNotify, FAL, hr, FALSE, "CSsdpSearchRequest::HrShutdown");
  488. return hr;
  489. }
  490. HRESULT CSsdpSearchRequest::HrCancelCallback()
  491. {
  492. HRESULT hr = S_OK;
  493. CLock lock(m_critSec);
  494. m_bShutdown = TRUE;
  495. hr = HrDeleteTimer();
  496. WakeupSelect();
  497. TraceHr(ttidSsdpCNotify, FAL, hr, FALSE, "CSsdpSearchRequest::HrCancelCallback");
  498. return hr;
  499. }
  500. void CSsdpSearchRequest::WakeupSelect()
  501. {
  502. SOCKADDR_IN sockAddrIn;
  503. int nAddrInSize = sizeof(sockAddrIn);
  504. long nCount = m_socketList.GetCount();
  505. for(long n = 0; n < nCount; ++n)
  506. {
  507. if(SOCKET_ERROR != getsockname(m_socketList[n].m_socket, reinterpret_cast<sockaddr*>(&sockAddrIn), &nAddrInSize))
  508. {
  509. sockAddrIn.sin_addr.s_addr = inet_addr("127.0.0.1");
  510. TraceTag(ttidSsdpCSearch, "CSsdpSearchRequest::WakeupSelect() - sending to 127.0.0.1:%d", ntohs(sockAddrIn.sin_port));
  511. // Will select get this if the socket is not bound to ADDR_ANY?
  512. SocketSend("Q", m_socketList[n].m_socket, &sockAddrIn);
  513. }
  514. else
  515. {
  516. TraceTag(ttidSsdpCSearch, "CSsdpSearchRequest::WakeupSelect() - failed to send loopback packet. (%d)", GetLastError());
  517. // select will eventually timeout, just slower.
  518. }
  519. }
  520. }
  521. HRESULT CSsdpSearchRequest::HrGetCacheResult()
  522. {
  523. HRESULT hr = S_OK;
  524. CLock lock(m_critSec);
  525. MessageList * pMessageList = NULL;
  526. char * szType = NULL;
  527. hr = m_strType.HrGetMultiByteWithAlloc(&szType);
  528. if(SUCCEEDED(hr))
  529. {
  530. RpcTryExcept
  531. {
  532. LookupCacheRpc(szType, &pMessageList);
  533. }
  534. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  535. {
  536. hr = HRESULT_FROM_WIN32(RpcExceptionCode());
  537. TraceTag(ttidSsdpCSearch, "CSsdpSearchRequest::HrGetCacheResult - LookupCacheRpc failed (%x)", RpcExceptionCode());
  538. }
  539. RpcEndExcept
  540. delete [] szType;
  541. if(pMessageList)
  542. {
  543. for(long n = 0; n < pMessageList->size; ++n)
  544. {
  545. hr = HrAddRequestToResponseMessageList(&pMessageList->list[n]);
  546. if(FAILED(hr))
  547. {
  548. break;
  549. }
  550. }
  551. for(long n = 0; n < pMessageList->size; ++n)
  552. {
  553. FreeSsdpRequest(&pMessageList->list[n]);
  554. }
  555. delete [] pMessageList->list;
  556. delete pMessageList;
  557. // Make the callbacks
  558. ResponseMessageList::Iterator iter;
  559. if(S_OK == m_responseMessageList.GetIterator(iter))
  560. {
  561. SSDP_MESSAGE * pSsdpMessage = NULL;
  562. while(S_OK == iter.HrGetItem(&pSsdpMessage))
  563. {
  564. if(m_pfnCallback)
  565. {
  566. (*m_pfnCallback)(SSDP_FOUND, pSsdpMessage, m_pvContext);
  567. }
  568. if(S_OK != iter.HrNext())
  569. {
  570. break;
  571. }
  572. }
  573. }
  574. }
  575. }
  576. TraceHr(ttidSsdpCNotify, FAL, hr, FALSE, "CSsdpSearchRequest::HrGetCacheResult");
  577. return hr;
  578. }
  579. BOOL CSsdpSearchRequest::FIsInListNotify(const CUString & strType)
  580. {
  581. HRESULT hr = S_OK;
  582. CLock lock(m_critSec);
  583. char * szType = NULL;
  584. hr = strType.HrGetMultiByteWithAlloc(&szType);
  585. if(SUCCEEDED(hr))
  586. {
  587. if(!IsInListNotify(szType))
  588. {
  589. hr = S_FALSE;
  590. }
  591. delete [] szType;
  592. }
  593. TraceHr(ttidSsdpCNotify, FAL, hr, FALSE, "CSsdpSearchRequest::FIsInListNotify");
  594. return S_OK == hr;
  595. }
  596. HRESULT CSsdpSearchRequest::HrAddRequestToResponseMessageList(SSDP_REQUEST * pRequest)
  597. {
  598. HRESULT hr = S_OK;
  599. CLock lock(m_critSec);
  600. // Build a temporary item in a list and then transfer
  601. ResponseMessageList responseMessageList;
  602. hr = responseMessageList.HrPushFrontDefault();
  603. if(SUCCEEDED(hr))
  604. {
  605. if(InitializeSsdpMessageFromRequest(&responseMessageList.Front(), pRequest))
  606. {
  607. m_responseMessageList.Prepend(responseMessageList);
  608. }
  609. }
  610. TraceHr(ttidSsdpCNotify, FAL, hr, FALSE, "CSsdpSearchRequest::HrAddRequestToResponseMessageList");
  611. return hr;
  612. }
  613. BOOL CSsdpSearchRequest::FIsInResponseMessageList(const char * szUSN)
  614. {
  615. CLock lock(m_critSec);
  616. BOOL bRet = FALSE;
  617. ResponseMessageList::Iterator iter;
  618. if(S_OK == m_responseMessageList.GetIterator(iter))
  619. {
  620. SSDP_MESSAGE * pSsdpMessage = NULL;
  621. while(S_OK == iter.HrGetItem(&pSsdpMessage))
  622. {
  623. if(!lstrcmpA(szUSN, pSsdpMessage->szUSN))
  624. {
  625. bRet = TRUE;
  626. break;
  627. }
  628. if(S_OK != iter.HrNext())
  629. {
  630. break;
  631. }
  632. }
  633. }
  634. return bRet;
  635. }
  636. DWORD CSsdpSearchRequest::DwThreadFunc()
  637. {
  638. HRESULT hr = S_OK;
  639. fd_set setReadSocket;
  640. timeval tvSelectTimeOut;
  641. tvSelectTimeOut.tv_sec = SELECT_TIMEOUT;
  642. tvSelectTimeOut.tv_usec = 0;
  643. long nRet;
  644. if(m_bOnlyLoopBack)
  645. {
  646. hr = HrProcessLoopbackAddrOnly();
  647. }
  648. if(FAILED(hr))
  649. {
  650. m_bShutdown = TRUE;
  651. SetEvent(m_hEventDone);
  652. }
  653. while(!m_bShutdown)
  654. {
  655. char * szRecvBuf = NULL;
  656. u_long ulBytesReceived;
  657. SOCKADDR_IN sockAddrInRemoteSocket;
  658. SSDP_REQUEST ssdpRequestResponse;
  659. u_long ulBufferSize;
  660. int nSockAddrInSize = sizeof(sockAddrInRemoteSocket);
  661. long n;
  662. long nCount;
  663. FD_ZERO(&setReadSocket);
  664. nCount = m_socketList.GetCount();
  665. for(n = 0; n < nCount; ++n)
  666. {
  667. FD_SET(m_socketList[n].m_socket, &setReadSocket);
  668. }
  669. TraceTag(ttidSsdpCSearch, "CSsdpSearchRequest::DwThreadFunc(this=%x) - about to call select", this);
  670. nRet = select(-1, &setReadSocket, NULL, NULL, &tvSelectTimeOut);
  671. if(SOCKET_ERROR == nRet)
  672. {
  673. TraceTag(ttidSsdpCSearch, "CSsdpSearchRequest::DwThreadFunc - select failed(%d)", nRet);
  674. break;
  675. }
  676. if(!nRet)
  677. {
  678. TraceTag(ttidSsdpCSearch, "CSsdpSearchRequest::DwThreadFunc !!! select timed out !!!, where is loopback packet? ");
  679. hr = HrDeleteTimer();
  680. break;
  681. }
  682. BOOL bBreak = FALSE;
  683. for(n = 0; n < nCount; ++n)
  684. {
  685. if(FD_ISSET(m_socketList[n].m_socket, &setReadSocket))
  686. {
  687. ioctlsocket(m_socketList[n].m_socket, FIONREAD, &ulBufferSize);
  688. szRecvBuf = new char[ulBufferSize + 1];
  689. if(!szRecvBuf)
  690. {
  691. hr = E_OUTOFMEMORY;
  692. }
  693. if(FAILED(hr))
  694. {
  695. hr = HrDeleteTimer();
  696. bBreak = TRUE;
  697. break;
  698. }
  699. if(SUCCEEDED(hr))
  700. {
  701. TraceTag(ttidSsdpCSearch, "CSsdpSearchRequest::DwThreadFunc(this=%x) - about to call recvfrom", this);
  702. ulBytesReceived = recvfrom(m_socketList[n].m_socket, szRecvBuf, ulBufferSize, 0,
  703. reinterpret_cast<sockaddr*>(&sockAddrInRemoteSocket), &nSockAddrInSize);
  704. if(SOCKET_ERROR == ulBytesReceived)
  705. {
  706. CLock lock(m_critSec);
  707. delete [] szRecvBuf;
  708. DWORD dwError = WSAGetLastError();
  709. if(WSAECONNRESET == dwError)
  710. {
  711. TraceTag(ttidSsdpCSearch, "CSsdpSearchRequest::DwThreadFunc - recvfrom failed as this socket has received port unreachable");
  712. continue;
  713. }
  714. TraceTag(ttidError, "CSsdpSearchRequest::DwThreadFunc - recvfrom failed(%d)", dwError);
  715. hr = HrDeleteTimer();
  716. bBreak = TRUE;
  717. break;
  718. }
  719. else
  720. {
  721. szRecvBuf[ulBytesReceived] = 0;
  722. TraceTag(ttidSsdpCSearch, "CSsdpSearchRequest::DwThreadFunc(this=%x) - recvfrom returned: %s", this, szRecvBuf);
  723. }
  724. }
  725. if(SUCCEEDED(hr))
  726. {
  727. if(!InitializeSsdpRequest(&ssdpRequestResponse))
  728. {
  729. hr = E_OUTOFMEMORY;
  730. }
  731. if(SUCCEEDED(hr))
  732. {
  733. if(ParseSsdpResponse(szRecvBuf, &ssdpRequestResponse))
  734. {
  735. // Set the interface on which we received this
  736. ssdpRequestResponse.guidInterface = m_socketList[n].m_guidInterface;
  737. // preserve source address if possible.
  738. // hack here where we use szSID to hold address
  739. // this should not be used for search response normally.
  740. if (ssdpRequestResponse.Headers[GENA_SID] == NULL)
  741. {
  742. char* pszIp = GetSourceAddress(sockAddrInRemoteSocket);
  743. ssdpRequestResponse.Headers[GENA_SID] = (CHAR *) midl_user_allocate(
  744. sizeof(CHAR) * (strlen(pszIp) + 1));
  745. if (ssdpRequestResponse.Headers[GENA_SID])
  746. {
  747. strcpy(ssdpRequestResponse.Headers[GENA_SID], pszIp);
  748. }
  749. }
  750. // Check duplicate
  751. if(!FIsInResponseMessageList(ssdpRequestResponse.Headers[SSDP_USN]))
  752. {
  753. // Build a temporary item in a list and then transfer
  754. ResponseMessageList responseMessageList;
  755. hr = responseMessageList.HrPushFrontDefault();
  756. if(SUCCEEDED(hr))
  757. {
  758. if(InitializeSsdpMessageFromRequest(&responseMessageList.Front(), &ssdpRequestResponse))
  759. {
  760. if(m_pfnCallback)
  761. {
  762. (*m_pfnCallback)(SSDP_FOUND, &responseMessageList.Front(), m_pvContext);
  763. }
  764. CLock lock(m_critSec);
  765. m_responseMessageList.Prepend(responseMessageList);
  766. }
  767. }
  768. RpcTryExcept
  769. {
  770. TraceTag(ttidSsdpCSearch, "CSsdpSearchRequest::DwThreadFunc(this=%x) - about to call UpdateCacheRpc", this);
  771. UpdateCacheRpc(&ssdpRequestResponse);
  772. }
  773. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  774. {
  775. hr = HRESULT_FROM_WIN32(RpcExceptionCode());
  776. TraceTag(ttidSsdpCSearch, "CSsdpSearchRequest::DwThreadFunc - UpdateCacheRpc failed (%x)", RpcExceptionCode());
  777. }
  778. RpcEndExcept
  779. }
  780. FreeSsdpRequest(&ssdpRequestResponse);
  781. }
  782. }
  783. if(FAILED(hr))
  784. {
  785. TraceTag(ttidSsdpCSearch, "CSsdpSearchRequest::DwThreadFunc(this=%x) - processing of select failed", this);
  786. }
  787. }
  788. delete [] szRecvBuf;
  789. szRecvBuf = NULL;
  790. }
  791. if(bBreak)
  792. {
  793. break;
  794. }
  795. }
  796. }
  797. // FindServices ideally should Get Cache at the of search to the most up-to-date info.
  798. // FindServicesCallback ideally should Get Cache first to give faster responses.
  799. // Get the cache at the beginning to make the code common.
  800. {
  801. CLock lock(m_critSec);
  802. long nCount = m_socketList.GetCount();
  803. for(long n = 0; n < nCount; ++n)
  804. {
  805. closesocket(m_socketList[n].m_socket);
  806. }
  807. m_socketList.Clear();
  808. }
  809. if(m_pfnCallback)
  810. {
  811. (*m_pfnCallback)(SSDP_DONE, NULL, m_pvContext);
  812. }
  813. TraceHr(ttidSsdpCNotify, FAL, hr, FALSE, "CSsdpSearchRequest::DwThreadFunc");
  814. return hr;
  815. }
  816. void CSsdpSearchRequest::TimerFired()
  817. {
  818. HRESULT hr = S_OK;
  819. TraceTag(ttidSsdpCSearch, "CSsdpSearchRequest::TimerFired(this=%x, count=%d)", this, m_nNumOfRetry);
  820. if(m_bShutdown)
  821. {
  822. SetEvent(m_hEventDone);
  823. return;
  824. }
  825. _try
  826. {
  827. if(0 == m_nNumOfRetry)
  828. {
  829. TraceTag(ttidSsdpSearchResp, "CSsdpSearchRequest::TimerFired(this=%x) - timed out", this);
  830. m_bShutdown = TRUE;
  831. WakeupSelect();
  832. SetEvent(m_hEventDone);
  833. }
  834. else
  835. {
  836. char * szSearch = NULL;
  837. hr = m_strSearch.HrGetMultiByteWithAlloc(&szSearch);
  838. if(SUCCEEDED(hr))
  839. {
  840. hr = HrSocketSend(szSearch);
  841. delete [] szSearch;
  842. if(SUCCEEDED(hr))
  843. {
  844. --m_nNumOfRetry;
  845. hr = m_timer.HrSetTimerInFired(MX_VALUE);
  846. TraceTag(ttidSsdpSearchResp, "CSsdpSearchRequest::TimerFired(this=%x) - Num of Retry %d", this,m_nNumOfRetry);
  847. }
  848. if(FAILED(hr))
  849. {
  850. TraceHr(ttidSsdpSearchResp, FAL, hr, FALSE, "CSsdpSearchRequest::TimerFired - failed to restart timer");
  851. m_bShutdown = TRUE;
  852. WakeupSelect();
  853. SetEvent(m_hEventDone);
  854. }
  855. }
  856. }
  857. }
  858. _finally
  859. {
  860. }
  861. }
  862. BOOL CSsdpSearchRequest::TimerTryToLock()
  863. {
  864. return m_critSec.FTryEnter();
  865. }
  866. void CSsdpSearchRequest::TimerUnlock()
  867. {
  868. m_critSec.Leave();
  869. }
  870. HRESULT CSsdpSearchRequest::HrInitializeSsdpSearchRequest(SSDP_REQUEST * pRequest,char * szType)
  871. {
  872. HRESULT hr = S_OK;
  873. ZeroMemory(pRequest, sizeof(SSDP_REQUEST));
  874. pRequest->Method = SSDP_M_SEARCH;
  875. pRequest->RequestUri = MulticastUri;
  876. pRequest->Headers[SSDP_MAN] = SearchHeader;
  877. pRequest->Headers[SSDP_MX] = MX;
  878. pRequest->Headers[SSDP_HOST] = new char[sizeof(CHAR) *
  879. (strlen(SSDP_ADDR) +
  880. 1 + // colon
  881. 6 + // port number
  882. 1)];
  883. if(!pRequest->Headers[SSDP_HOST])
  884. {
  885. hr = E_OUTOFMEMORY;
  886. }
  887. if(SUCCEEDED(hr))
  888. {
  889. wsprintfA(pRequest->Headers[SSDP_HOST], "%s:%d", SSDP_ADDR, SSDP_PORT);
  890. hr = HrCopyString(szType, &pRequest->Headers[SSDP_ST]);
  891. }
  892. if(FAILED(hr))
  893. {
  894. delete [] pRequest->Headers[SSDP_HOST];
  895. delete [] pRequest->Headers[SSDP_ST];
  896. ZeroMemory(pRequest, sizeof(SSDP_REQUEST));
  897. }
  898. TraceHr(ttidSsdpCNotify, FAL, hr, FALSE, "CSsdpSearchRequest::HrInitializeSsdpSearchRequest");
  899. return hr;
  900. }
  901. HRESULT CSsdpSearchRequest::HrGetFirstService(SSDP_MESSAGE ** ppSsdpMessage)
  902. {
  903. HRESULT hr = S_OK;
  904. CLock lock(m_critSec);
  905. hr = m_responseMessageList.GetIterator(m_iterCurrentResponse);
  906. if(S_OK == hr)
  907. {
  908. m_iterCurrentResponse.HrGetItem(ppSsdpMessage);
  909. m_iterCurrentResponse.HrNext();
  910. }
  911. TraceHr(ttidSsdpCNotify, FAL, hr, FALSE, "CSsdpSearchRequest::HrGetFirstService");
  912. return hr;
  913. }
  914. HRESULT CSsdpSearchRequest::HrGetNextService(SSDP_MESSAGE ** ppSsdpMessage)
  915. {
  916. HRESULT hr = S_OK;
  917. CLock lock(m_critSec);
  918. if(!m_iterCurrentResponse.FIsItem())
  919. {
  920. hr = S_FALSE;
  921. }
  922. if(S_OK == hr)
  923. {
  924. m_iterCurrentResponse.HrGetItem(ppSsdpMessage);
  925. m_iterCurrentResponse.HrNext();
  926. }
  927. TraceHr(ttidSsdpCNotify, FAL, hr, FALSE, "CSsdpSearchRequest::HrGetNextService");
  928. return hr;
  929. }
  930. HRESULT CSsdpSearchRequest::HrDeleteTimer()
  931. {
  932. HRESULT hr = S_OK;
  933. if (!InterlockedExchange((LONG*)&m_bDeletedTimer, TRUE))
  934. {
  935. hr = m_timer.HrDelete(INVALID_HANDLE_VALUE);
  936. }
  937. TraceHr(ttidSsdpNotify, FAL, hr, FALSE, "CSsdpSearchRequest::HrDeleteTimer");
  938. return hr;
  939. }
  940. CSsdpSearchRequestManager CSsdpSearchRequestManager::s_instance;
  941. CSsdpSearchRequestManager::CSsdpSearchRequestManager()
  942. {
  943. }
  944. CSsdpSearchRequestManager::~CSsdpSearchRequestManager()
  945. {
  946. }
  947. CSsdpSearchRequestManager & CSsdpSearchRequestManager::Instance()
  948. {
  949. return s_instance;
  950. }
  951. HRESULT CSsdpSearchRequestManager::HrCleanup()
  952. {
  953. HRESULT hr = S_OK;
  954. CLock lock(m_critSec);
  955. SearchRequestList::Iterator iter;
  956. if(S_OK == m_searchRequestList.GetIterator(iter))
  957. {
  958. CSsdpSearchRequest * pRequestIter = NULL;
  959. while(S_OK == iter.HrGetItem(&pRequestIter))
  960. {
  961. hr = pRequestIter->HrShutdown();
  962. if(S_OK != iter.HrNext())
  963. {
  964. break;
  965. }
  966. }
  967. }
  968. m_searchRequestList.Clear();
  969. TraceHr(ttidSsdpCNotify, FAL, hr, FALSE, "CSsdpSearchRequestManager::HrCleanup");
  970. return hr;
  971. }
  972. HRESULT CSsdpSearchRequestManager::HrCreateAsync(
  973. char * szType,
  974. BOOL bForceSearch,
  975. SERVICE_CALLBACK_FUNC pfnCallback,
  976. VOID * pvContext,
  977. CSsdpSearchRequest ** ppSearchRequest)
  978. {
  979. HRESULT hr = S_OK;
  980. if(!ppSearchRequest)
  981. {
  982. return E_POINTER;
  983. }
  984. if(!cInitialized)
  985. {
  986. return HRESULT_FROM_WIN32(ERROR_NOT_READY);
  987. }
  988. if(!szType || !pfnCallback)
  989. {
  990. return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  991. }
  992. SearchRequestList searchRequestList;
  993. hr = searchRequestList.HrPushFrontDefault();
  994. if(SUCCEEDED(hr))
  995. {
  996. hr = searchRequestList.Front().HrInitialize(szType);
  997. if(SUCCEEDED(hr))
  998. {
  999. hr = searchRequestList.Front().HrStartAsync(bForceSearch, pfnCallback, pvContext);
  1000. if(SUCCEEDED(hr))
  1001. {
  1002. CLock lock(m_critSec);
  1003. m_searchRequestList.Prepend(searchRequestList);
  1004. *ppSearchRequest = &m_searchRequestList.Front();
  1005. }
  1006. }
  1007. }
  1008. TraceHr(ttidSsdpCNotify, FAL, hr, FALSE, "CSsdpSearchRequestManager::HrCreateAsync");
  1009. return hr;
  1010. }
  1011. HRESULT CSsdpSearchRequestManager::HrCreateSync(
  1012. char * szType,
  1013. BOOL bForceSearch,
  1014. CSsdpSearchRequest ** ppSearchRequest)
  1015. {
  1016. HRESULT hr = S_OK;
  1017. if(!ppSearchRequest)
  1018. {
  1019. return E_POINTER;
  1020. }
  1021. if(!cInitialized)
  1022. {
  1023. return HRESULT_FROM_WIN32(ERROR_NOT_READY);
  1024. }
  1025. if(!szType)
  1026. {
  1027. return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  1028. }
  1029. SearchRequestList searchRequestList;
  1030. hr = searchRequestList.HrPushFrontDefault();
  1031. if(SUCCEEDED(hr))
  1032. {
  1033. hr = searchRequestList.Front().HrInitialize(szType);
  1034. if(SUCCEEDED(hr))
  1035. {
  1036. hr = searchRequestList.Front().HrStartSync(bForceSearch);
  1037. if(SUCCEEDED(hr))
  1038. {
  1039. CLock lock(m_critSec);
  1040. m_searchRequestList.Prepend(searchRequestList);
  1041. *ppSearchRequest = &m_searchRequestList.Front();
  1042. }
  1043. }
  1044. }
  1045. TraceHr(ttidSsdpCNotify, FAL, hr, FALSE, "CSsdpSearchRequestManager::HrCreateSync");
  1046. return hr;
  1047. }
  1048. HRESULT CSsdpSearchRequestManager::HrRemove(CSsdpSearchRequest * pSearchRequest)
  1049. {
  1050. HRESULT hr = S_FALSE;
  1051. SearchRequestList searchRequestList;
  1052. {
  1053. CLock lock(m_critSec);
  1054. SearchRequestList::Iterator iter;
  1055. if(S_OK == m_searchRequestList.GetIterator(iter))
  1056. {
  1057. CSsdpSearchRequest * pRequestIter = NULL;
  1058. while(S_OK == iter.HrGetItem(&pRequestIter))
  1059. {
  1060. if(pSearchRequest == pRequestIter)
  1061. {
  1062. iter.HrMoveToList(searchRequestList);
  1063. break;
  1064. }
  1065. if(S_OK != iter.HrNext())
  1066. {
  1067. break;
  1068. }
  1069. }
  1070. }
  1071. }
  1072. // Delete outside of lock
  1073. SearchRequestList::Iterator iter;
  1074. if(S_OK == searchRequestList.GetIterator(iter))
  1075. {
  1076. CSsdpSearchRequest * pRequestIter = NULL;
  1077. while(S_OK == iter.HrGetItem(&pRequestIter))
  1078. {
  1079. hr = pRequestIter->HrShutdown();
  1080. if(S_OK != iter.HrNext())
  1081. {
  1082. break;
  1083. }
  1084. }
  1085. }
  1086. TraceHr(ttidSsdpCNotify, FAL, hr, FALSE, "CSsdpSearchRequestManager::HrRemove");
  1087. return hr;
  1088. }
  1089. HRESULT CSsdpSearchRequestManager::HrGetFirstService(CSsdpSearchRequest * pSearchRequest, SSDP_MESSAGE ** ppSsdpMessage)
  1090. {
  1091. HRESULT hr = S_FALSE;
  1092. SearchRequestList::Iterator iter;
  1093. if(S_OK == m_searchRequestList.GetIterator(iter))
  1094. {
  1095. CSsdpSearchRequest * pRequestIter = NULL;
  1096. while(S_OK == iter.HrGetItem(&pRequestIter))
  1097. {
  1098. if(pSearchRequest == pRequestIter)
  1099. {
  1100. hr = pRequestIter->HrGetFirstService(ppSsdpMessage);
  1101. break;
  1102. }
  1103. if(S_OK != iter.HrNext())
  1104. {
  1105. break;
  1106. }
  1107. }
  1108. }
  1109. TraceHr(ttidSsdpCNotify, FAL, hr, FALSE, "CSsdpSearchRequestManager::HrGetFirstService");
  1110. return hr;
  1111. }
  1112. HRESULT CSsdpSearchRequestManager::HrGetNextService(CSsdpSearchRequest * pSearchRequest, SSDP_MESSAGE ** ppSsdpMessage)
  1113. {
  1114. HRESULT hr = S_FALSE;
  1115. SearchRequestList::Iterator iter;
  1116. if(S_OK == m_searchRequestList.GetIterator(iter))
  1117. {
  1118. CSsdpSearchRequest * pRequestIter = NULL;
  1119. while(S_OK == iter.HrGetItem(&pRequestIter))
  1120. {
  1121. if(pSearchRequest == pRequestIter)
  1122. {
  1123. hr = pRequestIter->HrGetNextService(ppSsdpMessage);
  1124. break;
  1125. }
  1126. if(S_OK != iter.HrNext())
  1127. {
  1128. break;
  1129. }
  1130. }
  1131. }
  1132. TraceHr(ttidSsdpCNotify, FAL, hr, FALSE, "CSsdpSearchRequestManager::HrGetNextService");
  1133. return hr;
  1134. }
  1135. BOOL InitializeListSearch()
  1136. {
  1137. return TRUE;
  1138. }
  1139. VOID CleanupListSearch()
  1140. {
  1141. CSsdpSearchRequestManager::Instance().HrCleanup();
  1142. }
  1143. HANDLE WINAPI FindServicesCallback (CHAR * szType,
  1144. VOID * pReserved ,
  1145. BOOL fForceSearch,
  1146. SERVICE_CALLBACK_FUNC fnCallback,
  1147. VOID *Context)
  1148. {
  1149. if (!cInitialized)
  1150. {
  1151. SetLastError(ERROR_NOT_READY);
  1152. return INVALID_HANDLE_VALUE;
  1153. }
  1154. if (szType == NULL || !*szType || fnCallback == NULL || pReserved != NULL)
  1155. {
  1156. SetLastError(ERROR_INVALID_PARAMETER);
  1157. return INVALID_HANDLE_VALUE;
  1158. }
  1159. CSsdpSearchRequest * pSearchRequest = NULL;
  1160. HRESULT hr = CSsdpSearchRequestManager::Instance().HrCreateAsync(szType, fForceSearch, fnCallback, Context, &pSearchRequest);
  1161. if(FAILED(hr))
  1162. {
  1163. SetLastError(DwWin32ErrorFromHr(hr));
  1164. return INVALID_HANDLE_VALUE;
  1165. }
  1166. return pSearchRequest;
  1167. }
  1168. BOOL WINAPI FindServicesCancel(HANDLE SearchHandle)
  1169. {
  1170. CSsdpSearchRequest * pRequest = reinterpret_cast<CSsdpSearchRequest*>(SearchHandle);
  1171. HRESULT hr = pRequest->HrCancelCallback();
  1172. if(FAILED(hr))
  1173. {
  1174. SetLastError(DwWin32ErrorFromHr(hr));
  1175. }
  1176. return S_OK == hr;
  1177. }
  1178. BOOL WINAPI FindServicesClose(HANDLE SearchHandle)
  1179. {
  1180. CSsdpSearchRequest * pRequest = reinterpret_cast<CSsdpSearchRequest*>(SearchHandle);
  1181. HRESULT hr = CSsdpSearchRequestManager::Instance().HrRemove(pRequest);
  1182. if(FAILED(hr))
  1183. {
  1184. SetLastError(DwWin32ErrorFromHr(hr));
  1185. }
  1186. return S_OK == hr;
  1187. }
  1188. HANDLE WINAPI FindServices(CHAR* szType, VOID *pReserved , BOOL fForceSearch)
  1189. {
  1190. if (!cInitialized)
  1191. {
  1192. SetLastError(ERROR_NOT_READY);
  1193. return INVALID_HANDLE_VALUE;
  1194. }
  1195. if (szType == NULL || !*szType || pReserved != NULL)
  1196. {
  1197. SetLastError(ERROR_INVALID_PARAMETER);
  1198. return INVALID_HANDLE_VALUE;
  1199. }
  1200. CSsdpSearchRequest * pSearchRequest = NULL;
  1201. HRESULT hr = CSsdpSearchRequestManager::Instance().HrCreateSync(szType, fForceSearch, &pSearchRequest);
  1202. if(FAILED(hr))
  1203. {
  1204. SetLastError(DwWin32ErrorFromHr(hr));
  1205. return INVALID_HANDLE_VALUE;
  1206. }
  1207. return pSearchRequest;
  1208. }
  1209. BOOL WINAPI GetFirstService(HANDLE hFindServices, PSSDP_MESSAGE *ppSsdpService)
  1210. {
  1211. if (!cInitialized)
  1212. {
  1213. SetLastError(ERROR_NOT_READY);
  1214. return FALSE;
  1215. }
  1216. if (!ppSsdpService ||
  1217. !hFindServices ||
  1218. hFindServices == INVALID_HANDLE_VALUE)
  1219. {
  1220. SetLastError(ERROR_INVALID_PARAMETER);
  1221. return FALSE;
  1222. }
  1223. CSsdpSearchRequest * pRequest = reinterpret_cast<CSsdpSearchRequest*>(hFindServices);
  1224. HRESULT hr = CSsdpSearchRequestManager::Instance().HrGetFirstService(pRequest, ppSsdpService);
  1225. if(FAILED(hr))
  1226. {
  1227. SetLastError(DwWin32ErrorFromHr(hr));
  1228. }
  1229. return S_OK == hr;
  1230. }
  1231. BOOL WINAPI GetNextService(HANDLE hFindServices, PSSDP_MESSAGE *ppSsdpService)
  1232. {
  1233. if (!cInitialized)
  1234. {
  1235. SetLastError(ERROR_NOT_READY);
  1236. return FALSE;
  1237. }
  1238. if (!ppSsdpService ||
  1239. !hFindServices ||
  1240. hFindServices == INVALID_HANDLE_VALUE)
  1241. {
  1242. SetLastError(ERROR_INVALID_PARAMETER);
  1243. return FALSE;
  1244. }
  1245. CSsdpSearchRequest * pRequest = reinterpret_cast<CSsdpSearchRequest*>(hFindServices);
  1246. HRESULT hr = CSsdpSearchRequestManager::Instance().HrGetNextService(pRequest, ppSsdpService);
  1247. if(FAILED(hr))
  1248. {
  1249. SetLastError(DwWin32ErrorFromHr(hr));
  1250. }
  1251. return S_OK == hr;
  1252. }