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.

758 lines
17 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
  431. {
  432. // IO failed
  433. status = RtlNtStatusToDosError(ULONG(lpOverlapped->Internal));
  434. ASSERT(status != ERROR_MR_MID_NOT_FOUND);
  435. return status;
  436. }
  437. }
  438. char * _cdecl
  439. RpcStrTok(
  440. IN char * string,
  441. IN const char * control,
  442. IN OUT char ** ppStrPrev
  443. )
  444. /*++
  445. Routine Description:
  446. Tokenize string with delimiter in control. Similar to C runtime function
  447. strtok() but no state information is maintained. The caller is expected
  448. to give the string from where to tokenize next.
  449. strtok considers the string to consist of a sequence of zero or more
  450. text tokens separated by spans of one or more control chars. The first
  451. call, with string specified, returns a pointer to the first char of the
  452. first token, and will write a null char into string immediately
  453. following the returned token. Subsequent calls with zero for the first
  454. argument (string) will work thru the string until no tokens remain. The
  455. control string may be different from call to call. when no tokens remain
  456. in string a NULL pointer is returned. Remember the control chars with a
  457. bit map, one bit per ascii char. The null char is always a control char.
  458. Arguments:
  459. string - string to tokenize, or NULL to get next token
  460. control - string of characters to use as delimiters
  461. strPrev - string returned from the preceeding call to RpcStrTok().
  462. Note:
  463. a. Works only for ANSI character strings.
  464. b. Cloned from SLM project vctools [crt\crtw32\string\strtok.c].
  465. Return Value:
  466. pointer to first token in string, or if string was NULL, to next token
  467. NULL, when no more tokens remain.
  468. --*/
  469. {
  470. char *str;
  471. const char *ctrl = control;
  472. unsigned char map[32];
  473. int count;
  474. ASSERT(ppStrPrev != NULL);
  475. char * nextoken = *ppStrPrev;
  476. /* Clear control map */
  477. for (count = 0; count < 32; count++)
  478. map[count] = 0;
  479. /* Set bits in delimiter table */
  480. do {
  481. map[*ctrl >> 3] |= (1 << (*ctrl & 7));
  482. } while (*ctrl++);
  483. /* Initialize str. If string is NULL, set str to the saved
  484. * pointer (i.e., continue breaking tokens out of the string
  485. * from the last strtok call) */
  486. if (string)
  487. str = string;
  488. else
  489. str = nextoken;
  490. /* Find beginning of token (skip over leading delimiters). Note that
  491. * there is no token iff this loop sets str to point to the terminal
  492. * null (*str == '\0') */
  493. while ( (map[*str >> 3] & (1 << (*str & 7))) && *str )
  494. str++;
  495. string = str;
  496. /* Find the end of the token. If it is not the end of the string,
  497. * put a null there. */
  498. for ( ; *str ; str++ )
  499. if ( map[*str >> 3] & (1 << (*str & 7)) ) {
  500. *str++ = '\0';
  501. break;
  502. }
  503. /* Update nextoken (or the corresponding field in the per-thread data
  504. * structure). This should update *ppStrPrev. */
  505. nextoken = str;
  506. /* Determine if a token has been found. */
  507. if ( string == str )
  508. return NULL;
  509. else
  510. return string;
  511. }
  512. #if defined(DBG) && defined(TRANSPORT_DLL)
  513. BOOL ValidateError(
  514. IN unsigned int Status,
  515. IN unsigned int Count,
  516. IN const int ErrorList[])
  517. /*++
  518. Routine Description
  519. Tests that 'Status' is one of an expected set of error codes.
  520. Used on debug builds as part of the VALIDATE() macro.
  521. Example:
  522. VALIDATE(EventStatus)
  523. {
  524. RPC_P_CONNECTION_CLOSED,
  525. RPC_P_RECEIVE_FAILED,
  526. RPC_P_CONNECTION_SHUTDOWN
  527. // more error codes here
  528. } END_VALIDATE;
  529. This function is called with the RpcStatus and expected errors codes
  530. as parameters. If RpcStatus is not one of the expected error
  531. codes and it not zero a message will be printed to the debugger
  532. and the function will return false. The VALIDATE macro ASSERT's the
  533. return value.
  534. Arguments:
  535. Status - Status code in question.
  536. Count - number of variable length arguments
  537. ... - One or more expected status codes. Terminated with 0 (RPC_S_OK).
  538. Return Value:
  539. TRUE - Status code is in the list or the status is 0.
  540. FALSE - Status code is not in the list.
  541. --*/
  542. {
  543. unsigned i;
  544. for (i = 0; i < Count; i++)
  545. {
  546. if (ErrorList[i] == (int) Status)
  547. {
  548. return TRUE;
  549. }
  550. }
  551. PrintToDebugger("RPC Assertion: unexpected failure %lu (0lx%08x)\n",
  552. (unsigned long)Status, (unsigned long)Status);
  553. return(FALSE);
  554. }
  555. #endif