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.

1733 lines
40 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name :
  4. tcputil.cxx
  5. Abstract:
  6. This module contains common utility routines for the TCP services
  7. Author:
  8. Johnl 09-Oct-1994 Created.
  9. --*/
  10. #include "tcpdllp.hxx"
  11. #include <datetime.hxx>
  12. LPSTR
  13. ConvertUnicodeToAnsi(
  14. IN LPCWSTR lpszUnicode,
  15. IN LPSTR lpszAnsi,
  16. IN DWORD cbAnsi
  17. )
  18. /*++
  19. Description:
  20. Converts given null-terminated string into ANSI in the buffer supplied.
  21. Arguments:
  22. lpszUnicode null-terminated string in Unicode
  23. lpszAnsi buffer supplied to copy string after conversion.
  24. if ( lpszAnsi == NULL), then this module allocates space
  25. using TCP_ALLOC, which should be freed calling TCP_FREE
  26. by user.
  27. cbAnsi number of bytes in lpszAnsi if specified
  28. Returns:
  29. pointer to converted ANSI string. NULL on errors.
  30. History:
  31. MuraliK 12-01-1994 Created.
  32. --*/
  33. {
  34. DWORD cchLen;
  35. DWORD nBytes;
  36. LPSTR lpszAlloc = NULL;
  37. if ( lpszUnicode == NULL) {
  38. return (NULL);
  39. }
  40. if ( lpszAnsi == NULL) {
  41. //
  42. // multiply by 2 to accomodate DBCS
  43. //
  44. cchLen = wcslen( lpszUnicode);
  45. nBytes = (cchLen+1) * sizeof(CHAR) * 2;
  46. lpszAlloc = (LPSTR ) TCP_ALLOC( nBytes );
  47. } else {
  48. lpszAlloc = lpszAnsi;
  49. nBytes = cbAnsi;
  50. DBG_ASSERT(nBytes > 0);
  51. }
  52. if ( lpszAlloc != NULL) {
  53. cchLen = WideCharToMultiByte( CP_ACP,
  54. WC_COMPOSITECHECK,
  55. lpszUnicode,
  56. -1,
  57. lpszAlloc,
  58. nBytes,
  59. NULL, // lpszDefaultChar
  60. NULL // lpfDefaultUsed
  61. );
  62. DBG_ASSERT(cchLen == (strlen(lpszAlloc)+1) );
  63. if ( cchLen == 0 ) {
  64. //
  65. // There was a failure. Free up buffer if need be.
  66. //
  67. DBGPRINTF((DBG_CONTEXT,"WideCharToMultiByte failed with %d\n",
  68. GetLastError()));
  69. if ( lpszAnsi == NULL) {
  70. TCP_FREE( lpszAlloc);
  71. lpszAlloc = NULL;
  72. } else {
  73. lpszAlloc[cchLen] = '\0';
  74. }
  75. } else {
  76. DBG_ASSERT( cchLen <= nBytes );
  77. DBG_ASSERT(lpszAlloc[cchLen-1] == '\0');
  78. lpszAlloc[cchLen-1] = '\0';
  79. }
  80. }
  81. return ( lpszAlloc);
  82. } // ConvertUnicodeToAnsi
  83. /*******************************************************************
  84. NAME: ReadRegistryDword
  85. SYNOPSIS: Reads a DWORD value from the registry.
  86. ENTRY: hkey - Openned registry key to read
  87. pszValueName - The name of the value.
  88. dwDefaultValue - The default value to use if the
  89. value cannot be read.
  90. RETURNS DWORD - The value from the registry, or dwDefaultValue.
  91. ********************************************************************/
  92. DWORD ReadRegistryDwordA( HKEY hkey,
  93. LPCSTR pszValueName,
  94. DWORD dwDefaultValue )
  95. {
  96. DWORD err;
  97. DWORD dwBuffer;
  98. DWORD cbBuffer = sizeof(dwBuffer);
  99. DWORD dwType;
  100. if( hkey != NULL )
  101. {
  102. err = RegQueryValueExA( hkey,
  103. pszValueName,
  104. NULL,
  105. &dwType,
  106. (LPBYTE)&dwBuffer,
  107. &cbBuffer );
  108. if( ( err == NO_ERROR ) && ( dwType == REG_DWORD ) )
  109. {
  110. dwDefaultValue = dwBuffer;
  111. }
  112. }
  113. return dwDefaultValue;
  114. } // ReadRegistryDwordA()
  115. DWORD
  116. WriteRegistryDwordA(
  117. IN HKEY hkey,
  118. IN LPCSTR pszValueName,
  119. IN DWORD dwValue)
  120. /*++
  121. Description:
  122. Writes the given DWORD value into registry entry specified
  123. by hkey\pszValueName
  124. Arguments:
  125. hkey handle to registry key
  126. pszValueName name of the value
  127. dwValue new value for write
  128. Returns:
  129. Win32 error codes. NO_ERROR if successful.
  130. History:
  131. MuraliK 12-01-1994 Created.
  132. --*/
  133. {
  134. DWORD err;
  135. if ( (hkey == NULL) || (pszValueName == NULL) ) {
  136. err = ( ERROR_INVALID_PARAMETER);
  137. } else {
  138. err = RegSetValueExA( hkey,
  139. pszValueName,
  140. 0,
  141. REG_DWORD,
  142. (LPBYTE ) &dwValue,
  143. sizeof( dwValue));
  144. }
  145. return ( err);
  146. } // WriteRegistryDwordA()
  147. DWORD
  148. WriteRegistryStringA(
  149. IN HKEY hkey,
  150. IN LPCSTR pszValueName,
  151. IN LPCSTR pszValue,
  152. IN DWORD cbValue,
  153. IN DWORD dwType
  154. )
  155. /*++
  156. Description:
  157. Writes the given ANSI String into registry entry specified
  158. by hkey\pszValueName.
  159. Arguments:
  160. hkey handle to registry key
  161. pszValueName name of the value
  162. pszValue new value for write
  163. cbValue count of bytes of value written.
  164. Should include terminating null characters.
  165. dwType type of the value being written
  166. ( REG_SZ, REG_MULTI_SZ etc)
  167. Returns:
  168. Win32 error codes. NO_ERROR if successful.
  169. --*/
  170. {
  171. DWORD err;
  172. DBG_ASSERT(dwType != REG_MULTI_SZ);
  173. DBG_ASSERT( (dwType == REG_SZ) || (dwType == REG_EXPAND_SZ) );
  174. if ( (hkey == NULL) ||
  175. (pszValueName == NULL) ||
  176. (cbValue == 0) ) {
  177. err = ERROR_INVALID_PARAMETER;
  178. } else {
  179. err = RegSetValueExA(
  180. hkey,
  181. pszValueName,
  182. 0,
  183. dwType,
  184. (LPBYTE ) pszValue,
  185. cbValue); // + 1 for null character
  186. }
  187. return ( err);
  188. } // WriteRegistryStringA()
  189. DWORD
  190. WriteRegistryStringW(
  191. IN HKEY hkey,
  192. IN LPCWSTR pszValueName,
  193. IN LPCWSTR pszValue,
  194. IN DWORD cbValue,
  195. IN DWORD dwType)
  196. /*++
  197. Description:
  198. Writes the given ANSI String into registry entry specified
  199. by hkey\pszValueName.
  200. Arguments:
  201. hkey handle to registry key
  202. pszValueName name of the value
  203. pszValue new value for write
  204. cbValue count of bytes of value written.
  205. Should include terminating null characters.
  206. dwType type of the value being written
  207. ( REG_SZ, REG_MULTI_SZ etc)
  208. Returns:
  209. Win32 error codes. NO_ERROR if successful.
  210. --*/
  211. {
  212. DWORD err;
  213. LPSTR ansiValue = NULL;
  214. LPSTR ansiName = NULL;
  215. if ( (hkey == NULL) ||
  216. (pszValueName == NULL) ||
  217. (cbValue == 0) ) {
  218. err = ERROR_INVALID_PARAMETER;
  219. } else {
  220. //
  221. // Convert to ansi
  222. //
  223. ansiName = ConvertUnicodeToAnsi( pszValueName, NULL, 0 );
  224. ansiValue = ConvertUnicodeToAnsi( pszValue, NULL, 0 );
  225. if ( (ansiName != NULL) && (ansiValue != NULL) ) {
  226. err = WriteRegistryStringA(hkey,
  227. ansiName,
  228. ansiValue,
  229. strlen(ansiValue)+1,
  230. dwType
  231. );
  232. } else {
  233. err = ERROR_NOT_ENOUGH_MEMORY;
  234. }
  235. }
  236. if ( ansiName != NULL ) {
  237. TCP_FREE(ansiName);
  238. }
  239. if ( ansiValue != NULL ) {
  240. TCP_FREE(ansiValue);
  241. }
  242. return ( err);
  243. } // WriteRegistryStringW()
  244. /*******************************************************************
  245. NAME: ReadRegistryString
  246. SYNOPSIS: Allocates necessary buffer space for a registry
  247. string, then reads the string into the buffer.
  248. ENTRY: pszValueName - The name of the value.
  249. pszDefaultValue - The default value to use if the
  250. value cannot be read.
  251. fExpand - Expand environment strings if TRUE.
  252. RETURNS: TCHAR * - The string, NULL if error.
  253. NOTES: I always allocate one more character than actually
  254. necessary. This will ensure that any code expecting
  255. to read a REG_MULTI_SZ will not explode if the
  256. registry actually contains a REG_SZ.
  257. This function cannot be called until after
  258. InitializeGlobals().
  259. HISTORY:
  260. KeithMo 15-Mar-1993 Created.
  261. ********************************************************************/
  262. TCHAR * ReadRegistryString( HKEY hkey,
  263. LPCTSTR pszValueName,
  264. LPCTSTR pszDefaultValue,
  265. BOOL fExpand )
  266. {
  267. TCHAR * pszBuffer1;
  268. TCHAR * pszBuffer2;
  269. DWORD cbBuffer;
  270. DWORD dwType;
  271. DWORD err;
  272. //
  273. // Determine the buffer size.
  274. //
  275. pszBuffer1 = NULL;
  276. pszBuffer2 = NULL;
  277. cbBuffer = 0;
  278. if( hkey == NULL )
  279. {
  280. //
  281. // Pretend the key wasn't found.
  282. //
  283. err = ERROR_FILE_NOT_FOUND;
  284. }
  285. else
  286. {
  287. err = RegQueryValueEx( hkey,
  288. pszValueName,
  289. NULL,
  290. &dwType,
  291. NULL,
  292. &cbBuffer );
  293. if( ( err == NO_ERROR ) || ( err == ERROR_MORE_DATA ) )
  294. {
  295. if( ( dwType != REG_SZ ) &&
  296. ( dwType != REG_MULTI_SZ ) &&
  297. ( dwType != REG_EXPAND_SZ ) )
  298. {
  299. //
  300. // Type mismatch, registry data NOT a string.
  301. // Use default.
  302. //
  303. err = ERROR_FILE_NOT_FOUND;
  304. }
  305. else
  306. {
  307. //
  308. // Item found, allocate a buffer.
  309. //
  310. pszBuffer1 = (TCHAR *) TCP_ALLOC( cbBuffer+sizeof(TCHAR) );
  311. if( pszBuffer1 == NULL )
  312. {
  313. err = ERROR_NOT_ENOUGH_MEMORY;
  314. }
  315. else
  316. {
  317. //
  318. // Now read the value into the buffer.
  319. //
  320. err = RegQueryValueEx( hkey,
  321. pszValueName,
  322. NULL,
  323. NULL,
  324. (LPBYTE)pszBuffer1,
  325. &cbBuffer );
  326. }
  327. }
  328. }
  329. }
  330. if( err == ERROR_FILE_NOT_FOUND )
  331. {
  332. //
  333. // Item not found, use default value.
  334. //
  335. err = NO_ERROR;
  336. if( pszDefaultValue != NULL )
  337. {
  338. pszBuffer1 = (TCHAR *)TCP_ALLOC( (_tcslen(pszDefaultValue)+1) * sizeof(TCHAR) );
  339. if( pszBuffer1 == NULL )
  340. {
  341. err = ERROR_NOT_ENOUGH_MEMORY;
  342. }
  343. else
  344. {
  345. _tcscpy( pszBuffer1, pszDefaultValue );
  346. }
  347. }
  348. }
  349. if( err != NO_ERROR )
  350. {
  351. //
  352. // Tragic error reading registry, abort now.
  353. //
  354. goto ErrorCleanup;
  355. }
  356. //
  357. // pszBuffer1 holds the registry value. Now expand
  358. // the environment strings if necessary.
  359. //
  360. if( !fExpand )
  361. {
  362. return pszBuffer1;
  363. }
  364. //
  365. // Returns number of characters
  366. //
  367. cbBuffer = ExpandEnvironmentStrings( pszBuffer1,
  368. NULL,
  369. 0 );
  370. //
  371. // The ExpandEnvironmentStrings() API is kinda poor. In returning the
  372. // number of characters, we have no clue how large to make the buffer
  373. // in the case of DBCS characters. Lets assume that each character is
  374. // 2 bytes.
  375. //
  376. pszBuffer2 = (TCHAR *) TCP_ALLOC( (cbBuffer+1)*sizeof(WCHAR) );
  377. if( pszBuffer2 == NULL )
  378. {
  379. goto ErrorCleanup;
  380. }
  381. if( ExpandEnvironmentStrings( pszBuffer1,
  382. pszBuffer2,
  383. cbBuffer ) > cbBuffer )
  384. {
  385. goto ErrorCleanup;
  386. }
  387. //
  388. // pszBuffer2 now contains the registry value with
  389. // environment strings expanded.
  390. //
  391. TCP_FREE( pszBuffer1 );
  392. pszBuffer1 = NULL;
  393. return pszBuffer2;
  394. ErrorCleanup:
  395. //
  396. // Something tragic happend; free any allocated buffers
  397. // and return NULL to the caller, indicating failure.
  398. //
  399. if( pszBuffer1 != NULL )
  400. {
  401. TCP_FREE( pszBuffer1 );
  402. pszBuffer1 = NULL;
  403. }
  404. if( pszBuffer2 != NULL )
  405. {
  406. TCP_FREE( pszBuffer2 );
  407. pszBuffer2 = NULL;
  408. }
  409. return NULL;
  410. } // ReadRegistryString
  411. //
  412. // Chicago does not support the REG_MULTI_SZ registry value. As
  413. // a hack (er, workaround), we'll create *keys* in the registry
  414. // in place of REG_MULTI_SZ *values*. We'll then use the names
  415. // of any values under the key as the REG_MULTI_SZ entries. So,
  416. // instead of this:
  417. //
  418. // ..\Control\ServiceProvider
  419. // ProviderOrder = REG_MULTI_SZ "MSTCP"
  420. // "NWLINK"
  421. // "FOOBAR"
  422. //
  423. // We'll use this:
  424. //
  425. // ..\Control\Service\Provider\ProviderOrder
  426. // MSTCP = REG_SZ ""
  427. // NWLINK = REG_SZ ""
  428. // FOOBAR = REG_SZ ""
  429. //
  430. // This function takes an open registry key handle, enumerates
  431. // the names of values contained within the key, and constructs
  432. // a REG_MULTI_SZ string from the value names.
  433. //
  434. // Note that this function is not multithread safe; if another
  435. // thread (or process) creates or deletes values under the
  436. // specified key, the results are indeterminate.
  437. //
  438. // This function returns NULL on error. It returns non-NULL
  439. // on success, even if the resulting REG_MULTI_SZ is empty.
  440. //
  441. TCHAR *
  442. KludgeMultiSz(
  443. HKEY hkey,
  444. LPDWORD lpdwLength
  445. )
  446. {
  447. LONG err;
  448. DWORD iValue;
  449. DWORD cchTotal;
  450. DWORD cchValue;
  451. TCHAR szValue[MAX_PATH];
  452. LPTSTR lpMultiSz;
  453. LPTSTR lpTmp;
  454. LPTSTR lpEnd;
  455. //
  456. // Enumerate the values and total up the lengths.
  457. //
  458. iValue = 0;
  459. cchTotal = 0;
  460. for( ; ; )
  461. {
  462. cchValue = sizeof(szValue)/sizeof(TCHAR);
  463. err = RegEnumValue( hkey,
  464. iValue,
  465. szValue,
  466. &cchValue,
  467. NULL,
  468. NULL,
  469. NULL,
  470. NULL );
  471. if( err != NO_ERROR )
  472. {
  473. break;
  474. }
  475. //
  476. // Add the length of the value's name, plus one
  477. // for the terminator.
  478. //
  479. cchTotal += _tcslen( szValue ) + 1;
  480. //
  481. // Advance to next value.
  482. //
  483. iValue++;
  484. }
  485. //
  486. // Add one for the final terminating NULL.
  487. //
  488. cchTotal++;
  489. *lpdwLength = cchTotal;
  490. //
  491. // Allocate the MULTI_SZ buffer.
  492. //
  493. lpMultiSz = (TCHAR *) TCP_ALLOC( cchTotal * sizeof(TCHAR) );
  494. if( lpMultiSz == NULL )
  495. {
  496. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  497. return NULL;
  498. }
  499. memset( lpMultiSz, 0, cchTotal * sizeof(TCHAR) );
  500. //
  501. // Enumerate the values and append to the buffer.
  502. //
  503. iValue = 0;
  504. lpTmp = lpMultiSz;
  505. lpEnd = lpMultiSz + cchTotal;
  506. for( ; ; )
  507. {
  508. cchValue = sizeof(szValue)/sizeof(TCHAR);
  509. err = RegEnumValue( hkey,
  510. iValue,
  511. szValue,
  512. &cchValue,
  513. NULL,
  514. NULL,
  515. NULL,
  516. NULL );
  517. if( err != NO_ERROR )
  518. {
  519. break;
  520. }
  521. //
  522. // Compute the length of the value name (including
  523. // the terminating NULL).
  524. //
  525. cchValue = _tcslen( szValue ) + 1;
  526. //
  527. // Determine if there is room in the array, taking into
  528. // account the second NULL that terminates the string list.
  529. //
  530. if( ( lpTmp + cchValue + 1 ) > lpEnd )
  531. {
  532. break;
  533. }
  534. //
  535. // Append the value name.
  536. //
  537. _tcscpy( lpTmp, szValue );
  538. lpTmp += cchValue;
  539. //
  540. // Advance to next value.
  541. //
  542. iValue++;
  543. }
  544. //
  545. // Success!
  546. //
  547. return (LPTSTR)lpMultiSz;
  548. } // KludgeMultiSz
  549. BOOL
  550. ReadRegistryStr(
  551. IN HKEY hkeyReg,
  552. OUT STR & str,
  553. IN LPCTSTR lpszValueName,
  554. IN LPCTSTR lpszDefaultValue,
  555. IN BOOL fExpand )
  556. /*++
  557. Reads the registry string into the string buffer supplied.
  558. If there is no value in the registry the default value is set to
  559. be the value of the string.
  560. If an environment expansion is requested, it is also performed.
  561. Arguments:
  562. hkeyReg handle for registry entry
  563. str string to contain the result of read operation
  564. lpszValueName
  565. pointer to string containing the key name whose
  566. value needs to be fetched.
  567. lpszDefaultValue
  568. pointer to string containing a value which is used if no
  569. value exists in the registry.
  570. fExpand boolean flag indicating if an expansion is desired.
  571. Returns:
  572. FALSE if there is any error.
  573. TRUE when the string is successfully set.
  574. --*/
  575. {
  576. BOOL fReturn = FALSE;
  577. LPTSTR pszValueAlloc;
  578. pszValueAlloc = ReadRegistryString( hkeyReg, lpszValueName,
  579. lpszDefaultValue, fExpand);
  580. if ( pszValueAlloc != NULL) {
  581. fReturn = str.Copy( pszValueAlloc);
  582. TCP_FREE( pszValueAlloc);
  583. } else {
  584. DBG_ASSERT( fReturn == FALSE);
  585. }
  586. if ( !fReturn) {
  587. IF_DEBUG( ERROR) {
  588. DWORD err = GetLastError();
  589. DBGPRINTF(( DBG_CONTEXT,
  590. " Error %u in ReadRegistryString( %08x, %s).\n",
  591. err, hkeyReg, lpszValueName));
  592. SetLastError(err);
  593. }
  594. }
  595. return ( fReturn);
  596. } // ReadRegistryStr
  597. /*******************************************************************
  598. NAME: FlipSlashes
  599. SYNOPSIS: Flips the Unix-ish forward slashes ('/') into Dos-ish
  600. back slashes ('\').
  601. ENTRY: pszPath - The path to munge.
  602. RETURNS: TCHAR * - pszPath.
  603. HISTORY:
  604. KeithMo 04-Jun-1993 Created.
  605. ********************************************************************/
  606. TCHAR * FlipSlashes( TCHAR * pszPath )
  607. {
  608. TCHAR ch;
  609. TCHAR * pszScan = pszPath;
  610. while( ( ch = *pszScan ) != TEXT('\0') )
  611. {
  612. if( ch == TEXT('/') )
  613. {
  614. *pszScan = TEXT('\\');
  615. }
  616. pszScan++;
  617. }
  618. return pszPath;
  619. } // FlipSlashes
  620. /*++
  621. Copyright (c) 1991 Microsoft Corporation
  622. Module Name:
  623. i_ntoa.c
  624. Abstract:
  625. This module implements a routine to convert a numerical IP address
  626. into a dotted-decimal character string Internet address.
  627. Author:
  628. Mike Massa (mikemas) Sept 20, 1991
  629. Revision History:
  630. Who When What
  631. -------- -------- ----------------------------------------------
  632. mikemas 9-20-91 created
  633. davidtr 9-19-95 completely rewritten for performance
  634. muralik 3-Oct-1995 massaged it for Internet services
  635. Notes:
  636. Exports:
  637. InetNtoa()
  638. --*/
  639. #define UC(b) (((int)b)&0xff)
  640. //
  641. // This preinitialized array defines the strings to be used for
  642. // inet_ntoa. The index of each row corresponds to the value for a byte
  643. // in an IP address. The first three bytes of each row are the
  644. // char/string value for the byte, and the fourth byte in each row is
  645. // the length of the string required for the byte. This approach
  646. // allows a fast implementation with no jumps.
  647. //
  648. static BYTE NToACharStrings[][4] = {
  649. '0', 'x', 'x', 1,
  650. '1', 'x', 'x', 1,
  651. '2', 'x', 'x', 1,
  652. '3', 'x', 'x', 1,
  653. '4', 'x', 'x', 1,
  654. '5', 'x', 'x', 1,
  655. '6', 'x', 'x', 1,
  656. '7', 'x', 'x', 1,
  657. '8', 'x', 'x', 1,
  658. '9', 'x', 'x', 1,
  659. '1', '0', 'x', 2,
  660. '1', '1', 'x', 2,
  661. '1', '2', 'x', 2,
  662. '1', '3', 'x', 2,
  663. '1', '4', 'x', 2,
  664. '1', '5', 'x', 2,
  665. '1', '6', 'x', 2,
  666. '1', '7', 'x', 2,
  667. '1', '8', 'x', 2,
  668. '1', '9', 'x', 2,
  669. '2', '0', 'x', 2,
  670. '2', '1', 'x', 2,
  671. '2', '2', 'x', 2,
  672. '2', '3', 'x', 2,
  673. '2', '4', 'x', 2,
  674. '2', '5', 'x', 2,
  675. '2', '6', 'x', 2,
  676. '2', '7', 'x', 2,
  677. '2', '8', 'x', 2,
  678. '2', '9', 'x', 2,
  679. '3', '0', 'x', 2,
  680. '3', '1', 'x', 2,
  681. '3', '2', 'x', 2,
  682. '3', '3', 'x', 2,
  683. '3', '4', 'x', 2,
  684. '3', '5', 'x', 2,
  685. '3', '6', 'x', 2,
  686. '3', '7', 'x', 2,
  687. '3', '8', 'x', 2,
  688. '3', '9', 'x', 2,
  689. '4', '0', 'x', 2,
  690. '4', '1', 'x', 2,
  691. '4', '2', 'x', 2,
  692. '4', '3', 'x', 2,
  693. '4', '4', 'x', 2,
  694. '4', '5', 'x', 2,
  695. '4', '6', 'x', 2,
  696. '4', '7', 'x', 2,
  697. '4', '8', 'x', 2,
  698. '4', '9', 'x', 2,
  699. '5', '0', 'x', 2,
  700. '5', '1', 'x', 2,
  701. '5', '2', 'x', 2,
  702. '5', '3', 'x', 2,
  703. '5', '4', 'x', 2,
  704. '5', '5', 'x', 2,
  705. '5', '6', 'x', 2,
  706. '5', '7', 'x', 2,
  707. '5', '8', 'x', 2,
  708. '5', '9', 'x', 2,
  709. '6', '0', 'x', 2,
  710. '6', '1', 'x', 2,
  711. '6', '2', 'x', 2,
  712. '6', '3', 'x', 2,
  713. '6', '4', 'x', 2,
  714. '6', '5', 'x', 2,
  715. '6', '6', 'x', 2,
  716. '6', '7', 'x', 2,
  717. '6', '8', 'x', 2,
  718. '6', '9', 'x', 2,
  719. '7', '0', 'x', 2,
  720. '7', '1', 'x', 2,
  721. '7', '2', 'x', 2,
  722. '7', '3', 'x', 2,
  723. '7', '4', 'x', 2,
  724. '7', '5', 'x', 2,
  725. '7', '6', 'x', 2,
  726. '7', '7', 'x', 2,
  727. '7', '8', 'x', 2,
  728. '7', '9', 'x', 2,
  729. '8', '0', 'x', 2,
  730. '8', '1', 'x', 2,
  731. '8', '2', 'x', 2,
  732. '8', '3', 'x', 2,
  733. '8', '4', 'x', 2,
  734. '8', '5', 'x', 2,
  735. '8', '6', 'x', 2,
  736. '8', '7', 'x', 2,
  737. '8', '8', 'x', 2,
  738. '8', '9', 'x', 2,
  739. '9', '0', 'x', 2,
  740. '9', '1', 'x', 2,
  741. '9', '2', 'x', 2,
  742. '9', '3', 'x', 2,
  743. '9', '4', 'x', 2,
  744. '9', '5', 'x', 2,
  745. '9', '6', 'x', 2,
  746. '9', '7', 'x', 2,
  747. '9', '8', 'x', 2,
  748. '9', '9', 'x', 2,
  749. '1', '0', '0', 3,
  750. '1', '0', '1', 3,
  751. '1', '0', '2', 3,
  752. '1', '0', '3', 3,
  753. '1', '0', '4', 3,
  754. '1', '0', '5', 3,
  755. '1', '0', '6', 3,
  756. '1', '0', '7', 3,
  757. '1', '0', '8', 3,
  758. '1', '0', '9', 3,
  759. '1', '1', '0', 3,
  760. '1', '1', '1', 3,
  761. '1', '1', '2', 3,
  762. '1', '1', '3', 3,
  763. '1', '1', '4', 3,
  764. '1', '1', '5', 3,
  765. '1', '1', '6', 3,
  766. '1', '1', '7', 3,
  767. '1', '1', '8', 3,
  768. '1', '1', '9', 3,
  769. '1', '2', '0', 3,
  770. '1', '2', '1', 3,
  771. '1', '2', '2', 3,
  772. '1', '2', '3', 3,
  773. '1', '2', '4', 3,
  774. '1', '2', '5', 3,
  775. '1', '2', '6', 3,
  776. '1', '2', '7', 3,
  777. '1', '2', '8', 3,
  778. '1', '2', '9', 3,
  779. '1', '3', '0', 3,
  780. '1', '3', '1', 3,
  781. '1', '3', '2', 3,
  782. '1', '3', '3', 3,
  783. '1', '3', '4', 3,
  784. '1', '3', '5', 3,
  785. '1', '3', '6', 3,
  786. '1', '3', '7', 3,
  787. '1', '3', '8', 3,
  788. '1', '3', '9', 3,
  789. '1', '4', '0', 3,
  790. '1', '4', '1', 3,
  791. '1', '4', '2', 3,
  792. '1', '4', '3', 3,
  793. '1', '4', '4', 3,
  794. '1', '4', '5', 3,
  795. '1', '4', '6', 3,
  796. '1', '4', '7', 3,
  797. '1', '4', '8', 3,
  798. '1', '4', '9', 3,
  799. '1', '5', '0', 3,
  800. '1', '5', '1', 3,
  801. '1', '5', '2', 3,
  802. '1', '5', '3', 3,
  803. '1', '5', '4', 3,
  804. '1', '5', '5', 3,
  805. '1', '5', '6', 3,
  806. '1', '5', '7', 3,
  807. '1', '5', '8', 3,
  808. '1', '5', '9', 3,
  809. '1', '6', '0', 3,
  810. '1', '6', '1', 3,
  811. '1', '6', '2', 3,
  812. '1', '6', '3', 3,
  813. '1', '6', '4', 3,
  814. '1', '6', '5', 3,
  815. '1', '6', '6', 3,
  816. '1', '6', '7', 3,
  817. '1', '6', '8', 3,
  818. '1', '6', '9', 3,
  819. '1', '7', '0', 3,
  820. '1', '7', '1', 3,
  821. '1', '7', '2', 3,
  822. '1', '7', '3', 3,
  823. '1', '7', '4', 3,
  824. '1', '7', '5', 3,
  825. '1', '7', '6', 3,
  826. '1', '7', '7', 3,
  827. '1', '7', '8', 3,
  828. '1', '7', '9', 3,
  829. '1', '8', '0', 3,
  830. '1', '8', '1', 3,
  831. '1', '8', '2', 3,
  832. '1', '8', '3', 3,
  833. '1', '8', '4', 3,
  834. '1', '8', '5', 3,
  835. '1', '8', '6', 3,
  836. '1', '8', '7', 3,
  837. '1', '8', '8', 3,
  838. '1', '8', '9', 3,
  839. '1', '9', '0', 3,
  840. '1', '9', '1', 3,
  841. '1', '9', '2', 3,
  842. '1', '9', '3', 3,
  843. '1', '9', '4', 3,
  844. '1', '9', '5', 3,
  845. '1', '9', '6', 3,
  846. '1', '9', '7', 3,
  847. '1', '9', '8', 3,
  848. '1', '9', '9', 3,
  849. '2', '0', '0', 3,
  850. '2', '0', '1', 3,
  851. '2', '0', '2', 3,
  852. '2', '0', '3', 3,
  853. '2', '0', '4', 3,
  854. '2', '0', '5', 3,
  855. '2', '0', '6', 3,
  856. '2', '0', '7', 3,
  857. '2', '0', '8', 3,
  858. '2', '0', '9', 3,
  859. '2', '1', '0', 3,
  860. '2', '1', '1', 3,
  861. '2', '1', '2', 3,
  862. '2', '1', '3', 3,
  863. '2', '1', '4', 3,
  864. '2', '1', '5', 3,
  865. '2', '1', '6', 3,
  866. '2', '1', '7', 3,
  867. '2', '1', '8', 3,
  868. '2', '1', '9', 3,
  869. '2', '2', '0', 3,
  870. '2', '2', '1', 3,
  871. '2', '2', '2', 3,
  872. '2', '2', '3', 3,
  873. '2', '2', '4', 3,
  874. '2', '2', '5', 3,
  875. '2', '2', '6', 3,
  876. '2', '2', '7', 3,
  877. '2', '2', '8', 3,
  878. '2', '2', '9', 3,
  879. '2', '3', '0', 3,
  880. '2', '3', '1', 3,
  881. '2', '3', '2', 3,
  882. '2', '3', '3', 3,
  883. '2', '3', '4', 3,
  884. '2', '3', '5', 3,
  885. '2', '3', '6', 3,
  886. '2', '3', '7', 3,
  887. '2', '3', '8', 3,
  888. '2', '3', '9', 3,
  889. '2', '4', '0', 3,
  890. '2', '4', '1', 3,
  891. '2', '4', '2', 3,
  892. '2', '4', '3', 3,
  893. '2', '4', '4', 3,
  894. '2', '4', '5', 3,
  895. '2', '4', '6', 3,
  896. '2', '4', '7', 3,
  897. '2', '4', '8', 3,
  898. '2', '4', '9', 3,
  899. '2', '5', '0', 3,
  900. '2', '5', '1', 3,
  901. '2', '5', '2', 3,
  902. '2', '5', '3', 3,
  903. '2', '5', '4', 3,
  904. '2', '5', '5', 3
  905. };
  906. DWORD
  907. InetNtoa(
  908. IN struct in_addr inaddr,
  909. OUT CHAR * pchBuffer
  910. )
  911. /*++
  912. Routine Description:
  913. This function takes an Internet address structure specified by the
  914. in parameter. It returns an ASCII string representing the address
  915. in ".'' notation as "a.b.c.d".
  916. Arguments:
  917. inaddr - A structure which represents an Internet host address.
  918. pchBuffer - pointer to at least 16 character buffer for storing
  919. the result of conversion.
  920. Return Value:
  921. If no error occurs, InetNtoa() returns NO_ERROR with the buffer containing
  922. the text address in standard "." notation.
  923. Otherwise, it returns Win32 error code.
  924. --*/
  925. {
  926. PUCHAR p;
  927. PUCHAR buffer = (PUCHAR ) pchBuffer;
  928. PUCHAR b = buffer;
  929. if ( pchBuffer == NULL) {
  930. return ( ERROR_INSUFFICIENT_BUFFER);
  931. }
  932. //
  933. // We do not check for sufficient length of the buffer yet. !!
  934. //
  935. //
  936. // In an unrolled loop, calculate the string value for each of the four
  937. // bytes in an IP address. Note that for values less than 100 we will
  938. // do one or two extra assignments, but we save a test/jump with this
  939. // algorithm.
  940. //
  941. p = (PUCHAR) &inaddr;
  942. *b = NToACharStrings[*p][0];
  943. *(b+1) = NToACharStrings[*p][1];
  944. *(b+2) = NToACharStrings[*p][2];
  945. b += NToACharStrings[*p][3];
  946. *b++ = '.';
  947. p++;
  948. *b = NToACharStrings[*p][0];
  949. *(b+1) = NToACharStrings[*p][1];
  950. *(b+2) = NToACharStrings[*p][2];
  951. b += NToACharStrings[*p][3];
  952. *b++ = '.';
  953. p++;
  954. *b = NToACharStrings[*p][0];
  955. *(b+1) = NToACharStrings[*p][1];
  956. *(b+2) = NToACharStrings[*p][2];
  957. b += NToACharStrings[*p][3];
  958. *b++ = '.';
  959. p++;
  960. *b = NToACharStrings[*p][0];
  961. *(b+1) = NToACharStrings[*p][1];
  962. *(b+2) = NToACharStrings[*p][2];
  963. b += NToACharStrings[*p][3];
  964. *b = '\0';
  965. return ( NO_ERROR);
  966. } // InetNtoa()
  967. BOOL
  968. TcpSockSend(
  969. IN SOCKET sock,
  970. IN LPVOID pBuffer,
  971. IN DWORD cbBuffer,
  972. OUT PDWORD pcbTotalSent,
  973. IN DWORD nTimeout
  974. )
  975. /*++
  976. Description:
  977. Do async socket send
  978. Arguments:
  979. sock - socket
  980. pBuffer - buffer to send
  981. cbBuffer - size of buffer
  982. pcbTotalSent - bytes sent
  983. nTimeout - timeout in seconds to use
  984. Returns:
  985. FALSE if there is any error.
  986. TRUE otherwise
  987. --*/
  988. {
  989. INT serr = 0;
  990. INT cbSent;
  991. DWORD dwBytesSent = 0;
  992. DBG_ASSERT( pBuffer != NULL );
  993. //
  994. // Loop until there's no more data to send.
  995. //
  996. while( cbBuffer > 0 ) {
  997. //
  998. // Wait for the socket to become writeable.
  999. //
  1000. serr = 0;
  1001. if( serr == 0 ) {
  1002. //
  1003. // Write a block to the socket.
  1004. //
  1005. cbSent = send( sock, (CHAR *)pBuffer, (INT)cbBuffer, 0 );
  1006. if( cbSent < 0 ) {
  1007. //
  1008. // Socket error.
  1009. //
  1010. serr = WSAGetLastError();
  1011. DBGPRINTF((DBG_CONTEXT, "TcpSockSend error %d\n",serr));
  1012. } else {
  1013. dwBytesSent += (DWORD)cbSent;
  1014. IF_DEBUG( ERROR ) {
  1015. DBGPRINTF(( DBG_CONTEXT,
  1016. "HTTP: Synchronous send %d bytes @%p to socket %d\n",
  1017. cbSent, pBuffer, sock ));
  1018. }
  1019. }
  1020. }
  1021. if( serr != 0 ) {
  1022. break;
  1023. }
  1024. pBuffer = (LPVOID)( (LPBYTE)pBuffer + cbSent );
  1025. cbBuffer -= (DWORD)cbSent;
  1026. }
  1027. if (pcbTotalSent) {
  1028. *pcbTotalSent = dwBytesSent;
  1029. }
  1030. //
  1031. // Set up i/o handle to non-blocking mode , default for ATQ
  1032. //
  1033. if ( serr == 0 ) {
  1034. return(TRUE);
  1035. } else {
  1036. IF_DEBUG( ERROR ) {
  1037. DBGPRINTF(( DBG_CONTEXT,
  1038. "HTTP: Synchronous send socket error %d on socket %d.\n",
  1039. serr, sock));
  1040. }
  1041. SetLastError(serr);
  1042. return(FALSE);
  1043. }
  1044. } // SockSend
  1045. BOOL
  1046. TcpSockRecv(
  1047. IN SOCKET sock,
  1048. IN LPVOID pBuffer,
  1049. IN DWORD cbBuffer,
  1050. OUT LPDWORD pbReceived,
  1051. IN DWORD nTimeout
  1052. )
  1053. /*++
  1054. Description:
  1055. Do async socket recv
  1056. Arguments:
  1057. sock - The target socket.
  1058. pBuffer - Will receive the data.
  1059. cbBuffer - The size (in bytes) of the buffer.
  1060. pbReceived - Will receive the actual number of bytes
  1061. nTimeout - timeout in seconds
  1062. Returns:
  1063. TRUE, if successful
  1064. --*/
  1065. {
  1066. INT serr = 0;
  1067. DWORD cbTotal = 0;
  1068. INT cbReceived;
  1069. DWORD dwBytesRecv = 0;
  1070. BOOL fRead = FALSE;
  1071. DBG_ASSERT( pBuffer != NULL );
  1072. DBG_ASSERT( pbReceived != NULL );
  1073. //
  1074. // Wait for the socket to become readable.
  1075. //
  1076. serr = WaitForSocketWorker(
  1077. sock,
  1078. INVALID_SOCKET,
  1079. &fRead,
  1080. NULL,
  1081. nTimeout
  1082. );
  1083. if( serr == 0 )
  1084. {
  1085. //
  1086. // Read a block from the socket.
  1087. //
  1088. DBG_ASSERT( fRead);
  1089. cbReceived = recv( sock, (CHAR *)pBuffer, (INT)cbBuffer, 0 );
  1090. if( cbReceived < 0 )
  1091. {
  1092. //
  1093. // Socket error.
  1094. //
  1095. serr = WSAGetLastError();
  1096. }
  1097. else {
  1098. cbTotal = cbReceived;
  1099. }
  1100. }
  1101. if( serr == 0 )
  1102. {
  1103. //
  1104. // Return total byte count to caller.
  1105. //
  1106. *pbReceived = cbTotal;
  1107. }
  1108. else
  1109. {
  1110. IF_DEBUG( ERROR )
  1111. {
  1112. DBGPRINTF(( DBG_CONTEXT,
  1113. "HTTP: Syncronous rcv socket error %d during recv on socket %d\n",
  1114. serr,
  1115. sock ));
  1116. }
  1117. }
  1118. //
  1119. // Set up i/o handle to blocking mode , as blocking I/O is requested
  1120. //
  1121. if ( serr == 0 ) {
  1122. return(TRUE);
  1123. } else {
  1124. SetLastError(serr);
  1125. return(FALSE);
  1126. }
  1127. } // SockRecv
  1128. INT
  1129. WaitForSocketWorker(
  1130. IN SOCKET sockRead,
  1131. IN SOCKET sockWrite,
  1132. IN LPBOOL pfRead,
  1133. IN LPBOOL pfWrite,
  1134. IN DWORD nTimeout
  1135. )
  1136. /*++
  1137. Description:
  1138. Wait routine
  1139. NOTES: Any (but not all) sockets may be INVALID_SOCKET. For
  1140. each socket that is INVALID_SOCKET, the corresponding
  1141. pf* parameter may be NULL.
  1142. Arguments:
  1143. sockRead - The socket to check for readability.
  1144. sockWrite - The socket to check for writeability.
  1145. pfRead - Will receive TRUE if sockRead is readable.
  1146. pfWrite - Will receive TRUE if sockWrite is writeable.
  1147. nTimeout - timeout in seconds
  1148. Returns:
  1149. SOCKERR - 0 if successful, !0 if not. Will return
  1150. WSAETIMEDOUT if the timeout period expired.
  1151. --*/
  1152. {
  1153. INT serr = 0;
  1154. TIMEVAL timeout;
  1155. LPTIMEVAL ptimeout;
  1156. fd_set fdsRead;
  1157. fd_set fdsWrite;
  1158. INT res;
  1159. //
  1160. // Ensure we got valid parameters.
  1161. //
  1162. if( ( sockRead == INVALID_SOCKET ) &&
  1163. ( sockWrite == INVALID_SOCKET ) ) {
  1164. return WSAENOTSOCK;
  1165. }
  1166. timeout.tv_sec = (LONG )nTimeout;
  1167. if( timeout.tv_sec == 0 ) {
  1168. //
  1169. // If the connection timeout == 0, then we have no timeout.
  1170. // So, we block and wait for the specified conditions.
  1171. //
  1172. ptimeout = NULL;
  1173. } else {
  1174. //
  1175. // The connectio timeout is > 0, so setup the timeout structure.
  1176. //
  1177. timeout.tv_usec = 0;
  1178. ptimeout = &timeout;
  1179. }
  1180. for( ; ; ) {
  1181. //
  1182. // Setup our socket sets.
  1183. //
  1184. FD_ZERO( &fdsRead );
  1185. FD_ZERO( &fdsWrite );
  1186. if( sockRead != INVALID_SOCKET ) {
  1187. FD_SET( sockRead, &fdsRead );
  1188. DBG_ASSERT( pfRead != NULL );
  1189. *pfRead = FALSE;
  1190. }
  1191. if( sockWrite != INVALID_SOCKET ) {
  1192. FD_SET( sockWrite, &fdsWrite );
  1193. DBG_ASSERT( pfWrite != NULL );
  1194. *pfWrite = FALSE;
  1195. }
  1196. //
  1197. // Wait for one of the conditions to be met.
  1198. //
  1199. res = select( 0, &fdsRead, &fdsWrite, NULL, ptimeout );
  1200. if( res == 0 ) {
  1201. //
  1202. // Timeout.
  1203. //
  1204. serr = WSAETIMEDOUT;
  1205. break;
  1206. } else if( res == SOCKET_ERROR ) {
  1207. //
  1208. // Bad news.
  1209. //
  1210. serr = WSAGetLastError();
  1211. break;
  1212. } else {
  1213. BOOL fSomethingWasSet = FALSE;
  1214. if( pfRead != NULL ) {
  1215. *pfRead = FD_ISSET( sockRead, &fdsRead );
  1216. fSomethingWasSet = TRUE;
  1217. }
  1218. if( pfWrite != NULL ) {
  1219. *pfWrite = FD_ISSET( sockWrite, &fdsWrite );
  1220. fSomethingWasSet = TRUE;
  1221. }
  1222. if( fSomethingWasSet ) {
  1223. //
  1224. // Success.
  1225. //
  1226. serr = 0;
  1227. break;
  1228. } else {
  1229. //
  1230. // select() returned with neither a timeout, nor
  1231. // an error, nor any bits set. This feels bad...
  1232. //
  1233. DBG_ASSERT( FALSE );
  1234. continue;
  1235. }
  1236. }
  1237. }
  1238. return serr;
  1239. } // WaitForSocketWorker()
  1240. BOOL
  1241. TcpSockTest(
  1242. IN SOCKET sock
  1243. )
  1244. /*++
  1245. Description:
  1246. Test the socket if still connected.
  1247. Use select, and if readable, use recv
  1248. Arguments:
  1249. sock - socket
  1250. Returns:
  1251. TRUE if the socket most likely is still connected
  1252. FALSE if the socket is disconnected or an error occured
  1253. --*/
  1254. {
  1255. TIMEVAL timeout;
  1256. fd_set fdsRead;
  1257. INT res;
  1258. CHAR bOneByte;
  1259. // select for read with zero timeout
  1260. FD_ZERO( &fdsRead );
  1261. FD_SET( sock, &fdsRead );
  1262. timeout.tv_sec = 0;
  1263. timeout.tv_usec = 0;
  1264. res = select( 0, &fdsRead, NULL, NULL, &timeout );
  1265. if ( res == 0 ) {
  1266. // No data to be read --
  1267. // have to assume socket is still connected
  1268. return TRUE;
  1269. } else if ( res == SOCKET_ERROR ) {
  1270. // Something went wrong during select -- assume disconnected
  1271. return FALSE;
  1272. }
  1273. DBG_ASSERT( res == 1 );
  1274. // recv 1 byte (PEEK)
  1275. // select returning 1 above guarantees recv will not block
  1276. res = recv( sock, &bOneByte, 1, MSG_PEEK );
  1277. if ( res == 0 || res == SOCKET_ERROR ) {
  1278. // Socket closed or an error -- socket is disconnected
  1279. return FALSE;
  1280. }
  1281. DBG_ASSERT( res == 1 );
  1282. // Read one byte successfully -- assume still connected
  1283. return TRUE;
  1284. } // SockTest
  1285. BOOL
  1286. DoSynchronousReadFile(
  1287. IN HANDLE hFile,
  1288. IN PCHAR Buffer,
  1289. IN DWORD nBuffer,
  1290. OUT PDWORD nRead,
  1291. IN LPOVERLAPPED Overlapped
  1292. )
  1293. /*++
  1294. Description:
  1295. Does Asynchronous file reads. Assumes that NT handles are
  1296. opened for OVERLAPPED I/O.
  1297. Arguments:
  1298. hFile - Handle to use for the read
  1299. Buffer - Buffer to read with
  1300. nBuffer - size of buffer
  1301. nRead - returns the number of bytes read
  1302. Overlapped - user supplied overlapped structure
  1303. Returns:
  1304. TRUE/FALSE
  1305. --*/
  1306. {
  1307. BOOL fNewEvent = FALSE;
  1308. OVERLAPPED ov;
  1309. BOOL fRet = FALSE;
  1310. if ( Overlapped == NULL ) {
  1311. Overlapped = &ov;
  1312. ov.Offset = 0;
  1313. ov.OffsetHigh = 0;
  1314. ov.hEvent = IIS_CREATE_EVENT(
  1315. "OVERLAPPED::hEvent",
  1316. &ov,
  1317. TRUE,
  1318. FALSE
  1319. );
  1320. if ( ov.hEvent == NULL ) {
  1321. DBGPRINTF((DBG_CONTEXT,"CreateEvent failed with %d\n",
  1322. GetLastError()));
  1323. goto ErrorExit;
  1324. }
  1325. fNewEvent = TRUE;
  1326. }
  1327. DWORD err = NO_ERROR;
  1328. if ( !ReadFile( hFile,
  1329. Buffer,
  1330. nBuffer,
  1331. nRead,
  1332. Overlapped )) {
  1333. err = GetLastError();
  1334. if ( (err != ERROR_IO_PENDING) &&
  1335. (err != ERROR_HANDLE_EOF) ) {
  1336. DBGPRINTF((DBG_CONTEXT,"Error %d in ReadFile\n",
  1337. err));
  1338. goto ErrorExit;
  1339. }
  1340. }
  1341. if ( err == ERROR_IO_PENDING ) {
  1342. if ( !GetOverlappedResult( hFile,
  1343. Overlapped,
  1344. nRead,
  1345. TRUE )) {
  1346. err = GetLastError();
  1347. DBGPRINTF((DBG_CONTEXT,"Error %d in GetOverlappedResult\n",
  1348. err));
  1349. if ( err != ERROR_HANDLE_EOF ) {
  1350. goto ErrorExit;
  1351. }
  1352. }
  1353. }
  1354. fRet = TRUE;
  1355. ErrorExit:
  1356. if ( fNewEvent ) {
  1357. DBG_REQUIRE(CloseHandle( ov.hEvent ));
  1358. }
  1359. return(fRet);
  1360. } // DoSynchronousReadFile