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.

5404 lines
144 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1990 - 1999
  6. //
  7. // File: hndlsvr.cxx
  8. //
  9. //--------------------------------------------------------------------------
  10. /* --------------------------------------------------------------------
  11. Microsoft OS/2 LAN Manager
  12. Copyright(c) Microsoft Corp., 1990
  13. -------------------------------------------------------------------- */
  14. /* --------------------------------------------------------------------
  15. File : hndlsvr.cxx
  16. Description :
  17. This file contains the implementations of the classes defined in hndlsvr.hxx.
  18. These routines are independent of the actual RPC protocol / transport layer.
  19. In addition, these routines are also independent of the specific operating
  20. system in use.
  21. History :
  22. mikemon ??-??-?? Beginning of recorded history.
  23. mikemon 10-15-90 Changed the shutdown functionality to PauseExecution
  24. rather than suspending and resuming a thread.
  25. mikemon 12-28-90 Updated the comments to match reality.
  26. connieh 17-Feb-94 Created RPC_SERVER::RegisterRpcForwardFunction
  27. Kamen Moutafov (KamenM) Dec 99 - Feb 2000 - Support for cell debugging stuff
  28. -------------------------------------------------------------------- */
  29. #include <precomp.hxx>
  30. #include <queue.hxx>
  31. #include <hndlsvr.hxx>
  32. #include <svrbind.hxx>
  33. #include <thrdctx.hxx>
  34. #include <rpcobj.hxx>
  35. #include <rpccfg.h>
  36. #include <sdict2.hxx>
  37. #include <dispatch.h>
  38. #include <queue.hxx>
  39. #include <lpcpack.hxx>
  40. #include <lpcsvr.hxx>
  41. extern LRPC_SERVER *GlobalLrpcServer ;
  42. #include <ProtBind.hxx>
  43. #include <osfpcket.hxx>
  44. #include <bitset.hxx>
  45. #include <osfclnt.hxx>
  46. #include <secsvr.hxx>
  47. #include <osfsvr.hxx>
  48. #include <dgpkt.hxx>
  49. #include <dgsvr.hxx>
  50. RPC_STATUS RPC_ENTRY
  51. DefaultCallbackFn (
  52. IN RPC_IF_HANDLE InterfaceUuid,
  53. IN void *Context
  54. )
  55. /*++
  56. Function Name:DefaultCallbackFn
  57. Parameters:
  58. Description:
  59. Returns:
  60. RPC_S_OK: Access is allowed
  61. other failures: Access is denied
  62. --*/
  63. {
  64. RPC_CALL_ATTRIBUTES CallAttributes;
  65. RPC_STATUS Status;
  66. CallAttributes.Version = RPC_CALL_ATTRIBUTES_VERSION;
  67. CallAttributes.Flags = 0;
  68. Status = RpcServerInqCallAttributesW(Context,
  69. &CallAttributes);
  70. if (Status != RPC_S_OK)
  71. return Status;
  72. if ((CallAttributes.AuthenticationService == RPC_C_AUTHN_NONE)
  73. || (CallAttributes.AuthenticationLevel == RPC_C_AUTHN_LEVEL_NONE)
  74. || (CallAttributes.NullSession)
  75. )
  76. {
  77. return RPC_S_ACCESS_DENIED;
  78. }
  79. return RPC_S_OK;
  80. }
  81. RPC_INTERFACE::RPC_INTERFACE (
  82. IN RPC_SERVER_INTERFACE PAPI * RpcInterfaceInformation,
  83. IN RPC_SERVER * Server,
  84. IN unsigned int Flags,
  85. IN unsigned int MaxCalls,
  86. IN unsigned int MaxRpcSize,
  87. IN RPC_IF_CALLBACK_FN PAPI *IfCallbackFn,
  88. OUT RPC_STATUS *Status
  89. ) : NullManagerActiveCallCount(0), AutoListenCallCount(0)
  90. /*++
  91. Routine Description:
  92. This method will get called to construct an instance of the
  93. RPC_INTERFACE class. We have got to make a copy of the rpc interface
  94. information supplied. The copy is necessary because we do not delete
  95. interfaces when they are unregistered. We just mark them as being
  96. inactive. In addition, we need to set the NullManagerFlag
  97. to zero, since this is used as the flag indicating whether we have
  98. got a manager for the NULL type UUID.
  99. Arguments:
  100. RpcInterfaceInformation - Supplies the rpc interface information
  101. which describes this interface.
  102. Server - Supplies the rpc server which owns this rpc interface.
  103. --*/
  104. {
  105. ALLOCATE_THIS(RPC_INTERFACE);
  106. unsigned int Length;
  107. PipeInterfaceFlag = 0;
  108. SequenceNumber = 1;
  109. #if DBG
  110. Strict = iuschDontKnow;
  111. #endif
  112. if (RpcInterfaceInformation->Length > sizeof(RPC_SERVER_INTERFACE) )
  113. {
  114. Length = sizeof(RPC_SERVER_INTERFACE);
  115. }
  116. else
  117. {
  118. Length = RpcInterfaceInformation->Length;
  119. }
  120. if ((RpcInterfaceInformation->Length > NT351_INTERFACE_SIZE)
  121. && (RpcInterfaceInformation->Flags & RPC_INTERFACE_HAS_PIPES))
  122. {
  123. PipeInterfaceFlag = 1;
  124. }
  125. RpcpMemoryCopy(&(this->RpcInterfaceInformation), RpcInterfaceInformation, Length);
  126. NullManagerFlag = 0;
  127. ManagerCount = 0;
  128. this->Server = Server;
  129. this->Flags = Flags ;
  130. this->MaxCalls = MaxCalls ;
  131. this->MaxRpcSize = MaxRpcSize;
  132. fBindingsExported = 0;
  133. UuidVector = NULL;
  134. if (Flags & RPC_IF_ALLOW_SECURE_ONLY
  135. && IfCallbackFn == NULL)
  136. {
  137. this->CallbackFn = DefaultCallbackFn;
  138. }
  139. else
  140. {
  141. this->CallbackFn = IfCallbackFn ;
  142. }
  143. if (DoesInterfaceSupportMultipleTransferSyntaxes(RpcInterfaceInformation))
  144. {
  145. *Status = NdrServerGetSupportedSyntaxes(RpcInterfaceInformation,
  146. &NumberOfSupportedTransferSyntaxes,
  147. &TransferSyntaxesArray, &PreferredTransferSyntax);
  148. if (*Status != RPC_S_OK)
  149. return;
  150. }
  151. else
  152. {
  153. NumberOfSupportedTransferSyntaxes = 0;
  154. }
  155. *Status = RPC_S_OK;
  156. }
  157. RPC_STATUS
  158. RPC_INTERFACE::RegisterTypeManager (
  159. IN RPC_UUID PAPI * ManagerTypeUuid OPTIONAL,
  160. IN RPC_MGR_EPV PAPI * ManagerEpv OPTIONAL
  161. )
  162. /*++
  163. Routine Description:
  164. This method is used to register a type manager with this interface.
  165. If no type UUID is specified, or it is the NULL type UUID, we
  166. stick the manager entry point vector right in this instance (assuming
  167. that there is not already one), otherwise, we put it into the
  168. dictionary of interface manager objects.
  169. Arguments:
  170. ManagerTypeUuid - Optionally supplies the type UUID for the manager
  171. we want to register with this rpc interface. If no type UUID
  172. is supplied then the NULL type UUID is assumed.
  173. ManagerEpv - Supplies then entry point vector for this manager. This
  174. vector is used to dispatch from the stub to the application
  175. code.
  176. Return Values:
  177. RPC_S_OK - The type manager has been successfully added to this
  178. rpc interface.
  179. RPC_S_OUT_OF_MEMORY - Insufficient memory is availabe to add the
  180. type manager to the rpc interface.
  181. RPC_S_TYPE_ALREADY_REGISTERED - A manager entry point vector has
  182. already been registered for the this interface under the
  183. specified manager type UUID.
  184. --*/
  185. {
  186. RPC_INTERFACE_MANAGER * InterfaceManager;
  187. // First we need to check if the null UUID is being specified as
  188. // the type UUID; either, explicit or implicit by not specifying
  189. // a type UUID argument.
  190. RequestGlobalMutex();
  191. if ( (ARGUMENT_PRESENT(ManagerTypeUuid) == 0)
  192. || ( (ARGUMENT_PRESENT(ManagerTypeUuid) != 0)
  193. && (ManagerTypeUuid->IsNullUuid() != 0)))
  194. {
  195. if (NullManagerFlag != 0)
  196. {
  197. ClearGlobalMutex();
  198. return(RPC_S_TYPE_ALREADY_REGISTERED);
  199. }
  200. NullManagerEpv = ManagerEpv;
  201. NullManagerFlag = 1;
  202. ManagerCount += 1;
  203. ClearGlobalMutex();
  204. return(RPC_S_OK);
  205. }
  206. // If we reach here, a non-NULL type UUID is specified.
  207. InterfaceManager = FindInterfaceManager(ManagerTypeUuid);
  208. if (InterfaceManager == 0)
  209. {
  210. InterfaceManager = new RPC_INTERFACE_MANAGER(ManagerTypeUuid,
  211. ManagerEpv);
  212. if (InterfaceManager == 0)
  213. {
  214. ClearGlobalMutex();
  215. return(RPC_S_OUT_OF_MEMORY);
  216. }
  217. if (InterfaceManagerDictionary.Insert(InterfaceManager) == -1)
  218. {
  219. ClearGlobalMutex();
  220. delete InterfaceManager;
  221. return(RPC_S_OUT_OF_MEMORY);
  222. }
  223. ManagerCount += 1;
  224. ClearGlobalMutex();
  225. return(RPC_S_OK);
  226. }
  227. if (InterfaceManager->ValidManager() == 0)
  228. {
  229. InterfaceManager->SetManagerEpv(ManagerEpv);
  230. ManagerCount += 1;
  231. ClearGlobalMutex();
  232. return(RPC_S_OK);
  233. }
  234. ClearGlobalMutex();
  235. return(RPC_S_TYPE_ALREADY_REGISTERED);
  236. }
  237. RPC_INTERFACE_MANAGER *
  238. RPC_INTERFACE::FindInterfaceManager (
  239. IN RPC_UUID PAPI * ManagerTypeUuid
  240. )
  241. /*++
  242. Routine Description:
  243. This method is used to obtain the interface manager corresponding to
  244. the specified type UUID. The type UUID must not be the null UUID.
  245. Arguments:
  246. ManagerTypeUuid - Supplies the type UUID for which we are trying to
  247. find the interface manager.
  248. Return Value:
  249. If a interface manager for this type UUID is found, a pointer to it
  250. will be returned; otherwise, zero will be returned.
  251. --*/
  252. {
  253. RPC_INTERFACE_MANAGER * InterfaceManager;
  254. DictionaryCursor cursor;
  255. InterfaceManagerDictionary.Reset(cursor);
  256. while ((InterfaceManager = InterfaceManagerDictionary.Next(cursor)) != 0)
  257. {
  258. if (InterfaceManager->MatchTypeUuid(ManagerTypeUuid) == 0)
  259. return(InterfaceManager);
  260. }
  261. return(0);
  262. }
  263. RPC_STATUS
  264. RPC_INTERFACE::DispatchToStub (
  265. IN OUT PRPC_MESSAGE Message,
  266. IN unsigned int CallbackFlag,
  267. IN PRPC_DISPATCH_TABLE DispatchTableToUse,
  268. OUT RPC_STATUS PAPI * ExceptionCode
  269. )
  270. /*++
  271. Routine Description:
  272. This method is used to dispatch remote procedure calls to the
  273. appropriate stub and hence to the appropriate manager entry point.
  274. This routine is used for calls having a null UUID (implicit or
  275. explicit). We go to great pains to insure that we do not grab
  276. a mutex.
  277. Arguments:
  278. Message - Supplies the response message and returns the reply
  279. message.
  280. CallbackFlag - Supplies a flag indicating whether this is a callback
  281. or not. The argument will be zero if this is an original call,
  282. and non-zero if it is a callback.
  283. ExceptionCode - Returns the exact exception code if an exception
  284. occurs.
  285. Return Value:
  286. RPC_S_OK - This value will be returned if the operation completed
  287. successfully.
  288. RPC_S_PROCNUM_OUT_OF_RANGE - If the procedure number for this call is
  289. too large, this value will be returned.
  290. RPC_S_UNKNOWN_IF - If this interface does not exist, you will get this
  291. value back.
  292. RPC_S_NOT_LISTENING - The rpc server which owns this rpc interface
  293. is not listening for remote procedure calls right now.
  294. RPC_S_SERVER_TOO_BUSY - This call will cause there to be too many
  295. concurrent remote procedure calls for the rpc server which owns
  296. this interface.
  297. RPC_P_EXCEPTION_OCCURED - A fault occured, and we need to remote it. The
  298. ExceptionCode argument will contain the exception code for the
  299. fault.
  300. RPC_S_UNSUPPORTED_TYPE - This interface exists, but does not have a manager
  301. for the null type.
  302. --*/
  303. {
  304. RPC_STATUS RpcStatus = RPC_S_OK;
  305. if ( CallbackFlag == 0 )
  306. {
  307. NullManagerActiveCallCount.Increment();
  308. if ( NullManagerFlag == 0 )
  309. {
  310. NullManagerActiveCallCount.Decrement();
  311. RpcStatus = RPC_S_UNSUPPORTED_TYPE;
  312. RpcpErrorAddRecord(EEInfoGCRuntime,
  313. RpcStatus,
  314. EEInfoDLDispatchToStub10);
  315. if ( ManagerCount == 0 )
  316. {
  317. RpcStatus = RPC_S_UNKNOWN_IF;
  318. RpcpErrorAddRecord(EEInfoGCRuntime,
  319. RpcStatus,
  320. EEInfoDLDispatchToStub20);
  321. }
  322. }
  323. }
  324. if (RpcStatus != RPC_S_OK)
  325. {
  326. ((MESSAGE_OBJECT *) Message->Handle)->FreeBuffer(Message);
  327. return RpcStatus;
  328. }
  329. Message->ManagerEpv = NullManagerEpv;
  330. RpcStatus = DispatchToStubWorker(Message, CallbackFlag, DispatchTableToUse, ExceptionCode);
  331. if ( RpcStatus != RPC_S_OK
  332. || (((MESSAGE_OBJECT *) Message->Handle)->IsSyncCall()
  333. && CallbackFlag == 0 ))
  334. {
  335. NullManagerActiveCallCount.Decrement();
  336. }
  337. //
  338. // DispatchToStubWorker freed Message.Buffer if an error occurred.
  339. //
  340. return(RpcStatus);
  341. }
  342. RPC_STATUS
  343. RPC_INTERFACE::DispatchToStubWorker (
  344. IN OUT PRPC_MESSAGE Message,
  345. IN unsigned int CallbackFlag,
  346. IN PRPC_DISPATCH_TABLE DispatchTableToUse,
  347. OUT RPC_STATUS PAPI * ExceptionCode
  348. )
  349. /*++
  350. Routine Description:
  351. This method is used to dispatch remote procedure calls to the
  352. appropriate stub and hence to the appropriate manager entry point.
  353. It will be used for calls with and without objects specified.
  354. We go to great pains to insure that we do not grab a mutex.
  355. Arguments:
  356. Message - Supplies the response message and returns the reply
  357. message. If this routine returns anything other than RPC_S_OK
  358. Message->Buffer has already been freed.
  359. CallbackFlag - Supplies a flag indicating whether this is a callback
  360. or not. The argument will be zero if this is an original call,
  361. and non-zero if it is a callback.
  362. DispatchTableToUse - a pointer to the dispatch table to use. This is
  363. used to select b/n stubs for NDR20 and NDR64 transfer syntaxes
  364. ExceptionCode - Returns the exact exception code if an exception
  365. occurs.
  366. Return Value:
  367. RPC_S_OK - This value will be returned if the operation completed
  368. successfully.
  369. RPC_S_PROCNUM_OUT_OF_RANGE - If the procedure number for this call is
  370. too large, this value will be returned.
  371. RPC_S_NOT_LISTENING - The rpc server which owns this rpc interface
  372. is not listening for remote procedure calls right now.
  373. RPC_S_SERVER_TOO_BUSY - This call will cause there to be too many
  374. concurrent remote procedure calls for the rpc server which owns
  375. this interface.
  376. RPC_P_EXCEPTION_OCCURED - A fault occured, and we need to remote it. The
  377. ExceptionCode argument will contain the exception code for the
  378. fault.
  379. --*/
  380. {
  381. RPC_STATUS RpcStatus = RPC_S_OK;
  382. void * OldServerContextList;
  383. unsigned int procnum ;
  384. THREAD *Self = RpcpGetThreadPointer() ;
  385. ASSERT(Self);
  386. if (Flags & RPC_IF_OLE)
  387. {
  388. procnum = 0 ;
  389. }
  390. else
  391. {
  392. procnum = Message->ProcNum ;
  393. }
  394. if (CallbackFlag == 0)
  395. {
  396. if (IsAutoListenInterface())
  397. {
  398. if (AutoListenCallCount.GetInteger() >= (long) MaxCalls)
  399. {
  400. RpcStatus = RPC_S_SERVER_TOO_BUSY ;
  401. RpcpErrorAddRecord(EEInfoGCRuntime,
  402. RpcStatus,
  403. EEInfoDLDispatchToStubWorker10,
  404. (ULONG)AutoListenCallCount.GetInteger(),
  405. (ULONG)MaxCalls);
  406. }
  407. }
  408. else
  409. {
  410. if (Server->IsServerListening() == 0)
  411. {
  412. RpcStatus = RPC_S_NOT_LISTENING;
  413. RpcpErrorAddRecord(EEInfoGCRuntime,
  414. RpcStatus,
  415. EEInfoDLDispatchToStubWorker20);
  416. }
  417. else if (Server->fAccountForMaxCalls && Server->CallBeginning() == 0)
  418. {
  419. RpcStatus = RPC_S_SERVER_TOO_BUSY;
  420. RpcpErrorAddRecord(EEInfoGCRuntime,
  421. RpcStatus,
  422. EEInfoDLDispatchToStubWorker30);
  423. }
  424. }
  425. }
  426. if (procnum >=
  427. DispatchTableToUse->DispatchTableCount)
  428. {
  429. if (RpcStatus != RPC_S_SERVER_TOO_BUSY)
  430. {
  431. EndCall(CallbackFlag) ;
  432. }
  433. RpcStatus = RPC_S_PROCNUM_OUT_OF_RANGE;
  434. RpcpErrorAddRecord(EEInfoGCRuntime,
  435. RpcStatus,
  436. EEInfoDLDispatchToStubWorker40);
  437. }
  438. if (RpcStatus != RPC_S_OK)
  439. {
  440. MO(Message)->FreeBuffer(Message);
  441. return RpcStatus;
  442. }
  443. Server->IncomingCall();
  444. ((PRPC_RUNTIME_INFO) Message->ReservedForRuntime)->OldBuffer =
  445. Message->Buffer ;
  446. Message->RpcInterfaceInformation = &RpcInterfaceInformation;
  447. SCALL(Message)->DoPreDispatchProcessing(Message, CallbackFlag);
  448. if ( DispatchToStubInC(DispatchTableToUse->DispatchTable[procnum], Message, ExceptionCode) != 0 )
  449. {
  450. LogEvent(SU_EXCEPT, EV_STATUS, LongToPtr(*ExceptionCode),
  451. DispatchTableToUse->DispatchTable[procnum], (ULONG_PTR)Message, 1, 1);
  452. #if defined(DBG) && defined(i386)
  453. #if 1
  454. RtlCheckForOrphanedCriticalSections(NtCurrentThread());
  455. #endif
  456. #endif
  457. RpcStatus = RPC_P_EXCEPTION_OCCURED;
  458. RpcpErrorAddRecord(EEInfoGCApplication,
  459. *ExceptionCode,
  460. EEInfoDLRaiseExc,
  461. GetInterfaceFirstDWORD(),
  462. (short)procnum,
  463. Message->RpcFlags,
  464. GetCurrentThreadId());
  465. }
  466. RPC_MESSAGE OriginalMessage ;
  467. OriginalMessage.ReservedForRuntime = 0;
  468. OriginalMessage.Buffer =
  469. ((PRPC_RUNTIME_INFO) Message->ReservedForRuntime)->OldBuffer;
  470. Self->ResetYield();
  471. if (Self->IsSyncCall())
  472. {
  473. //
  474. // Since this is a sync call, we know that it has
  475. // not been freed yet. So we can safely touch it.
  476. //
  477. SCALL(Message)->DoPostDispatchProcessing();
  478. //
  479. // The dispatched call was a sync call
  480. //
  481. if (RPC_S_OK == RpcStatus)
  482. {
  483. //
  484. // If the stub didn't allocate an output buffer, do so now.
  485. //
  486. if (OriginalMessage.Buffer == Message->Buffer)
  487. {
  488. Message->RpcFlags = 0;
  489. Message->BufferLength = 0;
  490. MO(Message)->GetBuffer(Message, 0);
  491. }
  492. //
  493. // Free the [in] buffer that we saved.
  494. //
  495. MO(Message)->FreeBuffer(&OriginalMessage);
  496. EndCall(CallbackFlag) ;
  497. }
  498. else
  499. {
  500. ASSERT(RpcStatus == RPC_P_EXCEPTION_OCCURED) ;
  501. //
  502. // Free the buffer in the caller's message; this can be either
  503. // the [in] buffer or the [out] buffer, depending upon which
  504. // line of the stub caused the error.
  505. //
  506. // If the exception occurred after allocating the [out] buffer,
  507. // also free the [in] buffer.
  508. //
  509. if (OriginalMessage.Buffer != Message->Buffer)
  510. {
  511. MO(Message)->FreeBuffer(&OriginalMessage);
  512. }
  513. if (Message->Buffer)
  514. {
  515. MO(Message)->FreeBuffer(Message);
  516. }
  517. EndCall(CallbackFlag) ;
  518. }
  519. }
  520. else
  521. {
  522. //
  523. // The dispatched call was an async call
  524. //
  525. if (RpcStatus != RPC_S_OK
  526. && OriginalMessage.Buffer != Message->Buffer)
  527. {
  528. //
  529. // The dispatch buffer will be freed during cleanup
  530. // of the async call
  531. //
  532. MO(Message)->FreeBuffer(Message);
  533. }
  534. }
  535. return(RpcStatus);
  536. }
  537. void
  538. RPC_INTERFACE::EndCall(
  539. IN unsigned int CallbackFlag,
  540. BOOL fAsync
  541. )
  542. {
  543. if (fAsync)
  544. {
  545. NullManagerActiveCallCount.Decrement();
  546. }
  547. if (CallbackFlag == 0)
  548. {
  549. if (!(Flags & RPC_IF_AUTOLISTEN) && Server->fAccountForMaxCalls)
  550. {
  551. Server->CallEnding();
  552. }
  553. }
  554. }
  555. RPC_STATUS
  556. RPC_INTERFACE::DispatchToStubWithObject (
  557. IN OUT PRPC_MESSAGE Message,
  558. IN RPC_UUID * ObjectUuid,
  559. IN unsigned int CallbackFlag,
  560. IN PRPC_DISPATCH_TABLE DispatchTableToUse,
  561. OUT RPC_STATUS PAPI * ExceptionCode
  562. )
  563. /*++
  564. Routine Description:
  565. This method is used to dispatch remote procedure calls to the
  566. appropriate stub and hence to the appropriate manager entry point.
  567. This routine is used for calls which have an associated object.
  568. Arguments:
  569. Message - Supplies the response message and returns the reply
  570. message.
  571. ObjectUuid - Supplies the object uuid to map into the manager entry
  572. point for this call.
  573. CallbackFlag - Supplies a flag indicating whether this is a callback
  574. or not. The argument will be zero if this is an original call,
  575. and non-zero if it is a callback.
  576. ExceptionCode - Returns the exact exception code if an exception
  577. occurs.
  578. Return Value:
  579. RPC_S_OK - The operation completed successfully.
  580. RPC_S_PROCNUM_OUT_OF_RANGE - If the procedure number for this call is
  581. too large, this value will be returned.
  582. RPC_S_UNKNOWN_IF - If the specified manager is no longer
  583. valid, you will get this value back.
  584. RPC_S_NOT_LISTENING - The rpc server which owns this rpc interface
  585. is not listening for remote procedure calls right now.
  586. RPC_S_SERVER_TOO_BUSY - This call will cause there to be too many
  587. concurrent remote procedure calls for the rpc server which owns
  588. this interface.
  589. RPC_P_EXCEPTION_OCCURED - A fault occured, and we need to remote it. The
  590. ExceptionCode argument will contain the exception code for the
  591. fault.
  592. RPC_S_UNSUPPORTED_TYPE - There is no type manager for the object's type
  593. for this interface.
  594. --*/
  595. {
  596. RPC_UUID TypeUuid;
  597. RPC_STATUS RpcStatus;
  598. RPC_INTERFACE_MANAGER * RpcInterfaceManager;
  599. RpcStatus = ObjectInqType(ObjectUuid, &TypeUuid);
  600. VALIDATE(RpcStatus)
  601. {
  602. RPC_S_OK,
  603. RPC_S_OBJECT_NOT_FOUND
  604. } END_VALIDATE;
  605. if ( RpcStatus == RPC_S_OK )
  606. {
  607. RpcInterfaceManager = FindInterfaceManager(&TypeUuid);
  608. if ( ( RpcInterfaceManager != 0 )
  609. && ( ( CallbackFlag != 0 )
  610. || ( RpcInterfaceManager->ValidManager() != 0 ) ) )
  611. {
  612. Message->ManagerEpv = RpcInterfaceManager->QueryManagerEpv();
  613. if ( CallbackFlag == 0 )
  614. {
  615. RpcInterfaceManager->CallBeginning();
  616. }
  617. RpcStatus = DispatchToStubWorker(Message, CallbackFlag, DispatchTableToUse,
  618. ExceptionCode);
  619. if ( CallbackFlag == 0 )
  620. {
  621. RpcInterfaceManager->CallEnding();
  622. }
  623. return(RpcStatus);
  624. }
  625. if (this != GlobalManagementInterface)
  626. {
  627. // There is a type for this object, but no type manager for
  628. // this interface.
  629. RpcStatus = RPC_S_UNSUPPORTED_TYPE;
  630. if ( ManagerCount == 0 )
  631. {
  632. RpcStatus = RPC_S_UNKNOWN_IF;
  633. }
  634. ((MESSAGE_OBJECT *) Message->Handle)->FreeBuffer(Message);
  635. return RpcStatus;
  636. }
  637. }
  638. // There has not been a type registered for this object, so we will
  639. // just go ahead and try and use the NULL type manager.
  640. return(DispatchToStub(Message, CallbackFlag, DispatchTableToUse, ExceptionCode));
  641. }
  642. BOOL
  643. RPC_INTERFACE::IsObjectSupported (
  644. IN RPC_UUID * ObjectUuid
  645. )
  646. /*++
  647. Routine Description:
  648. Determines whether the manager for the given object UUID is registered.
  649. Arguments:
  650. ObjectUuid - the client's object UUID
  651. Return Value:
  652. RPC_S_OK if it is OK to dispatch
  653. RPC_S_UNKNOWN_IF if the interface is not registered
  654. RPC_S_UNSUPPORTED_TYPE if this particular object's type is not registered
  655. --*/
  656. {
  657. RPC_STATUS Status = RPC_S_OK;
  658. if (ObjectUuid->IsNullUuid() )
  659. {
  660. if ( NullManagerFlag == 0 )
  661. {
  662. Status = RPC_S_UNSUPPORTED_TYPE;
  663. if ( ManagerCount == 0 )
  664. {
  665. Status = RPC_S_UNKNOWN_IF;
  666. }
  667. }
  668. }
  669. else
  670. {
  671. RPC_UUID TypeUuid;
  672. Status = ObjectInqType(ObjectUuid, &TypeUuid);
  673. if ( Status == RPC_S_OK )
  674. {
  675. RPC_INTERFACE_MANAGER * RpcInterfaceManager = 0;
  676. RpcInterfaceManager = FindInterfaceManager(&TypeUuid);
  677. if (!RpcInterfaceManager ||
  678. !RpcInterfaceManager->ValidManager())
  679. {
  680. Status = RPC_S_UNSUPPORTED_TYPE;
  681. if ( ManagerCount == 0 )
  682. {
  683. Status = RPC_S_UNKNOWN_IF;
  684. }
  685. }
  686. }
  687. else
  688. {
  689. Status = RPC_S_OK;
  690. if ( NullManagerFlag == 0 )
  691. {
  692. Status = RPC_S_UNSUPPORTED_TYPE;
  693. if ( ManagerCount == 0 )
  694. {
  695. Status = RPC_S_UNKNOWN_IF;
  696. }
  697. }
  698. }
  699. }
  700. return Status;
  701. }
  702. RPC_STATUS
  703. RPC_INTERFACE::UpdateBindings (
  704. IN RPC_BINDING_VECTOR *BindingVector
  705. )
  706. /*++
  707. Function Name:UpdateEpMapperBindings
  708. Parameters:
  709. Description:
  710. Returns:
  711. --*/
  712. {
  713. RPC_STATUS Status;
  714. unsigned int Length;
  715. #if !defined(NO_LOCATOR_CODE)
  716. NS_ENTRY *NsEntry;
  717. #endif
  718. DictionaryCursor cursor;
  719. if (fBindingsExported)
  720. {
  721. Status = RegisterEntries(&RpcInterfaceInformation,
  722. BindingVector,
  723. UuidVector,
  724. (unsigned char *) Annotation,
  725. fReplace);
  726. if (Status != RPC_S_OK)
  727. {
  728. return Status;
  729. }
  730. }
  731. #if !defined(NO_LOCATOR_CODE)
  732. // shortcut the common path and avoid taking and holding
  733. // unnecessarily the high contention global mutex
  734. if (NsEntries.Size() == 0)
  735. return RPC_S_OK;
  736. RequestGlobalMutex();
  737. NsEntries.Reset(cursor);
  738. while ((NsEntry = NsEntries.Next(cursor)) != 0)
  739. {
  740. //
  741. // Actually update the locator bindings
  742. //
  743. Status = GlobalRpcServer->NsBindingUnexport(
  744. NsEntry->EntryNameSyntax,
  745. NsEntry->EntryName,
  746. &RpcInterfaceInformation);
  747. if (Status == RPC_S_OK)
  748. {
  749. Status = GlobalRpcServer->NsBindingExport(
  750. NsEntry->EntryNameSyntax,
  751. NsEntry->EntryName,
  752. &RpcInterfaceInformation,
  753. BindingVector);
  754. #if DBG
  755. if (Status != RPC_S_OK)
  756. {
  757. PrintToDebugger("RPC: Bindings were unexported, but could not re-export\n");
  758. }
  759. #endif
  760. }
  761. }
  762. ClearGlobalMutex();
  763. #endif
  764. return RPC_S_OK;
  765. }
  766. RPC_STATUS
  767. RPC_INTERFACE::InterfaceExported (
  768. IN UUID_VECTOR *MyObjectUuidVector,
  769. IN unsigned char *MyAnnotation,
  770. IN BOOL MyfReplace
  771. )
  772. /*++
  773. Function Name:InterfaceExported
  774. Parameters:
  775. Description:
  776. RpcEpRegister was called on this interface. We need to keep track
  777. of the parameters, so that if we get a PNP notification, we can update
  778. the bindings using there params
  779. Returns:
  780. RPC_S_OK: things went fine
  781. RPC_S_OUT_OF_MEMORY: ran out of memory
  782. --*/
  783. {
  784. RequestGlobalMutex();
  785. if (UuidVector
  786. && UuidVector != MyObjectUuidVector)
  787. {
  788. RpcpFarFree(UuidVector);
  789. UuidVector = 0;
  790. }
  791. if (MyObjectUuidVector)
  792. {
  793. if (UuidVector != MyObjectUuidVector)
  794. {
  795. int Size = MyObjectUuidVector->Count*(sizeof(UUID)+sizeof(UUID *))
  796. +sizeof(unsigned long);
  797. UUID *Uuids;
  798. unsigned i;
  799. UuidVector = (UUID_VECTOR *) RpcpFarAllocate(Size);
  800. if (UuidVector == 0)
  801. {
  802. ClearGlobalMutex();
  803. return RPC_S_OUT_OF_MEMORY;
  804. }
  805. Uuids = (UUID *) ((char *) UuidVector + sizeof(unsigned long)
  806. +(sizeof(UUID *) * MyObjectUuidVector->Count));
  807. UuidVector->Count = MyObjectUuidVector->Count;
  808. for (i = 0; i < UuidVector->Count; i++)
  809. {
  810. Uuids[i] = *(MyObjectUuidVector->Uuid[i]);
  811. UuidVector->Uuid[i] = &Uuids[i];
  812. }
  813. }
  814. }
  815. else
  816. {
  817. UuidVector = 0;
  818. }
  819. if (MyAnnotation)
  820. {
  821. strncpy((char *) Annotation, (char *) MyAnnotation, 63);
  822. Annotation[63]=0;
  823. }
  824. else
  825. {
  826. Annotation[0] = 0;
  827. }
  828. fReplace = MyfReplace;
  829. fBindingsExported = 1;
  830. ClearGlobalMutex();
  831. return RPC_S_OK;
  832. }
  833. #if !defined(NO_LOCATOR_CODE)
  834. NS_ENTRY *
  835. RPC_INTERFACE::FindEntry (
  836. IN unsigned long EntryNameSyntax,
  837. IN RPC_CHAR *EntryName
  838. )
  839. {
  840. NS_ENTRY *NsEntry;
  841. DictionaryCursor cursor;
  842. //
  843. // This function will always be called with the mutex held
  844. //
  845. NsEntries.Reset(cursor);
  846. while ((NsEntry = NsEntries.Next(cursor)) != 0)
  847. {
  848. if (NsEntry->Match(EntryNameSyntax, EntryName))
  849. {
  850. return NsEntry;
  851. }
  852. }
  853. return 0;
  854. }
  855. RPC_STATUS
  856. RPC_INTERFACE::NsInterfaceUnexported (
  857. IN unsigned long EntryNameSyntax,
  858. IN RPC_CHAR *EntryName
  859. )
  860. {
  861. NS_ENTRY *NsEntry;
  862. RequestGlobalMutex();
  863. NsEntry = FindEntry(EntryNameSyntax, EntryName);
  864. if (NsEntry == 0)
  865. {
  866. ClearGlobalMutex();
  867. #if DBG
  868. PrintToDebugger("RPC: No corresponding exported entry\n");
  869. #endif
  870. return RPC_S_ENTRY_NOT_FOUND;
  871. }
  872. NsEntries.Delete(NsEntry->Key);
  873. ClearGlobalMutex();
  874. return RPC_S_OK;
  875. }
  876. RPC_STATUS
  877. RPC_INTERFACE::NsInterfaceExported (
  878. IN unsigned long EntryNameSyntax,
  879. IN RPC_CHAR *EntryName
  880. )
  881. {
  882. RPC_STATUS Status = RPC_S_OK;
  883. NS_ENTRY *NsEntry;
  884. int retval;
  885. RequestGlobalMutex();
  886. NsEntry = FindEntry(EntryNameSyntax, EntryName);
  887. ClearGlobalMutex();
  888. if (NsEntry)
  889. {
  890. return RPC_S_OK;
  891. }
  892. NsEntry = new NS_ENTRY(
  893. EntryNameSyntax,
  894. EntryName,
  895. &Status);
  896. if (NsEntry == 0)
  897. {
  898. return RPC_S_OUT_OF_MEMORY;
  899. }
  900. if (Status != RPC_S_OK)
  901. {
  902. delete NsEntry;
  903. return Status;
  904. }
  905. RequestGlobalMutex();
  906. NsEntry->Key = NsEntries.Insert(NsEntry);
  907. ClearGlobalMutex();
  908. if (NsEntry->Key == -1)
  909. {
  910. delete NsEntry;
  911. return RPC_S_OUT_OF_MEMORY;
  912. }
  913. return RPC_S_OK;
  914. }
  915. #endif
  916. static unsigned int
  917. MatchSyntaxIdentifiers (
  918. IN PRPC_SYNTAX_IDENTIFIER ServerSyntax,
  919. IN PRPC_SYNTAX_IDENTIFIER ClientSyntax
  920. )
  921. /*++
  922. Routine Description:
  923. This method compares two syntax identifiers (which consist of a
  924. uuid, a major version number, and a minor version number). In
  925. order for the syntax identifiers to match, the uuids must be the
  926. same, the major version numbers must be the same, and the client
  927. minor version number must be less than or equal to the server
  928. minor version number.
  929. Arguments:
  930. ServerSyntax - Supplies the server syntax identifier.
  931. ClientSyntax - Supplies the client syntax identifer.
  932. Return Value:
  933. Zero will be returned if the client syntax identifier matches the
  934. server syntax identifier; otherwise, non-zero will be returned.
  935. --*/
  936. {
  937. if (RpcpMemoryCompare(&(ServerSyntax->SyntaxGUID),
  938. &(ClientSyntax->SyntaxGUID), sizeof(UUID)) != 0)
  939. return(1);
  940. if (ServerSyntax->SyntaxVersion.MajorVersion
  941. != ClientSyntax->SyntaxVersion.MajorVersion)
  942. return(1);
  943. if (ServerSyntax->SyntaxVersion.MinorVersion
  944. < ClientSyntax->SyntaxVersion.MinorVersion)
  945. return(1);
  946. return(0);
  947. }
  948. unsigned int
  949. RPC_INTERFACE::MatchInterfaceIdentifier (
  950. IN PRPC_SYNTAX_IDENTIFIER InterfaceIdentifier
  951. )
  952. /*++
  953. Routine Description:
  954. This method compares the supplied interface identifier (which consists
  955. of the interface uuid and interface version) against that contained
  956. in this rpc interface. In order for this rpc interface to match,
  957. the interface uuids must be the same, the interface major versions
  958. must be the same, and the supplied interface minor version must be
  959. less than or equal to the interface minor version contained in this
  960. rpc interface.
  961. Arguments:
  962. InterfaceIdentifier - Supplies the interface identifier to compare
  963. against that contained in this rpc interface.
  964. Return Value:
  965. Zero will be returned if the supplied interface identifer matches
  966. (according to the rules described above) the interface identifier
  967. contained in this rpc interface; otherwise, non-zero will be returned.
  968. --*/
  969. {
  970. if (ManagerCount == 0)
  971. return(1);
  972. return(MatchSyntaxIdentifiers(&(RpcInterfaceInformation.InterfaceId),
  973. InterfaceIdentifier));
  974. }
  975. unsigned int
  976. RPC_INTERFACE::SelectTransferSyntax (
  977. IN PRPC_SYNTAX_IDENTIFIER ProposedTransferSyntaxes,
  978. IN unsigned int NumberOfTransferSyntaxes,
  979. OUT PRPC_SYNTAX_IDENTIFIER AcceptedTransferSyntax,
  980. OUT BOOL *fIsInterfaceTransferPreferred,
  981. OUT int *ProposedTransferSyntaxIndex,
  982. OUT int *AvailableTransferSyntaxIndex
  983. )
  984. /*++
  985. Routine Description:
  986. This method is used to select a transfer syntax from a list of one
  987. or more transfer syntaxes. If a transfer syntax is selected, then
  988. it will be returned in one of the arguments.
  989. Arguments:
  990. ProposedTransferSyntaxes - Supplies a list of one or more transfer
  991. syntaxes from which this interface should select one which it
  992. supports if possible.
  993. NumberOfTransferSyntaxes - Supplies the number of transfer syntaxes
  994. in the proposed transfer syntaxes argument.
  995. AcceptedTransferSyntax - Returns the selected transfer syntax, if
  996. one is selected.
  997. fIsInterfaceTransferPreferred - true if the selected transfer syntax
  998. is preferred by the server
  999. ProposedTransferSyntaxIndex - the index of the transfer syntax that is
  1000. chosen from the proposed transfer syntaxes array. Zero based.
  1001. AvailableTransferSyntaxIndex - the index of the transfer syntax that is
  1002. chosen from the available transfer syntaxes in the interface. This
  1003. value must be stored in the binding and retrieved when asking for the
  1004. transfer syntax and dispatch table. Zero based.
  1005. Return Value:
  1006. Zero will be returned if a transfer syntax is selected; otherwise,
  1007. non-zero will be returned.
  1008. --*/
  1009. {
  1010. unsigned int ProposedIndex;
  1011. unsigned int AvailableIndex;
  1012. unsigned int NumberOfAvailableSyntaxes;
  1013. BOOL fMultipleTranfserSyntaxesSelected;
  1014. RPC_SYNTAX_IDENTIFIER *CurrentTransferSyntax;
  1015. RPC_SYNTAX_IDENTIFIER *BackupTransferSyntax = NULL;
  1016. int BackupProposedTransferSyntaxIndex;
  1017. int BackupAvailableTransferSyntaxIndex;
  1018. fMultipleTranfserSyntaxesSelected = AreMultipleTransferSyntaxesSupported();
  1019. if (fMultipleTranfserSyntaxesSelected)
  1020. NumberOfAvailableSyntaxes = NumberOfSupportedTransferSyntaxes;
  1021. else
  1022. NumberOfAvailableSyntaxes = 1;
  1023. for (AvailableIndex = 0; AvailableIndex < NumberOfAvailableSyntaxes; AvailableIndex ++)
  1024. {
  1025. if (fMultipleTranfserSyntaxesSelected)
  1026. CurrentTransferSyntax = &(TransferSyntaxesArray[AvailableIndex].TransferSyntax);
  1027. else
  1028. CurrentTransferSyntax = &RpcInterfaceInformation.TransferSyntax;
  1029. for (ProposedIndex = 0; ProposedIndex < NumberOfTransferSyntaxes;
  1030. ProposedIndex++)
  1031. {
  1032. if (MatchSyntaxIdentifiers(CurrentTransferSyntax,
  1033. &(ProposedTransferSyntaxes[ProposedIndex])) == 0)
  1034. {
  1035. // is this the preferred transfer syntax for the server?
  1036. if (AvailableIndex == PreferredTransferSyntax)
  1037. {
  1038. // this is the preferred transfer syntax - just
  1039. // copy it and return
  1040. RpcpMemoryCopy(AcceptedTransferSyntax,
  1041. &(ProposedTransferSyntaxes[ProposedIndex]),
  1042. sizeof(RPC_SYNTAX_IDENTIFIER));
  1043. *fIsInterfaceTransferPreferred = TRUE;
  1044. *ProposedTransferSyntaxIndex = ProposedIndex;
  1045. *AvailableTransferSyntaxIndex = AvailableIndex;
  1046. return(0);
  1047. }
  1048. else
  1049. {
  1050. // this is not the preferred syntax - just remeber this
  1051. // one (if no previous match was found) and continue
  1052. if (BackupTransferSyntax == NULL)
  1053. {
  1054. BackupTransferSyntax = &(ProposedTransferSyntaxes[ProposedIndex]);
  1055. BackupProposedTransferSyntaxIndex = ProposedIndex;
  1056. BackupAvailableTransferSyntaxIndex = AvailableIndex;
  1057. }
  1058. }
  1059. }
  1060. }
  1061. }
  1062. // if we're here, this means we didn't find the preferred transfer syntax
  1063. // check whether there is a backup syntax
  1064. if (BackupTransferSyntax)
  1065. {
  1066. RpcpMemoryCopy(AcceptedTransferSyntax, BackupTransferSyntax,
  1067. sizeof(RPC_SYNTAX_IDENTIFIER));
  1068. *fIsInterfaceTransferPreferred = FALSE;
  1069. *ProposedTransferSyntaxIndex = BackupProposedTransferSyntaxIndex;
  1070. *AvailableTransferSyntaxIndex = BackupAvailableTransferSyntaxIndex;
  1071. return(0);
  1072. }
  1073. // nada - no transfer syntax matches
  1074. return(1);
  1075. }
  1076. void RPC_INTERFACE::GetSelectedTransferSyntaxAndDispatchTable(IN int SelectedTransferSyntaxIndex,
  1077. OUT RPC_SYNTAX_IDENTIFIER **SelectedTransferSyntax,
  1078. OUT PRPC_DISPATCH_TABLE *SelectedDispatchTable)
  1079. {
  1080. MIDL_SYNTAX_INFO *SelectedSyntaxInfo;
  1081. if (DoesInterfaceSupportMultipleTransferSyntaxes(&RpcInterfaceInformation))
  1082. {
  1083. ASSERT((unsigned int)SelectedTransferSyntaxIndex <= NumberOfSupportedTransferSyntaxes);
  1084. SelectedSyntaxInfo = &TransferSyntaxesArray[SelectedTransferSyntaxIndex];
  1085. *SelectedTransferSyntax = &SelectedSyntaxInfo->TransferSyntax;
  1086. // DCOM has only one dispatch table - they change the dispatch target
  1087. // internally. They will define only the dispatch table in the
  1088. // interface
  1089. if (SelectedSyntaxInfo->DispatchTable)
  1090. *SelectedDispatchTable = SelectedSyntaxInfo->DispatchTable;
  1091. else
  1092. *SelectedDispatchTable = GetDefaultDispatchTable();
  1093. }
  1094. else
  1095. {
  1096. *SelectedTransferSyntax = &RpcInterfaceInformation.TransferSyntax;
  1097. *SelectedDispatchTable = GetDefaultDispatchTable();
  1098. }
  1099. }
  1100. RPC_STATUS
  1101. RPC_INTERFACE::UnregisterManagerEpv (
  1102. IN RPC_UUID PAPI * ManagerTypeUuid, OPTIONAL
  1103. IN unsigned int WaitForCallsToComplete
  1104. )
  1105. /*++
  1106. Routine Description:
  1107. In this method, we unregister one or all of the manager entry point
  1108. vectors for this interface, depending on what, if anything, is
  1109. specified for the manager type uuid argument.
  1110. Arguments:
  1111. ManagerTypeUuid - Optionally supplies the type uuid of the manager
  1112. entry point vector to be removed. If this argument is not supplied,
  1113. then all manager entry point vectors for this interface will
  1114. be removed.
  1115. WaitForCallsToComplete - Supplies a flag indicating whether or not
  1116. this routine should wait for all calls to complete using the
  1117. interface and manager being unregistered. A non-zero value
  1118. indicates to wait.
  1119. Return Value:
  1120. RPC_S_OK - The manager entry point vector(s) are(were) successfully
  1121. removed from the this interface.
  1122. RPC_S_UNKNOWN_MGR_TYPE - The specified type uuid is not registered
  1123. with this interface.
  1124. RPC_S_UNKNOWN_IF - The specified interface is not registered with
  1125. the rpc server.
  1126. --*/
  1127. {
  1128. RPC_INTERFACE_MANAGER * InterfaceManager;
  1129. DictionaryCursor cursor;
  1130. RequestGlobalMutex();
  1131. if (ManagerCount == 0)
  1132. {
  1133. ClearGlobalMutex();
  1134. return(RPC_S_UNKNOWN_MGR_TYPE);
  1135. }
  1136. if (ARGUMENT_PRESENT(ManagerTypeUuid) == 0)
  1137. {
  1138. InterfaceManagerDictionary.Reset(cursor);
  1139. while ((InterfaceManager = InterfaceManagerDictionary.Next(cursor)) != 0)
  1140. {
  1141. InterfaceManager->InvalidateManager();
  1142. }
  1143. ManagerCount = 0;
  1144. NullManagerFlag = 0;
  1145. ClearGlobalMutex();
  1146. if ( WaitForCallsToComplete != 0 )
  1147. {
  1148. while ( NullManagerActiveCallCount.GetInteger() > 0 )
  1149. {
  1150. PauseExecution(500L);
  1151. }
  1152. InterfaceManagerDictionary.Reset(cursor);
  1153. while ((InterfaceManager = InterfaceManagerDictionary.Next(cursor)) != 0)
  1154. {
  1155. while ( InterfaceManager->InquireActiveCallCount() > 0 )
  1156. {
  1157. PauseExecution(500L);
  1158. }
  1159. }
  1160. }
  1161. return(RPC_S_OK);
  1162. }
  1163. if (ManagerTypeUuid->IsNullUuid() != 0)
  1164. {
  1165. if (NullManagerFlag == 0)
  1166. {
  1167. ClearGlobalMutex();
  1168. return(RPC_S_UNKNOWN_MGR_TYPE);
  1169. }
  1170. ManagerCount -= 1;
  1171. NullManagerFlag = 0;
  1172. ClearGlobalMutex();
  1173. if ( WaitForCallsToComplete != 0 )
  1174. {
  1175. while ( NullManagerActiveCallCount.GetInteger() > 0 )
  1176. {
  1177. PauseExecution(500L);
  1178. }
  1179. }
  1180. return(RPC_S_OK);
  1181. }
  1182. InterfaceManager = FindInterfaceManager(ManagerTypeUuid);
  1183. if ( (InterfaceManager == 0)
  1184. || (InterfaceManager->ValidManager() == 0))
  1185. {
  1186. ClearGlobalMutex();
  1187. return(RPC_S_UNKNOWN_MGR_TYPE);
  1188. }
  1189. InterfaceManager->InvalidateManager();
  1190. ManagerCount -= 1;
  1191. ClearGlobalMutex();
  1192. if ( WaitForCallsToComplete != 0 )
  1193. {
  1194. while ( InterfaceManager->InquireActiveCallCount() > 0 )
  1195. {
  1196. PauseExecution(500L);
  1197. }
  1198. }
  1199. return(RPC_S_OK);
  1200. }
  1201. RPC_STATUS
  1202. RPC_INTERFACE::InquireManagerEpv (
  1203. IN RPC_UUID PAPI * ManagerTypeUuid, OPTIONAL
  1204. OUT RPC_MGR_EPV PAPI * PAPI * ManagerEpv
  1205. )
  1206. /*++
  1207. Routine Description:
  1208. This method is used to obtain the manager entry point vector
  1209. with the specified type uuid supported by this interface.
  1210. Arguments:
  1211. ManagerTypeUuid - Optionally supplies the type uuid of the manager
  1212. entry point vector we want returned. If no manager type uuid
  1213. is specified, then the null uuid is assumed.
  1214. ManagerEpv - Returns the manager entry point vector.
  1215. Return Value:
  1216. RPC_S_OK - The manager entry point vector has successfully been
  1217. returned.
  1218. RPC_S_UNKNOWN_MGR_TYPE - The specified type uuid is not registered
  1219. with the interface.
  1220. RPC_S_UNKNOWN_IF - The specified interface is not registered with
  1221. the rpc server.
  1222. --*/
  1223. {
  1224. RPC_INTERFACE_MANAGER * InterfaceManager;
  1225. RequestGlobalMutex();
  1226. if (ManagerCount == 0)
  1227. {
  1228. ClearGlobalMutex();
  1229. return(RPC_S_UNKNOWN_IF);
  1230. }
  1231. if ( (ARGUMENT_PRESENT(ManagerTypeUuid) == 0)
  1232. || (ManagerTypeUuid->IsNullUuid() != 0))
  1233. {
  1234. if (NullManagerFlag == 0)
  1235. {
  1236. ClearGlobalMutex();
  1237. return(RPC_S_UNKNOWN_MGR_TYPE);
  1238. }
  1239. *ManagerEpv = NullManagerEpv;
  1240. ClearGlobalMutex();
  1241. return(RPC_S_OK);
  1242. }
  1243. InterfaceManager = FindInterfaceManager(ManagerTypeUuid);
  1244. if ( (InterfaceManager == 0)
  1245. || (InterfaceManager->ValidManager() == 0))
  1246. {
  1247. ClearGlobalMutex();
  1248. return(RPC_S_UNKNOWN_MGR_TYPE);
  1249. }
  1250. *ManagerEpv = InterfaceManager->QueryManagerEpv();
  1251. ClearGlobalMutex();
  1252. return(RPC_S_OK);
  1253. }
  1254. RPC_STATUS
  1255. RPC_INTERFACE::UpdateRpcInterfaceInformation (
  1256. IN RPC_SERVER_INTERFACE PAPI * RpcInterfaceInformation,
  1257. IN unsigned int Flags,
  1258. IN unsigned int MaxCalls,
  1259. IN unsigned int MaxRpcSize,
  1260. IN RPC_IF_CALLBACK_FN PAPI *IfCallbackFn
  1261. )
  1262. /*++
  1263. Routine Description:
  1264. We never delete the interface objects from a server; we just invalidate
  1265. them. This means that if an interface has been complete unregistered
  1266. (ie. it has no managers), we need to update the interface information
  1267. again.
  1268. Arguments:
  1269. RpcInterfaceInformation - Supplies the interface information which this
  1270. interface should be using.
  1271. --*/
  1272. {
  1273. unsigned int Length;
  1274. RPC_STATUS Status;
  1275. Length = RpcInterfaceInformation->Length;
  1276. ASSERT((Length == sizeof(RPC_SERVER_INTERFACE)) ||
  1277. (Length == NT351_INTERFACE_SIZE));
  1278. // make it stick on free builds as well
  1279. if ((Length != sizeof(RPC_SERVER_INTERFACE)) &&
  1280. (Length != NT351_INTERFACE_SIZE))
  1281. return RPC_S_UNKNOWN_IF;
  1282. if ( ManagerCount == 0 )
  1283. {
  1284. if (DoesInterfaceSupportMultipleTransferSyntaxes(RpcInterfaceInformation))
  1285. {
  1286. Status = NdrServerGetSupportedSyntaxes(RpcInterfaceInformation,
  1287. &NumberOfSupportedTransferSyntaxes,
  1288. &TransferSyntaxesArray, &PreferredTransferSyntax);
  1289. if (Status != RPC_S_OK)
  1290. return Status;
  1291. }
  1292. else
  1293. {
  1294. NumberOfSupportedTransferSyntaxes = 0;
  1295. }
  1296. RpcpMemoryCopy(&(this->RpcInterfaceInformation),
  1297. RpcInterfaceInformation, Length);
  1298. }
  1299. if (Flags & RPC_IF_AUTOLISTEN
  1300. && (this->Flags & RPC_IF_AUTOLISTEN) == 0)
  1301. {
  1302. GlobalRpcServer->IncrementAutoListenInterfaceCount() ;
  1303. }
  1304. this->Flags = Flags ;
  1305. this->MaxCalls = MaxCalls ;
  1306. this->MaxRpcSize = MaxRpcSize;
  1307. SequenceNumber++ ;
  1308. if (Flags & RPC_IF_ALLOW_SECURE_ONLY
  1309. && IfCallbackFn == NULL)
  1310. {
  1311. this->CallbackFn = DefaultCallbackFn;
  1312. }
  1313. else
  1314. {
  1315. this->CallbackFn = IfCallbackFn ;
  1316. }
  1317. return RPC_S_OK;
  1318. }
  1319. RPC_IF_ID __RPC_FAR *
  1320. RPC_INTERFACE::InquireInterfaceId (
  1321. )
  1322. /*++
  1323. Return Value:
  1324. If this interface is active, its interface id will be returned in a
  1325. newly allocated chunk of memory; otherwise, zero will be returned.
  1326. --*/
  1327. {
  1328. RPC_IF_ID __RPC_FAR * RpcIfId;
  1329. if ( ManagerCount == 0 )
  1330. {
  1331. return(0);
  1332. }
  1333. RpcIfId = (RPC_IF_ID __RPC_FAR *) RpcpFarAllocate(sizeof(RPC_IF_ID));
  1334. if ( RpcIfId == 0 )
  1335. {
  1336. return(0);
  1337. }
  1338. RpcIfId->Uuid = RpcInterfaceInformation.InterfaceId.SyntaxGUID;
  1339. RpcIfId->VersMajor =
  1340. RpcInterfaceInformation.InterfaceId.SyntaxVersion.MajorVersion;
  1341. RpcIfId->VersMinor =
  1342. RpcInterfaceInformation.InterfaceId.SyntaxVersion.MinorVersion;
  1343. return(RpcIfId);
  1344. }
  1345. RPC_STATUS
  1346. RPC_INTERFACE::CheckSecurityIfNecessary(
  1347. IN void * Context
  1348. )
  1349. {
  1350. //
  1351. // If manager count in non-zero, this interface is still registered
  1352. // If it has been registered with a call back function, invoke the callback
  1353. // function, else return success....
  1354. RPC_IF_ID RpcIfId;
  1355. RPC_STATUS RpcStatus = RPC_S_OK;
  1356. if (CallbackFn != 0)
  1357. {
  1358. RpcIfId.Uuid = RpcInterfaceInformation.InterfaceId.SyntaxGUID;
  1359. RpcIfId.VersMajor =
  1360. RpcInterfaceInformation.InterfaceId.SyntaxVersion.MajorVersion;
  1361. RpcIfId.VersMinor =
  1362. RpcInterfaceInformation.InterfaceId.SyntaxVersion.MinorVersion;
  1363. BeginAutoListenCall();
  1364. if (ManagerCount == 0)
  1365. {
  1366. EndAutoListenCall();
  1367. return (RPC_S_UNKNOWN_IF);
  1368. }
  1369. RpcTryExcept
  1370. {
  1371. RpcStatus = CallbackFn(&RpcIfId, Context);
  1372. }
  1373. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  1374. {
  1375. RpcStatus = RPC_S_ACCESS_DENIED;
  1376. }
  1377. RpcEndExcept
  1378. EndAutoListenCall();
  1379. }
  1380. return(RpcStatus);
  1381. }
  1382. void
  1383. RPC_INTERFACE::WaitForCalls(
  1384. )
  1385. /*++
  1386. Routine Description:
  1387. Waits for the completion of all the calls on a given interface.
  1388. --*/
  1389. {
  1390. DictionaryCursor cursor;
  1391. RPC_INTERFACE_MANAGER * InterfaceManager;
  1392. while ( NullManagerActiveCallCount.GetInteger() > 0 )
  1393. {
  1394. PauseExecution(500L);
  1395. }
  1396. InterfaceManagerDictionary.Reset(cursor);
  1397. while ((InterfaceManager = InterfaceManagerDictionary.Next(cursor)) != 0)
  1398. {
  1399. while ( InterfaceManager->InquireActiveCallCount() > 0 )
  1400. {
  1401. PauseExecution(500L);
  1402. }
  1403. }
  1404. }
  1405. RPC_SERVER::RPC_SERVER (
  1406. IN OUT RPC_STATUS PAPI * RpcStatus
  1407. ) : AvailableCallCount(0),
  1408. ServerMutex(RpcStatus,
  1409. TRUE // pre-allocate semaphore
  1410. ),
  1411. StopListeningEvent(RpcStatus),
  1412. ThreadCacheMutex(RpcStatus,
  1413. TRUE, // pre-allocate semaphore
  1414. 100
  1415. ),
  1416. NumAutoListenInterfaces(0)
  1417. /*++
  1418. Routine Description:
  1419. This routine will get called to construct an instance of the
  1420. RPC_SERVER class.
  1421. --*/
  1422. {
  1423. ALLOCATE_THIS(RPC_SERVER);
  1424. ServerListeningFlag = 0;
  1425. ListeningThreadFlag = 0;
  1426. WaitingThreadFlag = 0;
  1427. MinimumCallThreads = 1;
  1428. MaximumConcurrentCalls = 1;
  1429. IncomingRpcCount = 0;
  1430. OutgoingRpcCount = 0;
  1431. ReceivedPacketCount = 0;
  1432. SentPacketCount = 0;
  1433. ThreadCache = 0;
  1434. ListenStatusCode = RPC_S_OK;
  1435. fAccountForMaxCalls = TRUE;
  1436. pRpcForwardFunction = (RPC_FORWARD_FUNCTION *)0;
  1437. #if !defined(NO_LOCATOR_CODE)
  1438. pNsBindingExport = 0;
  1439. pNsBindingUnexport = 0;
  1440. #endif
  1441. }
  1442. RPC_INTERFACE *
  1443. RPC_SERVER::FindInterface (
  1444. IN RPC_SERVER_INTERFACE PAPI * RpcInterfaceInformation
  1445. )
  1446. /*++
  1447. Routine Description:
  1448. This method is used to find the rpc interface registered with this
  1449. server which matches the supplied rpc interface information.
  1450. Arguments:
  1451. RpcInterfaceInformation - Supplies the rpc interface information
  1452. identifying the rpc interface we are looking for.
  1453. Return Value:
  1454. The rpc interface matching the supplied rpc interface information
  1455. will be returned if it is found; otherwise, zero will be returned.
  1456. --*/
  1457. {
  1458. RPC_INTERFACE * RpcInterface;
  1459. DictionaryCursor cursor;
  1460. ServerMutex.VerifyOwned();
  1461. RpcInterfaceDictionary.Reset(cursor);
  1462. while ((RpcInterface = RpcInterfaceDictionary.Next(cursor)) != 0)
  1463. {
  1464. if (RpcInterface->MatchRpcInterfaceInformation(
  1465. RpcInterfaceInformation) == 0)
  1466. {
  1467. return(RpcInterface);
  1468. }
  1469. }
  1470. // The management interface is implicitly registered in all servers.
  1471. if ( (GlobalManagementInterface)
  1472. && (GlobalManagementInterface->MatchRpcInterfaceInformation(
  1473. RpcInterfaceInformation) == 0) )
  1474. {
  1475. return(GlobalManagementInterface);
  1476. }
  1477. return(0);
  1478. }
  1479. int
  1480. RPC_SERVER::AddInterface (
  1481. IN RPC_INTERFACE * RpcInterface
  1482. )
  1483. /*++
  1484. Routine Description:
  1485. This method will be used to all an rpc interface to the set of
  1486. interfaces known about by this server.
  1487. Arguments:
  1488. RpcInterface - Supplies the rpc interface to add to the set of
  1489. interfaces.
  1490. Return Value:
  1491. Zero will be returned if the interface is successfully added to
  1492. the set; otherwise, non-zero will be returned indicating that
  1493. insufficient memory is available to complete the operation.
  1494. --*/
  1495. {
  1496. if (RpcInterfaceDictionary.Insert(RpcInterface) == -1)
  1497. {
  1498. ServerMutex.Clear();
  1499. return(-1);
  1500. }
  1501. return(0);
  1502. }
  1503. RPC_STATUS
  1504. RPC_SERVER::FindInterfaceTransfer (
  1505. IN PRPC_SYNTAX_IDENTIFIER InterfaceIdentifier,
  1506. IN PRPC_SYNTAX_IDENTIFIER ProposedTransferSyntaxes,
  1507. IN unsigned int NumberOfTransferSyntaxes,
  1508. OUT PRPC_SYNTAX_IDENTIFIER AcceptedTransferSyntax,
  1509. OUT RPC_INTERFACE ** AcceptingRpcInterface,
  1510. OUT BOOL *fInterfaceTransferIsPreferred,
  1511. OUT int *ProposedTransferSyntaxIndex,
  1512. OUT int *AvailableTransferSyntaxIndex
  1513. )
  1514. /*++
  1515. Routine Description:
  1516. This method is used to determine if a client bind request can be
  1517. accepted or not. All we have got to do here is hand off to the
  1518. server which owns this address.
  1519. Arguments:
  1520. InterfaceIdentifier - Supplies the syntax identifier for the
  1521. interface; this is the interface uuid and version.
  1522. ProposedTransferSyntaxes - Supplies a list of one or more transfer
  1523. syntaxes which the client initiating the binding supports. The
  1524. server should pick one of these which is supported by the
  1525. interface.
  1526. NumberOfTransferSyntaxes - Supplies the number of transfer syntaxes
  1527. specified in the proposed transfer syntaxes argument.
  1528. AcceptedTransferSyntax - Returns the transfer syntax which the
  1529. server accepted.
  1530. AcceptingRpcInterface - Returns a pointer to the rpc interface found
  1531. which supports the requested interface and one of the requested
  1532. transfer syntaxes.
  1533. fInterfaceTransferIsPreferred - non zero if the interface transfer
  1534. returned is preferred.
  1535. TransferSyntaxIndex - the index of the chosen transfer syntax in the
  1536. ProposedTransferSyntaxesArray
  1537. Return Value:
  1538. RPC_S_OK - The requested interface exists and it supports at least
  1539. one of the proposed transfer syntaxes. We are all set, now we
  1540. can make remote procedure calls.
  1541. RPC_S_UNSUPPORTED_TRANSFER_SYNTAX - The requested interface exists,
  1542. but it does not support any of the proposed transfer syntaxes.
  1543. RPC_S_UNKNOWN_IF - The requested interface is not supported
  1544. by this rpc server.
  1545. --*/
  1546. {
  1547. RPC_INTERFACE * RpcInterface;
  1548. unsigned int InterfaceFound = 0;
  1549. DictionaryCursor cursor;
  1550. ServerMutex.Request();
  1551. RpcInterfaceDictionary.Reset(cursor);
  1552. while ((RpcInterface = RpcInterfaceDictionary.Next(cursor)) != 0)
  1553. {
  1554. if (RpcInterface->MatchInterfaceIdentifier(InterfaceIdentifier) == 0)
  1555. {
  1556. InterfaceFound = 1;
  1557. if (RpcInterface->SelectTransferSyntax(ProposedTransferSyntaxes,
  1558. NumberOfTransferSyntaxes, AcceptedTransferSyntax,
  1559. fInterfaceTransferIsPreferred, ProposedTransferSyntaxIndex,
  1560. AvailableTransferSyntaxIndex) == 0)
  1561. {
  1562. ServerMutex.Clear();
  1563. *AcceptingRpcInterface = RpcInterface;
  1564. return(RPC_S_OK);
  1565. }
  1566. }
  1567. }
  1568. ServerMutex.Clear();
  1569. // The management interface is implicitly registered in all servers.
  1570. if ( (GlobalManagementInterface)
  1571. && (GlobalManagementInterface->MatchInterfaceIdentifier(
  1572. InterfaceIdentifier) == 0 ) )
  1573. {
  1574. InterfaceFound = 1;
  1575. if (GlobalManagementInterface->SelectTransferSyntax(
  1576. ProposedTransferSyntaxes, NumberOfTransferSyntaxes,
  1577. AcceptedTransferSyntax, fInterfaceTransferIsPreferred,
  1578. ProposedTransferSyntaxIndex, AvailableTransferSyntaxIndex) == 0)
  1579. {
  1580. *AcceptingRpcInterface = GlobalManagementInterface;
  1581. return(RPC_S_OK);
  1582. }
  1583. }
  1584. if (InterfaceFound == 0)
  1585. return(RPC_S_UNKNOWN_IF);
  1586. return(RPC_S_UNSUPPORTED_TRANS_SYN);
  1587. }
  1588. RPC_INTERFACE *
  1589. RPC_SERVER::FindInterface (
  1590. IN PRPC_SYNTAX_IDENTIFIER InterfaceIdentifier
  1591. )
  1592. /*++
  1593. Routine Description:
  1594. The datagram protocol module will use this routine to find the interface
  1595. with out worrying about the transfer syntax. Datagram RPC does not support
  1596. more than a single transfer syntax.
  1597. Arguments:
  1598. InterfaceIdentifier - Supplies the identifier (UUID and version) of the
  1599. interface we are trying to find.
  1600. Return Value:
  1601. If the interface is found it will be returned; otherwise, zero will be
  1602. returned.
  1603. --*/
  1604. {
  1605. RPC_INTERFACE * RpcInterface;
  1606. DictionaryCursor cursor;
  1607. ServerMutex.Request();
  1608. RpcInterfaceDictionary.Reset(cursor);
  1609. while ( (RpcInterface = RpcInterfaceDictionary.Next(cursor)) != 0)
  1610. {
  1611. if ( RpcInterface->MatchInterfaceIdentifier(InterfaceIdentifier)
  1612. == 0 )
  1613. {
  1614. ServerMutex.Clear();
  1615. return(RpcInterface);
  1616. }
  1617. }
  1618. ServerMutex.Clear();
  1619. // The management interface is implicitly registered in all servers.
  1620. if ( (GlobalManagementInterface)
  1621. && (GlobalManagementInterface->MatchInterfaceIdentifier(
  1622. InterfaceIdentifier) == 0) )
  1623. {
  1624. return(GlobalManagementInterface);
  1625. }
  1626. return(0);
  1627. }
  1628. RPC_STATUS
  1629. RPC_SERVER::ServerListen (
  1630. IN unsigned int MinimumCallThreads,
  1631. IN unsigned int MaximumConcurrentCalls,
  1632. IN unsigned int DontWait
  1633. )
  1634. /*++
  1635. Routine Description:
  1636. This method is called to start this rpc server listening for remote
  1637. procedure calls. We do not return until after StopServerListening
  1638. has been called and all active calls complete, or an error occurs.
  1639. Arguments:
  1640. MinimumCallThreads - Supplies the minimum number of call threads
  1641. which should be created to service remote procedure calls.
  1642. MaximumConcurrentCalls - Supplies the maximum concurrent calls this
  1643. rpc server is willing to accept at one time.
  1644. DontWait - Supplies a flag indicating whether or not to wait until
  1645. RpcMgmtStopServerListening has been called and all calls have
  1646. completed. A non-zero value indicates not to wait.
  1647. Return Value:
  1648. RPC_S_OK - Everything worked out in the end. All active calls
  1649. completed successfully after RPC_SERVER::StopServerListening
  1650. was called. No errors occured in the transports.
  1651. RPC_S_ALREADY_LISTENING - This rpc server is already listening.
  1652. RPC_S_NO_PROTSEQS_REGISTERED - No protocol sequences have been
  1653. registered with this rpc server. As a consequence it is
  1654. impossible for this rpc server to receive any remote procedure
  1655. calls, hence, the error code.
  1656. RPC_S_MAX_CALLS_TOO_SMALL - MaximumConcurrentCalls is smaller than
  1657. MinimumCallThreads or MaximumConcurrentCalls is zero.
  1658. --*/
  1659. {
  1660. RPC_ADDRESS * RpcAddress;
  1661. RPC_STATUS Status;
  1662. DictionaryCursor cursor;
  1663. if ( ( MaximumConcurrentCalls < MinimumCallThreads )
  1664. || ( MaximumConcurrentCalls == 0 ) )
  1665. {
  1666. return(RPC_S_MAX_CALLS_TOO_SMALL);
  1667. }
  1668. if ( MaximumConcurrentCalls > 0x7FFFFFFF )
  1669. {
  1670. MaximumConcurrentCalls = 0x7FFFFFFF;
  1671. }
  1672. ServerMutex.Request();
  1673. if ( ListeningThreadFlag != 0 )
  1674. {
  1675. ServerMutex.Clear();
  1676. return(RPC_S_ALREADY_LISTENING);
  1677. }
  1678. if ( RpcAddressDictionary.Size() == 0
  1679. && RpcDormantAddresses.IsQueueEmpty())
  1680. {
  1681. ServerMutex.Clear();
  1682. return(RPC_S_NO_PROTSEQS_REGISTERED);
  1683. }
  1684. this->MaximumConcurrentCalls = MaximumConcurrentCalls;
  1685. // if we are provided the default number, then we don't really care -
  1686. // play for optimal performance
  1687. if (MaximumConcurrentCalls == RPC_C_LISTEN_MAX_CALLS_DEFAULT)
  1688. fAccountForMaxCalls = FALSE;
  1689. this->MinimumCallThreads = MinimumCallThreads;
  1690. AvailableCallCount.SetInteger( MaximumConcurrentCalls );
  1691. RpcAddressDictionary.Reset(cursor);
  1692. while ( (RpcAddress = RpcAddressDictionary.Next(cursor)) != 0 )
  1693. {
  1694. Status = RpcAddress->ServerStartingToListen(
  1695. MinimumCallThreads,
  1696. MaximumConcurrentCalls);
  1697. if (Status)
  1698. {
  1699. ServerMutex.Clear();
  1700. return(Status);
  1701. }
  1702. }
  1703. StopListeningEvent.Lower();
  1704. ServerListeningFlag = 1;
  1705. ListeningThreadFlag = 1;
  1706. if ( DontWait != 0 )
  1707. {
  1708. ServerMutex.Clear();
  1709. return(RPC_S_OK);
  1710. }
  1711. WaitingThreadFlag = 1;
  1712. ServerMutex.Clear();
  1713. return(WaitForStopServerListening());
  1714. }
  1715. RPC_STATUS
  1716. RPC_SERVER::WaitForStopServerListening (
  1717. )
  1718. /*++
  1719. Routine Description:
  1720. We wait for StopServerListening to be called and then for all active
  1721. remote procedure calls to complete before returning.
  1722. Return Value:
  1723. RPC_S_OK - Everything worked out in the end. All active calls
  1724. completed successfully after RPC_SERVER::StopServerListening
  1725. was called. No errors occured in the transports.
  1726. --*/
  1727. {
  1728. RPC_ADDRESS * RpcAddress;
  1729. DictionaryCursor cursor;
  1730. RPC_INTERFACE * RpcInterface;
  1731. StopListeningEvent.Wait();
  1732. if ( ListenStatusCode != RPC_S_OK )
  1733. {
  1734. ListeningThreadFlag = 0;
  1735. return(ListenStatusCode);
  1736. }
  1737. RpcAddressDictionary.Reset(cursor);
  1738. while ( (RpcAddress = RpcAddressDictionary.Next(cursor)) != 0 )
  1739. {
  1740. RpcAddress->ServerStoppedListening();
  1741. }
  1742. RpcAddressDictionary.Reset(cursor);
  1743. while ( (RpcAddress = RpcAddressDictionary.Next(cursor)) != 0 )
  1744. {
  1745. RpcAddress->WaitForCalls();
  1746. }
  1747. // Wait for calls on all interfaces to complete
  1748. RpcInterfaceDictionary.Reset(cursor);
  1749. while ((RpcInterface = RpcInterfaceDictionary.Next(cursor)) != 0)
  1750. {
  1751. RpcInterface->WaitForCalls();
  1752. }
  1753. ServerMutex.Request();
  1754. WaitingThreadFlag = 0;
  1755. ListeningThreadFlag = 0;
  1756. ServerMutex.Clear();
  1757. return(RPC_S_OK);
  1758. }
  1759. RPC_STATUS
  1760. RPC_SERVER::WaitServerListen (
  1761. )
  1762. /*++
  1763. Routine Description:
  1764. This routine performs the wait that ServerListen normally performs
  1765. when the DontWait flag is not set. An application must call this
  1766. routine only after RpcServerListen has been called with the DontWait
  1767. flag set. We do not return until RpcMgmtStopServerListening is called
  1768. and all active remote procedure calls complete, or a fatal error occurs
  1769. in the runtime.
  1770. Return Value:
  1771. RPC_S_OK - Everything worked as expected. All active remote procedure
  1772. calls have completed. It is now safe to exit this process.
  1773. RPC_S_ALREADY_LISTENING - Another thread has already called
  1774. WaitServerListen and has not yet returned.
  1775. RPC_S_NOT_LISTENING - ServerListen has not yet been called.
  1776. --*/
  1777. {
  1778. ServerMutex.Request();
  1779. if ( ListeningThreadFlag == 0 )
  1780. {
  1781. ServerMutex.Clear();
  1782. return(RPC_S_NOT_LISTENING);
  1783. }
  1784. if ( WaitingThreadFlag != 0 )
  1785. {
  1786. ServerMutex.Clear();
  1787. return(RPC_S_ALREADY_LISTENING);
  1788. }
  1789. WaitingThreadFlag = 1;
  1790. ServerMutex.Clear();
  1791. return(WaitForStopServerListening());
  1792. }
  1793. void
  1794. RPC_SERVER::InquireStatistics (
  1795. OUT RPC_STATS_VECTOR * Statistics
  1796. )
  1797. /*++
  1798. Routine Description:
  1799. This method is used to obtain the statistics for this rpc server.
  1800. Arguments:
  1801. Statistics - Returns the statistics for this rpc server.
  1802. --*/
  1803. {
  1804. Statistics->Stats[RPC_C_STATS_CALLS_IN] = IncomingRpcCount;
  1805. Statistics->Stats[RPC_C_STATS_CALLS_OUT] = OutgoingRpcCount;
  1806. Statistics->Stats[RPC_C_STATS_PKTS_IN] = ReceivedPacketCount;
  1807. Statistics->Stats[RPC_C_STATS_PKTS_OUT] = SentPacketCount;
  1808. }
  1809. RPC_STATUS
  1810. RPC_SERVER::StopServerListening (
  1811. )
  1812. /*++
  1813. Routine Description:
  1814. This method is called to stop this rpc server from listening for
  1815. more remote procedure calls. Active calls are allowed to complete
  1816. (including callbacks). The thread which called ServerListen will
  1817. return when all active calls complete.
  1818. Return Value:
  1819. RPC_S_OK - The thread that called ServerListen has successfully been
  1820. notified that it should shutdown.
  1821. RPC_S_NOT_LISTENING - There is no thread currently listening.
  1822. --*/
  1823. {
  1824. if (ListeningThreadFlag == 0)
  1825. return(RPC_S_NOT_LISTENING);
  1826. ListenStatusCode = RPC_S_OK;
  1827. ServerListeningFlag = 0;
  1828. StopListeningEvent.Raise();
  1829. return(RPC_S_OK);
  1830. }
  1831. RPC_STATUS
  1832. RPC_SERVER::UseRpcProtocolSequence (
  1833. IN RPC_CHAR PAPI * NetworkAddress,
  1834. IN RPC_CHAR PAPI * RpcProtocolSequence,
  1835. IN unsigned int PendingQueueSize,
  1836. IN RPC_CHAR PAPI *Endpoint,
  1837. IN void PAPI * SecurityDescriptor,
  1838. IN unsigned long EndpointFlags,
  1839. IN unsigned long NICFlags
  1840. )
  1841. /*++
  1842. Routine Description:
  1843. This method is who does the work of creating new address (they
  1844. are called protocol sequences in the DCE lingo) and adding them to
  1845. this rpc server.
  1846. Arguments:
  1847. RpcProtocolSequence - Supplies the rpc protocol sequence we wish
  1848. to add to this rpc server.
  1849. PendingQueueSize - Supplies the size of the queue of pending
  1850. requests which should be created by the transport. Some transports
  1851. will not be able to make use of this value, while others will.
  1852. Endpoint - Optionally supplies an endpoint to be used for the new
  1853. address. If an endpoint is not specified, then we will let
  1854. the transport specify the endpoint.
  1855. SecurityDescriptor - Optionally supplies a security descriptor to
  1856. be placed on the rpc protocol sequence (address) we are adding
  1857. to this rpc server.
  1858. Return Value:
  1859. RPC_S_OK - The requested rpc protocol sequence has been added to
  1860. this rpc server.
  1861. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to add the
  1862. requested rpc protocol sequence to this rpc server.
  1863. RPC_S_PROTSEQ_NOT_SUPPORTED - The specified rpc protocol sequence
  1864. is not supported (but it appears to be valid).
  1865. RPC_S_INVALID_RPC_PROTSEQ - The specified rpc protocol sequence is
  1866. syntactically invalid.
  1867. RPC_S_DUPLICATE_ENDPOINT - The supplied endpoint has already been
  1868. added to this rpc server.
  1869. RPC_S_INVALID_SECURITY_DESC - The supplied security descriptor is
  1870. invalid.
  1871. --*/
  1872. {
  1873. TRANS_INFO *ServerTransInfo ;
  1874. RPC_STATUS Status;
  1875. RPC_ADDRESS * RpcAddress;
  1876. RPC_ADDRESS * Address;
  1877. NETWORK_ADDRESS_VECTOR *pNetworkAddressVector;
  1878. unsigned int StaticEndpointFlag;
  1879. int Key;
  1880. DictionaryCursor cursor;
  1881. THREAD *ThisThread;
  1882. ThisThread = ThreadSelf();
  1883. if (ThisThread == NULL)
  1884. return RPC_S_OUT_OF_MEMORY;
  1885. // remove old EEInfo
  1886. RpcpPurgeEEInfo();
  1887. if (IsServerSideDebugInfoEnabled())
  1888. {
  1889. Status = InitializeServerSideCellHeapIfNecessary();
  1890. if (Status != RPC_S_OK)
  1891. return Status;
  1892. }
  1893. if ( RpcpStringCompare(RpcProtocolSequence,
  1894. RPC_CONST_STRING("ncalrpc")) == 0 )
  1895. {
  1896. RpcAddress = LrpcCreateRpcAddress();
  1897. }
  1898. else if ( RpcpStringNCompare(
  1899. RPC_CONST_STRING("ncadg_"),
  1900. RpcProtocolSequence,
  1901. 6) == 0)
  1902. {
  1903. //
  1904. // Just use the osf mapping...it simply calls the
  1905. // protocol-independent ones.
  1906. //
  1907. Status = OsfMapRpcProtocolSequence(1,
  1908. RpcProtocolSequence,
  1909. &ServerTransInfo);
  1910. if (Status != RPC_S_OK)
  1911. {
  1912. return Status;
  1913. }
  1914. RpcAddress = DgCreateRpcAddress(ServerTransInfo);
  1915. }
  1916. else if ( RpcpStringNCompare(
  1917. RPC_CONST_STRING("ncacn_"),
  1918. RpcProtocolSequence,
  1919. 6) == 0)
  1920. {
  1921. Status = OsfMapRpcProtocolSequence(1,
  1922. RpcProtocolSequence,
  1923. &ServerTransInfo);
  1924. if (Status != RPC_S_OK)
  1925. {
  1926. return(Status);
  1927. }
  1928. RpcAddress = OsfCreateRpcAddress(ServerTransInfo);
  1929. }
  1930. else
  1931. {
  1932. return(RPC_S_PROTSEQ_NOT_SUPPORTED);
  1933. }
  1934. if (RpcAddress == 0)
  1935. {
  1936. return(RPC_S_OUT_OF_MEMORY);
  1937. }
  1938. if (ARGUMENT_PRESENT(Endpoint))
  1939. {
  1940. ServerMutex.Request();
  1941. RpcAddressDictionary.Reset(cursor);
  1942. while ((Address = RpcAddressDictionary.Next(cursor)) != 0)
  1943. {
  1944. if ( Address->SameEndpointAndProtocolSequence(
  1945. NetworkAddress,
  1946. RpcProtocolSequence,
  1947. Endpoint) != 0 )
  1948. {
  1949. ServerMutex.Clear();
  1950. delete RpcAddress;
  1951. return(RPC_S_DUPLICATE_ENDPOINT);
  1952. }
  1953. }
  1954. ServerMutex.Clear();
  1955. Endpoint = DuplicateString(Endpoint);
  1956. if (Endpoint == 0)
  1957. {
  1958. delete RpcAddress;
  1959. return(RPC_S_OUT_OF_MEMORY);
  1960. }
  1961. StaticEndpointFlag = 1;
  1962. }
  1963. else
  1964. {
  1965. //
  1966. // MACBUG:
  1967. // We need to include this for Macintosh/Win95 also...
  1968. //
  1969. ServerMutex.Request() ;
  1970. RpcAddressDictionary.Reset(cursor) ;
  1971. while ((Address = RpcAddressDictionary.Next(cursor)) != 0)
  1972. {
  1973. if ( Address->SameProtocolSequence(NetworkAddress,
  1974. RpcProtocolSequence) != 0 )
  1975. {
  1976. ServerMutex.Clear();
  1977. delete RpcAddress;
  1978. return(RPC_S_OK);
  1979. }
  1980. }
  1981. ServerMutex.Clear();
  1982. StaticEndpointFlag = 0;
  1983. } // else
  1984. if (EndpointFlags & RPC_C_DONT_FAIL)
  1985. {
  1986. RpcAddress->PnpNotify();
  1987. }
  1988. Status = RpcAddress->ServerSetupAddress(
  1989. NetworkAddress,
  1990. &Endpoint,
  1991. PendingQueueSize,
  1992. SecurityDescriptor,
  1993. EndpointFlags,
  1994. NICFlags,
  1995. &pNetworkAddressVector);
  1996. if (Status == RPC_S_OK)
  1997. {
  1998. RPC_CHAR *MyNetworkAddress = NULL;
  1999. RpcProtocolSequence = DuplicateString(RpcProtocolSequence);
  2000. if (RpcProtocolSequence == 0)
  2001. {
  2002. delete Endpoint;
  2003. delete RpcAddress;
  2004. return(RPC_S_OUT_OF_MEMORY);
  2005. }
  2006. if (ARGUMENT_PRESENT(NetworkAddress))
  2007. {
  2008. MyNetworkAddress = DuplicateString(NetworkAddress);
  2009. if (MyNetworkAddress == 0)
  2010. {
  2011. delete Endpoint;
  2012. delete RpcAddress;
  2013. delete RpcProtocolSequence;
  2014. return(RPC_S_OUT_OF_MEMORY);
  2015. }
  2016. }
  2017. Status = RpcAddress->SetEndpointAndStuff(
  2018. MyNetworkAddress,
  2019. Endpoint,
  2020. RpcProtocolSequence,
  2021. this,
  2022. StaticEndpointFlag,
  2023. PendingQueueSize,
  2024. SecurityDescriptor,
  2025. EndpointFlags,
  2026. NICFlags,
  2027. pNetworkAddressVector);
  2028. if (Status != RPC_S_OK)
  2029. {
  2030. delete RpcAddress;
  2031. return Status;
  2032. }
  2033. }
  2034. else
  2035. {
  2036. if (EndpointFlags & RPC_C_DONT_FAIL)
  2037. {
  2038. int retval;
  2039. RPC_CHAR *MyNetworkAddress = NULL;
  2040. RpcProtocolSequence = DuplicateString(RpcProtocolSequence);
  2041. if (RpcProtocolSequence == 0)
  2042. {
  2043. delete Endpoint;
  2044. delete RpcAddress;
  2045. return(RPC_S_OUT_OF_MEMORY);
  2046. }
  2047. if (ARGUMENT_PRESENT(NetworkAddress))
  2048. {
  2049. MyNetworkAddress = DuplicateString(NetworkAddress);
  2050. if (MyNetworkAddress == 0)
  2051. {
  2052. delete Endpoint;
  2053. delete RpcAddress;
  2054. delete RpcProtocolSequence;
  2055. return(RPC_S_OUT_OF_MEMORY);
  2056. }
  2057. }
  2058. Status = RpcAddress->SetEndpointAndStuff(
  2059. MyNetworkAddress,
  2060. Endpoint,
  2061. RpcProtocolSequence,
  2062. this,
  2063. StaticEndpointFlag,
  2064. PendingQueueSize,
  2065. SecurityDescriptor,
  2066. EndpointFlags,
  2067. NICFlags,
  2068. NULL);
  2069. if (Status != RPC_S_OK)
  2070. {
  2071. delete Endpoint;
  2072. delete RpcAddress;
  2073. return Status;
  2074. }
  2075. ServerMutex.Request();
  2076. retval = RpcDormantAddresses.PutOnQueue(RpcAddress, 0);
  2077. ServerMutex.Clear();
  2078. if (retval == 1)
  2079. {
  2080. delete Endpoint;
  2081. delete RpcAddress;
  2082. return RPC_S_OUT_OF_MEMORY;
  2083. }
  2084. ServerMutex.Request();
  2085. Status = RpcAddress->ServerStartingToListen(
  2086. MinimumCallThreads,
  2087. MaximumConcurrentCalls);
  2088. ServerMutex.Clear();
  2089. if (Status)
  2090. {
  2091. return(Status);
  2092. }
  2093. return RPC_S_OK;
  2094. }
  2095. else
  2096. {
  2097. delete RpcAddress;
  2098. return(Status);
  2099. }
  2100. }
  2101. Key = AddAddress(RpcAddress);
  2102. if (Key == -1)
  2103. {
  2104. delete RpcAddress;
  2105. return(RPC_S_OUT_OF_MEMORY);
  2106. }
  2107. RpcAddress->DictKey = Key;
  2108. ServerMutex.Request();
  2109. Status = RpcAddress->ServerStartingToListen(
  2110. MinimumCallThreads,
  2111. MaximumConcurrentCalls);
  2112. ServerMutex.Clear();
  2113. if (Status)
  2114. {
  2115. return(Status);
  2116. }
  2117. //
  2118. // Inform the transport that it can start.
  2119. //
  2120. RpcAddress->CompleteListen() ;
  2121. return(RPC_S_OK);
  2122. }
  2123. int
  2124. RPC_SERVER::AddAddress (
  2125. IN RPC_ADDRESS * RpcAddress
  2126. )
  2127. /*++
  2128. Routine Description:
  2129. This method is used to add an rpc address to the dictionary of
  2130. rpc addresses know about by this rpc server.
  2131. Arguments:
  2132. RpcAddress - Supplies the rpc address to be inserted into the
  2133. dictionary of rpc addresses.
  2134. Return Value:
  2135. RPC_S_OK - The supplied rpc address has been successfully added
  2136. to the dictionary.
  2137. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to insert
  2138. the rpc address into the dictionary.
  2139. --*/
  2140. {
  2141. int Key;
  2142. ServerMutex.Request();
  2143. Key = RpcAddressDictionary.Insert(RpcAddress);
  2144. ServerMutex.Clear();
  2145. return(Key);
  2146. }
  2147. RPC_STATUS
  2148. RPC_SERVER::UnregisterIf (
  2149. IN RPC_SERVER_INTERFACE PAPI * RpcInterfaceInformation OPTIONAL,
  2150. IN RPC_UUID PAPI * ManagerTypeUuid OPTIONAL,
  2151. IN unsigned int WaitForCallsToComplete
  2152. )
  2153. /*++
  2154. Routine Description:
  2155. This method does the work of unregistering an interface from this
  2156. rpc server. We actually do not remove the interface; what we do
  2157. is to one or all of the manager entry point vector depending upon
  2158. the type uuid argument supplied.
  2159. Arguments:
  2160. RpcInterfaceInformation - Supplies a description of the interface
  2161. for which we want to unregister one or all manager entry point
  2162. vectors.
  2163. ManagerTypeUuid - Optionally supplies the type uuid of the manager
  2164. entry point vector to be removed. If this argument is not supplied,
  2165. then all manager entry point vectors for this interface will
  2166. be removed.
  2167. WaitForCallsToComplete - Supplies a flag indicating whether or not
  2168. this routine should wait for all calls to complete using the
  2169. interface and manager being unregistered. A non-zero value
  2170. indicates to wait.
  2171. Return Value:
  2172. RPC_S_OK - The manager entry point vector(s) are(were) successfully
  2173. removed from the specified interface.
  2174. RPC_S_UNKNOWN_MGR_TYPE - The specified type uuid is not registered
  2175. with the interface.
  2176. RPC_S_UNKNOWN_IF - The specified interface is not registered with
  2177. the rpc server.
  2178. --*/
  2179. {
  2180. RPC_INTERFACE * RpcInterface;
  2181. RPC_STATUS RpcStatus;
  2182. RPC_STATUS Status;
  2183. int i;
  2184. DictionaryCursor cursor;
  2185. UNUSED(WaitForCallsToComplete);
  2186. if (ARGUMENT_PRESENT(RpcInterfaceInformation))
  2187. {
  2188. ServerMutex.Request();
  2189. RpcInterface = FindInterface(RpcInterfaceInformation);
  2190. ServerMutex.Clear();
  2191. if (RpcInterface == 0)
  2192. return(RPC_S_UNKNOWN_IF);
  2193. if (RpcInterface->IsAutoListenInterface())
  2194. {
  2195. GlobalRpcServer->DecrementAutoListenInterfaceCount() ;
  2196. while ( RpcInterface->InqAutoListenCallCount() )
  2197. {
  2198. RPC_ADDRESS * Address;
  2199. ServerMutex.Request();
  2200. RpcAddressDictionary.Reset(cursor);
  2201. while (0 != (Address = RpcAddressDictionary.Next(cursor)))
  2202. {
  2203. Address->EncourageCallCleanup(RpcInterface);
  2204. }
  2205. ServerMutex.Clear();
  2206. PauseExecution(500);
  2207. }
  2208. }
  2209. return(RpcInterface->UnregisterManagerEpv(ManagerTypeUuid,
  2210. WaitForCallsToComplete));
  2211. }
  2212. Status = RPC_S_UNKNOWN_MGR_TYPE;
  2213. ServerMutex.Request();
  2214. RpcInterfaceDictionary.Reset(cursor);
  2215. while ((RpcInterface = RpcInterfaceDictionary.Next(cursor)) != 0)
  2216. {
  2217. // auto-listen intefaces have to be individually unregistered
  2218. if (RpcInterface->IsAutoListenInterface())
  2219. {
  2220. continue;
  2221. }
  2222. RpcStatus = RpcInterface->UnregisterManagerEpv(ManagerTypeUuid,
  2223. WaitForCallsToComplete);
  2224. if (RpcStatus == RPC_S_OK)
  2225. {
  2226. Status = RPC_S_OK;
  2227. }
  2228. }
  2229. ServerMutex.Clear();
  2230. return(Status);
  2231. }
  2232. RPC_STATUS
  2233. RPC_SERVER::InquireManagerEpv (
  2234. IN RPC_SERVER_INTERFACE PAPI * RpcInterfaceInformation,
  2235. IN RPC_UUID PAPI * ManagerTypeUuid, OPTIONAL
  2236. OUT RPC_MGR_EPV PAPI * PAPI * ManagerEpv
  2237. )
  2238. /*++
  2239. Routine Description:
  2240. This method is used to obtain the manager entry point vector for
  2241. an interface supported by this rpc server. A type uuid argument
  2242. specifies which manager entry point vector is to be obtained.
  2243. Arguments:
  2244. RpcInterfaceInformation - Supplies a description of the interface.
  2245. ManagerTypeUuid - Optionally supplies the type uuid of the manager
  2246. entry point vector we want returned. If no manager type uuid
  2247. is specified, then the null uuid is assumed.
  2248. ManagerEpv - Returns the manager entry point vector.
  2249. Return Value:
  2250. RPC_S_OK - The manager entry point vector has successfully been
  2251. returned.
  2252. RPC_S_UNKNOWN_MGR_TYPE - The specified type uuid is not registered
  2253. with the interface.
  2254. RPC_S_UNKNOWN_IF - The specified interface is not registered with
  2255. the rpc server.
  2256. --*/
  2257. {
  2258. RPC_INTERFACE * RpcInterface;
  2259. ServerMutex.Request();
  2260. RpcInterface = FindInterface(RpcInterfaceInformation);
  2261. ServerMutex.Clear();
  2262. if (RpcInterface == 0)
  2263. return(RPC_S_UNKNOWN_IF);
  2264. return(RpcInterface->InquireManagerEpv(ManagerTypeUuid, ManagerEpv));
  2265. }
  2266. RPC_STATUS
  2267. RPC_SERVER::InquireBindings (
  2268. OUT RPC_BINDING_VECTOR PAPI * PAPI * BindingVector
  2269. )
  2270. /*++
  2271. Routine Description:
  2272. For each rpc protocol sequence registered with this rpc server
  2273. we want to create a binding handle which can be used to make
  2274. remote procedure calls using the registered rpc protocol sequence.
  2275. We return a vector of these binding handles.
  2276. Arguments:
  2277. BindingVector - Returns the vector of binding handles.
  2278. Return Value:
  2279. RPC_S_OK - At least one rpc protocol sequence has been registered
  2280. with this rpc server, and the operation completed successfully.
  2281. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to complete
  2282. the operation.
  2283. RPC_S_NO_BINDINGS - No rpc protocol sequences have been successfully
  2284. registered with this rpc server.
  2285. --*/
  2286. {
  2287. RPC_BINDING_VECTOR PAPI * RpcBindingVector;
  2288. unsigned int Index, RpcAddressIndex;
  2289. RPC_ADDRESS * RpcAddress;
  2290. BINDING_HANDLE * BindingHandle;
  2291. int i ;
  2292. RPC_CHAR PAPI * LocalNetworkAddress;
  2293. int count = 0 ;
  2294. DictionaryCursor cursor;
  2295. ServerMutex.Request();
  2296. if (RpcAddressDictionary.Size() == 0
  2297. && RpcDormantAddresses.IsQueueEmpty())
  2298. {
  2299. ServerMutex.Clear();
  2300. return(RPC_S_NO_BINDINGS);
  2301. }
  2302. RpcAddressDictionary.Reset(cursor);
  2303. while ((RpcAddress = RpcAddressDictionary.Next(cursor)) != 0)
  2304. {
  2305. count += RpcAddress->InqNumNetworkAddress();
  2306. }
  2307. RpcBindingVector = (RPC_BINDING_VECTOR PAPI *) RpcpFarAllocate(
  2308. sizeof(RPC_BINDING_VECTOR) + (count -1 )
  2309. * sizeof(RPC_BINDING_HANDLE) );
  2310. if (RpcBindingVector == 0)
  2311. {
  2312. ServerMutex.Clear();
  2313. return(RPC_S_OUT_OF_MEMORY);
  2314. }
  2315. RpcBindingVector->Count = count;
  2316. for (Index = 0; Index < RpcBindingVector->Count; Index++)
  2317. RpcBindingVector->BindingH[Index] = 0;
  2318. Index = 0;
  2319. RpcAddressDictionary.Reset(cursor);
  2320. while ((RpcAddress = RpcAddressDictionary.Next(cursor)) != 0)
  2321. {
  2322. RpcAddressIndex = 0;
  2323. LocalNetworkAddress = RpcAddress->
  2324. GetListNetworkAddress(RpcAddressIndex) ;
  2325. while(LocalNetworkAddress != NULL)
  2326. {
  2327. BindingHandle = RpcAddress->
  2328. InquireBinding(LocalNetworkAddress);
  2329. if (BindingHandle == 0)
  2330. {
  2331. ServerMutex.Clear();
  2332. RpcBindingVectorFree(&RpcBindingVector);
  2333. return(RPC_S_OUT_OF_MEMORY);
  2334. }
  2335. RpcBindingVector->BindingH[Index] = BindingHandle;
  2336. Index += 1;
  2337. RpcAddressIndex += 1;
  2338. LocalNetworkAddress = RpcAddress->
  2339. GetListNetworkAddress(RpcAddressIndex) ;
  2340. }
  2341. }
  2342. ServerMutex.Clear();
  2343. ASSERT(Index == RpcBindingVector->Count);
  2344. *BindingVector = RpcBindingVector;
  2345. return(RPC_S_OK);
  2346. }
  2347. RPC_STATUS
  2348. RPC_SERVER::RegisterAuthInfoHelper (
  2349. IN RPC_CHAR PAPI * ServerPrincipalName,
  2350. IN unsigned long AuthenticationService,
  2351. IN RPC_AUTH_KEY_RETRIEVAL_FN GetKeyFunction, OPTIONAL
  2352. IN void PAPI * Argument OPTIONAL
  2353. )
  2354. {
  2355. RPC_AUTHENTICATION * Service;
  2356. RPC_STATUS RpcStatus;
  2357. RPC_CHAR __RPC_FAR * PrincipalName;
  2358. DictionaryCursor cursor;
  2359. if (ServerPrincipalName == NULL)
  2360. {
  2361. ServerPrincipalName = new RPC_CHAR[1];
  2362. if (ServerPrincipalName == NULL)
  2363. {
  2364. return (RPC_S_OUT_OF_MEMORY);
  2365. }
  2366. ServerPrincipalName[0] = '\0';
  2367. }
  2368. if ( AuthenticationService == 0 )
  2369. {
  2370. return(RPC_S_UNKNOWN_AUTHN_SERVICE);
  2371. }
  2372. if (AuthenticationService == RPC_C_AUTHN_DEFAULT)
  2373. {
  2374. RpcpGetDefaultSecurityProviderInfo();
  2375. AuthenticationService = DefaultProviderId;
  2376. }
  2377. ServerMutex.Request();
  2378. AuthenticationDictionary.Reset(cursor);
  2379. while ( (Service = AuthenticationDictionary.Next(cursor)) != 0 )
  2380. {
  2381. if ( Service->AuthenticationService == AuthenticationService &&
  2382. 0 == RpcpStringCompare(Service->ServerPrincipalName, ServerPrincipalName))
  2383. {
  2384. Service->GetKeyFunction = GetKeyFunction;
  2385. Service->Argument = Argument;
  2386. ServerMutex.Clear();
  2387. // Flush the server-credentials cache
  2388. RpcStatus = RemoveCredentialsFromCache(AuthenticationService);
  2389. return (RpcStatus);
  2390. }
  2391. }
  2392. RpcStatus = IsAuthenticationServiceSupported(AuthenticationService);
  2393. if ( RpcStatus != RPC_S_OK )
  2394. {
  2395. ServerMutex.Clear();
  2396. if ( (RpcStatus == RPC_S_UNKNOWN_AUTHN_SERVICE) ||
  2397. (RpcStatus == RPC_S_UNKNOWN_AUTHN_LEVEL) )
  2398. {
  2399. return (RPC_S_UNKNOWN_AUTHN_SERVICE);
  2400. }
  2401. else
  2402. {
  2403. return (RPC_S_OUT_OF_MEMORY);
  2404. }
  2405. }
  2406. Service = new RPC_AUTHENTICATION;
  2407. if ( Service == 0 )
  2408. {
  2409. ServerMutex.Clear();
  2410. return(RPC_S_OUT_OF_MEMORY);
  2411. }
  2412. Service->AuthenticationService = AuthenticationService;
  2413. Service->ServerPrincipalName = DuplicateString(ServerPrincipalName);
  2414. Service->GetKeyFunction = GetKeyFunction;
  2415. Service->Argument = Argument;
  2416. if ( Service->ServerPrincipalName == 0 )
  2417. {
  2418. ServerMutex.Clear();
  2419. delete Service;
  2420. return(RPC_S_OUT_OF_MEMORY);
  2421. }
  2422. if ( AuthenticationDictionary.Insert(Service) == -1 )
  2423. {
  2424. ServerMutex.Clear();
  2425. delete Service;
  2426. return(RPC_S_OUT_OF_MEMORY);
  2427. }
  2428. ServerMutex.Clear();
  2429. return(RPC_S_OK);
  2430. }
  2431. RPC_STATUS
  2432. RPC_SERVER::AutoRegisterAuthSvc(
  2433. IN RPC_CHAR * ServerPrincipalName,
  2434. IN unsigned long AuthenticationService
  2435. )
  2436. {
  2437. RPC_STATUS Status;
  2438. DictionaryCursor cursor;
  2439. RPC_AUTHENTICATION * Service;
  2440. //
  2441. // Don't need to auto-register the provider if it is already registered
  2442. //
  2443. ServerMutex.Request();
  2444. AuthenticationDictionary.Reset(cursor);
  2445. while ( (Service = AuthenticationDictionary.Next(cursor)) != 0 )
  2446. {
  2447. if ( Service->AuthenticationService == AuthenticationService)
  2448. {
  2449. ServerMutex.Clear();
  2450. return (RPC_S_OK);
  2451. }
  2452. }
  2453. ServerMutex.Clear();
  2454. Status = RegisterAuthInfoHelper(ServerPrincipalName,
  2455. AuthenticationService,
  2456. NULL,
  2457. NULL);
  2458. if (Status == RPC_S_UNKNOWN_AUTHN_SERVICE)
  2459. {
  2460. //
  2461. // Ok to not register provider if it is disabled
  2462. //
  2463. return RPC_S_OK;
  2464. }
  2465. return Status;
  2466. }
  2467. RPC_STATUS
  2468. RPC_SERVER::RegisterAuthInformation (
  2469. IN RPC_CHAR PAPI * ServerPrincipalName,
  2470. IN unsigned long AuthenticationService,
  2471. IN RPC_AUTH_KEY_RETRIEVAL_FN GetKeyFunction, OPTIONAL
  2472. IN void PAPI * Argument OPTIONAL
  2473. )
  2474. /*++
  2475. Routine Description:
  2476. This method is used to register authentication, authorization, and
  2477. a server principal name to be used for security for this server. We
  2478. will use this information to authenticate remote procedure calls.
  2479. Arguments:
  2480. ServerPrincipalName - Supplies the principal name for the server.
  2481. AuthenticationService - Supplies an authentication service to use when
  2482. the server receives a remote procedure call.
  2483. GetKeyFunction - Optionally supplies a routine to be used when the runtime
  2484. needs an encryption key.
  2485. Argument - Optionally supplies an argument to be passed to the routine used
  2486. to get keys each time it is called.
  2487. Return Value:
  2488. RPC_S_OK - The authentication service and server principal name have
  2489. been registered with this RPC server.
  2490. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to complete the
  2491. operation.
  2492. RPC_S_UNKNOWN_AUTHN_SERVICE - The specified authentication service is
  2493. not supported.
  2494. --*/
  2495. {
  2496. RPC_STATUS Status;
  2497. RPC_CHAR *PrincName;
  2498. Status = RegisterAuthInfoHelper(ServerPrincipalName,
  2499. AuthenticationService,
  2500. GetKeyFunction,
  2501. Argument);
  2502. if (Status != RPC_S_OK)
  2503. {
  2504. return Status;
  2505. }
  2506. if (AuthenticationService != RPC_C_AUTHN_GSS_NEGOTIATE)
  2507. {
  2508. return RPC_S_OK;
  2509. }
  2510. Status = AutoRegisterAuthSvc(ServerPrincipalName, RPC_C_AUTHN_WINNT);
  2511. if (Status != RPC_S_OK)
  2512. {
  2513. return Status;
  2514. }
  2515. Status = AutoRegisterAuthSvc(ServerPrincipalName, RPC_C_AUTHN_GSS_KERBEROS);
  2516. return Status;
  2517. }
  2518. RPC_STATUS
  2519. RPC_SERVER::AcquireCredentials (
  2520. IN unsigned long AuthenticationService,
  2521. IN unsigned long AuthenticationLevel,
  2522. OUT SECURITY_CREDENTIALS ** SecurityCredentials
  2523. )
  2524. /*++
  2525. Routine Description:
  2526. The protocol modules will use this to obtain a set of credentials
  2527. for the specified authentication service, assuming that the server
  2528. supports them.
  2529. Arguments:
  2530. AuthenticationService - Supplies the authentication service for which
  2531. we hope to obtain credentials.
  2532. AuthenticationLevel - Supplies the authentication level to be used.
  2533. SecurityCredentials - Returns the security credentials.
  2534. Return Value:
  2535. RPC_S_OK - You have been given some security credentials, which you need
  2536. to free using RPC_SERVER::FreeCredentials when you are done with
  2537. them.
  2538. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to complete the
  2539. operation.
  2540. RPC_S_UNKNOWN_AUTHN_SERVICE - The specified authentication service is
  2541. not supported by the current configuration.
  2542. --*/
  2543. {
  2544. RPC_AUTHENTICATION * Service;
  2545. RPC_STATUS RpcStatus = RPC_S_OK;
  2546. DictionaryCursor cursor;
  2547. ServerMutex.Request();
  2548. AuthenticationDictionary.Reset(cursor);
  2549. while ( (Service = AuthenticationDictionary.Next(cursor)) != 0 )
  2550. {
  2551. if ( Service->AuthenticationService == AuthenticationService )
  2552. {
  2553. ServerMutex.Clear();
  2554. RpcStatus = FindServerCredentials(
  2555. Service->GetKeyFunction,
  2556. Service->Argument,
  2557. AuthenticationService,
  2558. AuthenticationLevel,
  2559. Service->ServerPrincipalName,
  2560. SecurityCredentials
  2561. );
  2562. VALIDATE(RpcStatus)
  2563. {
  2564. RPC_S_OK,
  2565. RPC_S_SEC_PKG_ERROR,
  2566. RPC_S_OUT_OF_MEMORY,
  2567. RPC_S_INVALID_AUTH_IDENTITY,
  2568. ERROR_SHUTDOWN_IN_PROGRESS,
  2569. RPC_S_UNKNOWN_AUTHN_SERVICE
  2570. } END_VALIDATE;
  2571. return(RpcStatus);
  2572. }
  2573. }
  2574. ServerMutex.Clear();
  2575. return(RPC_S_UNKNOWN_AUTHN_SERVICE);
  2576. }
  2577. void
  2578. RPC_SERVER::FreeCredentials (
  2579. IN SECURITY_CREDENTIALS * SecurityCredentials
  2580. )
  2581. /*++
  2582. Routine Description:
  2583. A protocol module will indicate that it is through using a set of
  2584. security credentials, obtained from RPC_SERVER::AcquireCredentials,
  2585. using this routine.
  2586. Arguments:
  2587. SecurityCredentials - Supplies the security credentials to be freed.
  2588. --*/
  2589. {
  2590. SecurityCredentials->FreeCredentials();
  2591. delete SecurityCredentials;
  2592. }
  2593. RPC_STATUS
  2594. RPC_SERVER::RegisterInterface (
  2595. IN RPC_SERVER_INTERFACE PAPI * RpcInterfaceInformation,
  2596. IN RPC_UUID PAPI * ManagerTypeUuid,
  2597. IN RPC_MGR_EPV PAPI * ManagerEpv,
  2598. IN unsigned int Flags,
  2599. IN unsigned int MaxCalls,
  2600. IN unsigned int MaxRpcSize,
  2601. IN RPC_IF_CALLBACK_FN PAPI *IfCallbackFn
  2602. )
  2603. /*++
  2604. Routine Description:
  2605. This routine is used by server application to register a manager
  2606. entry point vector and optionally an interface. If the interface
  2607. has not been registered, then it will be registered. If it has
  2608. already been registered, the manager entry point vector will be
  2609. added to it under the specified type uuid.
  2610. Arguments:
  2611. RpcInterfaceInformation - Supplies a description of the interface to
  2612. be registered. We will make a copy of this information.
  2613. ManagerTypeUuid - Optionally supplies the type uuid for the specified
  2614. manager entry point vector. If no type uuid is supplied, then
  2615. the null uuid will be used as the type uuid.
  2616. ManagerEpv - Optionally supplies a manager entry point vector corresponding
  2617. to the type uuid. If a manager entry point vector is not supplied,
  2618. then the manager entry point vector in the interface will be
  2619. used.
  2620. Return Value:
  2621. RPC_S_OK - The specified rpc interface has been successfully
  2622. registered with the rpc server. It is now ready to accept
  2623. remote procedure calls.
  2624. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to register
  2625. the rpc interface with the rpc server.
  2626. RPC_S_TYPE_ALREADY_REGISTERED - A manager entry point vector has
  2627. already been registered for the supplied rpc interface and
  2628. manager type UUID.
  2629. --*/
  2630. {
  2631. RPC_STATUS RpcStatus;
  2632. RPC_INTERFACE * RpcInterface;
  2633. RPC_ADDRESS *RpcAddress ;
  2634. DictionaryCursor cursor;
  2635. BOOL fInterfaceFound;
  2636. if ( ManagerEpv == 0 )
  2637. {
  2638. ManagerEpv = RpcInterfaceInformation->DefaultManagerEpv;
  2639. if ( (PtrToUlong(ManagerEpv)) == 0xFFFFFFFF)
  2640. {
  2641. // Stub compiled with -no_default_epv.
  2642. return (RPC_S_INVALID_ARG);
  2643. }
  2644. }
  2645. ServerMutex.Request();
  2646. RpcInterface = FindOrCreateInterfaceInternal(RpcInterfaceInformation, Flags, MaxCalls,
  2647. MaxRpcSize, IfCallbackFn, &RpcStatus, &fInterfaceFound);
  2648. if (RpcInterface == NULL)
  2649. {
  2650. ServerMutex.Clear();
  2651. return RpcStatus;
  2652. }
  2653. if (fInterfaceFound)
  2654. {
  2655. // if it was found, update the information
  2656. RpcStatus = RpcInterface->UpdateRpcInterfaceInformation(RpcInterfaceInformation,
  2657. Flags, MaxCalls, MaxRpcSize, IfCallbackFn);
  2658. if (RpcStatus != RPC_S_OK)
  2659. {
  2660. ServerMutex.Clear();
  2661. return RpcStatus;
  2662. }
  2663. }
  2664. RpcStatus = RpcInterface->RegisterTypeManager(ManagerTypeUuid, ManagerEpv);
  2665. if (Flags & RPC_IF_AUTOLISTEN)
  2666. {
  2667. RpcAddressDictionary.Reset(cursor);
  2668. while ( (RpcAddress = RpcAddressDictionary.Next(cursor)) != 0 )
  2669. {
  2670. RpcStatus = RpcAddress->ServerStartingToListen(
  2671. this->MinimumCallThreads,
  2672. MaxCalls);
  2673. if (RpcStatus != RPC_S_OK)
  2674. {
  2675. break;
  2676. }
  2677. }
  2678. }
  2679. ServerMutex.Clear();
  2680. return(RpcStatus);
  2681. }
  2682. void RPC_SERVER::CreateOrUpdateAddresses (void)
  2683. /*++
  2684. Function Name: CreateOrUpdateAddresses
  2685. Parameters:
  2686. Description:
  2687. The runtime just received a notification that a new protocol was loaded. We need
  2688. to create an ADDRESS object, listen on it and update the RPCSS bindings
  2689. appropriately.
  2690. Returns:
  2691. --*/
  2692. {
  2693. RPC_STATUS Status;
  2694. RPC_BINDING_VECTOR *BindingVector = 0;
  2695. RPC_INTERFACE * RpcInterface;
  2696. BOOL fChanged = 0;
  2697. RPC_ADDRESS *Address;
  2698. QUEUE tempQueue;
  2699. BOOL fTempQueueHasContents = FALSE;
  2700. int i;
  2701. DictionaryCursor cursor;
  2702. while (1)
  2703. {
  2704. unsigned int Length;
  2705. ServerMutex.Request();
  2706. Address = (RPC_ADDRESS *) RpcDormantAddresses.TakeOffQueue(&Length);
  2707. ServerMutex.Clear();
  2708. if (Address == 0)
  2709. {
  2710. break;
  2711. }
  2712. ASSERT(Length == 0);
  2713. if (Address->RestartAddress(MinimumCallThreads,
  2714. MaximumConcurrentCalls) != RPC_S_OK)
  2715. {
  2716. fTempQueueHasContents = TRUE;
  2717. if (tempQueue.PutOnQueue(Address, 0) != 0)
  2718. {
  2719. // putting on the temporary queue failed - out of memory
  2720. // in this case we'd rather cut the PnP process for now, and we'll
  2721. // go with what we have
  2722. // return the address
  2723. ServerMutex.Request();
  2724. // guaranteed to succeed
  2725. RpcDormantAddresses.PutOnQueue(Address, 0);
  2726. ServerMutex.Clear();
  2727. // break into merging the temp queue with the permanent one
  2728. break;
  2729. }
  2730. }
  2731. else
  2732. {
  2733. fChanged = 1;
  2734. }
  2735. }
  2736. if (fTempQueueHasContents)
  2737. {
  2738. ServerMutex.Request();
  2739. // merge back the queues - this should succeed if we have only added protocols. If we have
  2740. // removed protocols, this will fail, and we'll have a bug. Nothing we can do about it here.
  2741. RpcDormantAddresses.MergeWithQueue(&tempQueue);
  2742. ServerMutex.Clear();
  2743. }
  2744. if (fChanged)
  2745. {
  2746. ServerMutex.Request();
  2747. //
  2748. // Inquire the new bindings, and update them in the endpoint mapper
  2749. //
  2750. Status = InquireBindings(&BindingVector);
  2751. if (Status != RPC_S_OK)
  2752. {
  2753. goto Cleanup;
  2754. }
  2755. RpcInterfaceDictionary.Reset(cursor);
  2756. while ((RpcInterface = RpcInterfaceDictionary.Next(cursor)) != 0)
  2757. {
  2758. if (RpcInterface->NeedToUpdateBindings())
  2759. {
  2760. // we know an interface never gets deleted, only marked as
  2761. // unregistered. Therefore, it is safe to release the mutex
  2762. // and do the slow UpdateBindings outside the mutex
  2763. ServerMutex.Clear();
  2764. if ((Status = RpcInterface->UpdateBindings(BindingVector))
  2765. != RPC_S_OK)
  2766. {
  2767. goto Cleanup;
  2768. }
  2769. ServerMutex.Request();
  2770. }
  2771. }
  2772. ServerMutex.Clear();
  2773. Status = RpcBindingVectorFree(&BindingVector);
  2774. ASSERT(Status == RPC_S_OK);
  2775. }
  2776. return;
  2777. Cleanup:
  2778. if (BindingVector)
  2779. {
  2780. Status = RpcBindingVectorFree(&BindingVector);
  2781. ASSERT(Status == RPC_S_OK);
  2782. }
  2783. }
  2784. RPC_INTERFACE *
  2785. RPC_SERVER::FindOrCreateInterfaceInternal (
  2786. IN RPC_SERVER_INTERFACE PAPI * RpcInterfaceInformation,
  2787. IN unsigned int Flags,
  2788. IN unsigned int MaxCalls,
  2789. IN unsigned int MaxRpcSize,
  2790. IN RPC_IF_CALLBACK_FN PAPI *IfCallbackFn,
  2791. OUT RPC_STATUS *Status,
  2792. OUT BOOL *fInterfaceFound
  2793. )
  2794. /*++
  2795. Function Name: FindOrCreateInterfaceInternal
  2796. Parameters:
  2797. RpcInterfaceInformation
  2798. Flags
  2799. MaxCalls
  2800. MaxRpcSize
  2801. IfCallbackFn
  2802. Status - meaningless if the return value is not NULL.
  2803. fInterfaceFound - TRUE if the interface was found, FALSE if it was created
  2804. Description:
  2805. Find or creates an interface with the appropriate parameters
  2806. Returns:
  2807. --*/
  2808. {
  2809. RPC_INTERFACE * RpcInterface;
  2810. ServerMutex.VerifyOwned();
  2811. RpcInterface = FindInterface(RpcInterfaceInformation);
  2812. if ( RpcInterface == 0 )
  2813. {
  2814. RpcInterface = new RPC_INTERFACE(RpcInterfaceInformation,
  2815. this, Flags, MaxCalls, MaxRpcSize, IfCallbackFn, Status);
  2816. if ( RpcInterface == 0 )
  2817. {
  2818. *Status = RPC_S_OUT_OF_MEMORY;
  2819. return NULL;
  2820. }
  2821. if ( AddInterface(RpcInterface) != 0 )
  2822. {
  2823. delete RpcInterface;
  2824. *Status = RPC_S_OUT_OF_MEMORY;
  2825. return NULL;
  2826. }
  2827. if (Flags & RPC_IF_AUTOLISTEN)
  2828. {
  2829. GlobalRpcServer->IncrementAutoListenInterfaceCount() ;
  2830. }
  2831. *fInterfaceFound = FALSE;
  2832. }
  2833. else
  2834. {
  2835. *fInterfaceFound = TRUE;
  2836. }
  2837. *Status = RPC_S_OK;
  2838. return RpcInterface;
  2839. }
  2840. RPC_INTERFACE *
  2841. RPC_SERVER::FindOrCreateInterface (
  2842. IN RPC_SERVER_INTERFACE PAPI * RpcInterfaceInformation,
  2843. OUT RPC_STATUS *Status
  2844. )
  2845. {
  2846. RPC_INTERFACE * RpcInterface;
  2847. BOOL fIgnored;
  2848. ServerMutex.Request();
  2849. RpcInterface = FindOrCreateInterfaceInternal(RpcInterfaceInformation,
  2850. RPC_IF_ALLOW_SECURE_ONLY, 0, gMaxRpcSize, NULL, Status, &fIgnored);
  2851. ServerMutex.Clear();
  2852. return RpcInterface;
  2853. }
  2854. RPC_STATUS
  2855. RPC_SERVER::InterfaceExported (
  2856. IN RPC_SERVER_INTERFACE PAPI * RpcInterfaceInformation,
  2857. IN UUID_VECTOR *MyObjectUuidVector,
  2858. IN unsigned char *MyAnnotation,
  2859. IN BOOL MyfReplace
  2860. )
  2861. /*++
  2862. Function Name:InterfaceExported
  2863. Parameters:
  2864. Description:
  2865. RpcEpRegister was called on this interface. We need to keep track
  2866. of the parameters, so that if we get a PNP notification, we can update
  2867. the bindings using there params
  2868. Returns:
  2869. --*/
  2870. {
  2871. RPC_INTERFACE * RpcInterface;
  2872. RPC_STATUS Status;
  2873. RpcInterface = FindOrCreateInterface (RpcInterfaceInformation, &Status);
  2874. if (RpcInterface == NULL)
  2875. {
  2876. return Status;
  2877. }
  2878. return RpcInterface->InterfaceExported(
  2879. MyObjectUuidVector,
  2880. MyAnnotation,
  2881. MyfReplace);
  2882. }
  2883. #if !defined(NO_LOCATOR_CODE)
  2884. RPC_STATUS
  2885. RPC_SERVER::NsInterfaceExported (
  2886. IN unsigned long EntryNameSyntax,
  2887. IN RPC_CHAR *EntryName,
  2888. IN RPC_SERVER_INTERFACE PAPI * RpcInterfaceInformation,
  2889. IN BOOL fUnexport
  2890. )
  2891. {
  2892. RPC_INTERFACE * RpcInterface;
  2893. RPC_STATUS Status;
  2894. HMODULE hLocator;
  2895. if (pNsBindingExport == 0)
  2896. {
  2897. hLocator = LoadLibrary ((const RPC_SCHAR *)RPC_CONST_STRING("rpcns4.dll"));
  2898. if (hLocator == 0)
  2899. {
  2900. return RPC_S_OUT_OF_MEMORY;
  2901. }
  2902. pNsBindingExport = (NS_EXPORT_FUNC) GetProcAddress(hLocator,
  2903. "RpcNsBindingExportW");
  2904. if (pNsBindingExport == 0)
  2905. {
  2906. return RPC_S_OUT_OF_MEMORY;
  2907. }
  2908. pNsBindingUnexport = (NS_UNEXPORT_FUNC) GetProcAddress(hLocator,
  2909. "RpcNsBindingUnexportW");
  2910. if (pNsBindingUnexport == 0)
  2911. {
  2912. pNsBindingExport = 0;
  2913. return RPC_S_OUT_OF_MEMORY;
  2914. }
  2915. }
  2916. RpcInterface = FindOrCreateInterface (RpcInterfaceInformation, &Status);
  2917. if (RpcInterface == NULL)
  2918. {
  2919. return Status;
  2920. }
  2921. if (fUnexport == 0)
  2922. {
  2923. return RpcInterface->NsInterfaceExported(
  2924. EntryNameSyntax,
  2925. EntryName);
  2926. }
  2927. else
  2928. {
  2929. return RpcInterface->NsInterfaceUnexported(
  2930. EntryNameSyntax,
  2931. EntryName);
  2932. }
  2933. }
  2934. #endif
  2935. RPC_STATUS
  2936. RPC_SERVER::EnumerateAndCallEachAddress (
  2937. IN AddressCallbackType actType,
  2938. IN OUT void *Context OPTIONAL
  2939. )
  2940. /*++
  2941. Function Name: DestroyContextHandlesForInterface
  2942. Parameters:
  2943. actType - the type of callback.
  2944. Context - opaque memory block to be passed to the callback.
  2945. Description:
  2946. This function is called when we want to invoke a specific method
  2947. on each address.
  2948. Returns:
  2949. RPC_S_OK for success or RPC_S_* for error
  2950. --*/
  2951. {
  2952. RPC_ADDRESS_DICT AddressDict;
  2953. RPC_ADDRESS_DICT *AddressDictToUse;
  2954. RPC_ADDRESS *CurrentAddress;
  2955. BOOL UsingAddressDictionaryCopy;
  2956. int Result;
  2957. DictionaryCursor cursor;
  2958. DestroyContextHandleCallbackContext *ContextHandleContext;
  2959. // try to copy all entries in the address dictionary to the local
  2960. // dictionary. We will walk the address list from there to avoid
  2961. // holding the server mutex while walking potentially large tree.
  2962. // If we do that, only the page faults will be enough to kill the
  2963. // server. On the other hand, we can't rely that the memory will be
  2964. // there. Therefore, we attempt to copy the dictionary under the
  2965. // mutex, but if this fails, we will retain the mutex and go ahead
  2966. // with the cleanup. The logic behind this is that if we don't have
  2967. // the few bytes to copy the dictionary, probably the server isn't
  2968. // doing anything, and holding the mutex won't hurt it anymore
  2969. ServerMutex.Request();
  2970. #if DBG
  2971. if (actType == actDestroyContextHandle)
  2972. {
  2973. RPC_INTERFACE *Interface;
  2974. ContextHandleContext = (DestroyContextHandleCallbackContext *)Context;
  2975. Interface = FindInterface(ContextHandleContext->RpcInterfaceInformation);
  2976. ASSERT(Interface);
  2977. // the interface must use strict context handles
  2978. ASSERT(Interface->DoesInterfaceUseNonStrict() == FALSE);
  2979. }
  2980. #endif
  2981. UsingAddressDictionaryCopy = AddressDict.ExpandToSize(RpcAddressDictionary.Size());
  2982. if (UsingAddressDictionaryCopy)
  2983. {
  2984. AddressDictToUse = &AddressDict;
  2985. RpcAddressDictionary.Reset(cursor);
  2986. while ( (CurrentAddress = RpcAddressDictionary.Next(cursor)) != 0 )
  2987. {
  2988. // we never destroy addresses. Therefore, we don't need to mark
  2989. // those addresses as used in any way
  2990. Result = AddressDict.Insert(CurrentAddress);
  2991. // this must succeed as we have reserved enough size
  2992. ASSERT(Result != -1);
  2993. }
  2994. ServerMutex.Clear();
  2995. }
  2996. else
  2997. {
  2998. AddressDictToUse = &RpcAddressDictionary;
  2999. }
  3000. // N.B. We may, or may not have the ServerMutex here - depending on how
  3001. // we were doing with memory
  3002. AddressDictToUse->Reset(cursor);
  3003. while ( (CurrentAddress = AddressDictToUse->Next(cursor)) != 0 )
  3004. {
  3005. switch (actType)
  3006. {
  3007. case actDestroyContextHandle:
  3008. ContextHandleContext = (DestroyContextHandleCallbackContext *)Context;
  3009. CurrentAddress->DestroyContextHandlesForInterface(
  3010. ContextHandleContext->RpcInterfaceInformation,
  3011. ContextHandleContext->RundownContextHandles
  3012. );
  3013. break;
  3014. case actCleanupIdleSContext:
  3015. CurrentAddress->CleanupIdleSContexts();
  3016. break;
  3017. default:
  3018. ASSERT(0);
  3019. }
  3020. }
  3021. if (!UsingAddressDictionaryCopy)
  3022. {
  3023. ServerMutex.Clear();
  3024. }
  3025. return RPC_S_OK;
  3026. }
  3027. RPC_STATUS
  3028. RPC_ENTRY
  3029. I_RpcNsInterfaceExported (
  3030. IN unsigned long EntryNameSyntax,
  3031. IN unsigned short *EntryName,
  3032. IN RPC_SERVER_INTERFACE PAPI * RpcInterfaceInformation
  3033. )
  3034. {
  3035. #if !defined(NO_LOCATOR_CODE)
  3036. InitializeIfNecessary();
  3037. return (GlobalRpcServer->NsInterfaceExported(
  3038. EntryNameSyntax,
  3039. EntryName,
  3040. RpcInterfaceInformation, 0));
  3041. #else
  3042. return RPC_S_CANNOT_SUPPORT;
  3043. #endif
  3044. }
  3045. RPC_STATUS
  3046. RPC_ENTRY
  3047. I_RpcNsInterfaceUnexported (
  3048. IN unsigned long EntryNameSyntax,
  3049. IN unsigned short *EntryName,
  3050. IN RPC_SERVER_INTERFACE PAPI * RpcInterfaceInformation
  3051. )
  3052. {
  3053. #if !defined(NO_LOCATOR_CODE)
  3054. InitializeIfNecessary();
  3055. return (GlobalRpcServer->NsInterfaceExported(
  3056. EntryNameSyntax,
  3057. EntryName,
  3058. RpcInterfaceInformation, 1));
  3059. #else
  3060. return RPC_S_CANNOT_SUPPORT;
  3061. #endif
  3062. }
  3063. #define MAXIMUM_CACHED_THREAD_TIMEOUT (1000L * 60L * 60L)
  3064. void
  3065. BaseCachedThreadRoutine (
  3066. IN CACHED_THREAD * CachedThread
  3067. )
  3068. /*++
  3069. Routine Description:
  3070. Each thread will execute this routine. When it first gets called, it
  3071. will immediately call the procedure and parameter specified in the
  3072. cached thread object. After that it will wait on its event and then
  3073. execute the specified routine everytime it gets woken up. If the wait
  3074. on the event times out, the thread will exit unless it has been protected.
  3075. Arguments:
  3076. CachedThread - Supplies the cached thread object to be used by this
  3077. thread.
  3078. --*/
  3079. {
  3080. RPC_SERVER * RpcServer = CachedThread->OwningRpcServer;
  3081. THREAD *pThread = RpcpGetThreadPointer();
  3082. long WaitTimeout;
  3083. ASSERT(pThread);
  3084. while (pThread->ThreadHandle() == (void *) -1)
  3085. {
  3086. Sleep(1);
  3087. }
  3088. ASSERT(pThread->ThreadHandle());
  3089. CachedThread->SetThread(pThread);
  3090. if (pThread->DebugCell)
  3091. {
  3092. pThread->DebugCell->TID = (unsigned short)GetCurrentThreadId();
  3093. pThread->DebugCell->LastUpdateTime = NtGetTickCount();
  3094. }
  3095. for(;;)
  3096. {
  3097. if (CachedThread->CallProcedure())
  3098. {
  3099. #ifdef RPC_OLD_IO_PROTECTION
  3100. // This thread has already timed-out waiting on
  3101. // a transport level cache. Let it go now...
  3102. ASSERT(pThread->InqProtectCount() == 1);
  3103. #endif
  3104. if (pThread->IsIOPending() == FALSE)
  3105. {
  3106. delete CachedThread;
  3107. return;
  3108. }
  3109. // we're a cached IOCP thread - we need to unjoin the IOCP
  3110. UnjoinCompletionPort();
  3111. }
  3112. WaitTimeout = gThreadTimeout;
  3113. // Now we cache this thread. This consists of clearing the
  3114. // work available flag and inserting the thread cache object into
  3115. // the list thread cache objects.
  3116. CachedThread->WorkAvailableFlag = WorkIsNotAvailable;
  3117. RpcServer->ThreadCacheMutex.Request();
  3118. RpcServer->InsertIntoFreeList(CachedThread);
  3119. RpcServer->ThreadCacheMutex.Clear();
  3120. // Now we loop waiting for work. We get out of the loop in three
  3121. // ways: (1) a timeout occurs and there is work to do, (2) the
  3122. // event gets kicked because there is work to do, (3) a timeout
  3123. // occurs, there is no work to do, and the thread is not protected.
  3124. for (;;)
  3125. {
  3126. // Ignore spurious signals.
  3127. while( (CachedThread->WaitForWorkEvent.Wait(WaitTimeout) == 0)
  3128. && (CachedThread->WorkAvailableFlag == WorkIsNotAvailable) )
  3129. ;
  3130. if (CachedThread->WorkAvailableFlag == WorkIsAvailable)
  3131. {
  3132. break;
  3133. }
  3134. // We must take the lock to avoid a race condition where another
  3135. // thread is trying to signal us right now.
  3136. RpcServer->ThreadCacheMutex.Request();
  3137. if (CachedThread->WorkAvailableFlag)
  3138. {
  3139. RpcServer->ThreadCacheMutex.Clear();
  3140. break;
  3141. }
  3142. if (pThread->IsIOPending())
  3143. {
  3144. // If we reach here, there is no work available, and the thread
  3145. // is protected. We just need to wait again. There is no need to
  3146. // busy wait if the thread is protected and it keeps timing out.
  3147. if (WaitTimeout < MAXIMUM_CACHED_THREAD_TIMEOUT/2)
  3148. {
  3149. WaitTimeout = WaitTimeout * 2;
  3150. }
  3151. // Since this thread can't exit anyway, move it to the front of the
  3152. // free list so it will be reused first.
  3153. RpcServer->RemoveFromFreeList(CachedThread);
  3154. RpcServer->InsertIntoFreeList(CachedThread);
  3155. RpcServer->ThreadCacheMutex.Clear();
  3156. continue;
  3157. }
  3158. // No work available.
  3159. #ifdef RPC_OLD_IO_PROTECTION
  3160. ASSERT(pThread->InqProtectCount() == 1);
  3161. #endif
  3162. // There is no work available, and this thread is not
  3163. // protected, so we can safely let it commit suicide.
  3164. RpcServer->RemoveFromFreeList(CachedThread);
  3165. RpcServer->ThreadCacheMutex.Clear();
  3166. delete CachedThread;
  3167. return;
  3168. }
  3169. ASSERT(CachedThread->WorkAvailableFlag == WorkIsAvailable);
  3170. }
  3171. NO_RETURN;
  3172. }
  3173. RPC_STATUS
  3174. RPC_SERVER::CreateThread (
  3175. IN THREAD_PROC Procedure,
  3176. IN void * Parameter
  3177. )
  3178. /*++
  3179. Routine Description:
  3180. This routine is used to create a new thread which will begin
  3181. executing the specified procedure. The procedure will be passed
  3182. parameter as the argument.
  3183. Arguments:
  3184. Procedure - Supplies the procedure which the new thread should
  3185. begin executing.
  3186. Parameter - Supplies the argument to be passed to the procedure.
  3187. Return Value:
  3188. RPC_S_OK - We successfully created a new thread and started it
  3189. executing the supplied procedure.
  3190. RPC_S_OUT_OF_THREADS - We could not create another thread.
  3191. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to allocate
  3192. the data structures we need to complete this operation.
  3193. --*/
  3194. {
  3195. THREAD * Thread;
  3196. CACHED_THREAD * CachedThread;
  3197. RPC_STATUS RpcStatus = RPC_S_OK;
  3198. ThreadCacheMutex.Request();
  3199. CachedThread = RemoveHeadFromFreeList();
  3200. if (CachedThread)
  3201. {
  3202. // set all parameters within the mutex to avoid races
  3203. CachedThread->SetWakeUpThreadParams(Procedure, Parameter);
  3204. ThreadCacheMutex.Clear();
  3205. CachedThread->WakeUpThread();
  3206. return(RPC_S_OK);
  3207. }
  3208. ThreadCacheMutex.Clear();
  3209. if (IsServerSideDebugInfoEnabled())
  3210. {
  3211. RpcStatus = InitializeServerSideCellHeapIfNecessary();
  3212. if (RpcStatus != RPC_S_OK)
  3213. return RpcStatus;
  3214. }
  3215. CachedThread = new CACHED_THREAD(Procedure, Parameter, this, &RpcStatus);
  3216. if ( CachedThread == 0 )
  3217. {
  3218. return(RPC_S_OUT_OF_MEMORY);
  3219. }
  3220. if ( RpcStatus != RPC_S_OK )
  3221. {
  3222. delete CachedThread;
  3223. return(RpcStatus);
  3224. }
  3225. ASSERT( RpcStatus == RPC_S_OK );
  3226. Thread = new THREAD((THREAD_PROC) BaseCachedThreadRoutine, CachedThread,
  3227. &RpcStatus);
  3228. if (Thread == 0)
  3229. {
  3230. delete CachedThread;
  3231. return(RPC_S_OUT_OF_THREADS);
  3232. }
  3233. if (RpcStatus != RPC_S_OK)
  3234. {
  3235. delete CachedThread;
  3236. delete Thread;
  3237. if (RpcStatus == ERROR_MAX_THRDS_REACHED)
  3238. RpcStatus = RPC_S_OUT_OF_THREADS;
  3239. }
  3240. return(RpcStatus);
  3241. }
  3242. RPC_STATUS
  3243. RPC_SERVER::InquireInterfaceIds (
  3244. OUT RPC_IF_ID_VECTOR __RPC_FAR * __RPC_FAR * InterfaceIdVector
  3245. )
  3246. /*++
  3247. Routine Description:
  3248. This routine is used to obtain a vector of the interface identifiers of
  3249. the interfaces supported by this server.
  3250. Arguments:
  3251. IfIdVector - Returns a vector of the interfaces supported by this server.
  3252. Return Value:
  3253. RPC_S_OK - Everything worked out just great.
  3254. RPC_S_NO_INTERFACES - No interfaces have been registered with the runtime.
  3255. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to allocate
  3256. the interface id vector.
  3257. --*/
  3258. {
  3259. DictionaryCursor cursor;
  3260. ServerMutex.Request();
  3261. if (RpcInterfaceDictionary.Size() == 0)
  3262. {
  3263. ServerMutex.Clear();
  3264. *InterfaceIdVector = 0;
  3265. return RPC_S_NO_INTERFACES;
  3266. }
  3267. *InterfaceIdVector = (RPC_IF_ID_VECTOR __RPC_FAR *) RpcpFarAllocate(
  3268. sizeof(RPC_IF_ID_VECTOR) + (RpcInterfaceDictionary.Size() - 1)
  3269. * sizeof(RPC_IF_ID __RPC_FAR *));
  3270. if ( *InterfaceIdVector == 0 )
  3271. {
  3272. ServerMutex.Clear();
  3273. return(RPC_S_OUT_OF_MEMORY);
  3274. }
  3275. (*InterfaceIdVector)->Count = 0;
  3276. (*InterfaceIdVector)->IfId[0] = (RPC_IF_ID __RPC_FAR *) RpcpFarAllocate(
  3277. sizeof(RPC_IF_ID));
  3278. RpcInterfaceDictionary.Reset(cursor);
  3279. RPC_INTERFACE * RpcInterface;
  3280. while ((RpcInterface = RpcInterfaceDictionary.Next(cursor)) != 0)
  3281. {
  3282. (*InterfaceIdVector)->IfId[(*InterfaceIdVector)->Count] =
  3283. RpcInterface->InquireInterfaceId();
  3284. if ( (*InterfaceIdVector)->IfId[(*InterfaceIdVector)->Count] != 0 )
  3285. {
  3286. RPC_IF_ID * Interface = (*InterfaceIdVector)->IfId[(*InterfaceIdVector)->Count];
  3287. (*InterfaceIdVector)->Count += 1;
  3288. }
  3289. }
  3290. ServerMutex.Clear();
  3291. if (0 == (*InterfaceIdVector)->Count)
  3292. {
  3293. RpcpFarFree(*InterfaceIdVector);
  3294. *InterfaceIdVector = 0;
  3295. return RPC_S_NO_INTERFACES;
  3296. }
  3297. return(RPC_S_OK);
  3298. }
  3299. RPC_STATUS
  3300. RPC_SERVER::InquirePrincipalName (
  3301. IN unsigned long AuthenticationService,
  3302. OUT RPC_CHAR __RPC_FAR * __RPC_FAR * ServerPrincipalName
  3303. )
  3304. /*++
  3305. Routine Description:
  3306. Arguments:
  3307. Return Value:
  3308. RPC_S_OK - The operation completed successfully.
  3309. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to complete the
  3310. operation.
  3311. RPC_S_UNKNOWN_AUTHN_SERVICE - The specified authentication service is
  3312. not supported.
  3313. --*/
  3314. {
  3315. RPC_AUTHENTICATION * Service;
  3316. DictionaryCursor cursor;
  3317. ServerMutex.Request();
  3318. AuthenticationDictionary.Reset(cursor);
  3319. while ( (Service = AuthenticationDictionary.Next(cursor)) != 0 )
  3320. {
  3321. if ( Service->AuthenticationService == AuthenticationService )
  3322. {
  3323. ServerMutex.Clear();
  3324. *ServerPrincipalName = DuplicateString(
  3325. Service->ServerPrincipalName);
  3326. if ( *ServerPrincipalName == 0 )
  3327. {
  3328. return(RPC_S_OUT_OF_MEMORY);
  3329. }
  3330. return(RPC_S_OK);
  3331. }
  3332. }
  3333. ServerMutex.Clear();
  3334. return(RPC_S_UNKNOWN_AUTHN_SERVICE);
  3335. }
  3336. void
  3337. RPC_SERVER::RegisterRpcForwardFunction (
  3338. RPC_FORWARD_FUNCTION * pForwardFunction
  3339. )
  3340. /*++
  3341. Routine Description:
  3342. Sets the RPC_SERVER pEpmapperForwardFunction. (The pEpmapperForwardFunction
  3343. is the function the runtime can call when it receives a pkt for a
  3344. dynamic endpoint. pEpmapperForwardFunction will return endpoint of
  3345. the server to forward the pkt to).
  3346. Arguments:
  3347. pForwardFunction - pointer to the epmapper forward function.
  3348. Return Value:
  3349. none
  3350. --*/
  3351. {
  3352. pRpcForwardFunction = pForwardFunction;
  3353. }
  3354. RPC_STATUS
  3355. RPC_SERVER::UnregisterEndpoint (
  3356. IN RPC_CHAR __RPC_FAR * Protseq,
  3357. IN RPC_CHAR __RPC_FAR * Endpoint
  3358. )
  3359. {
  3360. return (RPC_S_CANNOT_SUPPORT);
  3361. }
  3362. RPC_ADDRESS::RPC_ADDRESS (
  3363. IN OUT RPC_STATUS PAPI * RpcStatus
  3364. ) : AddressMutex(RpcStatus,
  3365. TRUE // pre-allocate semaphore
  3366. )
  3367. /*++
  3368. Routine Description:
  3369. We just need to initialization some stuff to zero. That way if we
  3370. later have to delete this address because of an error in initialization
  3371. we can tell what instance variables need to be freed.
  3372. --*/
  3373. {
  3374. NetworkAddress = 0;
  3375. Endpoint = 0;
  3376. RpcProtocolSequence = 0;
  3377. }
  3378. RPC_ADDRESS::~RPC_ADDRESS (
  3379. )
  3380. /*++
  3381. Routine Description:
  3382. This routine will only get called if part way through initialization
  3383. an error occurs. We just need to free up any memory used by instance
  3384. variables. Once FireUpManager has been called and succeeds, the
  3385. address will never be destroyed.
  3386. --*/
  3387. {
  3388. if (Endpoint != 0)
  3389. delete Endpoint;
  3390. if (RpcProtocolSequence != 0)
  3391. delete RpcProtocolSequence;
  3392. }
  3393. RPC_CHAR *
  3394. RPC_ADDRESS::GetListNetworkAddress (
  3395. IN unsigned int Index
  3396. )
  3397. /*++
  3398. Routine Description:
  3399. A pointer to the network address for this address is returned.
  3400. --*/
  3401. {
  3402. if (Index >= pNetworkAddressVector->Count)
  3403. {
  3404. return (NULL);
  3405. }
  3406. return(pNetworkAddressVector->NetworkAddresses[Index]);
  3407. }
  3408. RPC_STATUS
  3409. RPC_ADDRESS::CopyDescriptor (
  3410. IN void *SecurityDescriptor,
  3411. OUT void **OutDescriptor
  3412. )
  3413. {
  3414. BOOL b;
  3415. SECURITY_DESCRIPTOR_CONTROL Control;
  3416. DWORD Revision;
  3417. DWORD BufferLength;
  3418. if ( IsValidSecurityDescriptor(SecurityDescriptor) == FALSE )
  3419. {
  3420. return(RPC_S_INVALID_SECURITY_DESC);
  3421. }
  3422. if (FALSE == GetSecurityDescriptorControl(SecurityDescriptor, &Control, &Revision))
  3423. {
  3424. return(RPC_S_INVALID_SECURITY_DESC);
  3425. }
  3426. if (Control & SE_SELF_RELATIVE)
  3427. {
  3428. //
  3429. // Already self-relative, just copy it.
  3430. //
  3431. BufferLength = GetSecurityDescriptorLength(SecurityDescriptor);
  3432. ASSERT(BufferLength >= sizeof(SECURITY_DESCRIPTOR));
  3433. *OutDescriptor = RpcpFarAllocate(BufferLength);
  3434. if (*OutDescriptor == 0)
  3435. {
  3436. return(RPC_S_OUT_OF_MEMORY);
  3437. }
  3438. memcpy(*OutDescriptor, SecurityDescriptor, BufferLength);
  3439. return(RPC_S_OK);
  3440. }
  3441. //
  3442. // Make self-relative and copy it.
  3443. //
  3444. BufferLength = 0;
  3445. b = MakeSelfRelativeSD(SecurityDescriptor, 0, &BufferLength);
  3446. ASSERT(b == FALSE);
  3447. if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER )
  3448. {
  3449. return(RPC_S_INVALID_SECURITY_DESC);
  3450. }
  3451. ASSERT(BufferLength >= sizeof(SECURITY_DESCRIPTOR_RELATIVE));
  3452. *OutDescriptor = RpcpFarAllocate(BufferLength);
  3453. if (*OutDescriptor == 0)
  3454. {
  3455. return(RPC_S_OUT_OF_MEMORY);
  3456. }
  3457. b = MakeSelfRelativeSD(SecurityDescriptor,
  3458. *OutDescriptor,
  3459. &BufferLength);
  3460. if (b == FALSE)
  3461. {
  3462. ASSERT(GetLastError() != ERROR_INSUFFICIENT_BUFFER);
  3463. delete *OutDescriptor;
  3464. return(RPC_S_OUT_OF_MEMORY);
  3465. }
  3466. return(RPC_S_OK);
  3467. }
  3468. RPC_STATUS
  3469. RPC_ADDRESS::SetEndpointAndStuff (
  3470. IN RPC_CHAR PAPI * NetworkAddress,
  3471. IN RPC_CHAR PAPI * Endpoint,
  3472. IN RPC_CHAR PAPI * RpcProtocolSequence,
  3473. IN RPC_SERVER * Server,
  3474. IN unsigned int StaticEndpointFlag,
  3475. IN unsigned int PendingQueueSize,
  3476. IN void PAPI *SecurityDescriptor,
  3477. IN unsigned long EndpointFlags,
  3478. IN unsigned long NICFlags,
  3479. IN NETWORK_ADDRESS_VECTOR *pNetworkAddressVector
  3480. )
  3481. /*++
  3482. Routine Description:
  3483. We just need to set some instance variables of this rpc address.
  3484. Arguments:
  3485. Endpoint - Supplies the endpoint for this rpc address.
  3486. RpcProtocolSequence - Supplies the rpc protocol sequence for this
  3487. rpc address.
  3488. Server - Supplies the rpc server which owns this rpc address.
  3489. StaticEndpointFlag - Supplies a flag which specifies whether this
  3490. address has a static endpoint or a dynamic endpoint.
  3491. --*/
  3492. {
  3493. RPC_STATUS Status;
  3494. this->NetworkAddress = NetworkAddress;
  3495. this->Endpoint = Endpoint;
  3496. this->RpcProtocolSequence = RpcProtocolSequence;
  3497. this->pNetworkAddressVector = pNetworkAddressVector;
  3498. this->Server = Server;
  3499. this->StaticEndpointFlag = StaticEndpointFlag;
  3500. this->PendingQueueSize = PendingQueueSize;
  3501. this->EndpointFlags = EndpointFlags;
  3502. this->NICFlags = NICFlags;
  3503. if (SecurityDescriptor)
  3504. {
  3505. Status = CopyDescriptor(SecurityDescriptor,
  3506. &this->SecurityDescriptor);
  3507. if (Status != RPC_S_OK)
  3508. {
  3509. return Status;
  3510. }
  3511. }
  3512. return RPC_S_OK;
  3513. }
  3514. RPC_STATUS
  3515. RPC_ADDRESS::FindInterfaceTransfer (
  3516. IN PRPC_SYNTAX_IDENTIFIER InterfaceIdentifier,
  3517. IN PRPC_SYNTAX_IDENTIFIER ProposedTransferSyntaxes,
  3518. IN unsigned int NumberOfTransferSyntaxes,
  3519. OUT PRPC_SYNTAX_IDENTIFIER AcceptedTransferSyntax,
  3520. OUT RPC_INTERFACE ** RpcInterface,
  3521. OUT BOOL *fIsInterfaceTransferPreferred,
  3522. OUT int *ProposedTransferSyntaxIndex,
  3523. OUT int *AvailableTransferSyntaxIndex
  3524. )
  3525. /*++
  3526. Routine Description:
  3527. This method is used to determine if a client bind request can be
  3528. accepted or not. All we have got to do here is hand off to the
  3529. server which owns this address.
  3530. Arguments:
  3531. InterfaceIdentifier - Supplies the syntax identifier for the
  3532. interface; this is the interface uuid and version.
  3533. ProposedTransferSyntaxes - Supplies a list of one or more transfer
  3534. syntaxes which the client initiating the binding supports. The
  3535. server should pick one of these which is supported by the
  3536. interface.
  3537. NumberOfTransferSyntaxes - Supplies the number of transfer syntaxes
  3538. specified in the proposed transfer syntaxes argument.
  3539. AcceptedTransferSyntax - Returns the transfer syntax which the
  3540. server accepted.
  3541. RpcInterface - Returns a pointer to the rpc interface found which
  3542. supports the requested interface and one of the requested transfer
  3543. syntaxes.
  3544. Return Value:
  3545. RPC_S_OK - The requested interface exists and it supports at least
  3546. one of the proposed transfer syntaxes. We are all set, now we
  3547. can make remote procedure calls.
  3548. RPC_P_UNSUPPORTED_TRANSFER_SYNTAX - The requested interface exists,
  3549. but it does not support any of the proposed transfer syntaxes.
  3550. RPC_P_UNSUPPORTED_INTERFACE - The requested interface is not supported
  3551. by this rpc server.
  3552. --*/
  3553. {
  3554. return Server->FindInterfaceTransfer(
  3555. InterfaceIdentifier,
  3556. ProposedTransferSyntaxes,
  3557. NumberOfTransferSyntaxes,
  3558. AcceptedTransferSyntax,
  3559. RpcInterface,
  3560. fIsInterfaceTransferPreferred,
  3561. ProposedTransferSyntaxIndex,
  3562. AvailableTransferSyntaxIndex);
  3563. }
  3564. BINDING_HANDLE *
  3565. RPC_ADDRESS::InquireBinding (
  3566. RPC_CHAR * LocalNetworkAddress
  3567. )
  3568. /*++
  3569. Routine Description:
  3570. We need to return create and return a binding handle which can
  3571. be used by a client to make remote procedure calls to this rpc
  3572. address.
  3573. Return Value:
  3574. A newly created binding handle will be returned, inless an out
  3575. of memory error occurs, in which case zero will be returned.
  3576. --*/
  3577. {
  3578. RPC_STATUS Status;
  3579. DCE_BINDING * DceBinding;
  3580. BINDING_HANDLE * BindingHandle;
  3581. RPC_CHAR * DynamicEndpoint = 0;
  3582. RPC_CHAR * PAPI * tmpPtr;
  3583. if(LocalNetworkAddress == 0)
  3584. {
  3585. LocalNetworkAddress = pNetworkAddressVector->NetworkAddresses[0];
  3586. }
  3587. DceBinding = new DCE_BINDING(
  3588. 0,
  3589. RpcProtocolSequence,
  3590. LocalNetworkAddress,
  3591. (StaticEndpointFlag != 0 ? Endpoint : 0),
  3592. 0,
  3593. &Status);
  3594. if ((DceBinding == 0)
  3595. || (Status != RPC_S_OK))
  3596. {
  3597. delete DceBinding;
  3598. return(0);
  3599. }
  3600. if (StaticEndpointFlag == 0)
  3601. {
  3602. DynamicEndpoint = DuplicateString(Endpoint);
  3603. if (DynamicEndpoint == 0)
  3604. {
  3605. delete DceBinding;
  3606. return(0);
  3607. }
  3608. }
  3609. BindingHandle = new SVR_BINDING_HANDLE(DceBinding, DynamicEndpoint, &Status);
  3610. if (BindingHandle == 0)
  3611. {
  3612. delete DceBinding;
  3613. }
  3614. return(BindingHandle);
  3615. }
  3616. RPC_STATUS
  3617. RPC_ADDRESS::ServerStartingToListen (
  3618. IN unsigned int MinimumCallThreads,
  3619. IN unsigned int MaximumConcurrentCalls
  3620. )
  3621. /*++
  3622. Routine Description:
  3623. This method will be called for each address when the server starts
  3624. listening. In addition, if an address is added while the server is
  3625. listening, then this method will be called. The purpose of the method
  3626. is to notify the address about the minimum number of call threads
  3627. required; the maximum concurrent calls can safely be ignored, but it
  3628. can be used to set an upper bound on the number of call threads.
  3629. Arguments:
  3630. MinimumCallThreads - Supplies a number indicating the minimum number
  3631. of call threads which should be created for this address.
  3632. MaximumConcurrentCalls - Supplies the maximum number of concurrent
  3633. calls which this server will support.
  3634. Return Value:
  3635. RPC_S_OK - This routine will always return this value. Protocol
  3636. support modules may return other values.
  3637. --*/
  3638. {
  3639. UNUSED(MinimumCallThreads);
  3640. UNUSED(MaximumConcurrentCalls);
  3641. return(RPC_S_OK);
  3642. }
  3643. void
  3644. RPC_ADDRESS::ServerStoppedListening (
  3645. )
  3646. /*++
  3647. Routine Description:
  3648. This routine will be called to notify an address that the server has
  3649. stopped listening for remote procedure calls. Each protocol module
  3650. may override this routine; it is safe not too, but not as efficient.
  3651. Note that this routine will be called before all calls using the
  3652. server have been allowed to complete.
  3653. --*/
  3654. {
  3655. }
  3656. long
  3657. RPC_ADDRESS::InqNumberOfActiveCalls (
  3658. )
  3659. /*++
  3660. Return Value:
  3661. Each protocol module will define this routine. We will use this
  3662. functionality when the server has stopped listening and is waiting
  3663. for all remote procedure calls to complete. The number of active calls
  3664. for the address will be returned.
  3665. --*/
  3666. {
  3667. return(ActiveCallCount);
  3668. }
  3669. RPC_STATUS
  3670. RPC_ADDRESS::RestartAddress (
  3671. IN unsigned int MinThreads,
  3672. IN unsigned int MaxCalls
  3673. )
  3674. {
  3675. RPC_STATUS Status;
  3676. int Key;
  3677. Status = ServerSetupAddress(
  3678. NetworkAddress,
  3679. &Endpoint,
  3680. PendingQueueSize,
  3681. SecurityDescriptor,
  3682. EndpointFlags,
  3683. NICFlags,
  3684. &pNetworkAddressVector);
  3685. if (Status != RPC_S_OK)
  3686. {
  3687. pNetworkAddressVector = NULL;
  3688. return Status;
  3689. }
  3690. Key = Server->AddAddress(this);
  3691. if (Key == -1)
  3692. {
  3693. return RPC_S_OUT_OF_MEMORY;
  3694. }
  3695. Server->ServerMutex.Request();
  3696. Status = ServerStartingToListen(MinThreads, MaxCalls);
  3697. Server->ServerMutex.Clear();
  3698. if (Status != RPC_S_OK)
  3699. {
  3700. return Status;
  3701. }
  3702. CompleteListen();
  3703. return RPC_S_OK;
  3704. }
  3705. void
  3706. RPC_ADDRESS::DestroyContextHandlesForInterface (
  3707. IN RPC_SERVER_INTERFACE PAPI * ,
  3708. IN BOOL
  3709. )
  3710. /*++
  3711. Function Name: DestroyContextHandlesForInterface
  3712. Parameters:
  3713. RpcInterfaceInformation - the interface for which context handles
  3714. are to be unregistered
  3715. RundownContextHandles - if non-zero, rundown the context handles. If
  3716. FALSE, destroy the runtime portion of the context handle resource,
  3717. but don't call the user rundown routine.
  3718. Description:
  3719. Each protocol engine will implement its own version of this routine,
  3720. if it supports the feature. For those who don't, this routine provides
  3721. default no-op behaviour
  3722. Returns:
  3723. --*/
  3724. {
  3725. }
  3726. void
  3727. RPC_ADDRESS::CleanupIdleSContexts (
  3728. void
  3729. )
  3730. /*++
  3731. Function Name: CleanupIdleSContexts
  3732. Parameters:
  3733. Description:
  3734. Each protocol engine will implement its own version of this routine,
  3735. if it supports the feature. For those who don't, this routine provides
  3736. default no-op behaviour
  3737. Returns:
  3738. --*/
  3739. {
  3740. }
  3741. /*====================================================================
  3742. SCONNECTION
  3743. ==================================================================== */
  3744. RPC_STATUS
  3745. SetThreadSecurityContext(
  3746. SECURITY_CONTEXT * Context
  3747. )
  3748. /*++
  3749. Routine Description:
  3750. RpcImpersonateClient() takes a handle_t, so many threads can impersonate
  3751. the client of a single SCONNECTION. RPC needs to record which context
  3752. each thread is using. It is logical to place this in the TLS, but threads
  3753. not created by RPC lack the THREAD structure in their TLS. This wrapper
  3754. function will store the security context in the TLS if available, or
  3755. place the context in a dictionary if not.
  3756. Arguments:
  3757. Context - the security context to associate with this thread
  3758. Return Value:
  3759. RPC_S_OK if successful
  3760. RPC_S_OUT_OF_MEMORY if the dictionary insertion failed
  3761. --*/
  3762. {
  3763. THREAD * ThreadInfo = ThreadSelf();
  3764. if (ThreadInfo)
  3765. {
  3766. ThreadInfo->SecurityContext = Context;
  3767. return RPC_S_OK;
  3768. }
  3769. return RPC_S_OUT_OF_MEMORY;
  3770. }
  3771. SECURITY_CONTEXT *
  3772. QueryThreadSecurityContext(
  3773. )
  3774. /*++
  3775. Routine Description:
  3776. Fetches the security context associated with this thread for this
  3777. connection. We check the TLS if available; if nothing is there
  3778. then we scan the connection's dictionary.
  3779. Arguments:
  3780. none
  3781. Return Value:
  3782. the associated security context, or zero if none is found
  3783. --*/
  3784. {
  3785. THREAD * ThreadInfo = ThreadSelf();
  3786. if (ThreadInfo)
  3787. {
  3788. if (ThreadInfo->SecurityContext)
  3789. {
  3790. return (SECURITY_CONTEXT *) ThreadInfo->SecurityContext;
  3791. }
  3792. }
  3793. return 0;
  3794. }
  3795. SECURITY_CONTEXT *
  3796. ClearThreadSecurityContext(
  3797. )
  3798. /*++
  3799. Routine Description:
  3800. Clears the association between this thread and its security context
  3801. for this connection.
  3802. Arguments:
  3803. none
  3804. Return Value:
  3805. the formerly associated security context, or zero if none was found
  3806. --*/
  3807. {
  3808. THREAD * ThreadInfo = ThreadSelf();
  3809. if (ThreadInfo)
  3810. {
  3811. SECURITY_CONTEXT * Context =
  3812. (SECURITY_CONTEXT *) ThreadInfo->SecurityContext;
  3813. if (Context)
  3814. {
  3815. ThreadInfo->SecurityContext = 0;
  3816. return Context;
  3817. }
  3818. }
  3819. return 0;
  3820. }
  3821. RPC_STATUS
  3822. SCALL::ImpersonateClient (
  3823. )
  3824. // This routine just returns RPC_CANNOT_SUPPORT indicating that this
  3825. // particular connection does not support impersonation.
  3826. {
  3827. ASSERT(0 && "improper SCALL member called\n");
  3828. return(RPC_S_CANNOT_SUPPORT);
  3829. }
  3830. RPC_STATUS
  3831. SCALL::RevertToSelf (
  3832. )
  3833. // We always return RPC_CANNOT_SUPPORT indicating that the particular
  3834. // connection does not support impersonation.
  3835. {
  3836. ASSERT(0 && "improper SCALL member called\n");
  3837. return(RPC_S_CANNOT_SUPPORT);
  3838. }
  3839. void
  3840. NDRSContextHandlePostDispatchProcessing (
  3841. IN SCALL *SCall,
  3842. ServerContextHandle *CtxHandle
  3843. );
  3844. void
  3845. SCALL::DoPostDispatchProcessing (
  3846. void
  3847. )
  3848. {
  3849. DictionaryCursor cursor;
  3850. ServerContextHandle *CtxHandle;
  3851. ServerContextHandle *RetrievedCtxHandle;
  3852. int Key;
  3853. // the list will contain all in-only context
  3854. // handles, as they don't get marshalled. It will also
  3855. // contain the marshalling buffers for the newly
  3856. // created context handles
  3857. if (ActiveContextHandles.Size() > 0)
  3858. {
  3859. // no need to synchronize access to the
  3860. // dictionary - only this call will be
  3861. // touching it
  3862. ActiveContextHandles.Reset(cursor);
  3863. while ((CtxHandle = ActiveContextHandles.NextWithKey(cursor, &Key)) != 0)
  3864. {
  3865. // ignore buffers
  3866. if ((ULONG_PTR)CtxHandle & SCALL::DictionaryEntryIsBuffer)
  3867. {
  3868. RetrievedCtxHandle = ActiveContextHandles.Delete(Key);
  3869. ASSERT(RetrievedCtxHandle == CtxHandle);
  3870. continue;
  3871. }
  3872. // NDRSContextHandlePostDispatchProcessing will remove the context handle
  3873. // from the dictionary - this doesn't interfere with our
  3874. // enumeration
  3875. NDRSContextHandlePostDispatchProcessing(this,
  3876. CtxHandle
  3877. );
  3878. }
  3879. }
  3880. }
  3881. RPC_STATUS
  3882. SCONNECTION::IsClientLocal (
  3883. OUT unsigned int PAPI * ClientLocalFlag
  3884. )
  3885. /*++
  3886. Routine Description:
  3887. The connection oriented protocol module will override this method;
  3888. all other protocol modules should just use this routine. We need this
  3889. support so that the security system can tell if a client is local or
  3890. remote.
  3891. Arguments:
  3892. ClientLocalFlag - Returns an indication of whether or not the client is
  3893. local (ie. on the same machine as the server). This field will be
  3894. set to a non-zero value to indicate that the client is local;
  3895. otherwise, the client is remote.
  3896. Return Value:
  3897. RPC_S_CANNOT_SUPPORT - This will always be used.
  3898. --*/
  3899. {
  3900. UNUSED(ClientLocalFlag);
  3901. ASSERT(0 && "improper SCALL member called\n");
  3902. return(RPC_S_CANNOT_SUPPORT);
  3903. }
  3904. RPC_STATUS
  3905. SCALL::CreateAndSaveAuthzContextFromToken (
  3906. IN OUT PAUTHZ_CLIENT_CONTEXT_HANDLE pAuthzClientContextPlaceholder OPTIONAL,
  3907. IN HANDLE ImpersonationToken,
  3908. IN AUTHZ_RESOURCE_MANAGER_HANDLE AuthzResourceManager,
  3909. IN PLARGE_INTEGER pExpirationTime OPTIONAL,
  3910. IN LUID Identifier,
  3911. IN DWORD Flags,
  3912. IN PVOID DynamicGroupArgs OPTIONAL,
  3913. OUT PAUTHZ_CLIENT_CONTEXT_HANDLE pAuthzClientContext
  3914. )
  3915. /*++
  3916. Routine Description:
  3917. Creates an Authz context from token. If saving is requested, it
  3918. tries to save it in a thread-safe manner and duplicates it before
  3919. returning. If saving is not requested, the resulting authz context
  3920. is simply returned. In both cases caller owns the returned auth
  3921. context.
  3922. Arguments:
  3923. pAuthzClientContextPlaceholder - contains a pointer to an authz placeholder.
  3924. If NULL, out of the ImpersonationToken an authz context will
  3925. be made and will be returned. If non-NULL, it must contain
  3926. NULL. In this case an authz context will be created from the token,
  3927. and it will be stored in the placeholder in a thread safe manner and a
  3928. duplicate will be made and returned in pAuthzClientContext.
  3929. ImpersonationToken - the impersonation token to use.
  3930. AuthzResourceManager - authz parameters (not interpreted)
  3931. pExpirationTime - authz parameters (not interpreted)
  3932. Identifier - authz parameters (not interpreted)
  3933. Flags - authz parameters (not interpreted)
  3934. DynamicGroupArgs - authz parameters (not interpreted)
  3935. pAuthzClientContext - contains the output authz context on success
  3936. Return Value:
  3937. Win32 error code. EEInfo has been added.
  3938. --*/
  3939. {
  3940. RPC_STATUS Status = RPC_S_OK;
  3941. BOOL Result;
  3942. AUTHZ_CLIENT_CONTEXT_HANDLE AuthzClientContext;
  3943. Result = AuthzInitializeContextFromTokenFn(
  3944. Flags,
  3945. ImpersonationToken,
  3946. AuthzResourceManager,
  3947. pExpirationTime,
  3948. Identifier,
  3949. DynamicGroupArgs,
  3950. &AuthzClientContext);
  3951. if (!Result)
  3952. {
  3953. Status = GetLastError();
  3954. RpcpErrorAddRecord(EEInfoGCAuthz,
  3955. Status,
  3956. EEInfoDLSCALL__CreateAndSaveAuthzContextFromToken10,
  3957. GetCurrentThreadId(),
  3958. (ULONGLONG)AuthzResourceManager);
  3959. return Status;
  3960. }
  3961. if (pAuthzClientContextPlaceholder)
  3962. {
  3963. if (InterlockedCompareExchangePointer((PVOID *)pAuthzClientContextPlaceholder,
  3964. AuthzClientContext,
  3965. NULL) != NULL)
  3966. {
  3967. // somebody beat us to the punch - free the context we obtained
  3968. AuthzFreeContextFn(AuthzClientContext);
  3969. // use the context that has been provided
  3970. AuthzClientContext = *pAuthzClientContextPlaceholder;
  3971. }
  3972. Status = DuplicateAuthzContext(AuthzClientContext,
  3973. pExpirationTime,
  3974. Identifier,
  3975. Flags,
  3976. DynamicGroupArgs,
  3977. pAuthzClientContext);
  3978. if (Status)
  3979. {
  3980. // EEInfo has already been added
  3981. return Status;
  3982. }
  3983. }
  3984. else
  3985. {
  3986. *pAuthzClientContext = AuthzClientContext;
  3987. }
  3988. return Status;
  3989. }
  3990. RPC_STATUS
  3991. SCALL::DuplicateAuthzContext (
  3992. IN AUTHZ_CLIENT_CONTEXT_HANDLE AuthzClientContext,
  3993. IN PLARGE_INTEGER pExpirationTime OPTIONAL,
  3994. IN LUID Identifier,
  3995. IN DWORD Flags,
  3996. IN PVOID DynamicGroupArgs OPTIONAL,
  3997. OUT PAUTHZ_CLIENT_CONTEXT_HANDLE pAuthzClientContext
  3998. )
  3999. /*++
  4000. Routine Description:
  4001. Take an Authz context, and make a duplicate of it, using the
  4002. specified parameters. This method is a wrapper for
  4003. AuthzInitializeContextFromContext, mainly adding error handling.
  4004. Arguments:
  4005. AuthzClientContext - source authz context
  4006. pExpirationTime - authz parameters (not interpreted)
  4007. Identifier - authz parameters (not interpreted)
  4008. Flags - authz parameters (not interpreted)
  4009. DynamicGroupArgs - authz parameters (not interpreted)
  4010. pAuthzClientContext - target authz context pointer
  4011. Return Value:
  4012. Win32 error code.
  4013. --*/
  4014. {
  4015. RPC_STATUS Status;
  4016. BOOL Result;
  4017. // Copy the authz context. We must do a copy,
  4018. // to avoid lifetime issues b/n our copy
  4019. // and the client copy
  4020. Result = AuthzInitializeContextFromAuthzContextFn(
  4021. Flags,
  4022. AuthzClientContext,
  4023. pExpirationTime,
  4024. Identifier,
  4025. DynamicGroupArgs,
  4026. pAuthzClientContext);
  4027. if (!Result)
  4028. {
  4029. Status = GetLastError();
  4030. RpcpErrorAddRecord(EEInfoGCAuthz,
  4031. Status,
  4032. EEInfoDLSCALL__DuplicateAuthzContext10,
  4033. GetCurrentThreadId(),
  4034. (ULONGLONG)AuthzClientContext);
  4035. }
  4036. else
  4037. Status = RPC_S_OK;
  4038. return Status;
  4039. }
  4040. /* ====================================================================
  4041. ASSOCIATION_HANDLE :
  4042. ==================================================================== */
  4043. static long AssociationIdCount = 0L;
  4044. void
  4045. DestroyContextCollection (
  4046. IN ContextCollection *CtxCollection
  4047. );
  4048. ASSOCIATION_HANDLE::ASSOCIATION_HANDLE (
  4049. void
  4050. )
  4051. {
  4052. CtxCollection = NULL;
  4053. AssociationID = InterlockedIncrement(&AssociationIdCount);
  4054. }
  4055. ASSOCIATION_HANDLE::~ASSOCIATION_HANDLE (
  4056. )
  4057. // We finally get to use the rundown routines for somethings. The association
  4058. // is being deleted which is the event that the rundown routines were waiting
  4059. // for.
  4060. {
  4061. FireRundown();
  4062. }
  4063. // Returns the context handle collection for this association.
  4064. RPC_STATUS
  4065. ASSOCIATION_HANDLE::GetAssociationContextCollection (
  4066. ContextCollection **CtxCollectionPlaceholder
  4067. )
  4068. /*++
  4069. Function Name: GetAssociationContextCollection
  4070. Parameters:
  4071. CtxCollectionPlaceholder - a placeholder where to put the pointer to
  4072. the context collection.
  4073. Description:
  4074. The context handle code will call the SCALL to get the collection
  4075. of context handles for this association. The SCALL method will
  4076. simply delegate to this.
  4077. This routine will check if the context handle collection was created
  4078. and if so, it will just return it. If it wasn't created, it will try
  4079. to create it.
  4080. Returns:
  4081. RPC_S_OK for success or RPC_S_* for error.
  4082. --*/
  4083. {
  4084. RPC_STATUS RpcStatus;
  4085. if (CtxCollection)
  4086. {
  4087. *CtxCollectionPlaceholder = CtxCollection;
  4088. return RPC_S_OK;
  4089. }
  4090. RpcStatus = NDRSContextInitializeCollection(&CtxCollection);
  4091. if (RpcStatus != RPC_S_OK)
  4092. return RpcStatus;
  4093. *CtxCollectionPlaceholder = CtxCollection;
  4094. return RpcStatus;
  4095. }
  4096. void
  4097. ASSOCIATION_HANDLE::FireRundown (
  4098. void
  4099. )
  4100. {
  4101. int nRetries = 20;
  4102. RPC_STATUS status;
  4103. if (CtxCollection)
  4104. {
  4105. // make a best effort to make sure there is another listening thread
  4106. // besides this one. If we repeatedly fail, we fire the rundown
  4107. // anyway - currently few servers use outgoing RPC callbacks into the
  4108. // same process, so we'd rather risk an unlikely deadlock than cause
  4109. // a sure leak
  4110. while (nRetries > 0)
  4111. {
  4112. status = CreateThread();
  4113. if (status == RPC_S_OK)
  4114. break;
  4115. Sleep(10);
  4116. nRetries --;
  4117. }
  4118. DestroyContextCollection(CtxCollection);
  4119. if (status == RPC_S_OK)
  4120. RundownNotificationCompleted();
  4121. }
  4122. }
  4123. // do nothing in the base case
  4124. RPC_STATUS ASSOCIATION_HANDLE::CreateThread(void)
  4125. {
  4126. return RPC_S_OK;
  4127. }
  4128. void ASSOCIATION_HANDLE::RundownNotificationCompleted(void)
  4129. {
  4130. }
  4131. void
  4132. ASSOCIATION_HANDLE::DestroyContextHandlesForInterface (
  4133. IN RPC_SERVER_INTERFACE PAPI * RpcInterfaceInformation,
  4134. IN BOOL RundownContextHandles
  4135. )
  4136. /*++
  4137. Function Name: DestroyContextHandlesForInterface
  4138. Parameters:
  4139. RpcInterfaceInformation - the interface for which context handles
  4140. are to be unregistered
  4141. RundownContextHandles - if non-zero, rundown the context handles. If
  4142. FALSE, destroy the runtime portion of the context handle resource,
  4143. but don't call the user rundown routine.
  4144. Description:
  4145. The association will call into NDR to destroy the specified context
  4146. handles. It will either have a reference on the association, or the
  4147. association mutex. Both ways, we're safe from destruction, and NDR
  4148. will synchronize access to the list internally. The address has made
  4149. a best effort not to hold the association mutex. If memory is low,
  4150. it may end up doing so, however.
  4151. Returns:
  4152. --*/
  4153. {
  4154. ContextCollection *LocalCtxCollection;
  4155. void *pGuard;
  4156. // N.B. An association mutex may be held on entry for this
  4157. // function. The server mutex may be held as well
  4158. LocalCtxCollection = CtxCollection;
  4159. // shortcut the common path
  4160. if (!LocalCtxCollection)
  4161. return;
  4162. pGuard = &RpcInterfaceInformation->InterfaceId;
  4163. // call into NDR to destroy the context handles
  4164. DestroyContextHandlesForGuard(LocalCtxCollection,
  4165. RundownContextHandles,
  4166. pGuard);
  4167. }
  4168. /* ====================================================================
  4169. Routine to initialize the server DLL.
  4170. ==================================================================== */
  4171. int
  4172. InitializeServerDLL (
  4173. )
  4174. {
  4175. GetMaxRpcSizeAndThreadPoolParameters();
  4176. if (InitializeClientDLL() != 0)
  4177. return(1);
  4178. #if 0
  4179. if (InitializeSTransports() != 0)
  4180. return(1);
  4181. #endif
  4182. if (InitializeObjectDictionary() != 0)
  4183. return(1);
  4184. if (InitializeRpcServer() != 0)
  4185. return(1);
  4186. if (InitializeRpcProtocolLrpc() != 0)
  4187. return(1);
  4188. return(0);
  4189. }
  4190. #if DBG
  4191. void
  4192. RpcpInterfaceForCallDoesNotUseStrict (
  4193. IN RPC_BINDING_HANDLE BindingHandle
  4194. )
  4195. {
  4196. SCALL *SCall;
  4197. if (((MESSAGE_OBJECT *)BindingHandle)->Type(SCALL_TYPE))
  4198. {
  4199. SCall = (SCALL *)BindingHandle;
  4200. SCall->InterfaceForCallDoesNotUseStrict();
  4201. }
  4202. }
  4203. #endif
  4204. RPC_STATUS
  4205. InqLocalConnAddress (
  4206. IN SCALL *SCall,
  4207. IN OUT void *Buffer,
  4208. IN OUT unsigned long *BufferSize,
  4209. OUT unsigned long *AddressFormat
  4210. )
  4211. /*++
  4212. Routine Description:
  4213. This routine is used by a server application to inquire about the local
  4214. address on which a call is made.
  4215. Arguments:
  4216. Binding - Supplies a valid server binding. The binding must have been
  4217. verified to be an SCALL by the caller.
  4218. Buffer - The buffer that will receive the output address
  4219. BufferSize - the size of the supplied Buffer on input. On output the
  4220. number of bytes written to the buffer. If the buffer is too small
  4221. to receive all the output data, ERROR_MORE_DATA is returned,
  4222. nothing is written to the buffer, and BufferSize is set to
  4223. the size of the buffer needed to return all the data.
  4224. AddressFormat - a constant indicating the format of the returned address.
  4225. Currently supported are RPC_P_ADDR_FORMAT_TCP_IPV4 and
  4226. RPC_P_ADDR_FORMAT_TCP_IPV6.
  4227. Return Values:
  4228. RPC_S_OK - success.
  4229. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to complete this
  4230. operation.
  4231. RPC_S_INVALID_BINDING - The supplied client binding is invalid.
  4232. RPC_S_CANNOT_SUPPORT - The local address was inquired for a protocol
  4233. sequence that doesn't support this type of functionality. Currently
  4234. only ncacn_ip_tcp supports it.
  4235. RPC_S_* or Win32 error for other errors
  4236. --*/
  4237. {
  4238. // is this an osf scall?
  4239. if (!SCall->InvalidHandle(OSF_SCALL_TYPE))
  4240. {
  4241. OSF_SCALL *OsfSCall;
  4242. OsfSCall = (OSF_SCALL *)SCall;
  4243. return OsfSCall->InqLocalConnAddress(
  4244. Buffer,
  4245. BufferSize,
  4246. AddressFormat);
  4247. }
  4248. else if (!SCall->InvalidHandle(DG_SCALL_TYPE))
  4249. {
  4250. // this is a dg call
  4251. DG_SCALL *DgSCall;
  4252. DgSCall = (DG_SCALL *)SCall;
  4253. return DgSCall->InqLocalConnAddress(
  4254. Buffer,
  4255. BufferSize,
  4256. AddressFormat);
  4257. }
  4258. else
  4259. {
  4260. // the others don't support it
  4261. return RPC_S_CANNOT_SUPPORT;
  4262. }
  4263. }