FreeRDP
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Modules Pages
listener.c
1
20#include <freerdp/config.h>
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <fcntl.h>
26#include <errno.h>
27
28#include <winpr/crt.h>
29#include <winpr/windows.h>
30#include <freerdp/log.h>
31
32#ifndef _WIN32
33#include <netdb.h>
34#include <unistd.h>
35#include <sys/un.h>
36#include <sys/ioctl.h>
37#include <sys/socket.h>
38#include <arpa/inet.h>
39#include <netinet/in.h>
40#include <net/if.h>
41#endif
42
43#if defined(HAVE_AF_VSOCK_H)
44#include <ctype.h>
45#include <linux/vm_sockets.h>
46#endif
47
48#include <winpr/handle.h>
49
50#include "listener.h"
51#include "utils.h"
52
53#define TAG FREERDP_TAG("core.listener")
54
55static BOOL freerdp_listener_open_from_vsock(WINPR_ATTR_UNUSED freerdp_listener* instance,
56 WINPR_ATTR_UNUSED const char* bind_address,
57 WINPR_ATTR_UNUSED UINT16 port)
58{
59#if defined(HAVE_AF_VSOCK_H)
60 rdpListener* listener = (rdpListener*)instance->listener;
61 const int sockfd = socket(AF_VSOCK, SOCK_STREAM, 0);
62 if (sockfd == -1)
63 {
64 char ebuffer[256] = { 0 };
65 WLog_ERR(TAG, "Error creating socket: %s", winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
66 return FALSE;
67 }
68 const int flags = fcntl(sockfd, F_GETFL, 0);
69 if (fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) == -1)
70 {
71 char ebuffer[256] = { 0 };
72 WLog_ERR(TAG, "Error making socket nonblocking: %s",
73 winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
74 close(sockfd);
75 return FALSE;
76 }
77 struct sockaddr_vm addr = { 0 };
78
79 addr.svm_family = AF_VSOCK;
80 addr.svm_port = port;
81
82 errno = 0;
83 char* ptr = NULL;
84 unsigned long val = strtoul(bind_address, &ptr, 10);
85 if (errno || (val > UINT32_MAX))
86 {
87 char ebuffer[256] = { 0 };
88 WLog_ERR(TAG, "could not extract port from '%s', value=%ul, error=%s", bind_address, val,
89 winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
90 close(sockfd);
91 return FALSE;
92 }
93 addr.svm_cid = WINPR_ASSERTING_INT_CAST(unsigned int, val);
94 if (bind(sockfd, (struct sockaddr*)&addr, sizeof(struct sockaddr_vm)) == -1)
95 {
96 char ebuffer[256] = { 0 };
97 WLog_ERR(TAG, "Error binding vsock at cid %d port %d: %s", addr.svm_cid, port,
98 winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
99 close(sockfd);
100 return FALSE;
101 }
102
103 if (listen(sockfd, 10) == -1)
104 {
105 char ebuffer[256] = { 0 };
106 WLog_ERR(TAG, "Error listening to socket at cid %d port %d: %s", addr.svm_cid, port,
107 winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
108 close(sockfd);
109 return FALSE;
110 }
111 listener->sockfds[listener->num_sockfds] = sockfd;
112 listener->events[listener->num_sockfds] = WSACreateEvent();
113
114 if (!listener->events[listener->num_sockfds])
115 {
116 listener->num_sockfds = 0;
117 }
118
119 WSAEventSelect((SOCKET)sockfd, listener->events[listener->num_sockfds],
120 FD_READ | FD_ACCEPT | FD_CLOSE);
121 listener->num_sockfds++;
122
123 WLog_INFO(TAG, "Listening on %s:%d", bind_address, port);
124 return TRUE;
125#else
126 WLog_ERR(TAG, "compiled without AF_VSOCK, '%s' not supported", bind_address);
127 return FALSE;
128#endif
129}
130
131static BOOL freerdp_listener_open(freerdp_listener* instance, const char* bind_address, UINT16 port)
132{
133 int ai_flags = 0;
134 int status = 0;
135 int sockfd = 0;
136 char addr[64];
137 void* sin_addr = NULL;
138 int option_value = 0;
139 struct addrinfo* res = NULL;
140 rdpListener* listener = (rdpListener*)instance->listener;
141#ifdef _WIN32
142 u_long arg;
143#endif
144
145 if (!bind_address)
146 ai_flags = AI_PASSIVE;
147
148 if (utils_is_vsock(bind_address))
149 {
150 bind_address = utils_is_vsock(bind_address);
151 return freerdp_listener_open_from_vsock(instance, bind_address, port);
152 }
153
154 res = freerdp_tcp_resolve_host(bind_address, port, ai_flags);
155
156 if (!res)
157 return FALSE;
158
159 for (struct addrinfo* ai = res; ai && (listener->num_sockfds < 5); ai = ai->ai_next)
160 {
161 if ((ai->ai_family != AF_INET) && (ai->ai_family != AF_INET6))
162 continue;
163
164 if (listener->num_sockfds == MAX_LISTENER_HANDLES)
165 {
166 WLog_ERR(TAG, "too many listening sockets");
167 continue;
168 }
169
170 sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
171
172 if (sockfd == -1)
173 {
174 WLog_ERR(TAG, "socket");
175 continue;
176 }
177
178 option_value = 1;
179
180 if (ai->ai_family == AF_INET)
181 sin_addr = &(((struct sockaddr_in*)ai->ai_addr)->sin_addr);
182 else
183 {
184 sin_addr = &(((struct sockaddr_in6*)ai->ai_addr)->sin6_addr);
185 if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&option_value,
186 sizeof(option_value)) == -1)
187 WLog_ERR(TAG, "setsockopt");
188 }
189
190 inet_ntop(ai->ai_family, sin_addr, addr, sizeof(addr));
191
192 if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (void*)&option_value,
193 sizeof(option_value)) == -1)
194 WLog_ERR(TAG, "setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR)");
195
196#ifndef _WIN32
197 if (fcntl(sockfd, F_SETFL, O_NONBLOCK) != 0)
198 WLog_ERR(TAG, "fcntl(sockfd, F_SETFL, O_NONBLOCK)");
199#else
200 arg = 1;
201 ioctlsocket(sockfd, FIONBIO, &arg);
202#endif
203 status = _bind((SOCKET)sockfd, ai->ai_addr, WINPR_ASSERTING_INT_CAST(int, ai->ai_addrlen));
204
205 if (status != 0)
206 {
207 closesocket((SOCKET)sockfd);
208 continue;
209 }
210
211 status = _listen((SOCKET)sockfd, 10);
212
213 if (status != 0)
214 {
215 WLog_ERR(TAG, "listen");
216 closesocket((SOCKET)sockfd);
217 continue;
218 }
219
220 /* FIXME: these file descriptors do not work on Windows */
221 listener->sockfds[listener->num_sockfds] = sockfd;
222 listener->events[listener->num_sockfds] = WSACreateEvent();
223
224 if (!listener->events[listener->num_sockfds])
225 {
226 listener->num_sockfds = 0;
227 break;
228 }
229
230 WSAEventSelect((SOCKET)sockfd, listener->events[listener->num_sockfds],
231 FD_READ | FD_ACCEPT | FD_CLOSE);
232 listener->num_sockfds++;
233 WLog_INFO(TAG, "Listening on [%s]:%" PRIu16, addr, port);
234 }
235
236 freeaddrinfo(res);
237 return (listener->num_sockfds > 0 ? TRUE : FALSE);
238}
239
240static BOOL freerdp_listener_open_local(freerdp_listener* instance, const char* path)
241{
242#ifndef _WIN32
243 int status = 0;
244 int sockfd = 0;
245 struct sockaddr_un addr = { 0 };
246 rdpListener* listener = (rdpListener*)instance->listener;
247 HANDLE hevent = NULL;
248
249 if (listener->num_sockfds == MAX_LISTENER_HANDLES)
250 {
251 WLog_ERR(TAG, "too many listening sockets");
252 return FALSE;
253 }
254
255 sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
256
257 if (sockfd == -1)
258 {
259 WLog_ERR(TAG, "socket");
260 return FALSE;
261 }
262
263 int rc = fcntl(sockfd, F_SETFL, O_NONBLOCK);
264 if (rc != 0)
265 {
266 WLog_ERR(TAG, "fcntl(sockfd, F_SETFL, O_NONBLOCK)");
267 closesocket((SOCKET)sockfd);
268 return FALSE;
269 }
270
271 addr.sun_family = AF_UNIX;
272 strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
273 unlink(path);
274 status = _bind((SOCKET)sockfd, (struct sockaddr*)&addr, sizeof(addr));
275
276 if (status != 0)
277 {
278 WLog_ERR(TAG, "bind");
279 closesocket((SOCKET)sockfd);
280 return FALSE;
281 }
282
283 status = _listen((SOCKET)sockfd, 10);
284
285 if (status != 0)
286 {
287 WLog_ERR(TAG, "listen");
288 closesocket((SOCKET)sockfd);
289 return FALSE;
290 }
291
292 hevent = CreateFileDescriptorEvent(NULL, FALSE, FALSE, sockfd, WINPR_FD_READ);
293
294 if (!hevent)
295 {
296 WLog_ERR(TAG, "failed to create sockfd event");
297 closesocket((SOCKET)sockfd);
298 return FALSE;
299 }
300
301 listener->sockfds[listener->num_sockfds] = sockfd;
302 listener->events[listener->num_sockfds] = hevent;
303 listener->num_sockfds++;
304 WLog_INFO(TAG, "Listening on socket %s.", addr.sun_path);
305 return TRUE;
306#else
307 return TRUE;
308#endif
309}
310
311static BOOL freerdp_listener_open_from_socket(freerdp_listener* instance, int fd)
312{
313#ifndef _WIN32
314 rdpListener* listener = (rdpListener*)instance->listener;
315
316 if (listener->num_sockfds == MAX_LISTENER_HANDLES)
317 {
318 WLog_ERR(TAG, "too many listening sockets");
319 return FALSE;
320 }
321
322 if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
323 return FALSE;
324
325 listener->sockfds[listener->num_sockfds] = fd;
326 listener->events[listener->num_sockfds] = WSACreateEvent();
327
328 if (!listener->events[listener->num_sockfds])
329 return FALSE;
330
331 WSAEventSelect((SOCKET)fd, listener->events[listener->num_sockfds],
332 FD_READ | FD_ACCEPT | FD_CLOSE);
333
334 listener->num_sockfds++;
335 WLog_INFO(TAG, "Listening on socket %d.", fd);
336 return TRUE;
337#else
338 return FALSE;
339#endif
340}
341
342static void freerdp_listener_close(freerdp_listener* instance)
343{
344 rdpListener* listener = (rdpListener*)instance->listener;
345
346 for (int i = 0; i < listener->num_sockfds; i++)
347 {
348 closesocket((SOCKET)listener->sockfds[i]);
349 (void)CloseHandle(listener->events[i]);
350 }
351
352 listener->num_sockfds = 0;
353}
354
355#if defined(WITH_FREERDP_DEPRECATED)
356static BOOL freerdp_listener_get_fds(freerdp_listener* instance, void** rfds, int* rcount)
357{
358 rdpListener* listener = (rdpListener*)instance->listener;
359
360 if (listener->num_sockfds < 1)
361 return FALSE;
362
363 for (int index = 0; index < listener->num_sockfds; index++)
364 {
365 rfds[*rcount] = (void*)(long)(listener->sockfds[index]);
366 (*rcount)++;
367 }
368
369 return TRUE;
370}
371#endif
372
373static DWORD freerdp_listener_get_event_handles(freerdp_listener* instance, HANDLE* events,
374 DWORD nCount)
375{
376 rdpListener* listener = (rdpListener*)instance->listener;
377
378 if (listener->num_sockfds < 1)
379 return 0;
380
381 if (listener->num_sockfds > (INT64)nCount)
382 return 0;
383
384 for (int index = 0; index < listener->num_sockfds; index++)
385 {
386 events[index] = listener->events[index];
387 }
388
389 return WINPR_ASSERTING_INT_CAST(uint32_t, listener->num_sockfds);
390}
391
392BOOL freerdp_peer_set_local_and_hostname(freerdp_peer* client,
393 const struct sockaddr_storage* peer_addr)
394{
395 const void* sin_addr = NULL;
396 const BYTE localhost6_bytes[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
397
398 WINPR_ASSERT(client);
399 WINPR_ASSERT(peer_addr);
400
401 if (peer_addr->ss_family == AF_INET)
402 {
403 const UINT32* usin_addr = sin_addr = &(((const struct sockaddr_in*)peer_addr)->sin_addr);
404
405 if ((*usin_addr) == 0x0100007f)
406 client->local = TRUE;
407 }
408 else if (peer_addr->ss_family == AF_INET6)
409 {
410 const struct sockaddr_in6* usin_addr = sin_addr =
411 &(((const struct sockaddr_in6*)peer_addr)->sin6_addr);
412
413 if (memcmp(usin_addr, localhost6_bytes, 16) == 0)
414 client->local = TRUE;
415 }
416
417#ifndef _WIN32
418#if defined(HAVE_AF_VSOCK_H)
419 else if (peer_addr->ss_family == AF_UNIX || peer_addr->ss_family == AF_VSOCK)
420#else
421 else if (peer_addr->ss_family == AF_UNIX)
422#endif
423 client->local = TRUE;
424#endif
425
426 if (client->local)
427 WLog_INFO(TAG, "Accepting client from localhost");
428
429 if (sin_addr)
430 inet_ntop(peer_addr->ss_family, sin_addr, client->hostname, sizeof(client->hostname));
431
432 return TRUE;
433}
434
435static BOOL freerdp_check_and_create_client(freerdp_listener* instance, int peer_sockfd,
436 const struct sockaddr_storage* peer_addr)
437{
438 WINPR_ASSERT(instance);
439 WINPR_ASSERT(peer_sockfd >= 0);
440 WINPR_ASSERT(peer_addr);
441
442 const BOOL check = IFCALLRESULT(TRUE, instance->CheckPeerAcceptRestrictions, instance);
443 if (!check)
444 {
445 closesocket((SOCKET)peer_sockfd);
446 return TRUE;
447 }
448
449 freerdp_peer* client = freerdp_peer_new(peer_sockfd);
450 if (!client)
451 {
452 closesocket((SOCKET)peer_sockfd);
453 return FALSE;
454 }
455
456 if (!freerdp_peer_set_local_and_hostname(client, peer_addr))
457 {
458 freerdp_peer_free(client);
459 return FALSE;
460 }
461
462 const BOOL peer_accepted = IFCALLRESULT(FALSE, instance->PeerAccepted, instance, client);
463 if (!peer_accepted)
464 {
465 WLog_ERR(TAG, "PeerAccepted callback failed");
466 freerdp_peer_free(client);
467 }
468
469 return TRUE;
470}
471
472static BOOL freerdp_listener_check_fds(freerdp_listener* instance)
473{
474 rdpListener* listener = (rdpListener*)instance->listener;
475
476 if (listener->num_sockfds < 1)
477 return FALSE;
478
479 for (int i = 0; i < listener->num_sockfds; i++)
480 {
481 struct sockaddr_storage peer_addr = { 0 };
482
483 (void)WSAResetEvent(listener->events[i]);
484 int peer_addr_size = sizeof(peer_addr);
485 SOCKET peer_sockfd =
486 _accept((SOCKET)listener->sockfds[i], (struct sockaddr*)&peer_addr, &peer_addr_size);
487
488 if (peer_sockfd == (SOCKET)-1)
489 {
490 char buffer[128] = { 0 };
491#ifdef _WIN32
492 int wsa_error = WSAGetLastError();
493
494 /* No data available */
495 if (wsa_error == WSAEWOULDBLOCK)
496 continue;
497
498#else
499
500 if (errno == EAGAIN || errno == EWOULDBLOCK)
501 continue;
502
503#endif
504 WLog_WARN(TAG, "accept failed with %s", winpr_strerror(errno, buffer, sizeof(buffer)));
505 return FALSE;
506 }
507
508 if (!freerdp_check_and_create_client(instance, (int)peer_sockfd, &peer_addr))
509 return FALSE;
510 }
511
512 return TRUE;
513}
514
515freerdp_listener* freerdp_listener_new(void)
516{
517 freerdp_listener* instance = NULL;
518 rdpListener* listener = NULL;
519 instance = (freerdp_listener*)calloc(1, sizeof(freerdp_listener));
520
521 if (!instance)
522 return NULL;
523
524 instance->Open = freerdp_listener_open;
525 instance->OpenLocal = freerdp_listener_open_local;
526 instance->OpenFromSocket = freerdp_listener_open_from_socket;
527#if defined(WITH_FREERDP_DEPRECATED)
528 instance->GetFileDescriptor = freerdp_listener_get_fds;
529#endif
530 instance->GetEventHandles = freerdp_listener_get_event_handles;
531 instance->CheckFileDescriptor = freerdp_listener_check_fds;
532 instance->Close = freerdp_listener_close;
533 listener = (rdpListener*)calloc(1, sizeof(rdpListener));
534
535 if (!listener)
536 {
537 free(instance);
538 return NULL;
539 }
540
541 listener->instance = instance;
542 instance->listener = (void*)listener;
543 return instance;
544}
545
546void freerdp_listener_free(freerdp_listener* instance)
547{
548 if (instance)
549 {
550 free(instance->listener);
551 free(instance);
552 }
553}