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.

1498 lines
39 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1997 - 1999
  3. Module Name:
  4. mqtrans.cxx
  5. Abstract:
  6. Support for MSMQ (Falcon) datagram transport. Based on MarioGo's
  7. DG transport code (dgtrans.cxx).
  8. Author:
  9. Edward Reus (edwardr) 04-Jul-1997
  10. Revision History:
  11. --*/
  12. #include <precomp.hxx>
  13. #include <trans.hxx>
  14. #include <dgtrans.hxx>
  15. #include <wswrap.hxx>
  16. #include "mqtrans.hxx"
  17. ////////////////////////////////////////////////////////////////////////
  18. //
  19. // MSMQ datagram routines.
  20. //
  21. //----------------------------------------------------------------
  22. RPC_STATUS
  23. MQ_SubmitReceive( IN MQ_DATAGRAM_ENDPOINT *pEndpoint,
  24. IN MQ_DATAGRAM *pDatagram )
  25. /*++
  26. Arguments:
  27. pEndpoint - The endpoint on which the receive should be posted.
  28. pDatagram - The datagram object to manage the receive.
  29. Return Value:
  30. RPC_P_IO_PENDING - OK
  31. RPC_S_OUT_OF_MEMORY
  32. RPC_S_OUT_OF_RESOURCES
  33. --*/
  34. {
  35. RPC_STATUS status;
  36. BOOL fRetry = TRUE;
  37. DWORD dwBytes = 0;
  38. DWORD dwStatus;
  39. HRESULT hr;
  40. while (fRetry)
  41. {
  42. if (pDatagram->pPacket == 0)
  43. {
  44. pDatagram->dwPacketSize = dwBytes;
  45. status = I_RpcTransDatagramAllocate2( pEndpoint,
  46. (BUFFER *)&pDatagram->pPacket,
  47. (PUINT) &pDatagram->dwPacketSize,
  48. (PVOID *) &pDatagram->pAddress);
  49. if (status != RPC_S_OK)
  50. {
  51. return RPC_S_OUT_OF_MEMORY;
  52. }
  53. ASSERT( pDatagram->pPacket );
  54. memset(pDatagram->pAddress,0,sizeof(MQ_ADDRESS));
  55. }
  56. pDatagram->cRecvAddr = sizeof(MQ_ADDRESS);
  57. ASSERT(*(PDWORD)pDatagram->pPacket = 0xDEADF00D);
  58. hr = AsyncReadQueue( pEndpoint,
  59. &pDatagram->Read,
  60. pDatagram->pAddress,
  61. pDatagram->pPacket,
  62. pDatagram->dwPacketSize );
  63. if (!FAILED(hr))
  64. {
  65. return RPC_P_IO_PENDING;
  66. }
  67. if (hr == MQ_ERROR_BUFFER_OVERFLOW)
  68. {
  69. // This can happen if there is already a large sized call on the queue.
  70. dwBytes = pDatagram->Read.aMsgPropVar[1].ulVal;
  71. dwStatus = I_RpcTransDatagramFree( pEndpoint,
  72. (BUFFER)pDatagram->pPacket,
  73. (PVOID) pDatagram->pAddress);
  74. pDatagram->pPacket = 0;
  75. pDatagram->dwPacketSize = 0;
  76. if (dwStatus != RPC_S_OK)
  77. {
  78. TransDbgPrint((DPFLTR_RPCPROXY_ID,
  79. DPFLTR_WARNING_LEVEL,
  80. RPCTRANS "MQ_SubmitReceive(): I_RpcTransDatagram() failed: %d\n",
  81. dwStatus));
  82. return RPC_S_OUT_OF_MEMORY;
  83. }
  84. }
  85. else
  86. {
  87. fRetry = FALSE;
  88. TransDbgPrint((DPFLTR_RPCPROXY_ID,
  89. DPFLTR_WARNING_LEVEL,
  90. RPCTRANS "MQ_SubmitReceive(): AsyncReadQueue() failed: 0x%x\n",
  91. hr));
  92. }
  93. }
  94. return RPC_S_OUT_OF_RESOURCES;
  95. }
  96. //----------------------------------------------------------------
  97. void
  98. MQ_SubmitReceives(
  99. BASE_ADDRESS *ThisEndpoint
  100. )
  101. /*++
  102. Routine Description:
  103. Helper function called when the pending IO count
  104. on an address is too low.
  105. Arguments:
  106. ThisEndpoint - The address to submit IOs on.
  107. Return Value:
  108. None
  109. --*/
  110. {
  111. PMQ_DATAGRAM pDg;
  112. PMQ_DATAGRAM_ENDPOINT pEndpoint = (PMQ_DATAGRAM_ENDPOINT)ThisEndpoint;
  113. if ( (!pEndpoint->fAllowReceives) || (!pEndpoint->hQueue) )
  114. {
  115. return;
  116. }
  117. do
  118. {
  119. BOOL fIoSubmitted;
  120. fIoSubmitted = FALSE;
  121. // Only one thread should be trying to submit IOs at a time.
  122. // This saves locking each DATAGRAM object.
  123. // Simple lock - but requires a loop. See the comment at the end
  124. // of the loop.
  125. if (pEndpoint->fSubmittingIos != 0)
  126. break;
  127. if (InterlockedIncrement(&pEndpoint->fSubmittingIos) != 1)
  128. break;
  129. // Submit new IOs on all the idle datagram objects
  130. for (int i = 0; i < pEndpoint->cMaximumIos; i++)
  131. {
  132. pDg = &pEndpoint->aDatagrams[i];
  133. if (pDg->Busy)
  134. {
  135. continue;
  136. }
  137. // Must be all set for the IO to complete before trying
  138. // to submit the IO.
  139. InterlockedIncrement(&pEndpoint->cPendingIos);
  140. pDg->Busy = TRUE;
  141. if (MQ_SubmitReceive(pEndpoint, pDg) == RPC_P_IO_PENDING)
  142. {
  143. fIoSubmitted = TRUE;
  144. }
  145. else
  146. {
  147. pDg->Busy = FALSE;
  148. InterlockedDecrement(&pEndpoint->cPendingIos);
  149. break;
  150. }
  151. }
  152. // Release the "lock" on the endpoint object.
  153. pEndpoint->fSubmittingIos = 0;
  154. if (!fIoSubmitted && pEndpoint->cPendingIos == 0)
  155. {
  156. // It appears that no IO is pending on the endpoint.
  157. COMMON_AddressManager(pEndpoint);
  158. return;
  159. }
  160. // Even if we submitted new IOs, they may all have completed
  161. // already. Which means we may need to loop and submit more
  162. // IOs. This is needed since the thread which completed the
  163. // last IO may have run into our lock and returned.
  164. }
  165. while (pEndpoint->cPendingIos == 0);
  166. return;
  167. }
  168. BOOL RPC_ENTRY MQ_AllowReceives(
  169. IN DG_TRANSPORT_ENDPOINT pvTransEndpoint,
  170. IN BOOL fAllowReceives,
  171. IN BOOL fCancelPendingIos )
  172. {
  173. BOOL fPrevAllowReceives;
  174. MQ_DATAGRAM_ENDPOINT *pEndpoint = (MQ_DATAGRAM_ENDPOINT*)pvTransEndpoint;
  175. fPrevAllowReceives = pEndpoint->fAllowReceives;
  176. pEndpoint->fAllowReceives = fAllowReceives;
  177. if (!pEndpoint->cPendingIos)
  178. {
  179. MQ_SubmitReceives(pEndpoint);
  180. }
  181. ASSERT( !fCancelPendingIos ); // Not implemented yet.
  182. return fPrevAllowReceives;
  183. }
  184. RPC_STATUS RPC_ENTRY
  185. MQ_SendPacket(
  186. IN DG_TRANSPORT_ENDPOINT ThisEndpoint,
  187. IN DG_TRANSPORT_ADDRESS pvAddress,
  188. IN BUFFER pHeader,
  189. IN unsigned cHeader,
  190. IN BUFFER pBody,
  191. IN unsigned cBody,
  192. IN BUFFER pTrailer,
  193. IN unsigned cTrailer
  194. )
  195. /*++
  196. Routine Description:
  197. Sends a packet to an address.
  198. The routine will send a packet built out of the three buffers supplied.
  199. All the buffers are optional, the actual packet sent will be built from
  200. all the buffers actually supplied. In each call at least buffer should
  201. NOT be null.
  202. Arguments:
  203. ThisEndpoint - Endpoint to send from.
  204. pAddress - Address to send to.
  205. pHeader - First data buffer
  206. cHeader - Size of the first data buffer or 0.
  207. pBody - Second data buffer
  208. cBody - Size of the second data buffer or 0.
  209. pTrailer - Third data buffer.
  210. cTrailer - Size of the third data buffer or 0.
  211. Return Value:
  212. RPC_S_OK
  213. RPC_S_OUT_OF_RESOURCES
  214. RPC_S_OUT_OF_MEMORY
  215. RPC_P_SEND_FAILED
  216. --*/
  217. {
  218. RPC_STATUS Status;
  219. MQ_DATAGRAM_ENDPOINT *pEndpoint = (MQ_DATAGRAM_ENDPOINT*)ThisEndpoint;
  220. MQ_ADDRESS *pAddress = (MQ_ADDRESS*)pvAddress;
  221. UCHAR *pBuffer;
  222. UCHAR *pTemp;
  223. DWORD dwBytes = cHeader + cBody + cTrailer;
  224. HRESULT hr;
  225. BOOL fNeedToFree = FALSE;
  226. ASSERT(dwBytes);
  227. //
  228. // Buffer assembly. I get the data PDU as up to three separate pieces,
  229. // so it needs to be assembled before being sent. For Falcon (which can't
  230. // do scatter/gather) this is expensive (allocate() + memcpy()'s). We try
  231. // to be cheap and avoid the allocation, or do an _alloca() off the stack
  232. // instead of the heap.
  233. //
  234. if ( (cHeader==0) && (cBody > 0) && (cTrailer == 0) )
  235. {
  236. pBuffer = pBody;
  237. }
  238. else if ( ((cBody == 0) && (cTrailer == 0))
  239. || ((pHeader+cHeader == pBody) && (pTrailer == 0)) )
  240. {
  241. pBuffer = pHeader;
  242. }
  243. else
  244. {
  245. pBuffer = (UCHAR*)I_RpcAllocate(dwBytes);
  246. fNeedToFree = TRUE;
  247. if (!pBuffer)
  248. {
  249. return RPC_S_OUT_OF_MEMORY;
  250. }
  251. pTemp = pBuffer;
  252. if (cHeader)
  253. {
  254. memcpy(pTemp,pHeader,cHeader);
  255. pTemp += cHeader;
  256. }
  257. if (cBody)
  258. {
  259. memcpy(pTemp,pBody,cBody);
  260. pTemp += cBody;
  261. }
  262. if (cTrailer)
  263. {
  264. memcpy(pTemp,pTrailer,cTrailer);
  265. }
  266. ASSERT(pTemp != pBuffer);
  267. }
  268. #ifdef MAJOR_DBG
  269. TransDbgPrint((DPFLTR_RPCPROXY_ID,
  270. DPFLTR_WARNING_LEVEL,
  271. RPCTRANS "MQ_SendPacket():\n"));
  272. TransDbgPrint((DPFLTR_RPCPROXY_ID,
  273. DPFLTR_WARNING_LEVEL,
  274. " To: %S: %S\n",
  275. pAddress->wsMachine,
  276. pAddress->wsQName));
  277. TransDbgPrint((DPFLTR_RPCPROXY_ID,
  278. DPFLTR_WARNING_LEVEL,
  279. " Size: %d\n",
  280. dwBytes));
  281. DG_DbgPrintPacket(pBuffer);
  282. #endif
  283. hr = MQ_SendToQueue( pEndpoint, pAddress, pBuffer, dwBytes );
  284. Status = MQ_MapStatusCode(hr,RPC_P_SEND_FAILED);
  285. if (Status != RPC_S_OK)
  286. {
  287. if (fNeedToFree)
  288. {
  289. I_RpcFree(pBuffer);
  290. }
  291. return Status;
  292. }
  293. if ( (pEndpoint->cMinimumIos)
  294. && (pEndpoint->cPendingIos <= pEndpoint->cMaximumIos) )
  295. {
  296. MQ_SubmitReceives(pEndpoint);
  297. }
  298. if (fNeedToFree)
  299. {
  300. I_RpcFree(pBuffer);
  301. }
  302. return RPC_S_OK;
  303. }
  304. RPC_STATUS RPC_ENTRY
  305. MQ_ForwardPacket(
  306. IN DG_TRANSPORT_ENDPOINT ThisEndpoint,
  307. IN BUFFER pHeader,
  308. IN unsigned cHeader,
  309. IN BUFFER pBody,
  310. IN unsigned cBody,
  311. IN BUFFER pTrailer,
  312. IN unsigned cTrailer,
  313. IN CHAR * pszPort
  314. )
  315. /*++
  316. Routine Description:
  317. Sends a packet to the server it was originally destined for (that
  318. is, the client had a dynamic endpoint it wished the enpoint mapper
  319. to resolve and forward the packet to).
  320. Arguments:
  321. ThisEndpoint - The endpoint to forward the packet from.
  322. // Buffer like DG_SendPacket
  323. pszPort - Pointer to the server port num to forward to.
  324. This is in an Ansi string.
  325. Return Value:
  326. RPC_S_CANT_CREATE_ENDPOINT - pEndpoint invalid.
  327. results of MQ_SendPacket().
  328. --*/
  329. {
  330. PMQ_DATAGRAM_ENDPOINT pEndpoint = (PMQ_DATAGRAM_ENDPOINT)ThisEndpoint;
  331. MQ_ADDRESS Address;
  332. MQ_ADDRESS *pAddress = &Address;
  333. RPC_CHAR wsPort[MQ_MAX_Q_NAME_LEN];
  334. UNICODE_STRING UnicodePort;
  335. ANSI_STRING AsciiPort;
  336. DWORD Status;
  337. NTSTATUS NtStatus;
  338. //
  339. // Convert pszPort to Unicode:
  340. //
  341. RtlInitAnsiString(&AsciiPort, pszPort);
  342. UnicodePort.Buffer = wsPort;
  343. UnicodePort.Length = 0;
  344. UnicodePort.MaximumLength = MQ_MAX_Q_NAME_LEN * sizeof(RPC_CHAR);
  345. NtStatus = RtlAnsiStringToUnicodeString(&UnicodePort,
  346. &AsciiPort,
  347. FALSE);
  348. if (!NT_SUCCESS(NtStatus))
  349. {
  350. return RPC_S_CANT_CREATE_ENDPOINT;
  351. }
  352. //
  353. // Try to connect to the server (to forward the packet to):
  354. //
  355. Status = ConnectToServerQueue(pAddress, NULL, wsPort );
  356. if (Status != RPC_S_OK)
  357. {
  358. return RPC_S_CANT_CREATE_ENDPOINT;
  359. }
  360. //
  361. // Forward the packet on:
  362. //
  363. Status = MQ_SendPacket(ThisEndpoint,
  364. pAddress,
  365. pHeader,
  366. cHeader,
  367. pBody,
  368. cBody,
  369. pTrailer,
  370. cTrailer );
  371. //
  372. // Release the connection, we shouldn't need it any more:
  373. //
  374. DisconnectFromServer(pAddress);
  375. return Status;
  376. }
  377. RPC_STATUS
  378. RPC_ENTRY
  379. MQ_ResizePacket(
  380. IN DG_TRANSPORT_ENDPOINT ThisEndpoint,
  381. OUT DG_TRANSPORT_ADDRESS *pReplyAddress,
  382. OUT PUINT pBufferLength,
  383. OUT BUFFER *pBuffer
  384. )
  385. {
  386. RPC_STATUS Status = RPC_P_TIMEOUT;
  387. DWORD dwBytes = 0;
  388. MQ_DATAGRAM_ENDPOINT *pEndpoint = (MQ_DATAGRAM_ENDPOINT*)ThisEndpoint;
  389. MQ_DATAGRAM *pDatagram = &pEndpoint->aDatagrams[0];
  390. dwBytes = pDatagram->Read.aMsgPropVar[1].ulVal;
  391. ASSERT(dwBytes);
  392. #ifdef DBG
  393. DbgPrint("MQ_ResizePacket(): dwBytes: %d\n",dwBytes);
  394. #endif
  395. if ( (pDatagram->pPacket) && (pDatagram->dwPacketSize < dwBytes) )
  396. {
  397. Status = I_RpcTransDatagramFree( pEndpoint,
  398. (BUFFER)pDatagram->pPacket,
  399. (PVOID) pDatagram->pAddress);
  400. pDatagram->pPacket = 0;
  401. pDatagram->dwPacketSize = 0;
  402. if (Status != RPC_S_OK)
  403. {
  404. return RPC_S_OUT_OF_MEMORY;
  405. }
  406. }
  407. if (!pDatagram->pPacket)
  408. {
  409. pDatagram->dwPacketSize = dwBytes;
  410. Status = I_RpcTransDatagramAllocate2( pEndpoint,
  411. (BUFFER *)&pDatagram->pPacket,
  412. (PUINT) &pDatagram->dwPacketSize,
  413. (PVOID *) &pDatagram->pAddress);
  414. if (Status != RPC_S_OK)
  415. {
  416. return RPC_S_OUT_OF_MEMORY;
  417. }
  418. pDatagram->cRecvAddr = sizeof(MQ_ADDRESS);
  419. ASSERT( pDatagram->pPacket );
  420. }
  421. #ifdef DBG
  422. DbgPrint("MQ_ResizePacket(): Ok\n");
  423. #endif
  424. return RPC_P_TIMEOUT;
  425. }
  426. RPC_STATUS
  427. RPC_ENTRY
  428. MQ_ReceivePacket(
  429. IN DG_TRANSPORT_ENDPOINT ThisEndpoint,
  430. OUT DG_TRANSPORT_ADDRESS *pReplyAddress,
  431. OUT PUINT pBufferLength,
  432. OUT BUFFER *pBuffer,
  433. IN LONG Timeout
  434. )
  435. /*++
  436. Routine Description:
  437. Used to wait for a datagram from a server. Returns the data
  438. returned and the address of the machine which replied.
  439. This is a blocking API. It should only be called during sync
  440. client RPC threads.
  441. Arguments:
  442. Endpoint - The endpoint to receive from.
  443. ReplyAddress - Contain the source address of the datagram if
  444. successful.
  445. BufferLength - The size of Buffer on input, the size of the
  446. datagram received on output.
  447. Timeout - Milliseconds to wait for a datagram.
  448. Return Value:
  449. RPC_S_OK
  450. RPC_P_OVERSIZE_PACKET - Datagram > BufferLength arrived,
  451. first BufferLength bytes of Buffer contain the partial datagram.
  452. RPC_P_RECEIVE_FAILED
  453. RPC_P_TIMEOUT
  454. --*/
  455. {
  456. RPC_STATUS Status = RPC_P_TIMEOUT;
  457. DWORD dwBytes;
  458. BOOL fRetry = TRUE;
  459. HRESULT hr;
  460. MQ_DATAGRAM_ENDPOINT *pEndpoint = (MQ_DATAGRAM_ENDPOINT*)ThisEndpoint;
  461. MQ_DATAGRAM *pDatagram = &pEndpoint->aDatagrams[0];
  462. ASSERT((pEndpoint->type & TYPE_MASK) == CLIENT);
  463. ASSERT(pEndpoint->aDatagrams[0].Read.ol.hEvent);
  464. #if TRUE
  465. while (fRetry)
  466. {
  467. fRetry = FALSE;
  468. if (pDatagram->Busy == 0)
  469. {
  470. Status = MQ_SubmitReceive(pEndpoint,pDatagram);
  471. if (Status != RPC_P_IO_PENDING)
  472. {
  473. return Status;
  474. }
  475. pDatagram->Busy = TRUE;
  476. }
  477. else
  478. {
  479. ASSERT(pDatagram->Busy);
  480. ASSERT(pDatagram->pPacket);
  481. Status = RPC_P_IO_PENDING;
  482. }
  483. if (Status == RPC_P_IO_PENDING)
  484. {
  485. Status = WaitForSingleObjectEx(pDatagram->Read.ol.hEvent,
  486. Timeout,
  487. TRUE);
  488. if (Status != STATUS_WAIT_0)
  489. {
  490. // In the timeout case we just want to return.
  491. if (Status == WAIT_IO_COMPLETION)
  492. {
  493. TransDbgPrint((DPFLTR_RPCPROXY_ID,
  494. DPFLTR_WARNING_LEVEL,
  495. RPCTRANS "MQ_ReceivePacket() cancelled.\n"));
  496. }
  497. else
  498. {
  499. ASSERT(Status == STATUS_TIMEOUT);
  500. }
  501. ASSERT(pDatagram->Busy);
  502. return RPC_P_TIMEOUT;
  503. }
  504. }
  505. MQ_FillInAddress(pDatagram->pAddress,pDatagram->Read.aMsgPropVar);
  506. }
  507. ASSERT((Status == RPC_S_OK)||(Status == RPC_P_OVERSIZE_PACKET));
  508. ASSERT(pDatagram->Busy);
  509. ASSERT(pDatagram->pPacket);
  510. // ASSERT(dwBytes <= pDatagram->dwPacketSize);
  511. *pBuffer = (BUFFER)pDatagram->pPacket;
  512. *pBufferLength = pDatagram->Read.aMsgPropVar[1].ulVal;
  513. // dwBytes;
  514. *pReplyAddress = pDatagram->pAddress;
  515. pDatagram->pPacket = 0;
  516. pDatagram->dwPacketSize = 0;
  517. pDatagram->Busy = 0;
  518. return Status;
  519. #else
  520. if (pDatagram->Busy == 0)
  521. {
  522. hr = PeekQueue( pEndpoint, Timeout, &dwBytes );
  523. Status = MQ_MapStatusCode(hr,RPC_P_RECEIVE_FAILED);
  524. if (Status != RPC_S_OK)
  525. {
  526. return Status;
  527. }
  528. if ( (pDatagram->pPacket) && (pDatagram->dwPacketSize < dwBytes) )
  529. {
  530. Status = I_RpcTransDatagramFree( pEndpoint,
  531. (BUFFER)pDatagram->pPacket,
  532. (PVOID) pDatagram->pAddress);
  533. pDatagram->pPacket = 0;
  534. pDatagram->dwPacketSize = 0;
  535. if (Status != RPC_S_OK)
  536. {
  537. return RPC_S_OUT_OF_MEMORY;
  538. }
  539. }
  540. if (!pDatagram->pPacket)
  541. {
  542. pDatagram->dwPacketSize = dwBytes;
  543. Status = I_RpcTransDatagramAllocate2( pEndpoint,
  544. (BUFFER *)&pDatagram->pPacket,
  545. (PUINT) &pDatagram->dwPacketSize,
  546. (PVOID *) &pDatagram->pAddress);
  547. if (Status != RPC_S_OK)
  548. {
  549. return RPC_S_OUT_OF_MEMORY;
  550. }
  551. pDatagram->cRecvAddr = sizeof(MQ_ADDRESS);
  552. ASSERT( pDatagram->pPacket );
  553. }
  554. pDatagram->Busy = TRUE;
  555. dwBytes = pDatagram->dwPacketSize;
  556. hr = ReadQueue( pEndpoint, Timeout, pDatagram->pAddress, pDatagram->pPacket, &dwBytes );
  557. Status = MQ_MapStatusCode(hr,RPC_P_RECEIVE_FAILED);
  558. if (FAILED(hr))
  559. {
  560. TransDbgPrint((DPFLTR_RPCPROXY_ID,
  561. DPFLTR_WARNING_LEVEL,
  562. RPCTRANS "ReadQueue() failed: 0x%x\n",
  563. hr));
  564. pDatagram->Busy = FALSE;
  565. return Status;
  566. }
  567. }
  568. #ifdef MAJOR_DBG
  569. TransDbgPrint((DPFLTR_RPCPROXY_ID,
  570. DPFLTR_WARNING_LEVEL,
  571. RPCTRANS "MQ_ReceivePacket():\n"));
  572. TransDbgPrint((DPFLTR_RPCPROXY_ID,
  573. DPFLTR_WARNING_LEVEL,
  574. " Receive on: %S\n",
  575. pEndpoint->wsQName));
  576. TransDbgPrint((DPFLTR_RPCPROXY_ID,
  577. DPFLTR_WARNING_LEVEL,
  578. " From: %S\n",
  579. pDatagram->pAddress->wsQName));
  580. TransDbgPrint((DPFLTR_RPCPROXY_ID,
  581. DPFLTR_WARNING_LEVEL,
  582. " Size: %d\n",
  583. dwBytes));
  584. DG_DbgPrintPacket(pDatagram->pPacket);
  585. #endif
  586. ASSERT((Status == RPC_S_OK)||(Status == RPC_P_OVERSIZE_PACKET));
  587. ASSERT(pDatagram->Busy);
  588. ASSERT(pDatagram->pPacket);
  589. ASSERT(dwBytes <= pDatagram->dwPacketSize);
  590. *pBuffer = (BUFFER)pDatagram->pPacket;
  591. *pBufferLength = dwBytes;
  592. *pReplyAddress = pDatagram->pAddress;
  593. pDatagram->pPacket = 0;
  594. pDatagram->dwPacketSize = 0;
  595. pDatagram->Busy = 0;
  596. return Status;
  597. #endif
  598. }
  599. RPC_STATUS
  600. MQ_CreateEndpoint(
  601. OUT MQ_DATAGRAM_ENDPOINT *pEndpoint,
  602. IN MQ_ADDRESS *pAddress,
  603. IN void *pSecurityDescriptor,
  604. IN DWORD dwEndpointFlags,
  605. IN PROTOCOL_ID id,
  606. IN BOOL fClient,
  607. IN BOOL fAsync
  608. )
  609. /*++
  610. Routine Description:
  611. Creates a new endpoint.
  612. Arguments:
  613. pEndpoint - The runtime allocated endpoint structure to
  614. filled in.
  615. pSockAddr - An initialized sockaddr with the correct
  616. (or no) endpoint.
  617. id - The id of the protocol to use in creating the address.
  618. fClient - If TRUE this is a client endpoint
  619. fAsync - If TRUE this endpoint is "async" which means that
  620. a) It should be added to the IO completion port and
  621. b) that the transport should pend a number of receives
  622. on the endpoint automatically.
  623. Return Value:
  624. RPC_S_OK
  625. RPC_S_OUT_OF_MEMORY
  626. RPC_S_OUT_OF_RESOURCES
  627. RPC_S_CANT_CREATE_ENDPOINT
  628. RPC_S_DUPLICATE_ENDPOINT
  629. --*/
  630. {
  631. MQ_DATAGRAM *pDatagram;
  632. int i;
  633. int err;
  634. int length;
  635. RPC_STATUS Status = RPC_S_OK;
  636. HRESULT hr;
  637. UUID uuid;
  638. DWORD dwSize;
  639. RPC_CHAR *pwsUuid;
  640. RPC_CHAR wsQName[MQ_MAX_Q_NAME_LEN];
  641. RPC_CHAR wsMachine[MAX_COMPUTERNAME_LEN];
  642. pEndpoint->type = DATAGRAM | ADDRESS;
  643. pEndpoint->id = id;
  644. pEndpoint->pAddressVector = 0;
  645. pEndpoint->SubmitListen = MQ_SubmitReceives;
  646. pEndpoint->InAddressList = NotInList;
  647. pEndpoint->pNext = 0;
  648. pEndpoint->fSubmittingIos = 0;
  649. pEndpoint->cPendingIos = 0;
  650. pEndpoint->cMinimumIos = 0;
  651. pEndpoint->cMaximumIos = 0;
  652. pEndpoint->aDatagrams = 0;
  653. pEndpoint->pFirstAddress = pEndpoint;
  654. pEndpoint->pNextAddress = 0;
  655. pEndpoint->hQueue = 0;
  656. pEndpoint->hAdminQueue = 0;
  657. // If we're told not to listen, then we won't allow receives
  658. // until we are specifically told to do so...
  659. #ifdef RPC_C_MQ_DONT_LISTEN
  660. pEndpoint->fAllowReceives = !(dwEndpointFlags & RPC_C_MQ_DONT_LISTEN);
  661. #else
  662. pEndpoint->fAllowReceives = TRUE;
  663. #endif
  664. pEndpoint->fAck = FALSE;
  665. pEndpoint->ulDelivery = RPC_C_MQ_EXPRESS;
  666. pEndpoint->ulPriority = DEFAULT_PRIORITY;
  667. pEndpoint->ulJournaling = RPC_C_MQ_JOURNAL_NONE;
  668. pEndpoint->ulTimeToReachQueue = INFINITE;
  669. pEndpoint->ulTimeToReceive = INFINITE;
  670. pEndpoint->fAuthenticate = FALSE;
  671. pEndpoint->fEncrypt = FALSE;
  672. pEndpoint->ulPrivacyLevel = 0;
  673. // Machine name:
  674. dwSize = sizeof(wsMachine);
  675. if (!GetComputerName((RPC_SCHAR *)wsMachine,&dwSize))
  676. {
  677. return RPC_S_OUT_OF_MEMORY;
  678. }
  679. // Get the name of the machine that the QM (mqsvc.exe)
  680. // is running on:
  681. dwSize = sizeof(pEndpoint->wsMachine);
  682. hr = QueryQM(pEndpoint->wsMachine,&dwSize);
  683. if (FAILED(hr))
  684. {
  685. Status = MQ_MapStatusCode(hr,RPC_S_CANT_CREATE_ENDPOINT);
  686. return Status;
  687. }
  688. //
  689. // See if this is a call from an RPC server or RPC client:
  690. //
  691. if (fClient)
  692. {
  693. pEndpoint->type |= CLIENT;
  694. // Queue name (a unique string...):
  695. Status = UuidCreate(&uuid);
  696. if ((Status != RPC_S_OK) && (Status != RPC_S_UUID_LOCAL_ONLY))
  697. {
  698. return Status;
  699. }
  700. if (UuidToString(&uuid,&pwsUuid) != RPC_S_OK)
  701. {
  702. return RPC_S_OUT_OF_MEMORY;
  703. }
  704. RpcpStringCopy(wsQName,TEXT("RpcCl-"));
  705. RpcpStringCat(wsQName,pwsUuid);
  706. // Function UuidCreate() allocated a string, free it:
  707. RpcStringFree(&pwsUuid);
  708. //
  709. // Create the queue for this endpoint:
  710. //
  711. hr = ClientSetupQueue( pEndpoint, pEndpoint->wsMachine, wsQName );
  712. Status = MQ_MapStatusCode(hr,RPC_S_CANT_CREATE_ENDPOINT);
  713. if (Status == RPC_S_OK)
  714. {
  715. MQ_RegisterQueueToDelete(pEndpoint->wsQFormat,wsMachine);
  716. }
  717. }
  718. else
  719. {
  720. pEndpoint->type |= SERVER;
  721. //
  722. // Create the queue for this server endpoint:
  723. //
  724. hr = ServerSetupQueue( pEndpoint,
  725. pEndpoint->wsMachine,
  726. pEndpoint->wsQName,
  727. pSecurityDescriptor,
  728. dwEndpointFlags );
  729. Status = MQ_MapStatusCode(hr,RPC_S_CANT_CREATE_ENDPOINT);
  730. //
  731. // Check to see if this queue is temporary. If so, then
  732. // register it with RPCSS to delete.
  733. //
  734. if ((Status == RPC_S_OK) && !(RPC_C_MQ_PERMANENT & dwEndpointFlags))
  735. {
  736. MQ_RegisterQueueToDelete(pEndpoint->wsQFormat,wsMachine);
  737. }
  738. }
  739. //
  740. // If the endpoint is going to async initialize async part
  741. // and add the socket to the IO completion port.
  742. //
  743. if (Status == RPC_S_OK)
  744. {
  745. int cMaxIos;
  746. int cMinIos;
  747. ASSERT(fAsync || fClient);
  748. // Step one, figure out the high and low mark for ios.
  749. if (fAsync)
  750. {
  751. // PERF REVIEW these parameters.
  752. cMaxIos = 2
  753. + (gfServerPlatform == TRUE) * 2
  754. + (fClient == FALSE) * gNumberOfProcessors;
  755. // This should be larger than zero so that we'll generally submit new
  756. // recvs during idle time rather then just after receiving a datagram.
  757. cMinIos = 1 + (fClient == FALSE ) * (gNumberOfProcessors/2);
  758. cMinIos = 1;
  759. cMaxIos = 1;
  760. }
  761. else
  762. {
  763. // For sync endpoints we need to allocate a single datagram
  764. // object for the receive.
  765. cMinIos = 0;
  766. cMaxIos = 1;
  767. }
  768. // ASSERT(cMinIos < cMaxIos); Not currently true...
  769. pEndpoint->cMinimumIos = cMinIos;
  770. pEndpoint->cMaximumIos = cMaxIos;
  771. // Allocate a chunk on memory to hold the array of datagrams
  772. // PERF: For clients, allocate larger array but don't submit all
  773. // the IOs unless we determine that the port is "really" active.
  774. pEndpoint->aDatagrams = new MQ_DATAGRAM[cMaxIos];
  775. if (pEndpoint->aDatagrams)
  776. {
  777. UINT type;
  778. type = DATAGRAM | RECEIVE;
  779. type |= (fClient) ? CLIENT : SERVER;
  780. for (i = 0; i < cMaxIos; i++)
  781. {
  782. pDatagram = &pEndpoint->aDatagrams[i];
  783. pDatagram->id = id;
  784. pDatagram->type = type;
  785. pDatagram->pEndpoint = pEndpoint;
  786. pDatagram->Busy = 0;
  787. pDatagram->pPacket = 0;
  788. pDatagram->dwPacketSize = 0;
  789. memset(&pDatagram->Read, 0, sizeof(pDatagram->Read));
  790. pDatagram->Read.pAsyncObject = pDatagram;
  791. }
  792. if (fAsync)
  793. {
  794. Status = COMMON_PrepareNewHandle((HANDLE)pEndpoint->hQueue);
  795. }
  796. else
  797. {
  798. // The receive operation on sync endpoints will may span
  799. // several receives. This means it can't use the thread
  800. // event, so allocate an event for the receive.
  801. HANDLE hEvent = CreateEvent(0, TRUE, FALSE, 0);
  802. if (!hEvent)
  803. {
  804. Status = RPC_S_OUT_OF_RESOURCES;
  805. }
  806. else
  807. {
  808. ASSERT(pDatagram == &pEndpoint->aDatagrams[0]);
  809. pDatagram->Read.ol.hEvent = hEvent;
  810. }
  811. }
  812. }
  813. else
  814. {
  815. Status = RPC_S_OUT_OF_MEMORY;
  816. }
  817. }
  818. // If adding a new failure case here, add code to close the sync receive event.
  819. if (Status != RPC_S_OK)
  820. {
  821. delete pEndpoint->aDatagrams;
  822. return Status;
  823. }
  824. return(RPC_S_OK);
  825. }
  826. void RPC_ENTRY
  827. MQ_ServerAbortListen(
  828. IN DG_TRANSPORT_ENDPOINT ThisEndpoint
  829. )
  830. /*++
  831. Routine Description:
  832. Callback after DG_CreateEndpoint has completed successfully
  833. but the runtime for some reason is not going to be able to
  834. listen on the endpoint.
  835. --*/
  836. {
  837. HRESULT hr;
  838. MQ_DATAGRAM_ENDPOINT *pEndpoint = (MQ_DATAGRAM_ENDPOINT*)ThisEndpoint;
  839. #ifdef MAJOR_DBG
  840. TransDbgPrint((DPFLTR_RPCPROXY_ID,
  841. DPFLTR_WARNING_LEVEL,
  842. RPCTRANS "MQ_ServerAbortListen(): %S\n",
  843. pEndpoint->wsQName));
  844. #endif
  845. ASSERT(pEndpoint->cPendingIos == 0);
  846. ASSERT(pEndpoint->hQueue);
  847. ASSERT(pEndpoint->pNext == 0);
  848. ASSERT(pEndpoint->type & SERVER);
  849. if (pEndpoint->pAddressVector)
  850. {
  851. delete pEndpoint->pAddressVector;
  852. }
  853. if (pEndpoint->aDatagrams)
  854. {
  855. delete pEndpoint->aDatagrams;
  856. }
  857. hr = ServerCloseQueue(pEndpoint);
  858. return;
  859. }
  860. RPC_STATUS RPC_ENTRY
  861. MQ_ClientCloseEndpoint(
  862. IN DG_TRANSPORT_ENDPOINT ThisEndpoint
  863. )
  864. /*++
  865. Routine Description:
  866. Called on sync client endpoints when they are no longer needed.
  867. Arguments:
  868. ThisEndpoint
  869. Return Value:
  870. RPC_S_OK
  871. --*/
  872. {
  873. HRESULT hr;
  874. PMQ_DATAGRAM_ENDPOINT pEndpoint = (PMQ_DATAGRAM_ENDPOINT)ThisEndpoint;
  875. PMQ_DATAGRAM pDatagram = &pEndpoint->aDatagrams[0];
  876. ASSERT((pEndpoint->type & TYPE_MASK) == CLIENT);
  877. ASSERT(pEndpoint->hQueue); // MQOpenQueue must have worked
  878. ASSERT(pEndpoint->cMinimumIos == 0);
  879. ASSERT(pEndpoint->cMaximumIos == 1); // Must not be async!
  880. ASSERT(pEndpoint->aDatagrams);
  881. // ASSERT(pEndpoint->Endpoint == 0);
  882. ASSERT(pEndpoint->pAddressVector == 0);
  883. // ASSERT(pEndpoint->pNext == 0);
  884. // Close & delete the client queue:
  885. hr = ClientCloseQueue(pEndpoint);
  886. // Free the receive buffer if allocated
  887. if (pDatagram->pPacket)
  888. {
  889. I_RpcTransDatagramFree(pEndpoint,
  890. (BUFFER)pDatagram->pPacket,
  891. pDatagram->pAddress
  892. );
  893. }
  894. if (pDatagram->Read.ol.hEvent)
  895. {
  896. CloseHandle(pDatagram->Read.ol.hEvent);
  897. }
  898. delete pDatagram;
  899. pEndpoint->aDatagrams = 0;
  900. return(RPC_S_OK);
  901. }
  902. RPC_STATUS RPC_ENTRY
  903. MQ_ServerListen(
  904. IN OUT DG_TRANSPORT_ENDPOINT ThisEndpoint,
  905. IN RPC_CHAR *NetworkAddress,
  906. IN OUT RPC_CHAR **ppEndpoint,
  907. IN void *pSecurityDescriptor,
  908. IN ULONG EndpointFlags,
  909. IN ULONG NICFlags,
  910. OUT NETWORK_ADDRESS_VECTOR **ppNetworkAddressVector
  911. )
  912. /*++
  913. Routine Description:
  914. Creates a server endpoint object to receive packets. New
  915. packets won't actually arrive until CompleteListen is
  916. called.
  917. Arguments:
  918. ThisEndpoint - Storage for the server endpoint object.
  919. ppEndpoint - The RPC_CHAR name of the endpoint to listen
  920. on or a pointer to 0 if the transport should choose
  921. the address. Contains the endpoint listened to on
  922. output. The caller should free this.
  923. EndpointFlags - Application flags passed into RPC via
  924. RpcServerUseProtseq*Ex.
  925. NICFlags - Application flags passed into RPC via
  926. RpcServerUseProtseq*Ex.
  927. pNetworkAddresses - A vector of the network addresses
  928. listened on by this call. This vector does
  929. not need to be freed.
  930. Return Value:
  931. RPC_S_OK
  932. RPC_S_OUT_OF_MEMORY
  933. RPC_S_OUT_OF_RESOURCES
  934. RPC_S_CANT_CREATE_ENDPOINT
  935. RPC_S_INVALID_ENDPOINT_FORMAT
  936. RPC_S_DUPLICATE_ENDPOINT
  937. --*/
  938. {
  939. RPC_STATUS Status;
  940. DWORD dwSize;
  941. UUID uuid;
  942. RPC_CHAR *pUuidStr;
  943. MQ_DATAGRAM_ENDPOINT *pEndpoint = (MQ_DATAGRAM_ENDPOINT*)ThisEndpoint;
  944. *ppNetworkAddressVector = 0;
  945. if (*ppEndpoint)
  946. {
  947. // Known Endpoint:
  948. RpcpStringCopy(pEndpoint->wsQName,*ppEndpoint);
  949. }
  950. else
  951. {
  952. // Dynamic Endpoint:
  953. Status = UuidCreate(&uuid);
  954. if ((Status != RPC_S_OK) && (Status != RPC_S_UUID_LOCAL_ONLY))
  955. {
  956. return Status;
  957. }
  958. Status = UuidToString(&uuid,&pUuidStr);
  959. if (Status != RPC_S_OK)
  960. {
  961. return Status;
  962. }
  963. RpcpStringCopy(pEndpoint->wsQName,TEXT("RpcSvr-"));
  964. RpcpStringCat(pEndpoint->wsQName,pUuidStr);
  965. RpcStringFree(&pUuidStr);
  966. dwSize = (1+RpcpStringLength(pEndpoint->wsQName))*(sizeof(RPC_CHAR));
  967. *ppEndpoint = (RPC_CHAR*)I_RpcAllocate(dwSize);
  968. if (!*ppEndpoint)
  969. {
  970. return RPC_S_OUT_OF_MEMORY;
  971. }
  972. RpcpStringCopy(*ppEndpoint,pEndpoint->wsQName);
  973. }
  974. //
  975. // Actually create the endpoint
  976. //
  977. Status = MQ_CreateEndpoint( pEndpoint,
  978. NULL,
  979. pSecurityDescriptor,
  980. EndpointFlags,
  981. MSMQ,
  982. FALSE, // Server
  983. TRUE ); // Async
  984. if (Status != RPC_S_OK)
  985. {
  986. return Status;
  987. }
  988. Status = MQ_BuildAddressVector(&pEndpoint->pAddressVector);
  989. if (Status != RPC_S_OK)
  990. {
  991. MQ_ServerAbortListen(ThisEndpoint);
  992. return Status;
  993. }
  994. *ppNetworkAddressVector = pEndpoint->pAddressVector;
  995. #if FALSE
  996. // If needed, figure out the dynamically allocated endpoint.
  997. if (!*pPort)
  998. {
  999. *pPort = new RPC_CHAR[IP_MAXIMUM_ENDPOINT];
  1000. if (!*pPort)
  1001. {
  1002. MQ_ServerAbortListen(ThisEndpoint);
  1003. return(RPC_S_OUT_OF_MEMORY);
  1004. }
  1005. port = ntohs(addr.inetaddr.sin_port);
  1006. PortNumberToEndpoint(port, *pPort);
  1007. }
  1008. // Figure out the network addresses
  1009. status = IP_BuildAddressVector(&pEndpoint->pAddressVector);
  1010. if (status != RPC_S_OK)
  1011. {
  1012. MQ_ServerAbortListen(ThisEndpoint);
  1013. return(status);
  1014. }
  1015. *ppNetworkAddressVector = pEndpoint->pAddressVector;
  1016. #endif
  1017. return RPC_S_OK;
  1018. }
  1019. RPC_STATUS
  1020. MQ_QueryEndpoint
  1021. (
  1022. IN void * pOriginalEndpoint,
  1023. OUT RPC_CHAR * pClientEndpoint
  1024. )
  1025. {
  1026. MQ_ADDRESS *pAddress = (MQ_ADDRESS*)pOriginalEndpoint;
  1027. if (!RpcpStringLength(pAddress->wsQName))
  1028. {
  1029. ParseQueuePathName(pAddress->wsMsgLabel,
  1030. pAddress->wsMachine,
  1031. pAddress->wsQName);
  1032. }
  1033. RpcpStringCopy(pClientEndpoint,pAddress->wsQName);
  1034. return RPC_S_OK;
  1035. }
  1036. RPC_STATUS
  1037. MQ_QueryAddress
  1038. (
  1039. IN void * pOriginalEndpoint,
  1040. OUT RPC_CHAR * pClientAddress
  1041. )
  1042. {
  1043. MQ_ADDRESS *pAddress = (MQ_ADDRESS*)pOriginalEndpoint;
  1044. if (!RpcpStringLength(pAddress->wsMachine))
  1045. {
  1046. ParseQueuePathName(pAddress->wsMsgLabel,
  1047. pAddress->wsMachine,
  1048. pAddress->wsQName);
  1049. }
  1050. RpcpStringCopy(pClientAddress,pAddress->wsMachine);
  1051. return RPC_S_OK;
  1052. }
  1053. RPC_STATUS
  1054. RPC_ENTRY
  1055. MQ_ClientInitializeAddress
  1056. (
  1057. OUT DG_TRANSPORT_ADDRESS pvAddress,
  1058. IN RPC_CHAR *pNetworkAddress,
  1059. IN RPC_CHAR *pEndpoint,
  1060. IN BOOL fUseCache,
  1061. IN BOOL fBroadcast
  1062. )
  1063. /*++
  1064. Routine Description:
  1065. Initializes a address object for sending to a server.
  1066. Arguments:
  1067. pvAddress - Storage for the address
  1068. pNetworkAddress - The address of the server or 0 if local
  1069. pEndpoint - The endpoint of the server
  1070. fUseCache - If TRUE then the transport may use a cached
  1071. value from a previous call on the same NetworkAddress.
  1072. fBroadcast - If TRUE, NetworkAddress is ignored and a broadcast
  1073. address is used.
  1074. Return Value:
  1075. RPC_S_OK - Success, name resolved and, optionally, added to cache.
  1076. RPC_P_FOUND_IN_CACHE - Success, returned only if fUseCache is TRUE
  1077. and the was name found in local cache.
  1078. RPC_P_MATCHED_CACHE - Partial success, fUseCache is FALSE and the
  1079. result of the lookup was the same as the value previously
  1080. in the cache.
  1081. RPC_S_OUT_OF_MEMORY
  1082. RPC_S_OUT_OF_RESOURCES
  1083. RPC_S_INVALID_ENDPOINT_FORMAT
  1084. RPC_S_SERVER_UNAVAILABLE
  1085. --*/
  1086. {
  1087. RPC_STATUS Status = RPC_S_OK;
  1088. MQ_ADDRESS *pAddress = (MQ_ADDRESS*)pvAddress;
  1089. ASSERT(pvAddress);
  1090. Status = ConnectToServerQueue(pAddress,pNetworkAddress,pEndpoint);
  1091. return Status;
  1092. }
  1093. RPC_STATUS
  1094. RPC_ENTRY
  1095. MQ_ClientOpenEndpoint(
  1096. OUT DG_TRANSPORT_ENDPOINT ThisEndpoint,
  1097. IN BOOL fAsync,
  1098. DWORD Flags
  1099. )
  1100. {
  1101. RPC_STATUS Status;
  1102. MQ_DATAGRAM_ENDPOINT *pEndpoint = (MQ_DATAGRAM_ENDPOINT*)ThisEndpoint;
  1103. Status = MQ_CreateEndpoint(pEndpoint, NULL, NULL, 0, MSMQ, TRUE, fAsync);
  1104. return Status;
  1105. }
  1106. RPC_STATUS
  1107. RPC_ENTRY
  1108. MQ_GetEndpointStats(
  1109. IN DG_TRANSPORT_ENDPOINT ThisEndpoint,
  1110. OUT DG_ENDPOINT_STATS * pStats
  1111. )
  1112. {
  1113. pStats->PreferredPduSize = MQ_PREFERRED_PDU_SIZE;
  1114. pStats->MaxPduSize = MQ_MAX_PDU_SIZE;
  1115. pStats->MaxPacketSize = MQ_MAX_PACKET_SIZE;
  1116. pStats->ReceiveBufferSize = MQ_RECEIVE_BUFFER_SIZE;
  1117. return RPC_S_OK;
  1118. }
  1119. //----------------------------------------------------------------
  1120. // MQ_InquireAuthClient()
  1121. //
  1122. // Fill out security information for the transport.
  1123. //
  1124. // NOTE: The returned SID (ppSid) is a pointer to the one in the
  1125. // client endpoint. The caller can't free it and should make
  1126. // its own copy...
  1127. //----------------------------------------------------------------
  1128. RPC_STATUS
  1129. RPC_ENTRY
  1130. MQ_InquireAuthClient( void *pvClientEndpoint,
  1131. RPC_CHAR **ppPrincipal,
  1132. SID **ppSid,
  1133. ULONG *pulAuthnLevel,
  1134. ULONG *pulAuthnService,
  1135. ULONG *pulAuthzService )
  1136. {
  1137. RPC_STATUS Status = RPC_S_OK;
  1138. MQ_ADDRESS *pClientEndpoint = (MQ_ADDRESS*)(pvClientEndpoint);
  1139. SID *pClientSid;
  1140. DWORD dwSize;
  1141. ASSERT(pulAuthnLevel);
  1142. ASSERT(pulAuthnService);
  1143. ASSERT(pulAuthzService);
  1144. if (pClientEndpoint)
  1145. {
  1146. *ppPrincipal = NULL;
  1147. *pulAuthnService = RPC_C_AUTHN_MQ;
  1148. *pulAuthzService = RPC_C_AUTHZ_NONE;
  1149. //
  1150. // The authentication level:
  1151. //
  1152. if (pClientEndpoint->fAuthenticated)
  1153. {
  1154. if (pClientEndpoint->ulPrivacyLevel == MQMSG_PRIV_LEVEL_BODY)
  1155. *pulAuthnLevel = RPC_C_AUTHN_LEVEL_PKT_PRIVACY;
  1156. else
  1157. *pulAuthnLevel = RPC_C_AUTHN_LEVEL_PKT_INTEGRITY;
  1158. }
  1159. else if (pClientEndpoint->ulPrivacyLevel == MQMSG_PRIV_LEVEL_BODY)
  1160. {
  1161. *pulAuthnLevel = RPC_C_AUTHN_LEVEL_PKT_PRIVACY;
  1162. }
  1163. else
  1164. {
  1165. *pulAuthnLevel = RPC_C_AUTHN_LEVEL_NONE;
  1166. }
  1167. if ( IsValidSid((PSID)(pClientEndpoint->aSidBuffer)) )
  1168. *ppSid = (SID*)(pClientEndpoint->aSidBuffer);
  1169. else
  1170. *ppSid = NULL;
  1171. }
  1172. else
  1173. Status = RPC_S_BINDING_HAS_NO_AUTH;
  1174. return Status;
  1175. }