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.

933 lines
23 KiB

  1. /*
  2. * Purpose: C++ API for finding the telephony
  3. * servers in Active Directory
  4. *
  5. */
  6. #ifndef UNICODE
  7. #define UNICODE
  8. #endif
  9. #ifndef _UNICODE
  10. #define _UNICODE
  11. #endif
  12. #include <windows.h>
  13. #include <objbase.h>
  14. #include <activeds.h>
  15. #include "tspi.h"
  16. #include "tapi.h"
  17. #include "dslookup.h"
  18. #include "utils.h"
  19. #include "tchar.h"
  20. const TCHAR gszNoDSQuery[] = TEXT("NoDSQuery");
  21. const TCHAR gszStatusActive[] = TEXT("S{Active}");
  22. const TCHAR gszTTLWithBrace[] = TEXT("TTL{");
  23. //
  24. // Utility functions
  25. //
  26. //
  27. // GetIntFromString
  28. // Utility function used for retrieving TTL information
  29. // Parameters:
  30. // sz - String that contains the integer
  31. // dwDigits - Number of digits to convert
  32. //
  33. int GetIntFromString (LPTSTR & sz, DWORD dwDigits)
  34. {
  35. int iRet = 0;
  36. while (*sz != 0 && dwDigits)
  37. {
  38. iRet = ((iRet << 3) + (iRet << 1)) + // IRet * 10
  39. + (*sz - '0');
  40. ++sz;
  41. --dwDigits;
  42. }
  43. return iRet;
  44. }
  45. //
  46. // Rules:
  47. // The following codes are not thread safe, the caller
  48. // needs to be concious about synchronization.
  49. // Currently theses are only used in remotesp.tsp
  50. //
  51. /**********************************************************
  52. * Get TAPI servers list from the registry
  53. *********************************************************/
  54. DWORD gdwCurServerNum = 0;
  55. HKEY ghRegistry = NULL;
  56. BOOL
  57. RegOpenServerLookup(
  58. HKEY hRegistry
  59. )
  60. {
  61. if (NULL != ghRegistry)
  62. {
  63. // Already have a search in progress or the
  64. // caller did not close the last search.
  65. return FALSE;
  66. }
  67. else
  68. {
  69. ghRegistry = hRegistry;
  70. return TRUE;
  71. }
  72. }
  73. BOOL
  74. RegGetNextServer(
  75. LPTSTR pszServerName,
  76. DWORD dwSize
  77. )
  78. {
  79. DWORD dwRet;
  80. LOG((TL_TRACE, "GetNextServer entered"));
  81. TCHAR szServerN[24];
  82. DWORD dwType;
  83. wsprintf(szServerN, TEXT("Server%d"), gdwCurServerNum++);
  84. LOG((TL_INFO, "RegGetNextServer: Getting server %d from reg", gdwCurServerNum-1));
  85. dwRet = RegQueryValueEx(
  86. ghRegistry,
  87. szServerN,
  88. 0,
  89. &dwType,
  90. (LPBYTE) pszServerName,
  91. &dwSize
  92. );
  93. if (ERROR_SUCCESS != dwRet)
  94. {
  95. LOG((TL_INFO, "Got last server"));
  96. LOG((TL_TRACE, "GetNextServer exited"));
  97. return FALSE;
  98. }
  99. LOG((TL_TRACE, "GetNextServer exited"));
  100. return TRUE;
  101. }
  102. BOOL
  103. RegCloseLookup(
  104. void
  105. )
  106. {
  107. LOG((TL_INFO, "Closing directory lookup"));
  108. ghRegistry = NULL;
  109. gdwCurServerNum = 0;
  110. return TRUE;
  111. }
  112. /**********************************************************
  113. * Enumerate published telephony servers
  114. *********************************************************/
  115. typedef struct _TAPISRV_LOOKUP_CTX {
  116. ADS_SEARCH_HANDLE hDirSearch;
  117. IDirectorySearch * pDirSearch;
  118. } TAPISRV_LOOKUP_CTX, *PTAPISRV_LOOKUP_CTX;
  119. // gszTapisrvGuid needs to be consistant with server\dspub.cpp
  120. const WCHAR gszTapisrvGuid[] = L"keywords=B1A37774-E3F7-488E-ADBFD4DB8A4AB2E5";
  121. //
  122. // GetGC
  123. //
  124. // Retrieve the IDirectorySearch of the Global Catalog (GC)
  125. // for SCP maintenance / discovery
  126. //
  127. HRESULT GetGC (IDirectorySearch ** ppGC)
  128. {
  129. HRESULT hr = S_OK;
  130. IEnumVARIANT * pEnum = NULL;
  131. IADsContainer * pCont = NULL;
  132. VARIANT var;
  133. IDispatch * pDisp = NULL;
  134. ULONG lFetch;
  135. // Set IDirectorySearch pointer to NULL.
  136. *ppGC = NULL;
  137. // First, bind to the GC: namespace container object. The "real" GC DN
  138. // is a single immediate child of the GC: namespace, which must
  139. // be obtained using enumeration.
  140. hr = ADsOpenObject(
  141. TEXT("GC:"),
  142. NULL,
  143. NULL,
  144. ADS_SECURE_AUTHENTICATION, //Use Secure Authentication
  145. IID_IADsContainer,
  146. (void**)&pCont
  147. );
  148. if (FAILED(hr))
  149. {
  150. LOG((TL_ERROR, "ADsOpenObject failed: 0x%x\n", hr));
  151. goto cleanup;
  152. }
  153. // Fetch an enumeration interface for the GC container.
  154. hr = ADsBuildEnumerator(pCont, &pEnum);
  155. if (FAILED(hr)) {
  156. LOG((TL_ERROR, "ADsBuildEnumerator failed: 0x%x\n", hr));
  157. goto cleanup;
  158. }
  159. //Now enumerate. There's only one child of the GC: object.
  160. hr = ADsEnumerateNext(pEnum, 1, &var, &lFetch);
  161. if (FAILED(hr)) {
  162. LOG((TL_ERROR, "ADsEnumerateNext failed: 0x%x\n", hr));
  163. goto cleanup;
  164. }
  165. if (( hr == S_OK ) && ( lFetch == 1 ) )
  166. {
  167. pDisp = V_DISPATCH(&var);
  168. hr = pDisp->QueryInterface( IID_IDirectorySearch, (void**)ppGC);
  169. }
  170. cleanup:
  171. if (pEnum)
  172. {
  173. ADsFreeEnumerator(pEnum);
  174. }
  175. if (pCont)
  176. {
  177. pCont->Release();
  178. }
  179. if (pDisp)
  180. {
  181. (pDisp)->Release();
  182. }
  183. return hr;
  184. }
  185. //
  186. // DsOpenServerLookup
  187. // Start the operation of tapisrv server lookup
  188. // pctx - The lookup context
  189. //
  190. HRESULT
  191. DsOpenServerLookup(
  192. PTAPISRV_LOOKUP_CTX pctx
  193. )
  194. {
  195. HRESULT hr = S_OK;
  196. ADS_SEARCHPREF_INFO SearchPref[3];
  197. BOOL bInited = FALSE;
  198. DWORD dwPref;
  199. WCHAR *szAttribs[]={
  200. L"distinguishedName"
  201. };
  202. if (pctx == NULL)
  203. {
  204. hr = E_INVALIDARG;
  205. goto ExitHere;
  206. }
  207. pctx->hDirSearch = NULL;
  208. pctx->pDirSearch = NULL;
  209. hr = CoInitializeEx (NULL, COINIT_MULTITHREADED);
  210. if (FAILED (hr))
  211. {
  212. goto ExitHere;
  213. }
  214. bInited = TRUE;
  215. // Get the global catalog
  216. hr = GetGC (&pctx->pDirSearch);
  217. if (FAILED (hr) || pctx->pDirSearch == NULL)
  218. {
  219. goto ExitHere;
  220. }
  221. // Set up the search. We want to do a deep search.
  222. // Note that we are not expecting thousands of objects
  223. // in this example, so we will ask for 10 rows / page.
  224. dwPref=sizeof(SearchPref)/sizeof(ADS_SEARCHPREF_INFO);
  225. SearchPref[0].dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE;
  226. SearchPref[0].vValue.dwType = ADSTYPE_INTEGER;
  227. SearchPref[0].vValue.Integer = ADS_SCOPE_SUBTREE;
  228. SearchPref[1].dwSearchPref = ADS_SEARCHPREF_PAGESIZE;
  229. SearchPref[1].vValue.dwType = ADSTYPE_INTEGER;
  230. SearchPref[1].vValue.Integer = 10;
  231. SearchPref[2].dwSearchPref = ADS_SEARCHPREF_TIME_LIMIT;
  232. SearchPref[2].vValue.dwType = ADSTYPE_INTEGER;
  233. SearchPref[2].vValue.Integer = 5 * 60; // 5 minute search timeout
  234. hr = pctx->pDirSearch->SetSearchPreference(SearchPref, dwPref);
  235. if (FAILED(hr)) {
  236. LOG((TL_ERROR, "Failed to set search prefs: hr:0x%x\n", hr));
  237. goto ExitHere;
  238. }
  239. // Now execute the search
  240. hr = pctx->pDirSearch->ExecuteSearch(
  241. (LPWSTR)gszTapisrvGuid,
  242. szAttribs,
  243. sizeof(szAttribs) / sizeof(WCHAR *),
  244. &pctx->hDirSearch
  245. );
  246. ExitHere:
  247. if (FAILED(hr) && pctx != NULL)
  248. {
  249. if (pctx->pDirSearch)
  250. {
  251. pctx->pDirSearch->Release();
  252. }
  253. }
  254. if (FAILED(hr) && bInited)
  255. {
  256. CoUninitialize ();
  257. }
  258. return hr;
  259. }
  260. //
  261. // DsGetNextServer
  262. //
  263. // Return the next server name (in ANSI since that is what the
  264. // RPC subsystem uses)
  265. //
  266. // returns S_FALSE if no more server to enumerate
  267. //
  268. HRESULT
  269. DsGetNextServer(
  270. PTAPISRV_LOOKUP_CTX pctx,
  271. LPTSTR pszServerName,
  272. DWORD dwSize
  273. )
  274. {
  275. HRESULT hr = S_OK;
  276. ADS_SEARCH_COLUMN Col;
  277. TCHAR szDN[MAX_PATH];
  278. WCHAR *szAttribs[]={
  279. L"serviceDNSName",
  280. L"serviceBindingInformation",
  281. };
  282. ADS_ATTR_INFO *pPropEntries = NULL;
  283. DWORD dwNumAttrGot;
  284. IDirectoryObject * pSCP = NULL;
  285. int i;
  286. LPWSTR wsz;
  287. BOOL bCheckedBinding;
  288. if (pctx == NULL || pctx->pDirSearch == NULL ||
  289. pctx->hDirSearch == NULL ||
  290. dwSize < sizeof(WCHAR))
  291. {
  292. hr = E_INVALIDARG;
  293. goto ExitHere;
  294. }
  295. hr = pctx->pDirSearch->GetNextRow(pctx->hDirSearch);
  296. if (SUCCEEDED (hr) && hr != S_ADS_NOMORE_ROWS)
  297. {
  298. hr = pctx->pDirSearch->GetColumn(
  299. pctx->hDirSearch,
  300. L"distinguishedName",
  301. &Col
  302. );
  303. if (FAILED (hr))
  304. {
  305. goto ExitHere;
  306. }
  307. _tcscpy (szDN, TEXT("LDAP://"));
  308. _tcsncpy (
  309. szDN + _tcslen (szDN),
  310. Col.pADsValues->CaseExactString,
  311. sizeof(szDN)/sizeof(TCHAR) - _tcslen (szDN)
  312. );
  313. pctx->pDirSearch->FreeColumn(&Col);
  314. hr = ADsGetObject (
  315. szDN,
  316. IID_IDirectoryObject,
  317. (void **)&pSCP
  318. );
  319. if (FAILED(hr))
  320. {
  321. LOG((TL_ERROR, "DsGetNextServer: ADsGetObject %S failed", szDN));
  322. goto ExitHere;
  323. }
  324. LOG((TL_TRACE, "DsGetNextServer: ADsGetObject %S succeeded", szDN));
  325. hr = pSCP->GetObjectAttributes (
  326. szAttribs,
  327. sizeof(szAttribs) / sizeof(WCHAR *),
  328. &pPropEntries,
  329. &dwNumAttrGot
  330. );
  331. if (FAILED(hr) || dwNumAttrGot != sizeof(szAttribs) / sizeof(WCHAR *))
  332. {
  333. LOG((TL_ERROR, "DsGetNextServer: GetObjectAttributes %S failed", szDN));
  334. goto ExitHere;
  335. }
  336. LOG((TL_TRACE, "DsGetNextServer: GetObjectAttributes %S succeeded", szDN));
  337. bCheckedBinding = FALSE;
  338. for (i=0;i<(int)dwNumAttrGot;i++)
  339. {
  340. if (_tcsicmp(TEXT("serviceDNSName"), pPropEntries[i].pszAttrName) ==0 &&
  341. (pPropEntries[i].pADsValues->dwType == ADSTYPE_CASE_EXACT_STRING ||
  342. pPropEntries[i].pADsValues->dwType == ADSTYPE_CASE_IGNORE_STRING))
  343. {
  344. _tcsncpy (
  345. pszServerName,
  346. pPropEntries[i].pADsValues->CaseExactString,
  347. dwSize/sizeof(TCHAR)
  348. );
  349. pszServerName[dwSize/sizeof(TCHAR) - 1] = '\0';
  350. if (bCheckedBinding)
  351. {
  352. break;
  353. }
  354. }
  355. else if (_tcsicmp(TEXT("serviceBindingInformation"), pPropEntries[i].pszAttrName) ==0 &&
  356. (pPropEntries[i].pADsValues->dwType == ADSTYPE_CASE_EXACT_STRING ||
  357. pPropEntries[i].pADsValues->dwType == ADSTYPE_CASE_IGNORE_STRING))
  358. {
  359. SYSTEMTIME st;
  360. FILETIME ft1, ft2;
  361. bCheckedBinding = TRUE;
  362. wsz = pPropEntries[i].pADsValues->CaseExactString;
  363. wsz = wcsstr (wsz, gszStatusActive);
  364. if (wsz == NULL)
  365. {
  366. // No server status information or server is not active
  367. // ignore this server
  368. LOG((TL_ERROR, "DsGetNextServer: %S No server status information", szDN));
  369. hr = S_FALSE;
  370. break;
  371. }
  372. wsz += _tcslen(gszStatusActive); // skip "S{Active}" itself
  373. wsz = wcsstr (wsz, gszTTLWithBrace);
  374. if (wsz == NULL)
  375. {
  376. // No TTL found, corrupt serviceBindingInformation, ignore
  377. LOG((TL_ERROR, "DsGetNextServer: %S No TTL found", szDN));
  378. hr = S_FALSE;
  379. break;
  380. }
  381. wsz += _tcslen (gszTTLWithBrace); // skip "TTL{"
  382. //
  383. // The following codes parses the TTL information
  384. // created in server\dspub.cpp. They need to be
  385. // consistant. The current format is 5 digits for
  386. // year & 3 digits for milliseconds, 2 digits for
  387. // the remaining
  388. //
  389. st.wYear = (WORD) GetIntFromString (wsz, 5);
  390. st.wMonth = (WORD) GetIntFromString (wsz, 2);
  391. st.wDay = (WORD) GetIntFromString (wsz, 2),
  392. st.wHour = (WORD) GetIntFromString (wsz, 2);
  393. st.wMinute = (WORD) GetIntFromString (wsz, 2);
  394. st.wSecond = (WORD) GetIntFromString (wsz, 2);
  395. st.wMilliseconds = (WORD) GetIntFromString (wsz, 3);
  396. SystemTimeToFileTime (&st, &ft1);
  397. GetSystemTimeAsFileTime (&ft2);
  398. if (CompareFileTime (&ft1, &ft2) < 0)
  399. {
  400. // The TapiSCP object has passed its TTL, ignore
  401. hr = S_FALSE;
  402. LOG((TL_ERROR, "DsGetNextServer: %S The TapiSCP object has passed its TTL", szDN));
  403. break;
  404. }
  405. }
  406. }
  407. if (i == (int) dwNumAttrGot)
  408. {
  409. // Did not find an attribute
  410. hr = S_FALSE;
  411. }
  412. }
  413. ExitHere:
  414. if (pSCP)
  415. pSCP->Release();
  416. if (pPropEntries)
  417. FreeADsMem(pPropEntries);
  418. return hr;
  419. }
  420. //
  421. // DsCloseLookup
  422. // Close the TAPI DS published server lookup identified by pctx
  423. //
  424. HRESULT
  425. DsCloseLookup(
  426. PTAPISRV_LOOKUP_CTX pctx
  427. )
  428. {
  429. if (pctx && pctx->pDirSearch && pctx->hDirSearch)
  430. {
  431. pctx->pDirSearch->CloseSearchHandle(pctx->hDirSearch);
  432. }
  433. if (pctx && pctx->pDirSearch)
  434. {
  435. pctx->pDirSearch->Release();
  436. }
  437. CoUninitialize ();
  438. return S_OK;
  439. }
  440. /**********************************************************
  441. * Get TAPI servers list remotesp.tsp should contact
  442. * Servers include those specified in registry through
  443. * tcmsetup.exe and those servers published in the DS
  444. *********************************************************/
  445. typedef struct _SERVER_LOOKUP_ENTRY {
  446. TCHAR szServer[MAX_PATH];
  447. BOOL bFromReg;
  448. } SERVER_LOOKUP_ENTRY, *PSERVER_LOOKUP_ENTRY;
  449. typedef struct _SERVER_LOOKUP {
  450. DWORD dwTotalEntries;
  451. DWORD dwUsedEntries;
  452. SERVER_LOOKUP_ENTRY * aEntries;
  453. } SERVER_LOOKUP, *PSERVER_LOOKUP;
  454. SERVER_LOOKUP gLookup;
  455. DWORD gdwCurIndex;
  456. //
  457. // AddEntry : return FALSE if failed; otherwise, return true
  458. //
  459. BOOL
  460. AddEntry (
  461. LPTSTR szServer,
  462. BOOL bFromReg
  463. )
  464. {
  465. LPTSTR psz;
  466. if (gLookup.dwUsedEntries >= gLookup.dwTotalEntries)
  467. {
  468. PSERVER_LOOKUP_ENTRY pNew;
  469. pNew = (PSERVER_LOOKUP_ENTRY) DrvAlloc (
  470. sizeof(SERVER_LOOKUP_ENTRY) * (gLookup.dwTotalEntries + 5)
  471. );
  472. if (pNew == NULL)
  473. {
  474. return FALSE;
  475. }
  476. if (gLookup.dwUsedEntries > 0)
  477. {
  478. CopyMemory (
  479. pNew,
  480. gLookup.aEntries,
  481. sizeof(SERVER_LOOKUP_ENTRY) * gLookup.dwTotalEntries
  482. );
  483. }
  484. if (gLookup.aEntries)
  485. {
  486. DrvFree (gLookup.aEntries);
  487. }
  488. gLookup.aEntries = pNew;
  489. gLookup.dwTotalEntries += 5;
  490. }
  491. wcsncpy (
  492. gLookup.aEntries[gLookup.dwUsedEntries].szServer,
  493. szServer,
  494. sizeof(gLookup.aEntries[gLookup.dwUsedEntries].szServer)/sizeof(TCHAR)
  495. );
  496. psz = _tcschr(gLookup.aEntries[gLookup.dwUsedEntries].szServer, TEXT('.'));
  497. if (psz != NULL)
  498. {
  499. *psz = 0;
  500. }
  501. gLookup.aEntries[gLookup.dwUsedEntries].bFromReg = bFromReg;
  502. ++gLookup.dwUsedEntries;
  503. return TRUE;
  504. }
  505. BOOL
  506. IsServerInListOrSelf (
  507. LPTSTR szServer
  508. )
  509. {
  510. int i;
  511. TCHAR szServer1[MAX_PATH];
  512. LPTSTR psz;
  513. BOOL bRet = FALSE;
  514. _tcsncpy (szServer1, szServer, sizeof(szServer1)/sizeof(TCHAR));
  515. // A computer name might be DNS name like comp1.microsoft.com
  516. // only compare the computer name
  517. psz = _tcschr(szServer1, TEXT('.'));
  518. if (psz != NULL)
  519. {
  520. *psz = 0;
  521. }
  522. for (i = 0; i < (int)gLookup.dwUsedEntries; ++i)
  523. {
  524. if (_tcsicmp (szServer1, gLookup.aEntries[i].szServer) == 0)
  525. {
  526. bRet = TRUE;
  527. break;
  528. }
  529. }
  530. if (!bRet)
  531. {
  532. TCHAR szSelf[MAX_PATH];
  533. DWORD dwSize = sizeof(szSelf);
  534. if (GetComputerName (szSelf, &dwSize))
  535. {
  536. if (_tcsicmp (szServer1, szSelf) == 0)
  537. {
  538. bRet = TRUE;
  539. }
  540. }
  541. }
  542. return bRet;
  543. }
  544. BOOL OpenServerLookup (
  545. HKEY hRegistry
  546. )
  547. {
  548. BOOL bRet = TRUE;
  549. TCHAR szServer[MAX_PATH];
  550. TAPISRV_LOOKUP_CTX ctx;
  551. HRESULT hr;
  552. DWORD dwNoDSQuery = 0;
  553. DWORD dwSize = sizeof(dwNoDSQuery);
  554. gLookup.dwTotalEntries = 0;
  555. gLookup.dwUsedEntries = 0;
  556. gLookup.aEntries = NULL;
  557. //
  558. // First add the computer from registry
  559. //
  560. if (RegOpenServerLookup (hRegistry))
  561. {
  562. while (RegGetNextServer (szServer, sizeof(szServer)))
  563. {
  564. if (!IsServerInListOrSelf (szServer))
  565. {
  566. AddEntry (szServer, TRUE);
  567. }
  568. }
  569. RegCloseLookup ();
  570. }
  571. if (hRegistry != NULL)
  572. {
  573. if (ERROR_SUCCESS != RegQueryValueEx (
  574. hRegistry,
  575. gszNoDSQuery,
  576. NULL,
  577. NULL,
  578. (LPBYTE)&dwNoDSQuery,
  579. &dwSize
  580. ))
  581. {
  582. dwNoDSQuery = 0;
  583. }
  584. }
  585. //
  586. // Next add the computer from DS unless disabled
  587. //
  588. if (dwNoDSQuery == 0)
  589. {
  590. if (DsOpenServerLookup (&ctx) == S_OK)
  591. {
  592. while (SUCCEEDED(hr = DsGetNextServer (&ctx,szServer, sizeof(szServer))))
  593. {
  594. if (hr == S_ADS_NOMORE_ROWS)
  595. {
  596. break;
  597. }
  598. else if (hr != S_OK)
  599. {
  600. continue; // Server needs to be ignored
  601. }
  602. if (szServer[0] != 0 && !IsServerInListOrSelf (szServer))
  603. {
  604. AddEntry (szServer, FALSE);
  605. }
  606. }
  607. DsCloseLookup (&ctx);
  608. }
  609. }
  610. gdwCurIndex = 0;
  611. return TRUE;
  612. }
  613. BOOL GetNextServer (
  614. LPSTR szServer,
  615. DWORD dwSize,
  616. BOOL * pbReg
  617. )
  618. {
  619. BOOL bRet = TRUE;
  620. DWORD dwRet;
  621. if (gdwCurIndex >= gLookup.dwUsedEntries)
  622. {
  623. bRet = FALSE;
  624. goto ExitHere;
  625. }
  626. if (pbReg != NULL)
  627. {
  628. *pbReg = gLookup.aEntries[gdwCurIndex].bFromReg;
  629. }
  630. dwRet = WideCharToMultiByte(
  631. GetACP(),
  632. 0,
  633. gLookup.aEntries[gdwCurIndex].szServer,
  634. -1,
  635. szServer,
  636. dwSize,
  637. 0,
  638. NULL
  639. );
  640. if (dwRet == 0)
  641. {
  642. bRet = FALSE;
  643. goto ExitHere;
  644. }
  645. ++gdwCurIndex;
  646. ExitHere:
  647. return bRet;
  648. }
  649. BOOL CloseLookup (
  650. void
  651. )
  652. {
  653. if (gLookup.aEntries)
  654. {
  655. DrvFree (gLookup.aEntries);
  656. }
  657. gLookup.aEntries = NULL;
  658. gLookup.dwTotalEntries = 0;
  659. gLookup.dwUsedEntries = 0;
  660. gdwCurIndex = 0;
  661. return TRUE;
  662. }
  663. HRESULT SockStartup (
  664. RSPSOCKET * pSocket
  665. )
  666. {
  667. HRESULT hr = S_OK;
  668. BOOL bCleanup = FALSE;
  669. WSADATA wsadata;
  670. WORD wVersionRequested = MAKEWORD( 2, 2 );
  671. if (pSocket == NULL)
  672. {
  673. hr = LINEERR_INVALPARAM;
  674. goto ExitHere;
  675. }
  676. ZeroMemory (pSocket, sizeof(RSPSOCKET));
  677. bCleanup = TRUE;
  678. ZeroMemory (pSocket, sizeof(RSPSOCKET));
  679. pSocket->hWS2 = LoadLibrary (TEXT("ws2_32.dll"));
  680. if (pSocket->hWS2 == NULL)
  681. {
  682. hr = HRESULT_FROM_WIN32(GetLastError());
  683. goto ExitHere;
  684. }
  685. pSocket->pFnWSAStartup = (PFNWSASTARTUP)GetProcAddress (
  686. pSocket->hWS2,
  687. "WSAStartup"
  688. );
  689. pSocket->pFnWSACleanup = (PFNWSACLEANUP)GetProcAddress (
  690. pSocket->hWS2,
  691. "WSACleanup"
  692. );
  693. pSocket->pFngethostbyname = (PFNGETHOSTBYNAME)GetProcAddress(
  694. pSocket->hWS2,
  695. "gethostbyname"
  696. );
  697. if (pSocket->pFnWSAStartup == NULL ||
  698. pSocket->pFnWSACleanup == NULL ||
  699. pSocket->pFngethostbyname == NULL)
  700. {
  701. hr = LINEERR_OPERATIONFAILED;
  702. goto ExitHere;
  703. }
  704. pSocket->hICMP = LoadLibrary (TEXT("icmp.dll"));
  705. if (pSocket->hICMP == NULL)
  706. {
  707. hr = HRESULT_FROM_WIN32(GetLastError());
  708. goto ExitHere;
  709. }
  710. pSocket->pFnIcmpCreateFile = (PFNICMPCREATEFILE)GetProcAddress (
  711. pSocket->hICMP,
  712. "IcmpCreateFile"
  713. );
  714. pSocket->pFnIcmpCloseHandle = (PFNICMPCLOSEHANDLE)GetProcAddress (
  715. pSocket->hICMP,
  716. "IcmpCloseHandle"
  717. );
  718. pSocket->pFnIcmpSendEcho = (PFNICMPSENDECHO)GetProcAddress (
  719. pSocket->hICMP,
  720. "IcmpSendEcho"
  721. );
  722. if (pSocket->pFnIcmpCreateFile == NULL ||
  723. pSocket->pFnIcmpCreateFile == NULL ||
  724. pSocket->pFnIcmpCreateFile == NULL)
  725. {
  726. hr = LINEERR_OPERATIONFAILED;
  727. goto ExitHere;
  728. }
  729. hr = (*pSocket->pFnWSAStartup)(
  730. wVersionRequested,
  731. &wsadata
  732. );
  733. if(FAILED(hr))
  734. {
  735. goto ExitHere;
  736. }
  737. pSocket->IcmpHandle = (*pSocket->pFnIcmpCreateFile)();
  738. if (pSocket->IcmpHandle == INVALID_HANDLE_VALUE)
  739. {
  740. (*pSocket->pFnWSACleanup)();
  741. hr = LINEERR_OPERATIONFAILED;
  742. }
  743. ExitHere:
  744. if (hr != S_OK && bCleanup)
  745. {
  746. if (pSocket->hWS2 != NULL)
  747. {
  748. FreeLibrary (pSocket->hWS2);
  749. }
  750. if (pSocket->hICMP != NULL)
  751. {
  752. FreeLibrary (pSocket->hICMP);
  753. }
  754. ZeroMemory (pSocket, sizeof(RSPSOCKET));
  755. }
  756. return hr;
  757. }
  758. #define MAX_PACKET_SIZE 256
  759. #define PING_TIMEOUT 1000
  760. HRESULT SockIsServerResponding (
  761. RSPSOCKET * pSocket,
  762. char * szServer
  763. )
  764. {
  765. HRESULT hr = S_OK;
  766. unsigned long inetAddr;
  767. HOSTENT * pHost;
  768. BOOL bRet;
  769. CHAR ReplyBuf[MAX_PACKET_SIZE];
  770. // Validate parameters
  771. if (pSocket == NULL ||
  772. pSocket->hWS2 == NULL ||
  773. pSocket->hICMP == NULL ||
  774. pSocket->IcmpHandle == NULL ||
  775. pSocket->IcmpHandle == INVALID_HANDLE_VALUE)
  776. {
  777. hr = LINEERR_INVALPARAM;
  778. goto ExitHere;
  779. }
  780. // Get the server IP address
  781. pHost = (*pSocket->pFngethostbyname)(szServer);
  782. if (pHost == NULL)
  783. {
  784. hr = LINEERR_OPERATIONFAILED;
  785. goto ExitHere;
  786. }
  787. inetAddr = *(unsigned long *)pHost->h_addr;
  788. // Ping the server
  789. bRet = (*pSocket->pFnIcmpSendEcho)(
  790. pSocket->IcmpHandle,
  791. inetAddr,
  792. 0,
  793. 0,
  794. 0,
  795. (LPVOID)ReplyBuf,
  796. sizeof(ReplyBuf),
  797. PING_TIMEOUT
  798. );
  799. if (!bRet || ((PICMP_ECHO_REPLY)ReplyBuf)->Address != inetAddr)
  800. {
  801. hr = S_FALSE;
  802. }
  803. ExitHere:
  804. return hr;
  805. }
  806. HRESULT SockShutdown (
  807. RSPSOCKET * pSocket
  808. )
  809. {
  810. if (pSocket != NULL)
  811. {
  812. if (pSocket->IcmpHandle != INVALID_HANDLE_VALUE &&
  813. pSocket->IcmpHandle != NULL)
  814. {
  815. (*pSocket->pFnIcmpCloseHandle)(pSocket->IcmpHandle);
  816. }
  817. if (pSocket->hICMP != NULL)
  818. {
  819. FreeLibrary (pSocket->hICMP);
  820. }
  821. if (pSocket->hWS2 != NULL)
  822. {
  823. (*pSocket->pFnWSACleanup)();
  824. FreeLibrary (pSocket->hWS2);
  825. }
  826. ZeroMemory (pSocket, sizeof(RSPSOCKET));
  827. }
  828. return S_OK;
  829. }