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(rdpContext);
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
102struct testThreadArgs
103{
104 int port;
105 freerdp** arg;
106};
107
108static DWORD WINAPI testThread(LPVOID arg)
109{
110 char arg1[] = "/v:192.0.2.1:XXXXX";
111 char* argv[] = { "test", "/v:192.0.2.1:XXXXX" };
112 int rc = 0;
113 struct testThreadArgs* args = arg;
114 (void)_snprintf(arg1, 18, "/v:192.0.2.1:%d", args->port);
115 argv[1] = arg1;
116 rc = runInstance(ARRAYSIZE(argv), argv, args->arg, 5000);
117
118 if (rc != 1)
119 ExitThread(-1);
120
121 ExitThread(0);
122 return 0;
123}
124
125static int testAbort(int port)
126{
127 DWORD status = 0;
128 DWORD start = 0;
129 DWORD end = 0;
130 DWORD diff = 0;
131 HANDLE thread = nullptr;
132 struct testThreadArgs args;
133 freerdp* instance = nullptr;
134 s_sync = CreateEvent(nullptr, TRUE, FALSE, nullptr);
135
136 if (!s_sync)
137 return -1;
138
139 args.port = port;
140 args.arg = &instance;
141 start = GetTickCount();
142 thread = CreateThread(nullptr, 0, testThread, &args, 0, nullptr);
143
144 if (!thread)
145 {
146 (void)CloseHandle(s_sync);
147 s_sync = nullptr;
148 return -1;
149 }
150
151 (void)WaitForSingleObject(s_sync, INFINITE);
152 Sleep(100); /* Wait until freerdp_connect has been called */
153 if (instance)
154 {
155 freerdp_abort_connect_context(instance->context);
156
157 if (!freerdp_shall_disconnect_context(instance->context))
158 {
159 (void)CloseHandle(s_sync);
160 (void)CloseHandle(thread);
161 s_sync = nullptr;
162 return -1;
163 }
164 }
165
166 status = WaitForSingleObject(thread, 20000);
167 end = GetTickCount();
168 (void)CloseHandle(s_sync);
169 (void)CloseHandle(thread);
170 s_sync = nullptr;
171 diff = end - start;
172
173 if (diff > 5000)
174 {
175 printf("%s required %" PRIu32 "ms for the test\n", __func__, diff);
176 return -1;
177 }
178
179 if (WAIT_OBJECT_0 != status)
180 return -1;
181
182 printf("%s: Success!\n", __func__);
183 return 0;
184}
185
186static char* concatenate(size_t count, ...)
187{
188 char* rc = nullptr;
189 va_list ap = WINPR_C_ARRAY_INIT;
190 va_start(ap, count);
191 rc = _strdup(va_arg(ap, char*));
192 for (size_t x = 1; x < count; x++)
193 {
194 const char* cur = va_arg(ap, const char*);
195 char* tmp = GetCombinedPath(rc, cur);
196 free(rc);
197 rc = tmp;
198 }
199 va_end(ap);
200 return rc;
201}
202
203static BOOL prepare_certificates(const char* path)
204{
205 BOOL rc = FALSE;
206 char* exe = nullptr;
207 DWORD status = 0;
208 STARTUPINFOA si = WINPR_C_ARRAY_INIT;
209 PROCESS_INFORMATION process = WINPR_C_ARRAY_INIT;
210 char commandLine[8192] = WINPR_C_ARRAY_INIT;
211
212 if (!path)
213 return FALSE;
214
215 exe = concatenate(5, TESTING_OUTPUT_DIRECTORY, "winpr", "tools", "makecert-cli",
216 "winpr-makecert" CMAKE_EXECUTABLE_SUFFIX);
217 if (!exe)
218 return FALSE;
219 (void)_snprintf(commandLine, sizeof(commandLine), "%s -format crt -path . -n server", exe);
220
221 rc = CreateProcessA(exe, commandLine, nullptr, nullptr, TRUE, 0, nullptr, path, &si, &process);
222 free(exe);
223 if (!rc)
224 goto fail;
225 status = WaitForSingleObject(process.hProcess, 30000);
226 if (status != WAIT_OBJECT_0)
227 goto fail;
228 rc = TRUE;
229fail:
230 (void)CloseHandle(process.hProcess);
231 (void)CloseHandle(process.hThread);
232 return rc;
233}
234
235static int testSuccess(int port)
236{
237 int r = 0;
238 int rc = -2;
239 STARTUPINFOA si = WINPR_C_ARRAY_INIT;
240 PROCESS_INFORMATION process = WINPR_C_ARRAY_INIT;
241 char arg1[] = "/v:127.0.0.1:XXXXX";
242 char* clientArgs[] = { "test", "/v:127.0.0.1:XXXXX", "/cert:ignore", "/rfx", nullptr };
243 char* commandLine = nullptr;
244 size_t commandLineLen = 0;
245 int argc = 4;
246 char* path = nullptr;
247 char* wpath = nullptr;
248 char* exe = GetCombinedPath(TESTING_OUTPUT_DIRECTORY, "server");
249 (void)_snprintf(arg1, 18, "/v:127.0.0.1:%d", port);
250 clientArgs[1] = arg1;
251
252 if (!exe)
253 goto fail;
254
255 path = GetCombinedPath(exe, "Sample");
256 wpath = GetCombinedPath(exe, "Sample");
257 free(exe);
258 exe = nullptr;
259
260 if (!path || !wpath)
261 goto fail;
262
263 exe = GetCombinedPath(path, "sfreerdp-server" CMAKE_EXECUTABLE_SUFFIX);
264
265 if (!exe)
266 goto fail;
267
268 printf("Sample Server: %s\n", exe);
269 printf("Workspace: %s\n", wpath);
270
271 if (!winpr_PathFileExists(exe))
272 goto fail;
273
274 if (!prepare_certificates(wpath))
275 goto fail;
276
277 // Start sample server locally.
278 commandLineLen = strlen(exe) + strlen("--port=XXXXX") + 1;
279 commandLine = malloc(commandLineLen);
280
281 if (!commandLine)
282 goto fail;
283
284 (void)_snprintf(commandLine, commandLineLen, "%s --port=%d", exe, port);
285 si.cb = sizeof(si);
286
287 if (!CreateProcessA(nullptr, commandLine, nullptr, nullptr, FALSE, 0, nullptr, wpath, &si,
288 &process))
289 goto fail;
290
291 Sleep(5000); /* let the server start */
292 r = runInstance(argc, clientArgs, nullptr, 10000);
293
294 if (!TerminateProcess(process.hProcess, 0))
295 goto fail;
296
297 (void)WaitForSingleObject(process.hProcess, INFINITE);
298 (void)CloseHandle(process.hProcess);
299 (void)CloseHandle(process.hThread);
300 printf("%s: returned %d!\n", __func__, r);
301 rc = r;
302
303 if (rc == 0)
304 printf("%s: Success!\n", __func__);
305
306fail:
307 free(exe);
308 free(path);
309 free(wpath);
310 free(commandLine);
311 return rc;
312}
313
314int TestConnect(int argc, char* argv[])
315{
316 int randomPort = 0;
317 int random = 0;
318 WINPR_UNUSED(argc);
319 WINPR_UNUSED(argv);
320 if (winpr_RAND(&random, sizeof(random)) < 0)
321 return -1;
322 randomPort = 3389 + (random % 200);
323
324 /* Test connect to not existing server,
325 * check if timeout is honored. */
326 if (testTimeout(randomPort))
327 return -1;
328
329 /* Test connect to not existing server,
330 * check if connection abort is working. */
331 if (testAbort(randomPort))
332 return -1;
333
334 /* Test connect to existing server,
335 * check if connection is working. */
336 if (testSuccess(randomPort))
337 return -1;
338
339 return 0;
340}
FREERDP_API BOOL freerdp_settings_set_uint32(rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id, UINT32 val)
Sets a UINT32 settings value.
FREERDP_API BOOL freerdp_settings_set_bool(rdpSettings *settings, FreeRDP_Settings_Keys_Bool id, BOOL val)
Sets a BOOL settings value.