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.

762 lines
18 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1997 - 1999
  3. Module Name:
  4. Util.cxx
  5. Abstract:
  6. Transport/protocol independent helper functions.
  7. Author:
  8. Mario Goertzel [MarioGo]
  9. Revision History:
  10. MarioGo 2/21/1997 Bits 'n pieces
  11. --*/
  12. #include <precomp.hxx>
  13. RPC_STATUS
  14. EndpointToPortNumber(
  15. IN RPC_CHAR *endpoint,
  16. OUT USHORT &port)
  17. /*++
  18. Routine Description:
  19. Validates a unicode string which should contain a winsock (USHORT) port
  20. number and converts the string to an integer.
  21. Arguments:
  22. endpoint - The port number as a unicode string
  23. port - If successful, the port number.
  24. Return Value:
  25. RPC_S_OK
  26. RPC_S_INVALID_ENDPOINT_FORMAT
  27. --*/
  28. {
  29. RPC_CHAR *pT;
  30. #ifdef UNICODE
  31. ULONG lport = wcstol(endpoint, &pT, 10);
  32. #else
  33. ULONG lport = ANSI_strtol((const RPC_SCHAR *) endpoint, (RPC_SCHAR **) &pT, 10);
  34. #endif
  35. if (lport == 0 || lport > 0xFFFF || *pT != 0)
  36. {
  37. return(RPC_S_INVALID_ENDPOINT_FORMAT);
  38. }
  39. port = (USHORT)lport;
  40. return(RPC_S_OK);
  41. }
  42. RPC_STATUS
  43. EndpointToPortNumberA(
  44. IN char *endpoint,
  45. OUT USHORT &port)
  46. /*++
  47. Routine Description:
  48. Validates an ANSI string which should contain a winsock (USHORT) port
  49. number and converts the string to an integer.
  50. Arguments:
  51. endpoint - The port number as an ANSI string
  52. port - If successful, the port number.
  53. Return Value:
  54. RPC_S_OK
  55. RPC_S_INVALID_ENDPOINT_FORMAT
  56. --*/
  57. {
  58. char *pT;
  59. ULONG lport = ANSI_strtol(endpoint, &pT, 10);
  60. if (lport == 0 || lport > 0xFFFF || *pT != 0)
  61. {
  62. return(RPC_S_INVALID_ENDPOINT_FORMAT);
  63. }
  64. port = (USHORT)lport;
  65. return(RPC_S_OK);
  66. }
  67. void
  68. PortNumberToEndpoint(
  69. IN USHORT port,
  70. OUT RPC_CHAR *pEndpoint
  71. )
  72. {
  73. UNICODE_STRING UnicodeString;
  74. ASSERT(port);
  75. UnicodeString.Buffer = pEndpoint;
  76. UnicodeString.Length = 0;
  77. UnicodeString.MaximumLength = 6 * sizeof(RPC_CHAR);
  78. NTSTATUS status = RtlIntegerToUnicodeString(port, 0, &UnicodeString);
  79. ASSERT(NT_SUCCESS(status));
  80. }
  81. void
  82. PortNumberToEndpointA(
  83. IN USHORT port,
  84. OUT char *pEndpoint
  85. )
  86. {
  87. NTSTATUS status = RtlIntegerToChar(port,
  88. 10, // Base
  89. 6 * sizeof(char), // OutputLength
  90. pEndpoint);
  91. ASSERT(NT_SUCCESS(status));
  92. }
  93. inline
  94. UCHAR ConvertHexDigit(UCHAR digit)
  95. /*++
  96. Routine Description:
  97. Converts a character containing '0'-'9', 'a'-'f' or 'A'-'F' into the
  98. equivalent binary value: 0x0 - 0xF.
  99. Arguments:
  100. digit - The character to convert.
  101. Return Value:
  102. The value of digit or zero if the digit is not a hex digit.
  103. --*/
  104. {
  105. UCHAR r;
  106. r = digit - '0';
  107. if (r < 10)
  108. {
  109. return(r);
  110. }
  111. r = digit - 'a';
  112. if (r < 6)
  113. {
  114. return(r + 10);
  115. }
  116. r = digit - 'A';
  117. if (r < 6)
  118. {
  119. return(r + 10);
  120. }
  121. ASSERT(0);
  122. return 0;
  123. }
  124. UCHAR
  125. HexDigitsToBinary(
  126. IN UCHAR high,
  127. IN UCHAR low
  128. )
  129. /*++
  130. Routine Description:
  131. Builds an 8-bit value from two hex digits.
  132. --*/
  133. {
  134. return( ( ConvertHexDigit(high) << 4 ) | ConvertHexDigit(low) );
  135. }
  136. DWORD
  137. UTIL_WaitForSyncIO(
  138. LPOVERLAPPED lpOverlapped,
  139. IN BOOL fAlertable,
  140. IN DWORD dwTimeout
  141. )
  142. /*++
  143. Routine Description:
  144. The special part is that the same event (this's threads event)
  145. maybe used for multiple IOs at once. If another one of those
  146. IOs completes, it is ignored. This only returns when the IO
  147. specified by lpOverlapped finishes or an alert/timeout happens.
  148. Arguments:
  149. lpOverlapped - The status block associated with the IO in question.
  150. fAlertable - If TRUE, the wait is alertable
  151. dwTimeout - Milliseconds to wait for the IO.
  152. Return Value:
  153. Same as WaitForSingleObjectEx()
  154. --*/
  155. {
  156. DWORD status;
  157. for (;;)
  158. {
  159. if (HasOverlappedIoCompleted(lpOverlapped))
  160. {
  161. break;
  162. }
  163. status = WaitForSingleObjectEx(lpOverlapped->hEvent, dwTimeout, fAlertable);
  164. if (status != WAIT_OBJECT_0)
  165. {
  166. ASSERT( (status == WAIT_IO_COMPLETION && fAlertable)
  167. || (status == WAIT_TIMEOUT && (dwTimeout != INFINITE)));
  168. return(status);
  169. }
  170. if (HasOverlappedIoCompleted(lpOverlapped))
  171. {
  172. break;
  173. }
  174. // Another Io completed, just ignore it for now.
  175. ResetEvent(lpOverlapped->hEvent);
  176. }
  177. return(WAIT_OBJECT_0);
  178. }
  179. DWORD
  180. UTIL_WaitForSyncHTTP2IO(
  181. IN LPOVERLAPPED lpOverlapped,
  182. IN HANDLE hEvent,
  183. IN BOOL fAlertable,
  184. IN DWORD dwTimeout
  185. )
  186. /*++
  187. Routine Description:
  188. The special part is that the same event (this's threads event)
  189. maybe used for multiple IOs at once. If another one of those
  190. IOs completes, it is ignored. This only returns when the IO
  191. specified by lpOverlapped finishes or an alert/timeout happens.
  192. Arguments:
  193. lpOverlapped - The status block associated with the IO in question.
  194. hEvent - the event to wait on
  195. fAlertable - If TRUE, the wait is alertable
  196. dwTimeout - Milliseconds to wait for the IO.
  197. Return Value:
  198. Same as WaitForSingleObjectEx()
  199. --*/
  200. {
  201. DWORD status;
  202. ASSERT(hEvent);
  203. for (;;)
  204. {
  205. if (lpOverlapped->OffsetHigh)
  206. {
  207. break;
  208. }
  209. status = WaitForSingleObjectEx(hEvent, dwTimeout, fAlertable);
  210. if (status != WAIT_OBJECT_0)
  211. {
  212. ASSERT( (status == WAIT_IO_COMPLETION && fAlertable)
  213. || (status == WAIT_TIMEOUT && (dwTimeout != INFINITE)));
  214. return(status);
  215. }
  216. if (lpOverlapped->OffsetHigh)
  217. {
  218. break;
  219. }
  220. // Another Io completed, just ignore it for now.
  221. ResetEvent(hEvent);
  222. }
  223. return(WAIT_OBJECT_0);
  224. }
  225. RPC_STATUS
  226. UTIL_GetOverlappedResultEx(
  227. RPC_TRANSPORT_CONNECTION ThisConnection,
  228. LPOVERLAPPED lpOverlapped,
  229. LPDWORD lpNumberOfBytesTransferred,
  230. BOOL fAlertable,
  231. DWORD dwTimeout
  232. )
  233. /*++
  234. Routine Description:
  235. Similar to the Win32 API GetOverlappedResult.
  236. Works with thread event based IO. (even with multiple IOs/thread-event)
  237. Allows cancels
  238. Arguments:
  239. ThisConnection - RPC runtime connection associated with this IO.
  240. lpOverlapped - Overlapped structure of the IO in progress.
  241. Must contain a valid hEvent member.
  242. lpNumberOfBytesTransferred - see GetOverlappedResult
  243. fAlertable - If true, RPC cancels are enabled. This means the
  244. wait must be alertable and must follow a protocol to determine
  245. if a call has been cancelled.
  246. dwTimeout - Milliseconds to wait
  247. Return Value:
  248. RPC_S_Ok
  249. RPC_P_TIMEOUT
  250. RPC_S_CALL_CANCELLED
  251. --*/
  252. {
  253. BASE_ASYNC_OBJECT *Connection = (BASE_ASYNC_OBJECT *) ThisConnection;
  254. ASSERT(lpOverlapped->hEvent);
  255. RPC_STATUS status;
  256. DWORD canceltimeout = 0;
  257. for(;;)
  258. {
  259. // Wait for the IO to complete
  260. status = UTIL_WaitForSyncIO(lpOverlapped, fAlertable, dwTimeout);
  261. if (status == WAIT_OBJECT_0)
  262. {
  263. break;
  264. }
  265. if (status == WAIT_TIMEOUT)
  266. {
  267. ASSERT(dwTimeout != INFINITE);
  268. if (canceltimeout)
  269. {
  270. return(RPC_S_CALL_CANCELLED);
  271. }
  272. return(RPC_P_TIMEOUT);
  273. }
  274. ASSERT(status == WAIT_IO_COMPLETION);
  275. if ((Connection->type & TYPE_MASK) == CLIENT)
  276. {
  277. //
  278. // The RPC call may have been cancelled, need to call
  279. // into the runtime to find out.
  280. //
  281. status = I_RpcTransIoCancelled(ThisConnection, &canceltimeout);
  282. switch (status)
  283. {
  284. case RPC_S_OK:
  285. TransDbgPrint((DPFLTR_RPCPROXY_ID,
  286. DPFLTR_WARNING_LEVEL,
  287. RPCTRANS "RPC cancelled (%p)\n",
  288. lpOverlapped));
  289. if (canceltimeout == 0)
  290. {
  291. return (RPC_S_CALL_CANCELLED);
  292. }
  293. //
  294. // Convert to milliseconds
  295. //
  296. canceltimeout *= 1000;
  297. if (dwTimeout > canceltimeout)
  298. {
  299. dwTimeout = canceltimeout;
  300. }
  301. break;
  302. case RPC_S_NO_CALL_ACTIVE:
  303. //
  304. // ignore and continue
  305. //
  306. break;
  307. default:
  308. return RPC_S_CALL_CANCELLED;
  309. }
  310. }
  311. // Either the call was cancelled and timeout has been updated or
  312. // the call wasn't cancelled and we need to wait again.
  313. }
  314. // IO has completed
  315. ASSERT(HasOverlappedIoCompleted(lpOverlapped));
  316. // IO successful
  317. *lpNumberOfBytesTransferred = ULONG(lpOverlapped->InternalHigh);
  318. if ( NT_SUCCESS(lpOverlapped->Internal) )
  319. {
  320. return(RPC_S_OK);
  321. }
  322. // IO failed
  323. return RtlNtStatusToDosError(ULONG(lpOverlapped->Internal));
  324. }
  325. RPC_STATUS
  326. UTIL_GetOverlappedHTTP2ResultEx(
  327. RPC_TRANSPORT_CONNECTION ThisConnection,
  328. IN LPOVERLAPPED lpOverlapped,
  329. IN HANDLE hEvent,
  330. IN BOOL fAlertable,
  331. IN DWORD dwTimeout
  332. )
  333. /*++
  334. Routine Description:
  335. Similar to the Win32 API GetOverlappedResult.
  336. Works with thread event based IO. (even with multiple IOs/thread-event)
  337. Allows cancels
  338. Arguments:
  339. ThisConnection - RPC runtime connection associated with this IO.
  340. lpOverlapped - Overlapped structure of the IO in progress.
  341. Must contain a valid hEvent member.
  342. hEvent - event to wait on
  343. fAlertable - If true, RPC cancels are enabled. This means the
  344. wait must be alertable and must follow a protocol to determine
  345. if a call has been cancelled.
  346. dwTimeout - Milliseconds to wait
  347. Return Value:
  348. RPC_S_Ok
  349. RPC_P_TIMEOUT
  350. RPC_S_CALL_CANCELLED
  351. --*/
  352. {
  353. BASE_ASYNC_OBJECT *Connection = (BASE_ASYNC_OBJECT *) ThisConnection;
  354. ASSERT(hEvent);
  355. RPC_STATUS status;
  356. DWORD canceltimeout = 0;
  357. for(;;)
  358. {
  359. // Wait for the IO to complete
  360. status = UTIL_WaitForSyncHTTP2IO(lpOverlapped, hEvent, fAlertable, dwTimeout);
  361. if (status == WAIT_OBJECT_0)
  362. {
  363. break;
  364. }
  365. if (status == WAIT_TIMEOUT)
  366. {
  367. ASSERT(dwTimeout != INFINITE);
  368. if (canceltimeout)
  369. {
  370. return(RPC_S_CALL_CANCELLED);
  371. }
  372. return(RPC_P_TIMEOUT);
  373. }
  374. ASSERT(status == WAIT_IO_COMPLETION);
  375. if ((Connection->type & TYPE_MASK) == CLIENT)
  376. {
  377. //
  378. // The RPC call may have been cancelled, need to call
  379. // into the runtime to find out.
  380. //
  381. status = I_RpcTransIoCancelled(ThisConnection, &canceltimeout);
  382. switch (status)
  383. {
  384. case RPC_S_OK:
  385. TransDbgPrint((DPFLTR_RPCPROXY_ID,
  386. DPFLTR_WARNING_LEVEL,
  387. RPCTRANS "RPC cancelled (%p)\n",
  388. lpOverlapped));
  389. if (canceltimeout == 0)
  390. {
  391. return (RPC_S_CALL_CANCELLED);
  392. }
  393. //
  394. // Convert to milliseconds
  395. //
  396. canceltimeout *= 1000;
  397. if (dwTimeout > canceltimeout)
  398. {
  399. dwTimeout = canceltimeout;
  400. }
  401. break;
  402. case RPC_S_NO_CALL_ACTIVE:
  403. //
  404. // ignore and continue
  405. //
  406. break;
  407. default:
  408. return RPC_S_CALL_CANCELLED;
  409. }
  410. }
  411. // Either the call was cancelled and timeout has been updated or
  412. // the call wasn't cancelled and we need to wait again.
  413. }
  414. // IO has completed
  415. ASSERT(lpOverlapped->OffsetHigh);
  416. if (lpOverlapped->Internal == RPC_S_OK)
  417. {
  418. return(RPC_S_OK);
  419. }
  420. if ((lpOverlapped->Internal == RPC_P_CONNECTION_SHUTDOWN)
  421. || (lpOverlapped->Internal == RPC_P_RECEIVE_FAILED)
  422. || (lpOverlapped->Internal == RPC_P_SEND_FAILED)
  423. || (lpOverlapped->Internal == RPC_P_CONNECTION_CLOSED)
  424. || (lpOverlapped->Internal == RPC_S_OUT_OF_MEMORY)
  425. || (lpOverlapped->Internal == RPC_S_SERVER_UNAVAILABLE)
  426. || (lpOverlapped->Internal == RPC_S_PROTOCOL_ERROR) )
  427. {
  428. return lpOverlapped->Internal;
  429. }
  430. else if (lpOverlapped->Internal == RPC_S_OUT_OF_THREADS)
  431. {
  432. return RPC_S_OUT_OF_MEMORY;
  433. }
  434. else
  435. {
  436. // IO failed
  437. status = RtlNtStatusToDosError(ULONG(lpOverlapped->Internal));
  438. ASSERT(status != ERROR_MR_MID_NOT_FOUND);
  439. return status;
  440. }
  441. }
  442. char * _cdecl
  443. RpcStrTok(
  444. IN char * string,
  445. IN const char * control,
  446. IN OUT char ** ppStrPrev
  447. )
  448. /*++
  449. Routine Description:
  450. Tokenize string with delimiter in control. Similar to C runtime function
  451. strtok() but no state information is maintained. The caller is expected
  452. to give the string from where to tokenize next.
  453. strtok considers the string to consist of a sequence of zero or more
  454. text tokens separated by spans of one or more control chars. The first
  455. call, with string specified, returns a pointer to the first char of the
  456. first token, and will write a null char into string immediately
  457. following the returned token. Subsequent calls with zero for the first
  458. argument (string) will work thru the string until no tokens remain. The
  459. control string may be different from call to call. when no tokens remain
  460. in string a NULL pointer is returned. Remember the control chars with a
  461. bit map, one bit per ascii char. The null char is always a control char.
  462. Arguments:
  463. string - string to tokenize, or NULL to get next token
  464. control - string of characters to use as delimiters
  465. strPrev - string returned from the preceeding call to RpcStrTok().
  466. Note:
  467. a. Works only for ANSI character strings.
  468. b. Cloned from SLM project vctools [crt\crtw32\string\strtok.c].
  469. Return Value:
  470. pointer to first token in string, or if string was NULL, to next token
  471. NULL, when no more tokens remain.
  472. --*/
  473. {
  474. char *str;
  475. const char *ctrl = control;
  476. unsigned char map[32];
  477. int count;
  478. ASSERT(ppStrPrev != NULL);
  479. char * nextoken = *ppStrPrev;
  480. /* Clear control map */
  481. for (count = 0; count < 32; count++)
  482. map[count] = 0;
  483. /* Set bits in delimiter table */
  484. do {
  485. map[*ctrl >> 3] |= (1 << (*ctrl & 7));
  486. } while (*ctrl++);
  487. /* Initialize str. If string is NULL, set str to the saved
  488. * pointer (i.e., continue breaking tokens out of the string
  489. * from the last strtok call) */
  490. if (string)
  491. str = string;
  492. else
  493. str = nextoken;
  494. /* Find beginning of token (skip over leading delimiters). Note that
  495. * there is no token iff this loop sets str to point to the terminal
  496. * null (*str == '\0') */
  497. while ( (map[*str >> 3] & (1 << (*str & 7))) && *str )
  498. str++;
  499. string = str;
  500. /* Find the end of the token. If it is not the end of the string,
  501. * put a null there. */
  502. for ( ; *str ; str++ )
  503. if ( map[*str >> 3] & (1 << (*str & 7)) ) {
  504. *str++ = '\0';
  505. break;
  506. }
  507. /* Update nextoken (or the corresponding field in the per-thread data
  508. * structure). This should update *ppStrPrev. */
  509. nextoken = str;
  510. /* Determine if a token has been found. */
  511. if ( string == str )
  512. return NULL;
  513. else
  514. return string;
  515. }
  516. #if defined(DBG) && defined(TRANSPORT_DLL)
  517. BOOL ValidateError(
  518. IN unsigned int Status,
  519. IN unsigned int Count,
  520. IN const int ErrorList[])
  521. /*++
  522. Routine Description
  523. Tests that 'Status' is one of an expected set of error codes.
  524. Used on debug builds as part of the VALIDATE() macro.
  525. Example:
  526. VALIDATE(EventStatus)
  527. {
  528. RPC_P_CONNECTION_CLOSED,
  529. RPC_P_RECEIVE_FAILED,
  530. RPC_P_CONNECTION_SHUTDOWN
  531. // more error codes here
  532. } END_VALIDATE;
  533. This function is called with the RpcStatus and expected errors codes
  534. as parameters. If RpcStatus is not one of the expected error
  535. codes and it not zero a message will be printed to the debugger
  536. and the function will return false. The VALIDATE macro ASSERT's the
  537. return value.
  538. Arguments:
  539. Status - Status code in question.
  540. Count - number of variable length arguments
  541. ... - One or more expected status codes. Terminated with 0 (RPC_S_OK).
  542. Return Value:
  543. TRUE - Status code is in the list or the status is 0.
  544. FALSE - Status code is not in the list.
  545. --*/
  546. {
  547. unsigned i;
  548. for (i = 0; i < Count; i++)
  549. {
  550. if (ErrorList[i] == (int) Status)
  551. {
  552. return TRUE;
  553. }
  554. }
  555. PrintToDebugger("RPC Assertion: unexpected failure %lu (0lx%08x)\n",
  556. (unsigned long)Status, (unsigned long)Status);
  557. return(FALSE);
  558. }
  559. #endif