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