70b7a7d14c99bc648aa9947da96b1f58873fd50c
[reactos.git] / reactos / ntoskrnl / lpc / reply.c
1 /* $Id: reply.c,v 1.4 2001/01/18 15:00:09 dwelch 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 *
119 * DESCRIPTION
120 *
121 * ARGUMENTS
122 *
123 * RETURN VALUE
124 *
125 * REVISIONS
126 *
127 */
128 NTSTATUS STDCALL
129 NtReplyWaitReceivePort (HANDLE PortHandle,
130 PULONG PortId,
131 PLPC_MESSAGE LpcReply,
132 PLPC_MESSAGE LpcMessage)
133 {
134 NTSTATUS Status;
135 PEPORT Port;
136 KIRQL oldIrql;
137 PQUEUEDMESSAGE Request;
138
139 DPRINT("NtReplyWaitReceivePort(PortHandle %x, LpcReply %x, "
140 "LpcMessage %x)\n", PortHandle, LpcReply, LpcMessage);
141
142 Status = ObReferenceObjectByHandle(PortHandle,
143 PORT_ALL_ACCESS,
144 ExPortType,
145 UserMode,
146 (PVOID*)&Port,
147 NULL);
148 if (!NT_SUCCESS(Status))
149 {
150 DPRINT1("NtReplyWaitReceivePort() = %x\n", Status);
151 return(Status);
152 }
153
154 if (Port->State != EPORT_CONNECTED_CLIENT &&
155 Port->State != EPORT_CONNECTED_SERVER &&
156 LpcReply != NULL)
157 {
158 DPRINT1("NtReplyWaitReceivePort() = %x (State was %x)\n",
159 STATUS_PORT_DISCONNECTED, Port->State);
160 return(STATUS_PORT_DISCONNECTED);
161 }
162
163 /*
164 * Send the reply
165 */
166 if (LpcReply != NULL)
167 {
168 Status = EiReplyOrRequestPort(Port->OtherPort,
169 LpcReply,
170 LPC_REPLY,
171 Port);
172 KeSetEvent(&Port->OtherPort->Event, IO_NO_INCREMENT, FALSE);
173
174 if (!NT_SUCCESS(Status))
175 {
176 ObDereferenceObject(Port);
177 DPRINT1("NtReplyWaitReceivePort() = %x\n", Status);
178 return(Status);
179 }
180 }
181
182 /*
183 * Want for a message to be received
184 */
185 do
186 {
187 Status = KeWaitForSingleObject(&Port->Event,
188 UserRequest,
189 UserMode,
190 FALSE,
191 NULL);
192 if (!NT_SUCCESS(Status))
193 {
194 DPRINT1("NtReplyWaitReceivePort() = %x\n", Status);
195 return(Status);
196 }
197
198 /*
199 * Dequeue the message
200 */
201 KeAcquireSpinLock(&Port->Lock, &oldIrql);
202 Request = EiDequeueMessagePort(Port);
203
204 /*
205 * There is a race between the event being set and the port lock being
206 * taken in which another thread may dequeue the same request so
207 * we may need to loop.
208 */
209 if (Request == NULL)
210 {
211 KeReleaseSpinLock(&Port->Lock, oldIrql);
212 }
213 } while(Request == NULL);
214
215 memcpy(LpcMessage, &Request->Message, Request->Message.MessageSize);
216 if (Request->Message.MessageType == LPC_CONNECTION_REQUEST)
217 {
218 EiEnqueueConnectMessagePort(Port, Request);
219 KeReleaseSpinLock(&Port->Lock, oldIrql);
220 }
221 else
222 {
223 KeReleaseSpinLock(&Port->Lock, oldIrql);
224 ExFreePool(Request);
225 }
226
227 /*
228 * Dereference the port
229 */
230 ObDereferenceObject(Port);
231 return(STATUS_SUCCESS);
232 }
233
234
235 /**********************************************************************
236 * NAME
237 *
238 * DESCRIPTION
239 *
240 * ARGUMENTS
241 *
242 * RETURN VALUE
243 *
244 * REVISIONS
245 *
246 */
247 NTSTATUS STDCALL
248 NtReplyWaitReplyPort (HANDLE PortHandle,
249 PLPC_MESSAGE ReplyMessage)
250 {
251 UNIMPLEMENTED;
252 }
253
254
255 /* EOF */