Leaked source code of windows server 2003
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.

938 lines
24 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. hr = S_FALSE; // return a non-critical error so that we
  323. // ignore this server but don't abandon the search
  324. goto ExitHere;
  325. }
  326. LOG((TL_TRACE, "DsGetNextServer: ADsGetObject %S succeeded", szDN));
  327. hr = pSCP->GetObjectAttributes (
  328. szAttribs,
  329. sizeof(szAttribs) / sizeof(WCHAR *),
  330. &pPropEntries,
  331. &dwNumAttrGot
  332. );
  333. if (FAILED(hr) || dwNumAttrGot != sizeof(szAttribs) / sizeof(WCHAR *))
  334. {
  335. LOG((TL_ERROR, "DsGetNextServer: GetObjectAttributes %S failed", szDN));
  336. hr = S_FALSE;
  337. goto ExitHere;
  338. }
  339. LOG((TL_TRACE, "DsGetNextServer: GetObjectAttributes %S succeeded", szDN));
  340. bCheckedBinding = FALSE;
  341. for (i=0;i<(int)dwNumAttrGot;i++)
  342. {
  343. if (_tcsicmp(TEXT("serviceDNSName"), pPropEntries[i].pszAttrName) ==0 &&
  344. (pPropEntries[i].pADsValues->dwType == ADSTYPE_CASE_EXACT_STRING ||
  345. pPropEntries[i].pADsValues->dwType == ADSTYPE_CASE_IGNORE_STRING))
  346. {
  347. _tcsncpy (
  348. pszServerName,
  349. pPropEntries[i].pADsValues->CaseExactString,
  350. dwSize/sizeof(TCHAR)
  351. );
  352. pszServerName[dwSize/sizeof(TCHAR) - 1] = '\0';
  353. if (bCheckedBinding)
  354. {
  355. break;
  356. }
  357. }
  358. else if (_tcsicmp(TEXT("serviceBindingInformation"), pPropEntries[i].pszAttrName) ==0 &&
  359. (pPropEntries[i].pADsValues->dwType == ADSTYPE_CASE_EXACT_STRING ||
  360. pPropEntries[i].pADsValues->dwType == ADSTYPE_CASE_IGNORE_STRING))
  361. {
  362. SYSTEMTIME st;
  363. FILETIME ft1, ft2;
  364. bCheckedBinding = TRUE;
  365. wsz = pPropEntries[i].pADsValues->CaseExactString;
  366. wsz = wcsstr (wsz, gszStatusActive);
  367. if (wsz == NULL)
  368. {
  369. // No server status information or server is not active
  370. // ignore this server
  371. LOG((TL_ERROR, "DsGetNextServer: %S No server status information", szDN));
  372. hr = S_FALSE;
  373. break;
  374. }
  375. wsz += _tcslen(gszStatusActive); // skip "S{Active}" itself
  376. wsz = wcsstr (wsz, gszTTLWithBrace);
  377. if (wsz == NULL)
  378. {
  379. // No TTL found, corrupt serviceBindingInformation, ignore
  380. LOG((TL_ERROR, "DsGetNextServer: %S No TTL found", szDN));
  381. hr = S_FALSE;
  382. break;
  383. }
  384. wsz += _tcslen (gszTTLWithBrace); // skip "TTL{"
  385. //
  386. // The following codes parses the TTL information
  387. // created in server\dspub.cpp. They need to be
  388. // consistant. The current format is 5 digits for
  389. // year & 3 digits for milliseconds, 2 digits for
  390. // the remaining
  391. //
  392. st.wYear = (WORD) GetIntFromString (wsz, 5);
  393. st.wMonth = (WORD) GetIntFromString (wsz, 2);
  394. st.wDay = (WORD) GetIntFromString (wsz, 2),
  395. st.wHour = (WORD) GetIntFromString (wsz, 2);
  396. st.wMinute = (WORD) GetIntFromString (wsz, 2);
  397. st.wSecond = (WORD) GetIntFromString (wsz, 2);
  398. st.wMilliseconds = (WORD) GetIntFromString (wsz, 3);
  399. SystemTimeToFileTime (&st, &ft1);
  400. GetSystemTimeAsFileTime (&ft2);
  401. if (CompareFileTime (&ft1, &ft2) < 0)
  402. {
  403. // The TapiSCP object has passed its TTL, ignore
  404. hr = S_FALSE;
  405. LOG((TL_ERROR, "DsGetNextServer: %S The TapiSCP object has passed its TTL", szDN));
  406. break;
  407. }
  408. }
  409. }
  410. if (i == (int) dwNumAttrGot)
  411. {
  412. // Did not find an attribute
  413. hr = S_FALSE;
  414. }
  415. }
  416. ExitHere:
  417. if (pSCP)
  418. pSCP->Release();
  419. if (pPropEntries)
  420. FreeADsMem(pPropEntries);
  421. return hr;
  422. }
  423. //
  424. // DsCloseLookup
  425. // Close the TAPI DS published server lookup identified by pctx
  426. //
  427. HRESULT
  428. DsCloseLookup(
  429. PTAPISRV_LOOKUP_CTX pctx
  430. )
  431. {
  432. if (pctx && pctx->pDirSearch && pctx->hDirSearch)
  433. {
  434. pctx->pDirSearch->CloseSearchHandle(pctx->hDirSearch);
  435. }
  436. if (pctx && pctx->pDirSearch)
  437. {
  438. pctx->pDirSearch->Release();
  439. }
  440. CoUninitialize ();
  441. return S_OK;
  442. }
  443. /**********************************************************
  444. * Get TAPI servers list remotesp.tsp should contact
  445. * Servers include those specified in registry through
  446. * tcmsetup.exe and those servers published in the DS
  447. *********************************************************/
  448. typedef struct _SERVER_LOOKUP_ENTRY {
  449. TCHAR szServer[MAX_PATH];
  450. BOOL bFromReg;
  451. } SERVER_LOOKUP_ENTRY, *PSERVER_LOOKUP_ENTRY;
  452. typedef struct _SERVER_LOOKUP {
  453. DWORD dwTotalEntries;
  454. DWORD dwUsedEntries;
  455. SERVER_LOOKUP_ENTRY * aEntries;
  456. } SERVER_LOOKUP, *PSERVER_LOOKUP;
  457. SERVER_LOOKUP gLookup;
  458. DWORD gdwCurIndex;
  459. //
  460. // AddEntry : return FALSE if failed; otherwise, return true
  461. //
  462. BOOL
  463. AddEntry (
  464. LPTSTR szServer,
  465. BOOL bFromReg
  466. )
  467. {
  468. LPTSTR psz;
  469. if (gLookup.dwUsedEntries >= gLookup.dwTotalEntries)
  470. {
  471. PSERVER_LOOKUP_ENTRY pNew;
  472. pNew = (PSERVER_LOOKUP_ENTRY) DrvAlloc (
  473. sizeof(SERVER_LOOKUP_ENTRY) * (gLookup.dwTotalEntries + 5)
  474. );
  475. if (pNew == NULL)
  476. {
  477. return FALSE;
  478. }
  479. if (gLookup.dwUsedEntries > 0)
  480. {
  481. CopyMemory (
  482. pNew,
  483. gLookup.aEntries,
  484. sizeof(SERVER_LOOKUP_ENTRY) * gLookup.dwTotalEntries
  485. );
  486. }
  487. if (gLookup.aEntries)
  488. {
  489. DrvFree (gLookup.aEntries);
  490. }
  491. gLookup.aEntries = pNew;
  492. gLookup.dwTotalEntries += 5;
  493. }
  494. wcsncpy (
  495. gLookup.aEntries[gLookup.dwUsedEntries].szServer,
  496. szServer,
  497. sizeof(gLookup.aEntries[gLookup.dwUsedEntries].szServer)/sizeof(TCHAR)
  498. );
  499. psz = _tcschr(gLookup.aEntries[gLookup.dwUsedEntries].szServer, TEXT('.'));
  500. if (psz != NULL)
  501. {
  502. *psz = 0;
  503. }
  504. gLookup.aEntries[gLookup.dwUsedEntries].bFromReg = bFromReg;
  505. ++gLookup.dwUsedEntries;
  506. return TRUE;
  507. }
  508. BOOL
  509. IsServerInListOrSelf (
  510. LPTSTR szServer
  511. )
  512. {
  513. int i;
  514. TCHAR szServer1[MAX_PATH + 1];
  515. LPTSTR psz;
  516. BOOL bRet = FALSE;
  517. _tcsncpy (szServer1, szServer, MAX_PATH);
  518. szServer1[MAX_PATH] = 0;
  519. // A computer name might be DNS name like comp1.microsoft.com
  520. // only compare the computer name
  521. psz = _tcschr(szServer1, TEXT('.'));
  522. if (psz != NULL)
  523. {
  524. *psz = 0;
  525. }
  526. for (i = 0; i < (int)gLookup.dwUsedEntries; ++i)
  527. {
  528. if (_tcsicmp (szServer1, gLookup.aEntries[i].szServer) == 0)
  529. {
  530. bRet = TRUE;
  531. break;
  532. }
  533. }
  534. if (!bRet)
  535. {
  536. TCHAR szSelf[MAX_PATH];
  537. DWORD dwSize = sizeof(szSelf);
  538. if (GetComputerName (szSelf, &dwSize))
  539. {
  540. if (_tcsicmp (szServer1, szSelf) == 0)
  541. {
  542. bRet = TRUE;
  543. }
  544. }
  545. }
  546. return bRet;
  547. }
  548. BOOL OpenServerLookup (
  549. HKEY hRegistry
  550. )
  551. {
  552. BOOL bRet = TRUE;
  553. TCHAR szServer[MAX_PATH];
  554. TAPISRV_LOOKUP_CTX ctx;
  555. HRESULT hr;
  556. DWORD dwNoDSQuery = 0;
  557. DWORD dwSize = sizeof(dwNoDSQuery);
  558. gLookup.dwTotalEntries = 0;
  559. gLookup.dwUsedEntries = 0;
  560. gLookup.aEntries = NULL;
  561. //
  562. // First add the computer from registry
  563. //
  564. if (RegOpenServerLookup (hRegistry))
  565. {
  566. while (RegGetNextServer (szServer, sizeof(szServer)))
  567. {
  568. if (!IsServerInListOrSelf (szServer))
  569. {
  570. AddEntry (szServer, TRUE);
  571. }
  572. }
  573. RegCloseLookup ();
  574. }
  575. if (hRegistry != NULL)
  576. {
  577. if (ERROR_SUCCESS != RegQueryValueEx (
  578. hRegistry,
  579. gszNoDSQuery,
  580. NULL,
  581. NULL,
  582. (LPBYTE)&dwNoDSQuery,
  583. &dwSize
  584. ))
  585. {
  586. dwNoDSQuery = 0;
  587. }
  588. }
  589. //
  590. // Next add the computer from DS unless disabled
  591. //
  592. if (dwNoDSQuery == 0)
  593. {
  594. if (DsOpenServerLookup (&ctx) == S_OK)
  595. {
  596. while (SUCCEEDED(hr = DsGetNextServer (&ctx,szServer, sizeof(szServer))))
  597. {
  598. if (hr == S_ADS_NOMORE_ROWS)
  599. {
  600. break;
  601. }
  602. else if (hr != S_OK)
  603. {
  604. continue; // Server needs to be ignored
  605. }
  606. if (szServer[0] != 0 && !IsServerInListOrSelf (szServer))
  607. {
  608. AddEntry (szServer, FALSE);
  609. }
  610. }
  611. DsCloseLookup (&ctx);
  612. }
  613. }
  614. gdwCurIndex = 0;
  615. return TRUE;
  616. }
  617. BOOL GetNextServer (
  618. LPSTR szServer,
  619. DWORD dwSize,
  620. BOOL * pbReg
  621. )
  622. {
  623. BOOL bRet = TRUE;
  624. DWORD dwRet;
  625. if (gdwCurIndex >= gLookup.dwUsedEntries)
  626. {
  627. bRet = FALSE;
  628. goto ExitHere;
  629. }
  630. if (pbReg != NULL)
  631. {
  632. *pbReg = gLookup.aEntries[gdwCurIndex].bFromReg;
  633. }
  634. dwRet = WideCharToMultiByte(
  635. GetACP(),
  636. 0,
  637. gLookup.aEntries[gdwCurIndex].szServer,
  638. -1,
  639. szServer,
  640. dwSize,
  641. 0,
  642. NULL
  643. );
  644. if (dwRet == 0)
  645. {
  646. bRet = FALSE;
  647. goto ExitHere;
  648. }
  649. ++gdwCurIndex;
  650. ExitHere:
  651. return bRet;
  652. }
  653. BOOL CloseLookup (
  654. void
  655. )
  656. {
  657. if (gLookup.aEntries)
  658. {
  659. DrvFree (gLookup.aEntries);
  660. }
  661. gLookup.aEntries = NULL;
  662. gLookup.dwTotalEntries = 0;
  663. gLookup.dwUsedEntries = 0;
  664. gdwCurIndex = 0;
  665. return TRUE;
  666. }
  667. HRESULT SockStartup (
  668. RSPSOCKET * pSocket
  669. )
  670. {
  671. HRESULT hr = S_OK;
  672. BOOL bCleanup = FALSE;
  673. WSADATA wsadata;
  674. WORD wVersionRequested = MAKEWORD( 2, 2 );
  675. if (pSocket == NULL)
  676. {
  677. hr = LINEERR_INVALPARAM;
  678. goto ExitHere;
  679. }
  680. ZeroMemory (pSocket, sizeof(RSPSOCKET));
  681. bCleanup = TRUE;
  682. ZeroMemory (pSocket, sizeof(RSPSOCKET));
  683. pSocket->hWS2 = LoadLibrary (TEXT("ws2_32.dll"));
  684. if (pSocket->hWS2 == NULL)
  685. {
  686. hr = HRESULT_FROM_WIN32(GetLastError());
  687. goto ExitHere;
  688. }
  689. pSocket->pFnWSAStartup = (PFNWSASTARTUP)GetProcAddress (
  690. pSocket->hWS2,
  691. "WSAStartup"
  692. );
  693. pSocket->pFnWSACleanup = (PFNWSACLEANUP)GetProcAddress (
  694. pSocket->hWS2,
  695. "WSACleanup"
  696. );
  697. pSocket->pFngethostbyname = (PFNGETHOSTBYNAME)GetProcAddress(
  698. pSocket->hWS2,
  699. "gethostbyname"
  700. );
  701. if (pSocket->pFnWSAStartup == NULL ||
  702. pSocket->pFnWSACleanup == NULL ||
  703. pSocket->pFngethostbyname == NULL)
  704. {
  705. hr = LINEERR_OPERATIONFAILED;
  706. goto ExitHere;
  707. }
  708. pSocket->hICMP = LoadLibrary (TEXT("icmp.dll"));
  709. if (pSocket->hICMP == NULL)
  710. {
  711. hr = HRESULT_FROM_WIN32(GetLastError());
  712. goto ExitHere;
  713. }
  714. pSocket->pFnIcmpCreateFile = (PFNICMPCREATEFILE)GetProcAddress (
  715. pSocket->hICMP,
  716. "IcmpCreateFile"
  717. );
  718. pSocket->pFnIcmpCloseHandle = (PFNICMPCLOSEHANDLE)GetProcAddress (
  719. pSocket->hICMP,
  720. "IcmpCloseHandle"
  721. );
  722. pSocket->pFnIcmpSendEcho = (PFNICMPSENDECHO)GetProcAddress (
  723. pSocket->hICMP,
  724. "IcmpSendEcho"
  725. );
  726. if (pSocket->pFnIcmpCreateFile == NULL ||
  727. pSocket->pFnIcmpCloseHandle == NULL ||
  728. pSocket->pFnIcmpSendEcho == NULL)
  729. {
  730. hr = LINEERR_OPERATIONFAILED;
  731. goto ExitHere;
  732. }
  733. hr = (*pSocket->pFnWSAStartup)(
  734. wVersionRequested,
  735. &wsadata
  736. );
  737. if(FAILED(hr))
  738. {
  739. goto ExitHere;
  740. }
  741. pSocket->IcmpHandle = (*pSocket->pFnIcmpCreateFile)();
  742. if (pSocket->IcmpHandle == INVALID_HANDLE_VALUE)
  743. {
  744. (*pSocket->pFnWSACleanup)();
  745. hr = LINEERR_OPERATIONFAILED;
  746. }
  747. ExitHere:
  748. if (hr != S_OK && bCleanup)
  749. {
  750. if (pSocket->hWS2 != NULL)
  751. {
  752. FreeLibrary (pSocket->hWS2);
  753. }
  754. if (pSocket->hICMP != NULL)
  755. {
  756. FreeLibrary (pSocket->hICMP);
  757. }
  758. ZeroMemory (pSocket, sizeof(RSPSOCKET));
  759. }
  760. return hr;
  761. }
  762. #define MAX_PACKET_SIZE 256
  763. #define PING_TIMEOUT 1000
  764. HRESULT SockIsServerResponding (
  765. RSPSOCKET * pSocket,
  766. char * szServer
  767. )
  768. {
  769. HRESULT hr = S_OK;
  770. unsigned long inetAddr;
  771. HOSTENT * pHost;
  772. BOOL bRet;
  773. CHAR ReplyBuf[MAX_PACKET_SIZE];
  774. // Validate parameters
  775. if (pSocket == NULL ||
  776. pSocket->hWS2 == NULL ||
  777. pSocket->hICMP == NULL ||
  778. pSocket->IcmpHandle == NULL ||
  779. pSocket->IcmpHandle == INVALID_HANDLE_VALUE)
  780. {
  781. hr = LINEERR_INVALPARAM;
  782. goto ExitHere;
  783. }
  784. // Get the server IP address
  785. pHost = (*pSocket->pFngethostbyname)(szServer);
  786. if (pHost == NULL)
  787. {
  788. hr = LINEERR_OPERATIONFAILED;
  789. goto ExitHere;
  790. }
  791. inetAddr = *(unsigned long *)pHost->h_addr;
  792. // Ping the server
  793. bRet = (*pSocket->pFnIcmpSendEcho)(
  794. pSocket->IcmpHandle,
  795. inetAddr,
  796. 0,
  797. 0,
  798. 0,
  799. (LPVOID)ReplyBuf,
  800. sizeof(ReplyBuf),
  801. PING_TIMEOUT
  802. );
  803. if (!bRet || ((PICMP_ECHO_REPLY)ReplyBuf)->Address != inetAddr)
  804. {
  805. hr = S_FALSE;
  806. }
  807. ExitHere:
  808. return hr;
  809. }
  810. HRESULT SockShutdown (
  811. RSPSOCKET * pSocket
  812. )
  813. {
  814. if (pSocket != NULL)
  815. {
  816. if (pSocket->IcmpHandle != INVALID_HANDLE_VALUE &&
  817. pSocket->IcmpHandle != NULL)
  818. {
  819. (*pSocket->pFnIcmpCloseHandle)(pSocket->IcmpHandle);
  820. }
  821. if (pSocket->hICMP != NULL)
  822. {
  823. FreeLibrary (pSocket->hICMP);
  824. }
  825. if (pSocket->hWS2 != NULL)
  826. {
  827. (*pSocket->pFnWSACleanup)();
  828. FreeLibrary (pSocket->hWS2);
  829. }
  830. ZeroMemory (pSocket, sizeof(RSPSOCKET));
  831. }
  832. return S_OK;
  833. }