[NTDLL_WINETEST] Add a PCH.
[reactos.git] / modules / rostests / winetests / ntdll / port.c
1 /* Unit test suite for Ntdll Port API functions
2 *
3 * Copyright 2006 James Hawkins
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 */
19
20 #include "ntdll_test.h"
21
22 #ifndef __WINE_WINTERNL_H
23
24 typedef struct _CLIENT_ID
25 {
26 HANDLE UniqueProcess;
27 HANDLE UniqueThread;
28 } CLIENT_ID, *PCLIENT_ID;
29
30 typedef struct _LPC_SECTION_WRITE
31 {
32 ULONG Length;
33 HANDLE SectionHandle;
34 ULONG SectionOffset;
35 ULONG ViewSize;
36 PVOID ViewBase;
37 PVOID TargetViewBase;
38 } LPC_SECTION_WRITE, *PLPC_SECTION_WRITE;
39
40 typedef struct _LPC_SECTION_READ
41 {
42 ULONG Length;
43 ULONG ViewSize;
44 PVOID ViewBase;
45 } LPC_SECTION_READ, *PLPC_SECTION_READ;
46
47 typedef struct _LPC_MESSAGE
48 {
49 USHORT DataSize;
50 USHORT MessageSize;
51 USHORT MessageType;
52 USHORT VirtualRangesOffset;
53 CLIENT_ID ClientId;
54 ULONG_PTR MessageId;
55 ULONG_PTR SectionSize;
56 UCHAR Data[ANYSIZE_ARRAY];
57 } LPC_MESSAGE, *PLPC_MESSAGE;
58
59 #endif
60
61 /* on Wow64 we have to use the 64-bit layout */
62 typedef struct
63 {
64 USHORT DataSize;
65 USHORT MessageSize;
66 USHORT MessageType;
67 USHORT VirtualRangesOffset;
68 ULONGLONG ClientId[2];
69 ULONGLONG MessageId;
70 ULONGLONG SectionSize;
71 UCHAR Data[ANYSIZE_ARRAY];
72 } LPC_MESSAGE64;
73
74 union lpc_message
75 {
76 LPC_MESSAGE msg;
77 LPC_MESSAGE64 msg64;
78 };
79
80 /* Types of LPC messages */
81 #define UNUSED_MSG_TYPE 0
82 #define LPC_REQUEST 1
83 #define LPC_REPLY 2
84 #define LPC_DATAGRAM 3
85 #define LPC_LOST_REPLY 4
86 #define LPC_PORT_CLOSED 5
87 #define LPC_CLIENT_DIED 6
88 #define LPC_EXCEPTION 7
89 #define LPC_DEBUG_EVENT 8
90 #define LPC_ERROR_EVENT 9
91 #define LPC_CONNECTION_REQUEST 10
92
93 static const WCHAR PORTNAME[] = {'\\','M','y','P','o','r','t',0};
94
95 #define REQUEST1 "Request1"
96 #define REQUEST2 "Request2"
97 #define REPLY "Reply"
98
99 #define MAX_MESSAGE_LEN 30
100
101 static UNICODE_STRING port;
102
103 /* Function pointers for ntdll calls */
104 static HMODULE hntdll = 0;
105 static NTSTATUS (WINAPI *pNtCompleteConnectPort)(HANDLE);
106 static NTSTATUS (WINAPI *pNtAcceptConnectPort)(PHANDLE,ULONG,PLPC_MESSAGE,ULONG,
107 PLPC_SECTION_WRITE,PLPC_SECTION_READ);
108 static NTSTATUS (WINAPI *pNtReplyPort)(HANDLE,PLPC_MESSAGE);
109 static NTSTATUS (WINAPI *pNtReplyWaitReceivePort)(PHANDLE,PULONG,PLPC_MESSAGE,
110 PLPC_MESSAGE);
111 static NTSTATUS (WINAPI *pNtCreatePort)(PHANDLE,POBJECT_ATTRIBUTES,ULONG,ULONG,ULONG);
112 static NTSTATUS (WINAPI *pNtRequestWaitReplyPort)(HANDLE,PLPC_MESSAGE,PLPC_MESSAGE);
113 static NTSTATUS (WINAPI *pNtRequestPort)(HANDLE,PLPC_MESSAGE);
114 static NTSTATUS (WINAPI *pNtRegisterThreadTerminatePort)(HANDLE);
115 static NTSTATUS (WINAPI *pNtConnectPort)(PHANDLE,PUNICODE_STRING,
116 PSECURITY_QUALITY_OF_SERVICE,
117 PLPC_SECTION_WRITE,PLPC_SECTION_READ,
118 PVOID,PVOID,PULONG);
119 static NTSTATUS (WINAPI *pRtlInitUnicodeString)(PUNICODE_STRING,LPCWSTR);
120 static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
121
122 static BOOL is_wow64;
123
124 static BOOL init_function_ptrs(void)
125 {
126 hntdll = LoadLibraryA("ntdll.dll");
127
128 if (!hntdll)
129 return FALSE;
130
131 pNtCompleteConnectPort = (void *)GetProcAddress(hntdll, "NtCompleteConnectPort");
132 pNtAcceptConnectPort = (void *)GetProcAddress(hntdll, "NtAcceptConnectPort");
133 pNtReplyPort = (void *)GetProcAddress(hntdll, "NtReplyPort");
134 pNtReplyWaitReceivePort = (void *)GetProcAddress(hntdll, "NtReplyWaitReceivePort");
135 pNtCreatePort = (void *)GetProcAddress(hntdll, "NtCreatePort");
136 pNtRequestWaitReplyPort = (void *)GetProcAddress(hntdll, "NtRequestWaitReplyPort");
137 pNtRequestPort = (void *)GetProcAddress(hntdll, "NtRequestPort");
138 pNtRegisterThreadTerminatePort = (void *)GetProcAddress(hntdll, "NtRegisterThreadTerminatePort");
139 pNtConnectPort = (void *)GetProcAddress(hntdll, "NtConnectPort");
140 pRtlInitUnicodeString = (void *)GetProcAddress(hntdll, "RtlInitUnicodeString");
141
142 if (!pNtCompleteConnectPort || !pNtAcceptConnectPort ||
143 !pNtReplyWaitReceivePort || !pNtCreatePort || !pNtRequestWaitReplyPort ||
144 !pNtRequestPort || !pNtRegisterThreadTerminatePort ||
145 !pNtConnectPort || !pRtlInitUnicodeString)
146 {
147 win_skip("Needed port functions are not available\n");
148 FreeLibrary(hntdll);
149 return FALSE;
150 }
151
152 pIsWow64Process = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsWow64Process");
153 if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
154 return TRUE;
155 }
156
157 static void ProcessConnectionRequest(union lpc_message *LpcMessage, PHANDLE pAcceptPortHandle)
158 {
159 NTSTATUS status;
160
161 if (is_wow64)
162 {
163 ok(LpcMessage->msg64.MessageType == LPC_CONNECTION_REQUEST,
164 "Expected LPC_CONNECTION_REQUEST, got %d\n", LpcMessage->msg64.MessageType);
165 ok(!*LpcMessage->msg64.Data, "Expected empty string!\n");
166 }
167 else
168 {
169 ok(LpcMessage->msg.MessageType == LPC_CONNECTION_REQUEST,
170 "Expected LPC_CONNECTION_REQUEST, got %d\n", LpcMessage->msg.MessageType);
171 ok(!*LpcMessage->msg.Data, "Expected empty string!\n");
172 }
173
174 status = pNtAcceptConnectPort(pAcceptPortHandle, 0, &LpcMessage->msg, 1, NULL, NULL);
175 ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %x\n", status);
176
177 status = pNtCompleteConnectPort(*pAcceptPortHandle);
178 ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %x\n", status);
179 }
180
181 static void ProcessLpcRequest(HANDLE PortHandle, union lpc_message *LpcMessage)
182 {
183 NTSTATUS status;
184
185 if (is_wow64)
186 {
187 ok(LpcMessage->msg64.MessageType == LPC_REQUEST,
188 "Expected LPC_REQUEST, got %d\n", LpcMessage->msg64.MessageType);
189 ok(!strcmp((LPSTR)LpcMessage->msg64.Data, REQUEST2),
190 "Expected %s, got %s\n", REQUEST2, LpcMessage->msg64.Data);
191 strcpy((LPSTR)LpcMessage->msg64.Data, REPLY);
192
193 status = pNtReplyPort(PortHandle, &LpcMessage->msg);
194 ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %x\n", status);
195 ok(LpcMessage->msg64.MessageType == LPC_REQUEST,
196 "Expected LPC_REQUEST, got %d\n", LpcMessage->msg64.MessageType);
197 ok(!strcmp((LPSTR)LpcMessage->msg64.Data, REPLY),
198 "Expected %s, got %s\n", REPLY, LpcMessage->msg64.Data);
199 }
200 else
201 {
202 ok(LpcMessage->msg.MessageType == LPC_REQUEST,
203 "Expected LPC_REQUEST, got %d\n", LpcMessage->msg.MessageType);
204 ok(!strcmp((LPSTR)LpcMessage->msg.Data, REQUEST2),
205 "Expected %s, got %s\n", REQUEST2, LpcMessage->msg.Data);
206 strcpy((LPSTR)LpcMessage->msg.Data, REPLY);
207
208 status = pNtReplyPort(PortHandle, &LpcMessage->msg);
209 ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %x\n", status);
210 ok(LpcMessage->msg.MessageType == LPC_REQUEST,
211 "Expected LPC_REQUEST, got %d\n", LpcMessage->msg.MessageType);
212 ok(!strcmp((LPSTR)LpcMessage->msg.Data, REPLY),
213 "Expected %s, got %s\n", REPLY, LpcMessage->msg.Data);
214 }
215 }
216
217 static DWORD WINAPI test_ports_client(LPVOID arg)
218 {
219 SECURITY_QUALITY_OF_SERVICE sqos;
220 union lpc_message *LpcMessage, *out;
221 HANDLE PortHandle;
222 ULONG len, size;
223 NTSTATUS status;
224
225 sqos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
226 sqos.ImpersonationLevel = SecurityImpersonation;
227 sqos.ContextTrackingMode = SECURITY_STATIC_TRACKING;
228 sqos.EffectiveOnly = TRUE;
229
230 status = pNtConnectPort(&PortHandle, &port, &sqos, 0, 0, &len, NULL, NULL);
231 todo_wine ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %x\n", status);
232 if (status != STATUS_SUCCESS) return 1;
233
234 status = pNtRegisterThreadTerminatePort(PortHandle);
235 ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %x\n", status);
236
237 if (is_wow64)
238 {
239 size = FIELD_OFFSET(LPC_MESSAGE64, Data[MAX_MESSAGE_LEN]);
240 LpcMessage = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
241 out = HeapAlloc(GetProcessHeap(), 0, size);
242
243 LpcMessage->msg64.DataSize = strlen(REQUEST1) + 1;
244 LpcMessage->msg64.MessageSize = FIELD_OFFSET(LPC_MESSAGE64, Data[LpcMessage->msg64.DataSize]);
245 strcpy((LPSTR)LpcMessage->msg64.Data, REQUEST1);
246
247 status = pNtRequestPort(PortHandle, &LpcMessage->msg);
248 ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %x\n", status);
249 ok(LpcMessage->msg64.MessageType == 0, "Expected 0, got %d\n", LpcMessage->msg64.MessageType);
250 ok(!strcmp((LPSTR)LpcMessage->msg64.Data, REQUEST1),
251 "Expected %s, got %s\n", REQUEST1, LpcMessage->msg64.Data);
252
253 /* Fill in the message */
254 memset(LpcMessage, 0, size);
255 LpcMessage->msg64.DataSize = strlen(REQUEST2) + 1;
256 LpcMessage->msg64.MessageSize = FIELD_OFFSET(LPC_MESSAGE64, Data[LpcMessage->msg64.DataSize]);
257 strcpy((LPSTR)LpcMessage->msg64.Data, REQUEST2);
258
259 /* Send the message and wait for the reply */
260 status = pNtRequestWaitReplyPort(PortHandle, &LpcMessage->msg, &out->msg);
261 ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %x\n", status);
262 ok(!strcmp((LPSTR)out->msg64.Data, REPLY), "Expected %s, got %s\n", REPLY, out->msg64.Data);
263 ok(out->msg64.MessageType == LPC_REPLY, "Expected LPC_REPLY, got %d\n", out->msg64.MessageType);
264 }
265 else
266 {
267 size = FIELD_OFFSET(LPC_MESSAGE, Data[MAX_MESSAGE_LEN]);
268 LpcMessage = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
269 out = HeapAlloc(GetProcessHeap(), 0, size);
270
271 LpcMessage->msg.DataSize = strlen(REQUEST1) + 1;
272 LpcMessage->msg.MessageSize = FIELD_OFFSET(LPC_MESSAGE, Data[LpcMessage->msg.DataSize]);
273 strcpy((LPSTR)LpcMessage->msg.Data, REQUEST1);
274
275 status = pNtRequestPort(PortHandle, &LpcMessage->msg);
276 ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %x\n", status);
277 ok(LpcMessage->msg.MessageType == 0, "Expected 0, got %d\n", LpcMessage->msg.MessageType);
278 ok(!strcmp((LPSTR)LpcMessage->msg.Data, REQUEST1),
279 "Expected %s, got %s\n", REQUEST1, LpcMessage->msg.Data);
280
281 /* Fill in the message */
282 memset(LpcMessage, 0, size);
283 LpcMessage->msg.DataSize = strlen(REQUEST2) + 1;
284 LpcMessage->msg.MessageSize = FIELD_OFFSET(LPC_MESSAGE, Data[LpcMessage->msg.DataSize]);
285 strcpy((LPSTR)LpcMessage->msg.Data, REQUEST2);
286
287 /* Send the message and wait for the reply */
288 status = pNtRequestWaitReplyPort(PortHandle, &LpcMessage->msg, &out->msg);
289 ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %x\n", status);
290 ok(!strcmp((LPSTR)out->msg.Data, REPLY), "Expected %s, got %s\n", REPLY, out->msg.Data);
291 ok(out->msg.MessageType == LPC_REPLY, "Expected LPC_REPLY, got %d\n", out->msg.MessageType);
292 }
293
294 HeapFree(GetProcessHeap(), 0, out);
295 HeapFree(GetProcessHeap(), 0, LpcMessage);
296
297 return 0;
298 }
299
300 static void test_ports_server( HANDLE PortHandle )
301 {
302 HANDLE AcceptPortHandle;
303 union lpc_message *LpcMessage;
304 ULONG size;
305 NTSTATUS status;
306 BOOL done = FALSE;
307
308 size = FIELD_OFFSET(LPC_MESSAGE, Data) + MAX_MESSAGE_LEN;
309 LpcMessage = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
310
311 while (TRUE)
312 {
313 status = pNtReplyWaitReceivePort(PortHandle, NULL, NULL, &LpcMessage->msg);
314 todo_wine
315 {
316 ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %d(%x)\n", status, status);
317 }
318 /* STATUS_INVALID_HANDLE: win2k without admin rights will perform an
319 * endless loop here
320 */
321 if ((status == STATUS_NOT_IMPLEMENTED) ||
322 (status == STATUS_INVALID_HANDLE)) return;
323
324 switch (is_wow64 ? LpcMessage->msg64.MessageType : LpcMessage->msg.MessageType)
325 {
326 case LPC_CONNECTION_REQUEST:
327 ProcessConnectionRequest(LpcMessage, &AcceptPortHandle);
328 break;
329
330 case LPC_REQUEST:
331 ProcessLpcRequest(PortHandle, LpcMessage);
332 done = TRUE;
333 break;
334
335 case LPC_DATAGRAM:
336 if (is_wow64)
337 ok(!strcmp((LPSTR)LpcMessage->msg64.Data, REQUEST1),
338 "Expected %s, got %s\n", REQUEST1, LpcMessage->msg64.Data);
339 else
340 ok(!strcmp((LPSTR)LpcMessage->msg.Data, REQUEST1),
341 "Expected %s, got %s\n", REQUEST1, LpcMessage->msg.Data);
342 break;
343
344 case LPC_CLIENT_DIED:
345 ok(done, "Expected LPC request to be completed!\n");
346 HeapFree(GetProcessHeap(), 0, LpcMessage);
347 return;
348
349 default:
350 ok(FALSE, "Unexpected message: %d\n",
351 is_wow64 ? LpcMessage->msg64.MessageType : LpcMessage->msg.MessageType);
352 break;
353 }
354 }
355
356 HeapFree(GetProcessHeap(), 0, LpcMessage);
357 }
358
359 START_TEST(port)
360 {
361 OBJECT_ATTRIBUTES obj;
362 HANDLE port_handle;
363 NTSTATUS status;
364
365 if (!init_function_ptrs())
366 return;
367
368 pRtlInitUnicodeString(&port, PORTNAME);
369
370 memset(&obj, 0, sizeof(OBJECT_ATTRIBUTES));
371 obj.Length = sizeof(OBJECT_ATTRIBUTES);
372 obj.ObjectName = &port;
373
374 status = pNtCreatePort(&port_handle, &obj, 100, 100, 0);
375 if (status == STATUS_ACCESS_DENIED) skip("Not enough rights\n");
376 else todo_wine ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %d\n", status);
377
378 if (status == STATUS_SUCCESS)
379 {
380 DWORD id;
381 HANDLE thread = CreateThread(NULL, 0, test_ports_client, NULL, 0, &id);
382 ok(thread != NULL, "Expected non-NULL thread handle!\n");
383
384 test_ports_server( port_handle );
385 ok( WaitForSingleObject( thread, 10000 ) == 0, "thread didn't exit\n" );
386 CloseHandle(thread);
387 }
388 FreeLibrary(hntdll);
389 }