Stubs for some new LPC functions (w2k).
[reactos.git] / reactos / ntoskrnl / lpc / reply.c
1 /* $Id: reply.c,v 1.5 2001/01/29 00:13:22 ea Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/lpc/reply.c
6 * PURPOSE: Communication mechanism
7 * PROGRAMMER: David Welch (welch@cwcom.net)
8 * UPDATE HISTORY:
9 * Created 22/05/98
10 */
11
12 /* INCLUDES ******************************************************************/
13
14 #include <ddk/ntddk.h>
15 #include <internal/ob.h>
16 #include <internal/port.h>
17 #include <internal/dbg.h>
18
19 #define NDEBUG
20 #include <internal/debug.h>
21
22 /* FUNCTIONS *****************************************************************/
23
24 /**********************************************************************
25 * NAME
26 *
27 * DESCRIPTION
28 *
29 * ARGUMENTS
30 *
31 * RETURN VALUE
32 *
33 * REVISIONS
34 *
35 */
36 NTSTATUS STDCALL
37 EiReplyOrRequestPort (IN PEPORT Port,
38 IN PLPC_MESSAGE LpcReply,
39 IN ULONG MessageType,
40 IN PEPORT Sender)
41 {
42 KIRQL oldIrql;
43 PQUEUEDMESSAGE MessageReply;
44
45 if (Port == NULL)
46 {
47 KeBugCheck(0);
48 }
49
50 MessageReply = ExAllocatePool(NonPagedPool, sizeof(QUEUEDMESSAGE));
51 MessageReply->Sender = Sender;
52
53 if (LpcReply != NULL)
54 {
55 memcpy(&MessageReply->Message, LpcReply, LpcReply->MessageSize);
56 }
57
58 MessageReply->Message.Cid.UniqueProcess = PsGetCurrentProcessId();
59 MessageReply->Message.Cid.UniqueThread = PsGetCurrentThreadId();
60 MessageReply->Message.MessageType = MessageType;
61 MessageReply->Message.MessageId = InterlockedIncrement(&EiNextLpcMessageId);
62
63 KeAcquireSpinLock(&Port->Lock, &oldIrql);
64 EiEnqueueMessagePort(Port, MessageReply);
65 KeReleaseSpinLock(&Port->Lock, oldIrql);
66
67 return(STATUS_SUCCESS);
68 }
69
70
71 /**********************************************************************
72 * NAME EXPORTED
73 *
74 * DESCRIPTION
75 *
76 * ARGUMENTS
77 *
78 * RETURN VALUE
79 *
80 * REVISIONS
81 *
82 */
83 NTSTATUS STDCALL
84 NtReplyPort (IN HANDLE PortHandle,
85 IN PLPC_MESSAGE LpcReply)
86 {
87 NTSTATUS Status;
88 PEPORT Port;
89
90 DPRINT("NtReplyPort(PortHandle %x, LpcReply %x)\n", PortHandle, LpcReply);
91
92 Status = ObReferenceObjectByHandle(PortHandle,
93 PORT_ALL_ACCESS, /* AccessRequired */
94 ExPortType,
95 UserMode,
96 (PVOID*)&Port,
97 NULL);
98 if (!NT_SUCCESS(Status))
99 {
100 DPRINT("NtReplyPort() = %x\n", Status);
101 return(Status);
102 }
103
104 Status = EiReplyOrRequestPort(Port->OtherPort,
105 LpcReply,
106 LPC_REPLY,
107 Port);
108 KeSetEvent(&Port->OtherPort->Event, IO_NO_INCREMENT, FALSE);
109
110 ObDereferenceObject(Port);
111
112 return(Status);
113 }
114
115
116 /**********************************************************************
117 * NAME EXPORTED
118 * NtReplyWaitReceivePortEx
119 *
120 * DESCRIPTION
121 * Can be used with waitable ports.
122 * Present only in w2k+.
123 *
124 * ARGUMENTS
125 * PortHandle
126 * PortId
127 * LpcReply
128 * LpcMessage
129 * Timeout
130 *
131 * RETURN VALUE
132 *
133 * REVISIONS
134 *
135 */
136 NTSTATUS STDCALL
137 NtReplyWaitReceivePortEx(IN HANDLE PortHandle,
138 OUT PULONG PortId,
139 IN PLPC_MESSAGE LpcReply,
140 OUT PLPC_MESSAGE LpcMessage,
141 IN PLARGE_INTEGER Timeout)
142 {
143 NTSTATUS Status;
144 PEPORT Port;
145 KIRQL oldIrql;
146 PQUEUEDMESSAGE Request;
147
148 DPRINT("NtReplyWaitReceivePortEx(PortHandle %x, LpcReply %x, "
149 "LpcMessage %x)\n", PortHandle, LpcReply, LpcMessage);
150
151 Status = ObReferenceObjectByHandle(PortHandle,
152 PORT_ALL_ACCESS,
153 ExPortType,
154 UserMode,
155 (PVOID*)&Port,
156 NULL);
157 if (!NT_SUCCESS(Status))
158 {
159 DPRINT1("NtReplyWaitReceivePortEx() = %x\n", Status);
160 return(Status);
161 }
162
163 if (Port->State != EPORT_CONNECTED_CLIENT &&
164 Port->State != EPORT_CONNECTED_SERVER &&
165 LpcReply != NULL)
166 {
167 DPRINT1("NtReplyWaitReceivePortEx() = %x (State was %x)\n",
168 STATUS_PORT_DISCONNECTED, Port->State);
169 return(STATUS_PORT_DISCONNECTED);
170 }
171
172 /*
173 * Send the reply
174 */
175 if (LpcReply != NULL)
176 {
177 Status = EiReplyOrRequestPort(Port->OtherPort,
178 LpcReply,
179 LPC_REPLY,
180 Port);
181 KeSetEvent(&Port->OtherPort->Event, IO_NO_INCREMENT, FALSE);
182
183 if (!NT_SUCCESS(Status))
184 {
185 ObDereferenceObject(Port);
186 DPRINT1("NtReplyWaitReceivePortEx() = %x\n", Status);
187 return(Status);
188 }
189 }
190
191 /*
192 * Want for a message to be received
193 */
194 do
195 {
196 Status = KeWaitForSingleObject(&Port->Event,
197 UserRequest,
198 UserMode,
199 FALSE,
200 NULL);
201 if (!NT_SUCCESS(Status))
202 {
203 DPRINT1("NtReplyWaitReceivePortEx() = %x\n", Status);
204 return(Status);
205 }
206
207 /*
208 * Dequeue the message
209 */
210 KeAcquireSpinLock(&Port->Lock, &oldIrql);
211 Request = EiDequeueMessagePort(Port);
212
213 /*
214 * There is a race between the event being set and the port lock being
215 * taken in which another thread may dequeue the same request so
216 * we may need to loop.
217 */
218 if (Request == NULL)
219 {
220 KeReleaseSpinLock(&Port->Lock, oldIrql);
221 }
222 } while(Request == NULL);
223
224 memcpy(LpcMessage, &Request->Message, Request->Message.MessageSize);
225 if (Request->Message.MessageType == LPC_CONNECTION_REQUEST)
226 {
227 EiEnqueueConnectMessagePort(Port, Request);
228 KeReleaseSpinLock(&Port->Lock, oldIrql);
229 }
230 else
231 {
232 KeReleaseSpinLock(&Port->Lock, oldIrql);
233 ExFreePool(Request);
234 }
235
236 /*
237 * Dereference the port
238 */
239 ObDereferenceObject(Port);
240 return(STATUS_SUCCESS);
241 }
242
243
244 /**********************************************************************
245 * NAME EXPORTED
246 * NtReplyWaitReceivePort
247 *
248 * DESCRIPTION
249 * Can be used with waitable ports.
250 *
251 * ARGUMENTS
252 * PortHandle
253 * PortId
254 * LpcReply
255 * LpcMessage
256 *
257 * RETURN VALUE
258 *
259 * REVISIONS
260 *
261 */
262 NTSTATUS STDCALL
263 NtReplyWaitReceivePort (IN HANDLE PortHandle,
264 OUT PULONG PortId,
265 IN PLPC_MESSAGE LpcReply,
266 OUT PLPC_MESSAGE LpcMessage)
267 {
268 return NtReplyWaitReceivePortEx (
269 PortHandle,
270 PortId,
271 LpcReply,
272 LpcMessage,
273 NULL
274 );
275 }
276
277 /**********************************************************************
278 * NAME
279 *
280 * DESCRIPTION
281 *
282 * ARGUMENTS
283 *
284 * RETURN VALUE
285 *
286 * REVISIONS
287 *
288 */
289 NTSTATUS STDCALL
290 NtReplyWaitReplyPort (HANDLE PortHandle,
291 PLPC_MESSAGE ReplyMessage)
292 {
293 UNIMPLEMENTED;
294 }
295
296
297 /* EOF */