PageRenderTime 54ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/dlls/ntdll/tests/port.c

https://github.com/mirrors/wine
C | 400 lines | 311 code | 61 blank | 28 comment | 50 complexity | fb5ab495fa8e5f765bc6d36c4b54bda9 MD5 | raw file
Possible License(s): LGPL-3.0, LGPL-2.1, LGPL-2.0, CC-BY-SA-3.0, BSD-3-Clause
  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. #include <stdio.h>
  20. #include <stdarg.h>
  21. #include "ntstatus.h"
  22. #define WIN32_NO_STATUS
  23. #include "windef.h"
  24. #include "winbase.h"
  25. #include "winuser.h"
  26. #include "winreg.h"
  27. #include "winnls.h"
  28. #include "wine/test.h"
  29. #include "winternl.h"
  30. #ifndef __WINE_WINTERNL_H
  31. typedef struct _CLIENT_ID
  32. {
  33. HANDLE UniqueProcess;
  34. HANDLE UniqueThread;
  35. } CLIENT_ID, *PCLIENT_ID;
  36. typedef struct _LPC_SECTION_WRITE
  37. {
  38. ULONG Length;
  39. HANDLE SectionHandle;
  40. ULONG SectionOffset;
  41. ULONG ViewSize;
  42. PVOID ViewBase;
  43. PVOID TargetViewBase;
  44. } LPC_SECTION_WRITE, *PLPC_SECTION_WRITE;
  45. typedef struct _LPC_SECTION_READ
  46. {
  47. ULONG Length;
  48. ULONG ViewSize;
  49. PVOID ViewBase;
  50. } LPC_SECTION_READ, *PLPC_SECTION_READ;
  51. typedef struct _LPC_MESSAGE
  52. {
  53. USHORT DataSize;
  54. USHORT MessageSize;
  55. USHORT MessageType;
  56. USHORT VirtualRangesOffset;
  57. CLIENT_ID ClientId;
  58. ULONG_PTR MessageId;
  59. ULONG_PTR SectionSize;
  60. UCHAR Data[ANYSIZE_ARRAY];
  61. } LPC_MESSAGE, *PLPC_MESSAGE;
  62. #endif
  63. /* on Wow64 we have to use the 64-bit layout */
  64. typedef struct
  65. {
  66. USHORT DataSize;
  67. USHORT MessageSize;
  68. USHORT MessageType;
  69. USHORT VirtualRangesOffset;
  70. ULONGLONG ClientId[2];
  71. ULONGLONG MessageId;
  72. ULONGLONG SectionSize;
  73. UCHAR Data[ANYSIZE_ARRAY];
  74. } LPC_MESSAGE64;
  75. union lpc_message
  76. {
  77. LPC_MESSAGE msg;
  78. LPC_MESSAGE64 msg64;
  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. static const WCHAR PORTNAME[] = {'\\','M','y','P','o','r','t',0};
  93. #define REQUEST1 "Request1"
  94. #define REQUEST2 "Request2"
  95. #define REPLY "Reply"
  96. #define MAX_MESSAGE_LEN 30
  97. static UNICODE_STRING port;
  98. /* Function pointers for ntdll calls */
  99. static HMODULE hntdll = 0;
  100. static NTSTATUS (WINAPI *pNtCompleteConnectPort)(HANDLE);
  101. static NTSTATUS (WINAPI *pNtAcceptConnectPort)(PHANDLE,ULONG,PLPC_MESSAGE,ULONG,
  102. PLPC_SECTION_WRITE,PLPC_SECTION_READ);
  103. static NTSTATUS (WINAPI *pNtReplyPort)(HANDLE,PLPC_MESSAGE);
  104. static NTSTATUS (WINAPI *pNtReplyWaitReceivePort)(PHANDLE,PULONG,PLPC_MESSAGE,
  105. PLPC_MESSAGE);
  106. static NTSTATUS (WINAPI *pNtCreatePort)(PHANDLE,POBJECT_ATTRIBUTES,ULONG,ULONG,ULONG);
  107. static NTSTATUS (WINAPI *pNtRequestWaitReplyPort)(HANDLE,PLPC_MESSAGE,PLPC_MESSAGE);
  108. static NTSTATUS (WINAPI *pNtRequestPort)(HANDLE,PLPC_MESSAGE);
  109. static NTSTATUS (WINAPI *pNtRegisterThreadTerminatePort)(HANDLE);
  110. static NTSTATUS (WINAPI *pNtConnectPort)(PHANDLE,PUNICODE_STRING,
  111. PSECURITY_QUALITY_OF_SERVICE,
  112. PLPC_SECTION_WRITE,PLPC_SECTION_READ,
  113. PVOID,PVOID,PULONG);
  114. static NTSTATUS (WINAPI *pRtlInitUnicodeString)(PUNICODE_STRING,LPCWSTR);
  115. static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
  116. static BOOL is_wow64;
  117. static BOOL init_function_ptrs(void)
  118. {
  119. hntdll = LoadLibraryA("ntdll.dll");
  120. if (!hntdll)
  121. return FALSE;
  122. pNtCompleteConnectPort = (void *)GetProcAddress(hntdll, "NtCompleteConnectPort");
  123. pNtAcceptConnectPort = (void *)GetProcAddress(hntdll, "NtAcceptConnectPort");
  124. pNtReplyPort = (void *)GetProcAddress(hntdll, "NtReplyPort");
  125. pNtReplyWaitReceivePort = (void *)GetProcAddress(hntdll, "NtReplyWaitReceivePort");
  126. pNtCreatePort = (void *)GetProcAddress(hntdll, "NtCreatePort");
  127. pNtRequestWaitReplyPort = (void *)GetProcAddress(hntdll, "NtRequestWaitReplyPort");
  128. pNtRequestPort = (void *)GetProcAddress(hntdll, "NtRequestPort");
  129. pNtRegisterThreadTerminatePort = (void *)GetProcAddress(hntdll, "NtRegisterThreadTerminatePort");
  130. pNtConnectPort = (void *)GetProcAddress(hntdll, "NtConnectPort");
  131. pRtlInitUnicodeString = (void *)GetProcAddress(hntdll, "RtlInitUnicodeString");
  132. if (!pNtCompleteConnectPort || !pNtAcceptConnectPort ||
  133. !pNtReplyWaitReceivePort || !pNtCreatePort || !pNtRequestWaitReplyPort ||
  134. !pNtRequestPort || !pNtRegisterThreadTerminatePort ||
  135. !pNtConnectPort || !pRtlInitUnicodeString)
  136. {
  137. skip("Needed port functions are not available\n");
  138. FreeLibrary(hntdll);
  139. return FALSE;
  140. }
  141. pIsWow64Process = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsWow64Process");
  142. if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
  143. return TRUE;
  144. }
  145. static void ProcessConnectionRequest(union lpc_message *LpcMessage, PHANDLE pAcceptPortHandle)
  146. {
  147. NTSTATUS status;
  148. if (is_wow64)
  149. {
  150. ok(LpcMessage->msg64.MessageType == LPC_CONNECTION_REQUEST,
  151. "Expected LPC_CONNECTION_REQUEST, got %d\n", LpcMessage->msg64.MessageType);
  152. ok(!*LpcMessage->msg64.Data, "Expected empty string!\n");
  153. }
  154. else
  155. {
  156. ok(LpcMessage->msg.MessageType == LPC_CONNECTION_REQUEST,
  157. "Expected LPC_CONNECTION_REQUEST, got %d\n", LpcMessage->msg.MessageType);
  158. ok(!*LpcMessage->msg.Data, "Expected empty string!\n");
  159. }
  160. status = pNtAcceptConnectPort(pAcceptPortHandle, 0, &LpcMessage->msg, 1, NULL, NULL);
  161. ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %lx\n", status);
  162. status = pNtCompleteConnectPort(*pAcceptPortHandle);
  163. ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %lx\n", status);
  164. }
  165. static void ProcessLpcRequest(HANDLE PortHandle, union lpc_message *LpcMessage)
  166. {
  167. NTSTATUS status;
  168. if (is_wow64)
  169. {
  170. ok(LpcMessage->msg64.MessageType == LPC_REQUEST,
  171. "Expected LPC_REQUEST, got %d\n", LpcMessage->msg64.MessageType);
  172. ok(!strcmp((LPSTR)LpcMessage->msg64.Data, REQUEST2),
  173. "Expected %s, got %s\n", REQUEST2, LpcMessage->msg64.Data);
  174. strcpy((LPSTR)LpcMessage->msg64.Data, REPLY);
  175. status = pNtReplyPort(PortHandle, &LpcMessage->msg);
  176. ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %lx\n", status);
  177. ok(LpcMessage->msg64.MessageType == LPC_REQUEST,
  178. "Expected LPC_REQUEST, got %d\n", LpcMessage->msg64.MessageType);
  179. ok(!strcmp((LPSTR)LpcMessage->msg64.Data, REPLY),
  180. "Expected %s, got %s\n", REPLY, LpcMessage->msg64.Data);
  181. }
  182. else
  183. {
  184. ok(LpcMessage->msg.MessageType == LPC_REQUEST,
  185. "Expected LPC_REQUEST, got %d\n", LpcMessage->msg.MessageType);
  186. ok(!strcmp((LPSTR)LpcMessage->msg.Data, REQUEST2),
  187. "Expected %s, got %s\n", REQUEST2, LpcMessage->msg.Data);
  188. strcpy((LPSTR)LpcMessage->msg.Data, REPLY);
  189. status = pNtReplyPort(PortHandle, &LpcMessage->msg);
  190. ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %lx\n", status);
  191. ok(LpcMessage->msg.MessageType == LPC_REQUEST,
  192. "Expected LPC_REQUEST, got %d\n", LpcMessage->msg.MessageType);
  193. ok(!strcmp((LPSTR)LpcMessage->msg.Data, REPLY),
  194. "Expected %s, got %s\n", REPLY, LpcMessage->msg.Data);
  195. }
  196. }
  197. static DWORD WINAPI test_ports_client(LPVOID arg)
  198. {
  199. SECURITY_QUALITY_OF_SERVICE sqos;
  200. union lpc_message *LpcMessage, *out;
  201. HANDLE PortHandle;
  202. ULONG len, size;
  203. NTSTATUS status;
  204. sqos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
  205. sqos.ImpersonationLevel = SecurityImpersonation;
  206. sqos.ContextTrackingMode = SECURITY_STATIC_TRACKING;
  207. sqos.EffectiveOnly = TRUE;
  208. status = pNtConnectPort(&PortHandle, &port, &sqos, 0, 0, &len, NULL, NULL);
  209. todo_wine ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %lx\n", status);
  210. if (status != STATUS_SUCCESS) return 1;
  211. status = pNtRegisterThreadTerminatePort(PortHandle);
  212. ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %lx\n", status);
  213. if (is_wow64)
  214. {
  215. size = FIELD_OFFSET(LPC_MESSAGE64, Data[MAX_MESSAGE_LEN]);
  216. LpcMessage = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
  217. out = HeapAlloc(GetProcessHeap(), 0, size);
  218. LpcMessage->msg64.DataSize = strlen(REQUEST1) + 1;
  219. LpcMessage->msg64.MessageSize = FIELD_OFFSET(LPC_MESSAGE64, Data[LpcMessage->msg64.DataSize]);
  220. strcpy((LPSTR)LpcMessage->msg64.Data, REQUEST1);
  221. status = pNtRequestPort(PortHandle, &LpcMessage->msg);
  222. ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %lx\n", status);
  223. ok(LpcMessage->msg64.MessageType == 0, "Expected 0, got %d\n", LpcMessage->msg64.MessageType);
  224. ok(!strcmp((LPSTR)LpcMessage->msg64.Data, REQUEST1),
  225. "Expected %s, got %s\n", REQUEST1, LpcMessage->msg64.Data);
  226. /* Fill in the message */
  227. memset(LpcMessage, 0, size);
  228. LpcMessage->msg64.DataSize = strlen(REQUEST2) + 1;
  229. LpcMessage->msg64.MessageSize = FIELD_OFFSET(LPC_MESSAGE64, Data[LpcMessage->msg64.DataSize]);
  230. strcpy((LPSTR)LpcMessage->msg64.Data, REQUEST2);
  231. /* Send the message and wait for the reply */
  232. status = pNtRequestWaitReplyPort(PortHandle, &LpcMessage->msg, &out->msg);
  233. ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %lx\n", status);
  234. ok(!strcmp((LPSTR)out->msg64.Data, REPLY), "Expected %s, got %s\n", REPLY, out->msg64.Data);
  235. ok(out->msg64.MessageType == LPC_REPLY, "Expected LPC_REPLY, got %d\n", out->msg64.MessageType);
  236. }
  237. else
  238. {
  239. size = FIELD_OFFSET(LPC_MESSAGE, Data[MAX_MESSAGE_LEN]);
  240. LpcMessage = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
  241. out = HeapAlloc(GetProcessHeap(), 0, size);
  242. LpcMessage->msg.DataSize = strlen(REQUEST1) + 1;
  243. LpcMessage->msg.MessageSize = FIELD_OFFSET(LPC_MESSAGE, Data[LpcMessage->msg.DataSize]);
  244. strcpy((LPSTR)LpcMessage->msg.Data, REQUEST1);
  245. status = pNtRequestPort(PortHandle, &LpcMessage->msg);
  246. ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %lx\n", status);
  247. ok(LpcMessage->msg.MessageType == 0, "Expected 0, got %d\n", LpcMessage->msg.MessageType);
  248. ok(!strcmp((LPSTR)LpcMessage->msg.Data, REQUEST1),
  249. "Expected %s, got %s\n", REQUEST1, LpcMessage->msg.Data);
  250. /* Fill in the message */
  251. memset(LpcMessage, 0, size);
  252. LpcMessage->msg.DataSize = strlen(REQUEST2) + 1;
  253. LpcMessage->msg.MessageSize = FIELD_OFFSET(LPC_MESSAGE, Data[LpcMessage->msg.DataSize]);
  254. strcpy((LPSTR)LpcMessage->msg.Data, REQUEST2);
  255. /* Send the message and wait for the reply */
  256. status = pNtRequestWaitReplyPort(PortHandle, &LpcMessage->msg, &out->msg);
  257. ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %lx\n", status);
  258. ok(!strcmp((LPSTR)out->msg.Data, REPLY), "Expected %s, got %s\n", REPLY, out->msg.Data);
  259. ok(out->msg.MessageType == LPC_REPLY, "Expected LPC_REPLY, got %d\n", out->msg.MessageType);
  260. }
  261. HeapFree(GetProcessHeap(), 0, out);
  262. HeapFree(GetProcessHeap(), 0, LpcMessage);
  263. return 0;
  264. }
  265. static void test_ports_server( HANDLE PortHandle )
  266. {
  267. HANDLE AcceptPortHandle;
  268. union lpc_message *LpcMessage;
  269. ULONG size;
  270. NTSTATUS status;
  271. BOOL done = FALSE;
  272. size = FIELD_OFFSET(LPC_MESSAGE, Data) + MAX_MESSAGE_LEN;
  273. LpcMessage = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
  274. while (TRUE)
  275. {
  276. status = pNtReplyWaitReceivePort(PortHandle, NULL, NULL, &LpcMessage->msg);
  277. todo_wine
  278. {
  279. ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %ld(%lx)\n", status, status);
  280. }
  281. /* STATUS_INVALID_HANDLE: win2k without admin rights will perform an
  282. * endless loop here
  283. */
  284. if ((status == STATUS_NOT_IMPLEMENTED) ||
  285. (status == STATUS_INVALID_HANDLE)) return;
  286. switch (is_wow64 ? LpcMessage->msg64.MessageType : LpcMessage->msg.MessageType)
  287. {
  288. case LPC_CONNECTION_REQUEST:
  289. ProcessConnectionRequest(LpcMessage, &AcceptPortHandle);
  290. break;
  291. case LPC_REQUEST:
  292. ProcessLpcRequest(PortHandle, LpcMessage);
  293. done = TRUE;
  294. break;
  295. case LPC_DATAGRAM:
  296. if (is_wow64)
  297. ok(!strcmp((LPSTR)LpcMessage->msg64.Data, REQUEST1),
  298. "Expected %s, got %s\n", REQUEST1, LpcMessage->msg64.Data);
  299. else
  300. ok(!strcmp((LPSTR)LpcMessage->msg.Data, REQUEST1),
  301. "Expected %s, got %s\n", REQUEST1, LpcMessage->msg.Data);
  302. break;
  303. case LPC_CLIENT_DIED:
  304. ok(done, "Expected LPC request to be completed!\n");
  305. HeapFree(GetProcessHeap(), 0, LpcMessage);
  306. return;
  307. default:
  308. ok(FALSE, "Unexpected message: %d\n",
  309. is_wow64 ? LpcMessage->msg64.MessageType : LpcMessage->msg.MessageType);
  310. break;
  311. }
  312. }
  313. HeapFree(GetProcessHeap(), 0, LpcMessage);
  314. }
  315. START_TEST(port)
  316. {
  317. OBJECT_ATTRIBUTES obj;
  318. HANDLE port_handle;
  319. NTSTATUS status;
  320. if (!init_function_ptrs())
  321. return;
  322. pRtlInitUnicodeString(&port, PORTNAME);
  323. memset(&obj, 0, sizeof(OBJECT_ATTRIBUTES));
  324. obj.Length = sizeof(OBJECT_ATTRIBUTES);
  325. obj.ObjectName = &port;
  326. status = pNtCreatePort(&port_handle, &obj, 100, 100, 0);
  327. if (status == STATUS_ACCESS_DENIED) skip("Not enough rights\n");
  328. else ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %ld\n", status);
  329. if (status == STATUS_SUCCESS)
  330. {
  331. DWORD id;
  332. HANDLE thread = CreateThread(NULL, 0, test_ports_client, NULL, 0, &id);
  333. ok(thread != NULL, "Expected non-NULL thread handle!\n");
  334. test_ports_server( port_handle );
  335. ok( WaitForSingleObject( thread, 10000 ) == 0, "thread didn't exit\n" );
  336. CloseHandle(thread);
  337. }
  338. FreeLibrary(hntdll);
  339. }