Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

492 lines
14 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. net\routing\ipx\sap\lpcmgr.c
  5. Abstract:
  6. This module implements LPC interface supported by SAP agent
  7. Author:
  8. Vadim Eydelman 05-15-1995
  9. Revision History:
  10. --*/
  11. #include "sapp.h"
  12. // Context kept for each client that connects to us
  13. typedef struct _LPC_CLIENT_CONTEXT {
  14. LIST_ENTRY LCC_Link; // Link in client list
  15. HANDLE LCC_Port; // Port through which we talk
  16. LONG LCC_RefCount; // Reference count of this context block
  17. } LPC_CLIENT_CONTEXT, *PLPC_CLIENT_CONTEXT;
  18. // Queue of LPC requeuest to be processed and associated synchronization
  19. typedef struct _LPC_QUEUE {
  20. HANDLE LQ_Port; // LPC communication port
  21. HANDLE LQ_Thread; // Thread to wait on LPC port
  22. PLPC_PARAM_BLOCK LQ_Request; // Pending request
  23. LIST_ENTRY LQ_ClientList; // List of connected clients
  24. CRITICAL_SECTION LQ_Lock; // Protection
  25. } LPC_QUEUE, *PLPC_QUEUE;
  26. LPC_QUEUE LpcQueue;
  27. DWORD WINAPI
  28. LPCThread (
  29. LPVOID param
  30. );
  31. /*++
  32. *******************************************************************
  33. I n i t i a l i z e L P C S t u f f
  34. Routine Description:
  35. Allocates resources neccessary to implement LPC interface
  36. Arguments:
  37. none
  38. Return Value:
  39. NO_ERROR - port was created OK
  40. other - operation failed (windows error code)
  41. *******************************************************************
  42. --*/
  43. DWORD
  44. InitializeLPCStuff (
  45. void
  46. ) {
  47. InitializeCriticalSection (&LpcQueue.LQ_Lock);
  48. InitializeListHead (&LpcQueue.LQ_ClientList);
  49. LpcQueue.LQ_Request = NULL;
  50. LpcQueue.LQ_Port = NULL;
  51. LpcQueue.LQ_Thread = NULL;
  52. return NO_ERROR;
  53. }
  54. /*++
  55. *******************************************************************
  56. S t a r t L P C
  57. Routine Description:
  58. Start SAP LPC interface
  59. Arguments:
  60. None
  61. Return Value:
  62. NO_ERROR - LPC interface was started OK
  63. other - operation failed (windows error code)
  64. *******************************************************************
  65. --*/
  66. DWORD
  67. StartLPC (
  68. void
  69. ) {
  70. DWORD status;
  71. UNICODE_STRING UnicodeName;
  72. OBJECT_ATTRIBUTES ObjectAttributes;
  73. RtlInitUnicodeString(&UnicodeName, NWSAP_BIND_PORT_NAME_W);
  74. InitializeObjectAttributes(&ObjectAttributes,
  75. &UnicodeName,
  76. 0,
  77. NULL,
  78. NULL);
  79. LpcQueue.LQ_Port = NULL;
  80. status = NtCreatePort(&LpcQueue.LQ_Port,
  81. &ObjectAttributes,
  82. 0,
  83. NWSAP_BS_PORT_MAX_MESSAGE_LENGTH,
  84. NWSAP_BS_PORT_MAX_MESSAGE_LENGTH * 32);
  85. if (NT_SUCCESS(status)) {
  86. DWORD threadID;
  87. LpcQueue.LQ_Thread = CreateThread (
  88. NULL,
  89. 0,
  90. &LPCThread,
  91. NULL,
  92. 0,
  93. &threadID);
  94. if (LpcQueue.LQ_Thread!=NULL)
  95. return NO_ERROR;
  96. else {
  97. status = GetLastError ();
  98. Trace (DEBUG_FAILURES, "File: %s, line %ld."
  99. " Failed to start LPC thread (%0lx).",
  100. __FILE__, __LINE__, status);
  101. }
  102. NtClose (LpcQueue.LQ_Port);
  103. LpcQueue.LQ_Port = NULL;
  104. }
  105. else {
  106. Trace (DEBUG_FAILURES, "File: %s, line %ld."
  107. " Failed to create LPC port(%0lx).",
  108. __FILE__, __LINE__, status);
  109. }
  110. return status;
  111. }
  112. /*++
  113. *******************************************************************
  114. S h u t d o w n L P C
  115. Routine Description:
  116. Shuts SAP LPC interface down, closes all active sessions
  117. Arguments:
  118. None
  119. Return Value:
  120. NO_ERROR - LPC interface was shutdown OK
  121. other - operation failed (windows error code)
  122. *******************************************************************
  123. --*/
  124. DWORD
  125. ShutdownLPC (
  126. void
  127. ) {
  128. EnterCriticalSection (&LpcQueue.LQ_Lock);
  129. if (LpcQueue.LQ_Thread!=NULL) {
  130. UNICODE_STRING unistring;
  131. NTSTATUS status;
  132. SECURITY_QUALITY_OF_SERVICE qos;
  133. HANDLE lpcPortHandle;
  134. NWSAP_REQUEST_MESSAGE request;
  135. LeaveCriticalSection (&LpcQueue.LQ_Lock);
  136. /** Fill out the security quality of service **/
  137. qos.Length = sizeof(qos);
  138. qos.ImpersonationLevel = SecurityImpersonation;
  139. qos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  140. qos.EffectiveOnly = TRUE;
  141. /** Setup the unicode string of the port name **/
  142. RtlInitUnicodeString(&unistring, NWSAP_BIND_PORT_NAME_W);
  143. /** Do the connect **/
  144. status = NtConnectPort(
  145. &lpcPortHandle, /* We get a handle back */
  146. &unistring, /* Port name to connect to */
  147. &qos, /* Quality of service */
  148. NULL, /* Client View */
  149. NULL, /* Server View */
  150. NULL, /* MaxMessageLength */
  151. NULL, /* ConnectionInformation */
  152. NULL); /* ConnectionInformationLength */
  153. /** If error - just return it **/
  154. ASSERT (NT_SUCCESS(status));
  155. request.MessageType = NWSAP_LPCMSG_STOP;
  156. request.PortMessage.u1.s1.DataLength = (USHORT)(sizeof(request) - sizeof(PORT_MESSAGE));
  157. request.PortMessage.u1.s1.TotalLength = sizeof(request);
  158. request.PortMessage.u2.ZeroInit = 0;
  159. request.PortMessage.MessageId = 0;
  160. /** Send it and get a response **/
  161. status = NtRequestPort(
  162. lpcPortHandle,
  163. (PPORT_MESSAGE)&request);
  164. ASSERT (NT_SUCCESS(status));
  165. status = WaitForSingleObject (LpcQueue.LQ_Thread, INFINITE);
  166. ASSERT (status==WAIT_OBJECT_0);
  167. CloseHandle (lpcPortHandle);
  168. EnterCriticalSection (&LpcQueue.LQ_Lock);
  169. CloseHandle (LpcQueue.LQ_Thread);
  170. LpcQueue.LQ_Thread = NULL;
  171. }
  172. while (!IsListEmpty (&LpcQueue.LQ_ClientList)) {
  173. PLPC_CLIENT_CONTEXT clientContext = CONTAINING_RECORD (
  174. LpcQueue.LQ_ClientList.Flink,
  175. LPC_CLIENT_CONTEXT,
  176. LCC_Link);
  177. RemoveEntryList (&clientContext->LCC_Link);
  178. NtClose (clientContext->LCC_Port);
  179. clientContext->LCC_RefCount -= 1;
  180. if (clientContext->LCC_RefCount<0)
  181. GlobalFree (clientContext);
  182. }
  183. if (LpcQueue.LQ_Request!=NULL) {
  184. BOOL res;
  185. LpcQueue.LQ_Request->client = NULL;
  186. ProcessCompletedLpcRequest (LpcQueue.LQ_Request);
  187. LpcQueue.LQ_Request = NULL;
  188. }
  189. LeaveCriticalSection (&LpcQueue.LQ_Lock);
  190. NtClose (LpcQueue.LQ_Port);
  191. LpcQueue.LQ_Port = NULL;
  192. return NO_ERROR;
  193. }
  194. /*++
  195. *******************************************************************
  196. D e l e t e L P C S t u f f
  197. Routine Description:
  198. Disposes of resources allocated for LPC interface
  199. Arguments:
  200. None
  201. Return Value:
  202. None
  203. *******************************************************************
  204. --*/
  205. VOID
  206. DeleteLPCStuff (
  207. void
  208. ) {
  209. if (LpcQueue.LQ_Port!=NULL)
  210. ShutdownLPC ();
  211. DeleteCriticalSection (&LpcQueue.LQ_Lock);
  212. }
  213. /*++
  214. *******************************************************************
  215. L P C T h r e a d
  216. Routine Description:
  217. Thread to be used to wait for and initially process LPC requests
  218. Arguments:
  219. None
  220. Return Value:
  221. None
  222. *******************************************************************
  223. --*/
  224. #if _MSC_FULL_VER >= 13008827
  225. #pragma warning(push)
  226. #pragma warning(disable:4715) // Not all control paths return (due to infinite loop)
  227. #endif
  228. DWORD WINAPI
  229. LPCThread (
  230. LPVOID param
  231. ) {
  232. while (1) {
  233. if (InitLPCItem ()!=NO_ERROR)
  234. // Sleep for a while if there is an error and we have to continue
  235. Sleep (SAP_ERROR_COOL_OFF_TIME);
  236. }
  237. return NO_ERROR;
  238. }
  239. #if _MSC_FULL_VER >= 13008827
  240. #pragma warning(pop)
  241. #endif
  242. /*++
  243. *******************************************************************
  244. P r o c e s s L P C R e q u e s t s
  245. Routine Description:
  246. Waits for requests on LPC port and processes them
  247. Client requests that require additional processing by other SAP
  248. components are enqued into completion queue.
  249. This routine returns only when it encounters a request that requires
  250. additional processing or when error occurs
  251. Arguments:
  252. lreq - LPC parameter block to be filled and posted to completions queue
  253. Return Value:
  254. NO_ERROR - LPC request was received and posted to completio queue
  255. other - operation failed (LPC supplied error code)
  256. *******************************************************************
  257. --*/
  258. DWORD
  259. ProcessLPCRequests (
  260. PLPC_PARAM_BLOCK lreq
  261. ) {
  262. DWORD status;
  263. PLPC_CLIENT_CONTEXT clientContext;
  264. BOOL res;
  265. Trace (DEBUG_LPCREQ, "ProcessLPCRequests: entered.");
  266. EnterCriticalSection (&LpcQueue.LQ_Lock);
  267. LpcQueue.LQ_Request = lreq;
  268. Trace (DEBUG_LPCREQ, "ProcessLPCRequests: go lpcqueue lock.");
  269. while (TRUE) {
  270. LeaveCriticalSection (&LpcQueue.LQ_Lock);
  271. status = NtReplyWaitReceivePort(LpcQueue.LQ_Port,
  272. &clientContext,
  273. NULL,
  274. (PPORT_MESSAGE)lreq->request);
  275. EnterCriticalSection (&LpcQueue.LQ_Lock);
  276. if (NT_SUCCESS (status)) {
  277. switch (lreq->request->PortMessage.u2.s2.Type) {
  278. case LPC_CONNECTION_REQUEST:
  279. clientContext = (PLPC_CLIENT_CONTEXT)GlobalAlloc (
  280. GMEM_FIXED,
  281. sizeof (LPC_CLIENT_CONTEXT));
  282. if (clientContext!=NULL) {
  283. clientContext->LCC_Port = NULL;
  284. clientContext->LCC_RefCount = 0;
  285. status = NtAcceptConnectPort(
  286. &clientContext->LCC_Port,
  287. clientContext,
  288. &lreq->request->PortMessage,
  289. TRUE,
  290. NULL,
  291. NULL);
  292. if (NT_SUCCESS(status)) {
  293. status = NtCompleteConnectPort (
  294. clientContext->LCC_Port);
  295. if (NT_SUCCESS (status)) {
  296. InsertTailList (&LpcQueue.LQ_ClientList,
  297. &clientContext->LCC_Link);
  298. Trace (DEBUG_LPC, "New LPC client: %0lx.", clientContext);
  299. continue;
  300. }
  301. else
  302. Trace (DEBUG_FAILURES,
  303. "File: %s, line %ld."
  304. " Error in complete connect(nts:%0lx)."
  305. __FILE__, __LINE__, status);
  306. NtClose (clientContext->LCC_Port);
  307. }
  308. else
  309. Trace (DEBUG_FAILURES, "File: %s, line %ld."
  310. " Error in accept connect(%0lx)."
  311. __FILE__, __LINE__, status);
  312. GlobalFree (clientContext);
  313. }
  314. else {
  315. HANDLE Port;
  316. Trace (DEBUG_FAILURES, "File: %s, line %ld."
  317. " Could not allocate lpc client block(gle:%ld."
  318. __FILE__, __LINE__, GetLastError ());
  319. status = NtAcceptConnectPort(
  320. &Port,
  321. NULL,
  322. &lreq->request->PortMessage,
  323. FALSE,
  324. NULL,
  325. NULL);
  326. if (!NT_SUCCESS(status))
  327. Trace (DEBUG_FAILURES,
  328. "File: %s, line %ld."
  329. " Error in reject connect(nts:%0lx)."
  330. __FILE__, __LINE__, status);
  331. }
  332. continue;
  333. case LPC_REQUEST:
  334. lreq->client = (HANDLE)clientContext;
  335. clientContext->LCC_RefCount += 1;
  336. ProcessCompletedLpcRequest (LpcQueue.LQ_Request);
  337. LpcQueue.LQ_Request = NULL;
  338. break;
  339. case LPC_PORT_CLOSED:
  340. case LPC_CLIENT_DIED:
  341. Trace (DEBUG_LPC,
  342. " LPC client %0lx died.", clientContext);
  343. RemoveEntryList (&clientContext->LCC_Link);
  344. NtClose (clientContext->LCC_Port);
  345. clientContext->LCC_RefCount -= 1;
  346. if (clientContext->LCC_RefCount<0)
  347. GlobalFree (clientContext);
  348. continue;
  349. case LPC_DATAGRAM:
  350. if (lreq->request->MessageType==NWSAP_LPCMSG_STOP) {
  351. LeaveCriticalSection (&LpcQueue.LQ_Lock);
  352. Trace (DEBUG_LPC, " Stop message received -> exiting.");
  353. ExitThread (0);
  354. }
  355. default:
  356. Trace (DEBUG_FAILURES,
  357. "Unknown or not supported lpc message: %ld.",
  358. lreq->request->PortMessage.u2.s2.Type);
  359. continue;
  360. }
  361. }
  362. else
  363. Trace (DEBUG_FAILURES, "File: %s, line %ld."
  364. " Error on wait lpc request(%0lx).",
  365. __FILE__, __LINE__,
  366. status);
  367. break;
  368. }
  369. LeaveCriticalSection (&LpcQueue.LQ_Lock);
  370. return status;
  371. }
  372. /*++
  373. *******************************************************************
  374. S e n d L P C R e p l y
  375. Routine Description:
  376. Send reply for LPC request
  377. Arguments:
  378. client - context associated with client to reply to
  379. request - request to which to reply
  380. reply - reply to send
  381. Return Value:
  382. NO_ERROR - LPC reply was sent OK
  383. other - operation failed (LPC supplied error code)
  384. *******************************************************************
  385. --*/
  386. DWORD
  387. SendLPCReply (
  388. HANDLE client,
  389. PNWSAP_REQUEST_MESSAGE request,
  390. PNWSAP_REPLY_MESSAGE reply
  391. ) {
  392. DWORD status;
  393. PLPC_CLIENT_CONTEXT clientContext = (PLPC_CLIENT_CONTEXT)client;
  394. EnterCriticalSection (&LpcQueue.LQ_Lock);
  395. if (clientContext->LCC_RefCount>0) {
  396. reply->PortMessage.u1.s1.DataLength =
  397. sizeof(*reply) - sizeof(PORT_MESSAGE);
  398. reply->PortMessage.u1.s1.TotalLength = sizeof(*reply);
  399. reply->PortMessage.u2.ZeroInit = 0;
  400. reply->PortMessage.ClientId = request->PortMessage.ClientId;
  401. reply->PortMessage.MessageId = request->PortMessage.MessageId;
  402. status = NtReplyPort(clientContext->LCC_Port, (PPORT_MESSAGE)reply);
  403. clientContext->LCC_RefCount -= 1;
  404. }
  405. else {
  406. GlobalFree (clientContext);
  407. status = ERROR_INVALID_HANDLE;
  408. }
  409. LeaveCriticalSection (&LpcQueue.LQ_Lock);
  410. if (!NT_SUCCESS(status))
  411. Trace (DEBUG_FAILURES,
  412. "File: %s, line %ld. Error in lpc reply(nts:%0lx).",
  413. __FILE__, __LINE__, status);
  414. return status;
  415. }