FreeRDP
Loading...
Searching...
No Matches
TestConnect.c
1#include <winpr/sysinfo.h>
2#include <winpr/path.h>
3#include <winpr/crypto.h>
4#include <winpr/pipe.h>
5
6#include <freerdp/version.h>
7#include <freerdp/freerdp.h>
8#include <freerdp/gdi/gdi.h>
9#include <freerdp/client/cmdline.h>
10
11static HANDLE s_sync = nullptr;
12
13WINPR_ATTR_NODISCARD
14static int runInstance(int argc, char* argv[], freerdp** inst, DWORD timeout)
15{
16 int rc = -1;
17 RDP_CLIENT_ENTRY_POINTS clientEntryPoints = WINPR_C_ARRAY_INIT;
18 rdpContext* context = nullptr;
19
20 clientEntryPoints.Size = sizeof(RDP_CLIENT_ENTRY_POINTS);
21 clientEntryPoints.Version = RDP_CLIENT_INTERFACE_VERSION;
22 clientEntryPoints.ContextSize = sizeof(rdpClientContext);
23 context = freerdp_client_context_new(&clientEntryPoints);
24
25 if (!context)
26 goto finish;
27
28 if (inst)
29 *inst = context->instance;
30
31 context->instance->ChooseSmartcard = nullptr;
32 context->instance->PresentGatewayMessage = nullptr;
33 context->instance->LogonErrorInfo = nullptr;
34 context->instance->AuthenticateEx = nullptr;
35 context->instance->VerifyCertificateEx = nullptr;
36 context->instance->VerifyChangedCertificateEx = nullptr;
37
38 if (!freerdp_settings_set_bool(context->settings, FreeRDP_DeactivateClientDecoding, TRUE))
39 return FALSE;
40
41 if (freerdp_client_settings_parse_command_line(context->settings, argc, argv, FALSE) < 0)
42 goto finish;
43
44 if (!freerdp_settings_set_uint32(context->settings, FreeRDP_TcpConnectTimeout, timeout))
45 goto finish;
46
47 if (!freerdp_client_load_addins(context->channels, context->settings))
48 goto finish;
49
50 if (s_sync)
51 {
52 if (!SetEvent(s_sync))
53 goto finish;
54 }
55
56 rc = 1;
57
58 if (!freerdp_connect(context->instance))
59 goto finish;
60
61 rc = 2;
62
63 if (!freerdp_disconnect(context->instance))
64 goto finish;
65
66 rc = 0;
67finish:
68 freerdp_client_context_free(context);
69 if (inst)
70 *inst = nullptr;
71 return rc;
72}
73
74WINPR_ATTR_NODISCARD
75static int testTimeout(int port)
76{
77 const DWORD timeout = 200;
78 DWORD start = 0;
79 DWORD end = 0;
80 DWORD diff = 0;
81 char arg1[] = "/v:192.0.2.1:XXXXX";
82 char* argv[] = { "test", "/v:192.0.2.1:XXXXX" };
83 int rc = 0;
84 (void)_snprintf(arg1, 18, "/v:192.0.2.1:%d", port);
85 argv[1] = arg1;
86 start = GetTickCount();
87 rc = runInstance(ARRAYSIZE(argv), argv, nullptr, timeout);
88 end = GetTickCount();
89
90 if (rc != 1)
91 return -1;
92
93 diff = end - start;
94
95 if (diff > 4 * timeout)
96 return -1;
97
98 if (diff < timeout)
99 return -1;
100
101 printf("%s: Success!\n", __func__);
102 return 0;
103}
104
105/* Without a monitor list (no fullscreen, no multimon) freerdp_connect makes one monitor from the
106 * desktop settings. Its scale factors must be the desktop and the device scale factor, in that
107 * order: /scale-desktop sets only the first. The connection itself fails (nothing listens on the
108 * port); the monitor is made before. */
109WINPR_ATTR_NODISCARD
110static int testMonitorScaleFactors(void)
111{
112 int rc = -1;
113 char* argv[] = { "test", "/v:127.0.0.1:1", "/scale-desktop:200" };
114 RDP_CLIENT_ENTRY_POINTS clientEntryPoints = WINPR_C_ARRAY_INIT;
115 clientEntryPoints.Size = sizeof(RDP_CLIENT_ENTRY_POINTS);
116 clientEntryPoints.Version = RDP_CLIENT_INTERFACE_VERSION;
117 clientEntryPoints.ContextSize = sizeof(rdpClientContext);
118 rdpContext* context = freerdp_client_context_new(&clientEntryPoints);
119
120 if (!context)
121 return -1;
122
123 if (freerdp_client_settings_parse_command_line(context->settings, ARRAYSIZE(argv), argv,
124 FALSE) < 0)
125 goto finish;
126
127 (void)freerdp_connect(context->instance);
128
129 {
130 const rdpMonitor* monitor =
131 freerdp_settings_get_pointer_array(context->settings, FreeRDP_MonitorDefArray, 0);
132 if (!monitor || (freerdp_settings_get_uint32(context->settings, FreeRDP_MonitorCount) != 1))
133 goto finish;
134
135 const UINT32 desktop =
136 freerdp_settings_get_uint32(context->settings, FreeRDP_DesktopScaleFactor);
137 const UINT32 device =
138 freerdp_settings_get_uint32(context->settings, FreeRDP_DeviceScaleFactor);
139 if ((monitor->attributes.desktopScaleFactor != desktop) ||
140 (monitor->attributes.deviceScaleFactor != device) || (desktop != 200))
141 {
142 printf("%s: monitor scale %" PRIu32 "/%" PRIu32 ", expected %" PRIu32 "/%" PRIu32 "\n",
143 __func__, monitor->attributes.desktopScaleFactor,
144 monitor->attributes.deviceScaleFactor, desktop, device);
145 goto finish;
146 }
147 }
148
149 printf("%s: Success!\n", __func__);
150 rc = 0;
151finish:
152 freerdp_client_context_free(context);
153 return rc;
154}
155
156struct testThreadArgs
157{
158 int port;
159 freerdp** arg;
160};
161
162WINPR_ATTR_NODISCARD
163static DWORD WINAPI testThread(LPVOID arg)
164{
165 char arg1[] = "/v:192.0.2.1:XXXXX";
166 char* argv[] = { "test", "/v:192.0.2.1:XXXXX" };
167 int rc = 0;
168 struct testThreadArgs* args = arg;
169 (void)_snprintf(arg1, 18, "/v:192.0.2.1:%d", args->port);
170 argv[1] = arg1;
171 rc = runInstance(ARRAYSIZE(argv), argv, args->arg, 5000);
172
173 if (rc != 1)
174 ExitThread(-1);
175
176 ExitThread(0);
177 return 0;
178}
179
180WINPR_ATTR_NODISCARD
181static int testAbort(int port)
182{
183 DWORD status = 0;
184 DWORD start = 0;
185 DWORD end = 0;
186 DWORD diff = 0;
187 HANDLE thread = nullptr;
188 struct testThreadArgs args;
189 freerdp* instance = nullptr;
190 s_sync = CreateEvent(nullptr, TRUE, FALSE, nullptr);
191
192 if (!s_sync)
193 return -1;
194
195 args.port = port;
196 args.arg = &instance;
197 start = GetTickCount();
198 thread = CreateThread(nullptr, 0, testThread, &args, 0, nullptr);
199
200 if (!thread)
201 {
202 (void)CloseHandle(s_sync);
203 s_sync = nullptr;
204 return -1;
205 }
206
207 (void)WaitForSingleObject(s_sync, INFINITE);
208 Sleep(100); /* Wait until freerdp_connect has been called */
209 if (instance)
210 {
211 freerdp_abort_connect_context(instance->context);
212
213 if (!freerdp_shall_disconnect_context(instance->context))
214 {
215 (void)CloseHandle(s_sync);
216 (void)CloseHandle(thread);
217 s_sync = nullptr;
218 return -1;
219 }
220 }
221
222 status = WaitForSingleObject(thread, 20000);
223 end = GetTickCount();
224 (void)CloseHandle(s_sync);
225 (void)CloseHandle(thread);
226 s_sync = nullptr;
227 diff = end - start;
228
229 if (diff > 5000)
230 {
231 printf("%s required %" PRIu32 "ms for the test\n", __func__, diff);
232 return -1;
233 }
234
235 if (WAIT_OBJECT_0 != status)
236 return -1;
237
238 printf("%s: Success!\n", __func__);
239 return 0;
240}
241
242WINPR_ATTR_MALLOC(free, 1)
243static char* concatenate(size_t count, ...)
244{
245 char* rc = nullptr;
246 va_list ap = WINPR_C_ARRAY_INIT;
247 va_start(ap, count);
248 rc = _strdup(va_arg(ap, char*));
249 for (size_t x = 1; x < count; x++)
250 {
251 const char* cur = va_arg(ap, const char*);
252 char* tmp = GetCombinedPath(rc, cur);
253 free(rc);
254 rc = tmp;
255 }
256 va_end(ap);
257 return rc;
258}
259
260WINPR_ATTR_NODISCARD
261static BOOL prepare_certificates(const char* path)
262{
263 BOOL rc = FALSE;
264 char* exe = nullptr;
265 DWORD status = 0;
266 STARTUPINFOA si = WINPR_C_ARRAY_INIT;
267 PROCESS_INFORMATION process = WINPR_C_ARRAY_INIT;
268
269 if (!path)
270 return FALSE;
271
272 const char makecert[] = "winpr-makecert"
273#if defined(WITH_BINARY_VERSIONING)
274 FREERDP_API_VERSION
275#endif
276 CMAKE_EXECUTABLE_SUFFIX;
277
278 exe = concatenate(5, TESTING_OUTPUT_DIRECTORY, "winpr", "tools", "makecert-cli", makecert);
279 if (!exe)
280 return FALSE;
281
282 char commandLine[] = "-format crt -path . -n server";
283 printf("[%s]: %s %s\n", __func__, exe, commandLine);
284 rc = CreateProcessA(exe, commandLine, nullptr, nullptr, TRUE, 0, nullptr, path, &si, &process);
285 free(exe);
286 if (!rc)
287 goto fail;
288 status = WaitForSingleObject(process.hProcess, 30000);
289 if (status != WAIT_OBJECT_0)
290 goto fail;
291 rc = TRUE;
292fail:
293 (void)CloseHandle(process.hProcess);
294 (void)CloseHandle(process.hThread);
295 return rc;
296}
297
298WINPR_ATTR_NODISCARD
299static int testSuccess(int port)
300{
301 int r = 0;
302 int rc = -2;
303 STARTUPINFOA si = WINPR_C_ARRAY_INIT;
304 PROCESS_INFORMATION process = WINPR_C_ARRAY_INIT;
305 char arg1[] = "/v:127.0.0.1:XXXXX";
306 char* clientArgs[] = { "test", "/v:127.0.0.1:XXXXX", "/cert:ignore", "/rfx", nullptr };
307 char* commandLine = nullptr;
308 size_t commandLineLen = 0;
309 int argc = 4;
310 char* path = nullptr;
311 char* wpath = nullptr;
312 char* exe = GetCombinedPath(TESTING_OUTPUT_DIRECTORY, "server");
313 (void)_snprintf(arg1, 18, "/v:127.0.0.1:%d", port);
314 clientArgs[1] = arg1;
315
316 if (!exe)
317 goto fail;
318
319 path = GetCombinedPath(exe, "Sample");
320 wpath = GetCombinedPath(exe, "Sample");
321 free(exe);
322 exe = nullptr;
323
324 if (!path || !wpath)
325 goto fail;
326
327 const char srvexe[] = "sfreerdp-server"
328#if defined(WITH_BINARY_VERSIONING)
329 FREERDP_API_VERSION
330#endif
331 CMAKE_EXECUTABLE_SUFFIX;
332 exe = GetCombinedPath(path, srvexe);
333
334 if (!exe)
335 goto fail;
336
337 printf("Sample Server: %s\n", exe);
338 printf("Workspace: %s\n", wpath);
339
340 if (!winpr_PathFileExists(exe))
341 {
342 (void)fprintf(stderr, "[%s]: winpr_PathFileExists(%s) failed\n", __func__, exe);
343 goto fail;
344 }
345
346 if (!prepare_certificates(wpath))
347 {
348 (void)fprintf(stderr, "[%s]: prepare_certificates(%s) failed\n", __func__, wpath);
349 goto fail;
350 }
351
352 // Start sample server locally.
353 commandLineLen = strlen(exe) + strlen("--port=XXXXX") + 1;
354 commandLine = malloc(commandLineLen);
355
356 if (!commandLine)
357 goto fail;
358
359 (void)_snprintf(commandLine, commandLineLen, "%s --port=%d", exe, port);
360 si.cb = sizeof(si);
361
362 printf("Createing process with '%s'\n", commandLine);
363 if (!CreateProcessA(nullptr, commandLine, nullptr, nullptr, FALSE, 0, nullptr, wpath, &si,
364 &process))
365 {
366 (void)fprintf(stderr, "[%s]: CreateProcess failed\n", __func__);
367 goto fail;
368 }
369
370 Sleep(5000); /* let the server start */
371 r = runInstance(argc, clientArgs, nullptr, 10000);
372
373 if (!TerminateProcess(process.hProcess, 0))
374 {
375 (void)fprintf(stderr, "[%s]: TerminateProcess failed\n", __func__);
376 goto fail;
377 }
378
379 (void)WaitForSingleObject(process.hProcess, INFINITE);
380 (void)CloseHandle(process.hProcess);
381 (void)CloseHandle(process.hThread);
382 printf("%s: returned %d!\n", __func__, r);
383 rc = r;
384
385 if (rc == 0)
386 printf("%s: Success!\n", __func__);
387
388fail:
389 free(exe);
390 free(path);
391 free(wpath);
392 free(commandLine);
393 return rc;
394}
395
396int TestConnect(int argc, char* argv[])
397{
398 int randomPort = 0;
399 int random = 0;
400 WINPR_UNUSED(argc);
401 WINPR_UNUSED(argv);
402 if (winpr_RAND(&random, sizeof(random)) < 0)
403 {
404 (void)fprintf(stderr, "winpr_RAND failed\n");
405 return -1;
406 }
407
408 randomPort = 3389 + (random % 200);
409
410 /* The monitor made from the desktop settings keeps their scale factors apart. */
411 if (testMonitorScaleFactors())
412 {
413 (void)fprintf(stderr, "testMonitorScaleFactors failed\n");
414 return -1;
415 }
416
417 /* Test connect to not existing server,
418 * check if timeout is honored. */
419 if (testTimeout(randomPort))
420 {
421 (void)fprintf(stderr, "testTimeout failed\n");
422 return -1;
423 }
424
425 /* Test connect to not existing server,
426 * check if connection abort is working. */
427 if (testAbort(randomPort))
428 {
429 (void)fprintf(stderr, "testAbort failed\n");
430 return -1;
431 }
432
433 /* Test connect to existing server,
434 * check if connection is working. */
435 if (testSuccess(randomPort))
436 {
437 (void)fprintf(stderr, "testSuccess failed\n");
438 return -1;
439 }
440
441 return 0;
442}
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_bool(rdpSettings *settings, FreeRDP_Settings_Keys_Bool id, BOOL val)
Sets a BOOL settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_uint32(rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id, UINT32 val)
Sets a UINT32 settings value.
WINPR_ATTR_NODISCARD FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.