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.

522 lines
12 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1991 - 1999
  3. Module Name:
  4. msgapi.cxx
  5. Abstract:
  6. The I_RpcSendReceive API used to send and receive messages as part of
  7. a remote procedure call lives here. This API is used by both clients
  8. (to make calls) and by servers (to make callbacks).
  9. Author:
  10. Michael Montague (mikemon) 07-Nov-1991
  11. Revision History:
  12. Mazhar Mohammed (mazharm) 09-11-95 added I_RpcReceive, I_RpcSend
  13. Mazhar Mohammed (mazharm) 03-31-96 added support for async RPC
  14. I_RpcAsyncSend and I_RpcAsyncReceive
  15. Revision History:
  16. --*/
  17. #include <precomp.hxx>
  18. #define _SND_RECV_CALLED 0x100
  19. RPC_STATUS RPC_ENTRY
  20. I_RpcSendReceive (
  21. IN OUT PRPC_MESSAGE Message
  22. )
  23. /*++
  24. Routine Description:
  25. We do all of the protocol module independent work of making a remote
  26. procedure call; at least the part concerned with sending the request
  27. and receiving the response. The majority of the work is done by
  28. each rpc protocol module.
  29. Arguments:
  30. Message - Supplies and returns the information required to make
  31. the remote procedure call.
  32. Return Values:
  33. RPC_S_OK - The operation completed successfully.
  34. --*/
  35. {
  36. RPC_STATUS retval;
  37. THREAD *Thread;
  38. AssertRpcInitialized();
  39. ASSERT(!RpcpCheckHeap());
  40. Thread = ThreadSelf();
  41. if (!Thread)
  42. {
  43. return RPC_S_OUT_OF_MEMORY;
  44. }
  45. RpcpPurgeEEInfoFromThreadIfNecessary(Thread);
  46. MESSAGE_OBJECT *MObject = (MESSAGE_OBJECT *) Message->Handle;
  47. ASSERT( MObject->InvalidHandle(CALL_TYPE) == 0 );
  48. ASSERT( Message->Buffer != 0 );
  49. ASSERT( !COMPLETE(Message) );
  50. retval = MObject->SendReceive(Message);
  51. ASSERT(!RpcpCheckHeap());
  52. // Insure that the buffer is aligned on an eight byte boundary.
  53. #ifdef DEBUGRPC
  54. if ( retval == RPC_S_OK )
  55. {
  56. ASSERT( (((ULONG_PTR) Message->Buffer) % 8) == 0);
  57. // uncomment this to check for 16 byte alignment on 64 bits
  58. // ASSERT( IsBufferAligned(Message->Buffer) );
  59. }
  60. #endif // DEBUGRPC
  61. return(retval);
  62. }
  63. RPC_STATUS RPC_ENTRY
  64. I_RpcSend (
  65. IN OUT PRPC_MESSAGE Message
  66. )
  67. /*++
  68. Routine Description:
  69. This API is used in conjunction with pipes. This is used to send the marshalled
  70. parameters and the marshalled pipe data.
  71. Client: If the RPC_BUFFER_PARTIAL bit is set in Message->RpcFlags,
  72. this routine returns as soon as the buffer is sent. If the
  73. bit is not set, this routine blocks until the first reply fragment arrives.
  74. Server: The send always treated as a partial send.
  75. Arguments:
  76. Message - Supplies the information required to send the request
  77. Return Values:
  78. RPC_S_OK - The operation completed successfully.
  79. RPC_S_SEND_INCOMPLETE - The complete data wasn't sent, Message->Buffer
  80. points to the remaining data and Message->BufferLength indicates the length of the
  81. remaining data. Any additional data needs to be appended to the
  82. end of the buffer.
  83. --*/
  84. {
  85. RPC_STATUS retval;
  86. THREAD *Thread;
  87. PVOID MessageBuffer;
  88. AssertRpcInitialized();
  89. ASSERT(!RpcpCheckHeap());
  90. Thread = ThreadSelf();
  91. if (!Thread)
  92. {
  93. return RPC_S_OUT_OF_MEMORY;
  94. }
  95. RpcpPurgeEEInfoFromThreadIfNecessary(Thread);
  96. MESSAGE_OBJECT *MObject = (MESSAGE_OBJECT *) Message->Handle;
  97. ASSERT( MObject->InvalidHandle(CALL_TYPE) == 0 );
  98. MessageBuffer = Message->Buffer;
  99. ASSERT( MessageBuffer != 0 );
  100. if (ASYNC(Message))
  101. {
  102. retval = MObject->AsyncSend(Message);
  103. }
  104. else
  105. {
  106. retval = MObject->Send(Message);
  107. }
  108. ASSERT(!RpcpCheckHeap());
  109. // Insure that the buffer is aligned on an eight byte boundary.
  110. #ifdef DEBUGRPC
  111. if ( retval == RPC_S_OK )
  112. {
  113. ASSERT( (((ULONG_PTR) MessageBuffer) % 8) == 0);
  114. // uncomment this to check for 16 byte alignment on 64 bits
  115. //ASSERT( IsBufferAligned(MessageBuffer) );
  116. }
  117. #endif // DEBUGRPC
  118. return(retval);
  119. }
  120. RPC_STATUS RPC_ENTRY
  121. I_RpcReceive (
  122. IN OUT PRPC_MESSAGE Message,
  123. IN unsigned int Size
  124. )
  125. /*++
  126. Routine Description:
  127. This routine is used in conjunction with pipes. If the RPC_BUFFER_PARTIAL bit
  128. is set in Message->RpcFlags, this call blocks until some data is received. Size is
  129. used as a hint of how much data the caller is requesting. If the partial bit is not set,
  130. this call blocks until the complete buffer is received.
  131. Arguments:
  132. Message - Supplies the information required to make the receive
  133. Size - used as a hint to indicate the amount of data needed by the caller
  134. Return Values:
  135. RPC_S_OK - The operation completed successfully.
  136. --*/
  137. {
  138. RPC_STATUS retval;
  139. THREAD *Thread;
  140. AssertRpcInitialized();
  141. ASSERT(!RpcpCheckHeap());
  142. Thread = ThreadSelf();
  143. if (!Thread)
  144. {
  145. return RPC_S_OUT_OF_MEMORY;
  146. }
  147. RpcpPurgeEEInfoFromThreadIfNecessary(Thread);
  148. MESSAGE_OBJECT *MObject = (MESSAGE_OBJECT *) Message->Handle;
  149. ASSERT( MObject->InvalidHandle(CALL_TYPE) == 0 );
  150. //
  151. // Temp hack
  152. // Need to get Ryszard to fix
  153. // the NDR engine to never ask for 0 bytes
  154. // We can then change this to an ASSERT
  155. // ASSERT(Size)
  156. //
  157. if (Size == 0)
  158. Size = 1;
  159. if (ASYNC(Message))
  160. {
  161. retval = MObject->AsyncReceive(Message, Size);
  162. }
  163. else
  164. {
  165. retval = MObject->Receive(Message, Size);
  166. }
  167. ASSERT(!RpcpCheckHeap());
  168. // Insure that the buffer is aligned on an eight byte boundary.
  169. #ifdef DEBUGRPC
  170. if ( retval == RPC_S_OK )
  171. {
  172. ASSERT( (((ULONG_PTR) Message->Buffer) % 8) == 0);
  173. // uncomment this to check for 16 byte alignment on 64 bits
  174. // ASSERT( IsBufferAligned(Message->Buffer) );
  175. }
  176. #endif // DEBUGRPC
  177. return(retval);
  178. }
  179. RPC_STATUS RPC_ENTRY
  180. I_RpcAsyncSetHandle (
  181. IN PRPC_MESSAGE Message,
  182. IN PRPC_ASYNC_STATE pAsync
  183. )
  184. /*++
  185. This API is called on the client and server side. If this API is called on the
  186. server, runtime assumes that the call is async
  187. we will add more params later.
  188. --*/
  189. {
  190. RPC_STATUS retval;
  191. AssertRpcInitialized();
  192. ASSERT(!RpcpCheckHeap());
  193. MESSAGE_OBJECT *MObject = (MESSAGE_OBJECT *) Message->Handle;
  194. if (MObject->InvalidHandle(CALL_TYPE))
  195. {
  196. ASSERT(0);
  197. return (RPC_S_INVALID_BINDING);
  198. }
  199. #if DBG
  200. if (!MObject->InvalidHandle(CCALL_TYPE))
  201. {
  202. // if we end up with invalid pAsync here, this means we were either
  203. // called by a private test, or COM. Both should know better. The
  204. // public APIs should pass through NDR and NDR already should have
  205. // validated the parameters.
  206. ASSERT((pAsync->Lock == 0) || (pAsync->Lock == 1));
  207. }
  208. #endif
  209. retval = MObject->SetAsyncHandle(pAsync);
  210. if (retval == RPC_S_OK)
  211. {
  212. pAsync->RuntimeInfo = (void *) MObject;
  213. }
  214. ASSERT(!RpcpCheckHeap());
  215. return(retval);
  216. }
  217. RPC_STATUS RPC_ENTRY
  218. I_RpcAsyncAbortCall (
  219. IN PRPC_ASYNC_STATE pAsync,
  220. IN unsigned long ExceptionCode
  221. )
  222. /*++
  223. Routine Description:
  224. Arguments:
  225. pAsync - the async handle being registered
  226. Return Value:
  227. RPC_S_OK - the call succeeded.
  228. RPC_S_INVALID_HANDLE - the handle was bad.
  229. --*/
  230. {
  231. MESSAGE_OBJECT *MObject = (MESSAGE_OBJECT *) pAsync->RuntimeInfo;
  232. if (!ThreadSelf())
  233. {
  234. return RPC_S_OUT_OF_MEMORY;
  235. }
  236. if (MObject)
  237. {
  238. if (MObject->InvalidHandle(CALL_TYPE))
  239. {
  240. ASSERT(0);
  241. return (RPC_S_INVALID_BINDING);
  242. }
  243. return ((CALL *) MObject)->AbortAsyncCall(pAsync, ExceptionCode);
  244. }
  245. return RPC_S_INVALID_ASYNC_HANDLE;
  246. }
  247. #ifdef __cplusplus
  248. extern "C" {
  249. #endif
  250. RPC_STATUS
  251. I_RpcParseSecurity (
  252. IN RPC_CHAR * NetworkOptions,
  253. OUT SECURITY_QUALITY_OF_SERVICE * SecurityQualityOfService
  254. )
  255. /*++
  256. Routine Description:
  257. Parse a string of security options and build into the binary format
  258. required by the operating system. The network options must follow
  259. the following syntax. Case is not sensitive.
  260. security=
  261. [anonymous|identification|impersonation|delegation]
  262. [dynamic|static]
  263. [true|false]
  264. All three fields must be present. To specify impersonation
  265. with dynamic tracking and effective only, use the following
  266. string for the network options.
  267. "security=impersonation dynamic true"
  268. Arguments:
  269. NetworkOptions - Supplies the string containing the network options
  270. to be parsed.
  271. SecurityQualityOfService - Returns the binary format of the network
  272. options.
  273. Return Value:
  274. RPC_S_OK - The network options have been correctly parsed into binary
  275. format.
  276. RPC_S_INVALID_NETWORK_OPTIONS - The network options are invalid and
  277. cannot be parsed.
  278. --*/
  279. {
  280. ASSERT(NetworkOptions[0] != 0);
  281. // We need to parse the security information from the network
  282. // options, and then stuff it into the object attributes. To
  283. // begin with, we check for "security=" at the beginning of
  284. // the network options.
  285. if (RpcpStringNCompare(NetworkOptions, RPC_CONST_STRING("security="),
  286. sizeof("security=") - 1) != 0)
  287. {
  288. return(RPC_S_INVALID_NETWORK_OPTIONS);
  289. }
  290. NetworkOptions += sizeof("security=") - 1;
  291. // Ok, now we need to determine if the next field is one of
  292. // Anonymous, Identification, Impersonation, or Delegation.
  293. if (RpcpStringNCompare(NetworkOptions, RPC_CONST_STRING("anonymous"),
  294. sizeof("anonymous") - 1) == 0)
  295. {
  296. SecurityQualityOfService->ImpersonationLevel = SecurityAnonymous;
  297. NetworkOptions += sizeof("anonymous") - 1;
  298. }
  299. else if (RpcpStringNCompare(NetworkOptions, RPC_CONST_STRING("identification"),
  300. sizeof("identification") - 1) == 0)
  301. {
  302. SecurityQualityOfService->ImpersonationLevel = SecurityIdentification;
  303. NetworkOptions += sizeof("identification") - 1;
  304. }
  305. else if (RpcpStringNCompare(NetworkOptions, RPC_CONST_STRING("impersonation"),
  306. sizeof("impersonation") - 1) == 0)
  307. {
  308. SecurityQualityOfService->ImpersonationLevel = SecurityImpersonation;
  309. NetworkOptions += sizeof("impersonation") - 1;
  310. }
  311. else if (RpcpStringNCompare(NetworkOptions, RPC_CONST_STRING("delegation"),
  312. sizeof("delegation") - 1) == 0)
  313. {
  314. SecurityQualityOfService->ImpersonationLevel = SecurityDelegation;
  315. NetworkOptions += sizeof("delegation") - 1;
  316. }
  317. else
  318. {
  319. return(RPC_S_INVALID_NETWORK_OPTIONS);
  320. }
  321. if (*NetworkOptions != RPC_CONST_CHAR(' '))
  322. {
  323. return(RPC_S_INVALID_NETWORK_OPTIONS);
  324. }
  325. NetworkOptions++;
  326. // Next comes the context tracking field; it must be one of
  327. // dynamic or static.
  328. if (RpcpStringNCompare(NetworkOptions, RPC_CONST_STRING("dynamic"),
  329. sizeof("dynamic") - 1) == 0)
  330. {
  331. SecurityQualityOfService->ContextTrackingMode =
  332. SECURITY_DYNAMIC_TRACKING;
  333. NetworkOptions += sizeof("dynamic") - 1;
  334. }
  335. else if (RpcpStringNCompare(NetworkOptions, RPC_CONST_STRING("static"),
  336. sizeof("static") - 1) == 0)
  337. {
  338. SecurityQualityOfService->ContextTrackingMode =
  339. SECURITY_STATIC_TRACKING;
  340. NetworkOptions += sizeof("static") - 1;
  341. }
  342. else
  343. {
  344. return(RPC_S_INVALID_NETWORK_OPTIONS);
  345. }
  346. if (*NetworkOptions != RPC_CONST_CHAR(' '))
  347. {
  348. return(RPC_S_INVALID_NETWORK_OPTIONS);
  349. }
  350. NetworkOptions++;
  351. // Finally, comes the effective only flag. This must be one of
  352. // true or false.
  353. if (RpcpStringNCompare(NetworkOptions, RPC_CONST_STRING("true"),
  354. sizeof("true") - 1) == 0)
  355. {
  356. SecurityQualityOfService->EffectiveOnly = TRUE;
  357. NetworkOptions += sizeof("true") - 1;
  358. }
  359. else if (RpcpStringNCompare(NetworkOptions, RPC_CONST_STRING("false"),
  360. sizeof("false") - 1) == 0)
  361. {
  362. SecurityQualityOfService->EffectiveOnly = FALSE;
  363. NetworkOptions += sizeof("false") - 1;
  364. }
  365. else
  366. {
  367. return(RPC_S_INVALID_NETWORK_OPTIONS);
  368. }
  369. if (*NetworkOptions != 0)
  370. {
  371. return(RPC_S_INVALID_NETWORK_OPTIONS);
  372. }
  373. SecurityQualityOfService->Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
  374. return(RPC_S_OK);
  375. }
  376. #ifdef __cplusplus
  377. }
  378. #endif