FreeRDP
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 
10 static HANDLE s_sync = NULL;
11 
12 static int runInstance(int argc, char* argv[], freerdp** inst, DWORD timeout)
13 {
14  int rc = -1;
15  RDP_CLIENT_ENTRY_POINTS clientEntryPoints = { 0 };
16  rdpContext* context = NULL;
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 = NULL;
30  context->instance->PresentGatewayMessage = NULL;
31  context->instance->LogonErrorInfo = NULL;
32  context->instance->AuthenticateEx = NULL;
33  context->instance->VerifyCertificateEx = NULL;
34  context->instance->VerifyChangedCertificateEx = NULL;
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;
65 finish:
66  freerdp_client_context_free(context);
67  if (inst)
68  *inst = NULL;
69  return rc;
70 }
71 
72 static 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, NULL, 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 struct testThreadArgs
103 {
104  int port;
105  freerdp** arg;
106 };
107 
108 static 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 
125 static int testAbort(int port)
126 {
127  DWORD status = 0;
128  DWORD start = 0;
129  DWORD end = 0;
130  DWORD diff = 0;
131  HANDLE thread = NULL;
132  struct testThreadArgs args;
133  freerdp* instance = NULL;
134  s_sync = CreateEvent(NULL, TRUE, FALSE, NULL);
135 
136  if (!s_sync)
137  return -1;
138 
139  args.port = port;
140  args.arg = &instance;
141  start = GetTickCount();
142  thread = CreateThread(NULL, 0, testThread, &args, 0, NULL);
143 
144  if (!thread)
145  {
146  (void)CloseHandle(s_sync);
147  s_sync = NULL;
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 = NULL;
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 = NULL;
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 
186 static char* concatenate(size_t count, ...)
187 {
188  char* rc = NULL;
189  va_list ap = { 0 };
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 
203 static BOOL prepare_certificates(const char* path)
204 {
205  BOOL rc = FALSE;
206  char* exe = NULL;
207  DWORD status = 0;
208  STARTUPINFOA si = { 0 };
209  PROCESS_INFORMATION process = { 0 };
210  char commandLine[8192] = { 0 };
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, NULL, NULL, TRUE, 0, NULL, 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;
229 fail:
230  (void)CloseHandle(process.hProcess);
231  (void)CloseHandle(process.hThread);
232  return rc;
233 }
234 
235 static int testSuccess(int port)
236 {
237  int r = 0;
238  int rc = -2;
239  STARTUPINFOA si = { 0 };
240  PROCESS_INFORMATION process = { 0 };
241  char arg1[] = "/v:127.0.0.1:XXXXX";
242  char* clientArgs[] = { "test", "/v:127.0.0.1:XXXXX", "/cert:ignore", "/rfx", NULL };
243  char* commandLine = NULL;
244  size_t commandLineLen = 0;
245  int argc = 4;
246  char* path = NULL;
247  char* wpath = NULL;
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 = NULL;
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(NULL, commandLine, NULL, NULL, FALSE, 0, NULL, wpath, &si, &process))
288  goto fail;
289 
290  Sleep(5000); /* let the server start */
291  r = runInstance(argc, clientArgs, NULL, 10000);
292 
293  if (!TerminateProcess(process.hProcess, 0))
294  goto fail;
295 
296  (void)WaitForSingleObject(process.hProcess, INFINITE);
297  (void)CloseHandle(process.hProcess);
298  (void)CloseHandle(process.hThread);
299  printf("%s: returned %d!\n", __func__, r);
300  rc = r;
301 
302  if (rc == 0)
303  printf("%s: Success!\n", __func__);
304 
305 fail:
306  free(exe);
307  free(path);
308  free(wpath);
309  free(commandLine);
310  return rc;
311 }
312 
313 int TestConnect(int argc, char* argv[])
314 {
315  int randomPort = 0;
316  int random = 0;
317  WINPR_UNUSED(argc);
318  WINPR_UNUSED(argv);
319  winpr_RAND(&random, sizeof(random));
320  randomPort = 3389 + (random % 200);
321 
322  /* Test connect to not existing server,
323  * check if timeout is honored. */
324  if (testTimeout(randomPort))
325  return -1;
326 
327  /* Test connect to not existing server,
328  * check if connection abort is working. */
329  if (testAbort(randomPort))
330  return -1;
331 
332  /* Test connect to existing server,
333  * check if connection is working. */
334  if (testSuccess(randomPort))
335  return -1;
336 
337  return 0;
338 }
FREERDP_API BOOL freerdp_settings_set_uint32(rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id, UINT32 param)
Sets a UINT32 settings value.
FREERDP_API BOOL freerdp_settings_set_bool(rdpSettings *settings, FreeRDP_Settings_Keys_Bool id, BOOL param)
Sets a BOOL settings value.