1 /* Unit test suite for Ntdll Port API functions
3 * Copyright 2006 James Hawkins
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.
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.
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
24 #define WIN32_NO_STATUS
30 #include "wine/test.h"
33 #ifndef __WINE_WINTERNL_H
35 typedef struct _CLIENT_ID
39 } CLIENT_ID
, *PCLIENT_ID
;
41 typedef struct _LPC_SECTION_WRITE
49 } LPC_SECTION_WRITE
, *PLPC_SECTION_WRITE
;
51 typedef struct _LPC_SECTION_READ
56 } LPC_SECTION_READ
, *PLPC_SECTION_READ
;
58 typedef struct _LPC_MESSAGE
63 USHORT VirtualRangesOffset
;
66 ULONG_PTR SectionSize
;
67 UCHAR Data
[ANYSIZE_ARRAY
];
68 } LPC_MESSAGE
, *PLPC_MESSAGE
;
72 /* on Wow64 we have to use the 64-bit layout */
78 USHORT VirtualRangesOffset
;
79 ULONGLONG ClientId
[2];
81 ULONGLONG SectionSize
;
82 UCHAR Data
[ANYSIZE_ARRAY
];
91 /* Types of LPC messages */
92 #define UNUSED_MSG_TYPE 0
95 #define LPC_DATAGRAM 3
96 #define LPC_LOST_REPLY 4
97 #define LPC_PORT_CLOSED 5
98 #define LPC_CLIENT_DIED 6
99 #define LPC_EXCEPTION 7
100 #define LPC_DEBUG_EVENT 8
101 #define LPC_ERROR_EVENT 9
102 #define LPC_CONNECTION_REQUEST 10
104 static const WCHAR PORTNAME
[] = {'\\','M','y','P','o','r','t',0};
106 #define REQUEST1 "Request1"
107 #define REQUEST2 "Request2"
108 #define REPLY "Reply"
110 #define MAX_MESSAGE_LEN 30
112 static UNICODE_STRING port
;
114 /* Function pointers for ntdll calls */
115 static HMODULE hntdll
= 0;
116 static NTSTATUS (WINAPI
*pNtCompleteConnectPort
)(HANDLE
);
117 static NTSTATUS (WINAPI
*pNtAcceptConnectPort
)(PHANDLE
,ULONG
,PLPC_MESSAGE
,ULONG
,
118 PLPC_SECTION_WRITE
,PLPC_SECTION_READ
);
119 static NTSTATUS (WINAPI
*pNtReplyPort
)(HANDLE
,PLPC_MESSAGE
);
120 static NTSTATUS (WINAPI
*pNtReplyWaitReceivePort
)(PHANDLE
,PULONG
,PLPC_MESSAGE
,
122 static NTSTATUS (WINAPI
*pNtCreatePort
)(PHANDLE
,POBJECT_ATTRIBUTES
,ULONG
,ULONG
,ULONG
);
123 static NTSTATUS (WINAPI
*pNtRequestWaitReplyPort
)(HANDLE
,PLPC_MESSAGE
,PLPC_MESSAGE
);
124 static NTSTATUS (WINAPI
*pNtRequestPort
)(HANDLE
,PLPC_MESSAGE
);
125 static NTSTATUS (WINAPI
*pNtRegisterThreadTerminatePort
)(HANDLE
);
126 static NTSTATUS (WINAPI
*pNtConnectPort
)(PHANDLE
,PUNICODE_STRING
,
127 PSECURITY_QUALITY_OF_SERVICE
,
128 PLPC_SECTION_WRITE
,PLPC_SECTION_READ
,
130 static NTSTATUS (WINAPI
*pRtlInitUnicodeString
)(PUNICODE_STRING
,LPCWSTR
);
131 static BOOL (WINAPI
*pIsWow64Process
)(HANDLE
, PBOOL
);
133 static BOOL is_wow64
;
135 static BOOL
init_function_ptrs(void)
137 hntdll
= LoadLibraryA("ntdll.dll");
142 pNtCompleteConnectPort
= (void *)GetProcAddress(hntdll
, "NtCompleteConnectPort");
143 pNtAcceptConnectPort
= (void *)GetProcAddress(hntdll
, "NtAcceptConnectPort");
144 pNtReplyPort
= (void *)GetProcAddress(hntdll
, "NtReplyPort");
145 pNtReplyWaitReceivePort
= (void *)GetProcAddress(hntdll
, "NtReplyWaitReceivePort");
146 pNtCreatePort
= (void *)GetProcAddress(hntdll
, "NtCreatePort");
147 pNtRequestWaitReplyPort
= (void *)GetProcAddress(hntdll
, "NtRequestWaitReplyPort");
148 pNtRequestPort
= (void *)GetProcAddress(hntdll
, "NtRequestPort");
149 pNtRegisterThreadTerminatePort
= (void *)GetProcAddress(hntdll
, "NtRegisterThreadTerminatePort");
150 pNtConnectPort
= (void *)GetProcAddress(hntdll
, "NtConnectPort");
151 pRtlInitUnicodeString
= (void *)GetProcAddress(hntdll
, "RtlInitUnicodeString");
153 if (!pNtCompleteConnectPort
|| !pNtAcceptConnectPort
||
154 !pNtReplyWaitReceivePort
|| !pNtCreatePort
|| !pNtRequestWaitReplyPort
||
155 !pNtRequestPort
|| !pNtRegisterThreadTerminatePort
||
156 !pNtConnectPort
|| !pRtlInitUnicodeString
)
158 win_skip("Needed port functions are not available\n");
163 pIsWow64Process
= (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsWow64Process");
164 if (!pIsWow64Process
|| !pIsWow64Process( GetCurrentProcess(), &is_wow64
)) is_wow64
= FALSE
;
168 static void ProcessConnectionRequest(union lpc_message
*LpcMessage
, PHANDLE pAcceptPortHandle
)
174 ok(LpcMessage
->msg64
.MessageType
== LPC_CONNECTION_REQUEST
,
175 "Expected LPC_CONNECTION_REQUEST, got %d\n", LpcMessage
->msg64
.MessageType
);
176 ok(!*LpcMessage
->msg64
.Data
, "Expected empty string!\n");
180 ok(LpcMessage
->msg
.MessageType
== LPC_CONNECTION_REQUEST
,
181 "Expected LPC_CONNECTION_REQUEST, got %d\n", LpcMessage
->msg
.MessageType
);
182 ok(!*LpcMessage
->msg
.Data
, "Expected empty string!\n");
185 status
= pNtAcceptConnectPort(pAcceptPortHandle
, 0, &LpcMessage
->msg
, 1, NULL
, NULL
);
186 ok(status
== STATUS_SUCCESS
, "Expected STATUS_SUCCESS, got %x\n", status
);
188 status
= pNtCompleteConnectPort(*pAcceptPortHandle
);
189 ok(status
== STATUS_SUCCESS
, "Expected STATUS_SUCCESS, got %x\n", status
);
192 static void ProcessLpcRequest(HANDLE PortHandle
, union lpc_message
*LpcMessage
)
198 ok(LpcMessage
->msg64
.MessageType
== LPC_REQUEST
,
199 "Expected LPC_REQUEST, got %d\n", LpcMessage
->msg64
.MessageType
);
200 ok(!strcmp((LPSTR
)LpcMessage
->msg64
.Data
, REQUEST2
),
201 "Expected %s, got %s\n", REQUEST2
, LpcMessage
->msg64
.Data
);
202 strcpy((LPSTR
)LpcMessage
->msg64
.Data
, REPLY
);
204 status
= pNtReplyPort(PortHandle
, &LpcMessage
->msg
);
205 ok(status
== STATUS_SUCCESS
, "Expected STATUS_SUCCESS, got %x\n", status
);
206 ok(LpcMessage
->msg64
.MessageType
== LPC_REQUEST
,
207 "Expected LPC_REQUEST, got %d\n", LpcMessage
->msg64
.MessageType
);
208 ok(!strcmp((LPSTR
)LpcMessage
->msg64
.Data
, REPLY
),
209 "Expected %s, got %s\n", REPLY
, LpcMessage
->msg64
.Data
);
213 ok(LpcMessage
->msg
.MessageType
== LPC_REQUEST
,
214 "Expected LPC_REQUEST, got %d\n", LpcMessage
->msg
.MessageType
);
215 ok(!strcmp((LPSTR
)LpcMessage
->msg
.Data
, REQUEST2
),
216 "Expected %s, got %s\n", REQUEST2
, LpcMessage
->msg
.Data
);
217 strcpy((LPSTR
)LpcMessage
->msg
.Data
, REPLY
);
219 status
= pNtReplyPort(PortHandle
, &LpcMessage
->msg
);
220 ok(status
== STATUS_SUCCESS
, "Expected STATUS_SUCCESS, got %x\n", status
);
221 ok(LpcMessage
->msg
.MessageType
== LPC_REQUEST
,
222 "Expected LPC_REQUEST, got %d\n", LpcMessage
->msg
.MessageType
);
223 ok(!strcmp((LPSTR
)LpcMessage
->msg
.Data
, REPLY
),
224 "Expected %s, got %s\n", REPLY
, LpcMessage
->msg
.Data
);
228 static DWORD WINAPI
test_ports_client(LPVOID arg
)
230 SECURITY_QUALITY_OF_SERVICE sqos
;
231 union lpc_message
*LpcMessage
, *out
;
236 sqos
.Length
= sizeof(SECURITY_QUALITY_OF_SERVICE
);
237 sqos
.ImpersonationLevel
= SecurityImpersonation
;
238 sqos
.ContextTrackingMode
= SECURITY_STATIC_TRACKING
;
239 sqos
.EffectiveOnly
= TRUE
;
241 status
= pNtConnectPort(&PortHandle
, &port
, &sqos
, 0, 0, &len
, NULL
, NULL
);
242 todo_wine
ok(status
== STATUS_SUCCESS
, "Expected STATUS_SUCCESS, got %x\n", status
);
243 if (status
!= STATUS_SUCCESS
) return 1;
245 status
= pNtRegisterThreadTerminatePort(PortHandle
);
246 ok(status
== STATUS_SUCCESS
, "Expected STATUS_SUCCESS, got %x\n", status
);
250 size
= FIELD_OFFSET(LPC_MESSAGE64
, Data
[MAX_MESSAGE_LEN
]);
251 LpcMessage
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
252 out
= HeapAlloc(GetProcessHeap(), 0, size
);
254 LpcMessage
->msg64
.DataSize
= strlen(REQUEST1
) + 1;
255 LpcMessage
->msg64
.MessageSize
= FIELD_OFFSET(LPC_MESSAGE64
, Data
[LpcMessage
->msg64
.DataSize
]);
256 strcpy((LPSTR
)LpcMessage
->msg64
.Data
, REQUEST1
);
258 status
= pNtRequestPort(PortHandle
, &LpcMessage
->msg
);
259 ok(status
== STATUS_SUCCESS
, "Expected STATUS_SUCCESS, got %x\n", status
);
260 ok(LpcMessage
->msg64
.MessageType
== 0, "Expected 0, got %d\n", LpcMessage
->msg64
.MessageType
);
261 ok(!strcmp((LPSTR
)LpcMessage
->msg64
.Data
, REQUEST1
),
262 "Expected %s, got %s\n", REQUEST1
, LpcMessage
->msg64
.Data
);
264 /* Fill in the message */
265 memset(LpcMessage
, 0, size
);
266 LpcMessage
->msg64
.DataSize
= strlen(REQUEST2
) + 1;
267 LpcMessage
->msg64
.MessageSize
= FIELD_OFFSET(LPC_MESSAGE64
, Data
[LpcMessage
->msg64
.DataSize
]);
268 strcpy((LPSTR
)LpcMessage
->msg64
.Data
, REQUEST2
);
270 /* Send the message and wait for the reply */
271 status
= pNtRequestWaitReplyPort(PortHandle
, &LpcMessage
->msg
, &out
->msg
);
272 ok(status
== STATUS_SUCCESS
, "Expected STATUS_SUCCESS, got %x\n", status
);
273 ok(!strcmp((LPSTR
)out
->msg64
.Data
, REPLY
), "Expected %s, got %s\n", REPLY
, out
->msg64
.Data
);
274 ok(out
->msg64
.MessageType
== LPC_REPLY
, "Expected LPC_REPLY, got %d\n", out
->msg64
.MessageType
);
278 size
= FIELD_OFFSET(LPC_MESSAGE
, Data
[MAX_MESSAGE_LEN
]);
279 LpcMessage
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
280 out
= HeapAlloc(GetProcessHeap(), 0, size
);
282 LpcMessage
->msg
.DataSize
= strlen(REQUEST1
) + 1;
283 LpcMessage
->msg
.MessageSize
= FIELD_OFFSET(LPC_MESSAGE
, Data
[LpcMessage
->msg
.DataSize
]);
284 strcpy((LPSTR
)LpcMessage
->msg
.Data
, REQUEST1
);
286 status
= pNtRequestPort(PortHandle
, &LpcMessage
->msg
);
287 ok(status
== STATUS_SUCCESS
, "Expected STATUS_SUCCESS, got %x\n", status
);
288 ok(LpcMessage
->msg
.MessageType
== 0, "Expected 0, got %d\n", LpcMessage
->msg
.MessageType
);
289 ok(!strcmp((LPSTR
)LpcMessage
->msg
.Data
, REQUEST1
),
290 "Expected %s, got %s\n", REQUEST1
, LpcMessage
->msg
.Data
);
292 /* Fill in the message */
293 memset(LpcMessage
, 0, size
);
294 LpcMessage
->msg
.DataSize
= strlen(REQUEST2
) + 1;
295 LpcMessage
->msg
.MessageSize
= FIELD_OFFSET(LPC_MESSAGE
, Data
[LpcMessage
->msg
.DataSize
]);
296 strcpy((LPSTR
)LpcMessage
->msg
.Data
, REQUEST2
);
298 /* Send the message and wait for the reply */
299 status
= pNtRequestWaitReplyPort(PortHandle
, &LpcMessage
->msg
, &out
->msg
);
300 ok(status
== STATUS_SUCCESS
, "Expected STATUS_SUCCESS, got %x\n", status
);
301 ok(!strcmp((LPSTR
)out
->msg
.Data
, REPLY
), "Expected %s, got %s\n", REPLY
, out
->msg
.Data
);
302 ok(out
->msg
.MessageType
== LPC_REPLY
, "Expected LPC_REPLY, got %d\n", out
->msg
.MessageType
);
305 HeapFree(GetProcessHeap(), 0, out
);
306 HeapFree(GetProcessHeap(), 0, LpcMessage
);
311 static void test_ports_server( HANDLE PortHandle
)
313 HANDLE AcceptPortHandle
;
314 union lpc_message
*LpcMessage
;
319 size
= FIELD_OFFSET(LPC_MESSAGE
, Data
) + MAX_MESSAGE_LEN
;
320 LpcMessage
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
324 status
= pNtReplyWaitReceivePort(PortHandle
, NULL
, NULL
, &LpcMessage
->msg
);
327 ok(status
== STATUS_SUCCESS
, "Expected STATUS_SUCCESS, got %d(%x)\n", status
, status
);
329 /* STATUS_INVALID_HANDLE: win2k without admin rights will perform an
332 if ((status
== STATUS_NOT_IMPLEMENTED
) ||
333 (status
== STATUS_INVALID_HANDLE
)) return;
335 switch (is_wow64
? LpcMessage
->msg64
.MessageType
: LpcMessage
->msg
.MessageType
)
337 case LPC_CONNECTION_REQUEST
:
338 ProcessConnectionRequest(LpcMessage
, &AcceptPortHandle
);
342 ProcessLpcRequest(PortHandle
, LpcMessage
);
348 ok(!strcmp((LPSTR
)LpcMessage
->msg64
.Data
, REQUEST1
),
349 "Expected %s, got %s\n", REQUEST1
, LpcMessage
->msg64
.Data
);
351 ok(!strcmp((LPSTR
)LpcMessage
->msg
.Data
, REQUEST1
),
352 "Expected %s, got %s\n", REQUEST1
, LpcMessage
->msg
.Data
);
355 case LPC_CLIENT_DIED
:
356 ok(done
, "Expected LPC request to be completed!\n");
357 HeapFree(GetProcessHeap(), 0, LpcMessage
);
361 ok(FALSE
, "Unexpected message: %d\n",
362 is_wow64
? LpcMessage
->msg64
.MessageType
: LpcMessage
->msg
.MessageType
);
367 HeapFree(GetProcessHeap(), 0, LpcMessage
);
372 OBJECT_ATTRIBUTES obj
;
376 if (!init_function_ptrs())
379 pRtlInitUnicodeString(&port
, PORTNAME
);
381 memset(&obj
, 0, sizeof(OBJECT_ATTRIBUTES
));
382 obj
.Length
= sizeof(OBJECT_ATTRIBUTES
);
383 obj
.ObjectName
= &port
;
385 status
= pNtCreatePort(&port_handle
, &obj
, 100, 100, 0);
386 if (status
== STATUS_ACCESS_DENIED
) skip("Not enough rights\n");
387 else todo_wine
ok(status
== STATUS_SUCCESS
, "Expected STATUS_SUCCESS, got %d\n", status
);
389 if (status
== STATUS_SUCCESS
)
392 HANDLE thread
= CreateThread(NULL
, 0, test_ports_client
, NULL
, 0, &id
);
393 ok(thread
!= NULL
, "Expected non-NULL thread handle!\n");
395 test_ports_server( port_handle
);
396 ok( WaitForSingleObject( thread
, 10000 ) == 0, "thread didn't exit\n" );