20#include <freerdp/config.h>
29#include <winpr/windows.h>
30#include <freerdp/log.h>
39#include <sys/socket.h>
41#include <netinet/in.h>
45#if defined(HAVE_AF_VSOCK_H)
47#include <linux/vm_sockets.h>
50#include <winpr/handle.h>
55#define TAG FREERDP_TAG("core.listener")
57static BOOL freerdp_listener_open_from_vsock(WINPR_ATTR_UNUSED freerdp_listener* instance,
58 WINPR_ATTR_UNUSED
const char* bind_address,
59 WINPR_ATTR_UNUSED UINT16 port)
61#if defined(HAVE_AF_VSOCK_H)
62 rdpListener* listener = (rdpListener*)instance->listener;
63 const int sockfd = socket(AF_VSOCK, SOCK_STREAM, 0);
66 char ebuffer[256] = WINPR_C_ARRAY_INIT;
67 WLog_ERR(TAG,
"Error creating socket: %s", winpr_strerror(errno, ebuffer,
sizeof(ebuffer)));
70 const int flags = fcntl(sockfd, F_GETFL, 0);
71 if (fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) == -1)
73 char ebuffer[256] = WINPR_C_ARRAY_INIT;
74 WLog_ERR(TAG,
"Error making socket nonblocking: %s",
75 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)));
79 struct sockaddr_vm addr = WINPR_C_ARRAY_INIT;
81 addr.svm_family = AF_VSOCK;
86 unsigned long val = strtoul(bind_address, &ptr, 10);
87 if (errno || (val > UINT32_MAX))
90 if ((val == ULONG_MAX) && (errno == 0))
94 char ebuffer[256] = WINPR_C_ARRAY_INIT;
95 WLog_ERR(TAG,
"could not extract port from '%s', value=%lu, error=%s", bind_address,
96 val, winpr_strerror(errno, ebuffer,
sizeof(ebuffer)));
101 addr.svm_cid = WINPR_ASSERTING_INT_CAST(
unsigned int, val);
102 if (bind(sockfd, (
struct sockaddr*)&addr,
sizeof(
struct sockaddr_vm)) == -1)
104 char ebuffer[256] = WINPR_C_ARRAY_INIT;
105 WLog_ERR(TAG,
"Error binding vsock at cid %u port %d: %s", addr.svm_cid, port,
106 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)));
111 if (listen(sockfd, 10) == -1)
113 char ebuffer[256] = WINPR_C_ARRAY_INIT;
114 WLog_ERR(TAG,
"Error listening to socket at cid %u port %d: %s", addr.svm_cid, port,
115 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)));
119 listener->sockfds[listener->num_sockfds] = sockfd;
120 listener->events[listener->num_sockfds] = WSACreateEvent();
122 if (!listener->events[listener->num_sockfds])
124 listener->num_sockfds = 0;
127 WSAEventSelect((SOCKET)sockfd, listener->events[listener->num_sockfds],
128 FD_READ | FD_ACCEPT | FD_CLOSE);
129 listener->num_sockfds++;
131 WLog_INFO(TAG,
"Listening on %s:%d", bind_address, port);
134 WLog_ERR(TAG,
"compiled without AF_VSOCK, '%s' not supported", bind_address);
139static BOOL freerdp_listener_open(freerdp_listener* instance,
const char* bind_address, UINT16 port)
145 void* sin_addr =
nullptr;
146 int option_value = 0;
147 struct addrinfo* res =
nullptr;
148 rdpListener* listener = (rdpListener*)instance->listener;
154 ai_flags = AI_PASSIVE;
156 if (utils_is_vsock(bind_address))
158 bind_address = utils_is_vsock(bind_address);
159 return freerdp_listener_open_from_vsock(instance, bind_address, port);
162 res = freerdp_tcp_resolve_host(bind_address, port, ai_flags);
167 for (
struct addrinfo* ai = res; ai && (listener->num_sockfds < 5); ai = ai->ai_next)
169 if ((ai->ai_family != AF_INET) && (ai->ai_family != AF_INET6))
172 if (listener->num_sockfds == MAX_LISTENER_HANDLES)
174 WLog_ERR(TAG,
"too many listening sockets");
178 sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
182 WLog_ERR(TAG,
"socket");
188 if (ai->ai_family == AF_INET)
189 sin_addr = &((WINPR_PACKED_ALIGN_CAST(
struct sockaddr_in*, ai->ai_addr))->sin_addr);
192 sin_addr = &((WINPR_PACKED_ALIGN_CAST(
struct sockaddr_in6*, ai->ai_addr))->sin6_addr);
193 if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (
void*)&option_value,
194 sizeof(option_value)) == -1)
195 WLog_ERR(TAG,
"setsockopt");
198 inet_ntop(ai->ai_family, sin_addr, addr,
sizeof(addr));
200 if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (
void*)&option_value,
201 sizeof(option_value)) == -1)
202 WLog_ERR(TAG,
"setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR)");
205 if (fcntl(sockfd, F_SETFL, O_NONBLOCK) != 0)
206 WLog_ERR(TAG,
"fcntl(sockfd, F_SETFL, O_NONBLOCK)");
209 ioctlsocket(sockfd, FIONBIO, &arg);
211 status = _bind((SOCKET)sockfd, ai->ai_addr, WINPR_ASSERTING_INT_CAST(
int, ai->ai_addrlen));
215 closesocket((SOCKET)sockfd);
219 status = _listen((SOCKET)sockfd, 10);
223 WLog_ERR(TAG,
"listen");
224 closesocket((SOCKET)sockfd);
229 listener->sockfds[listener->num_sockfds] = sockfd;
230 listener->events[listener->num_sockfds] = WSACreateEvent();
232 if (!listener->events[listener->num_sockfds])
234 listener->num_sockfds = 0;
238 WSAEventSelect((SOCKET)sockfd, listener->events[listener->num_sockfds],
239 FD_READ | FD_ACCEPT | FD_CLOSE);
240 listener->num_sockfds++;
241 WLog_INFO(TAG,
"Listening on [%s]:%" PRIu16, addr, port);
245 return ((listener->num_sockfds > 0));
248static BOOL freerdp_listener_open_local(freerdp_listener* instance,
const char* path)
253 struct sockaddr_un addr = WINPR_C_ARRAY_INIT;
254 rdpListener* listener = (rdpListener*)instance->listener;
255 HANDLE hevent =
nullptr;
257 if (listener->num_sockfds == MAX_LISTENER_HANDLES)
259 WLog_ERR(TAG,
"too many listening sockets");
263 sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
267 WLog_ERR(TAG,
"socket");
271 int rc = fcntl(sockfd, F_SETFL, O_NONBLOCK);
274 WLog_ERR(TAG,
"fcntl(sockfd, F_SETFL, O_NONBLOCK)");
275 closesocket((SOCKET)sockfd);
279 addr.sun_family = AF_UNIX;
280 strncpy(addr.sun_path, path,
sizeof(addr.sun_path) - 1);
282 status = _bind((SOCKET)sockfd, (
struct sockaddr*)&addr,
sizeof(addr));
286 WLog_ERR(TAG,
"bind");
287 closesocket((SOCKET)sockfd);
291 status = _listen((SOCKET)sockfd, 10);
295 WLog_ERR(TAG,
"listen");
296 closesocket((SOCKET)sockfd);
300 hevent = CreateFileDescriptorEvent(
nullptr, FALSE, FALSE, sockfd, WINPR_FD_READ);
304 WLog_ERR(TAG,
"failed to create sockfd event");
305 closesocket((SOCKET)sockfd);
309 listener->sockfds[listener->num_sockfds] = sockfd;
310 listener->events[listener->num_sockfds] = hevent;
311 listener->num_sockfds++;
312 WLog_INFO(TAG,
"Listening on socket %s.", addr.sun_path);
317 rdpListener* listener = (rdpListener*)instance->listener;
318 SOCKADDR_UN addr = WINPR_C_ARRAY_INIT;
319 u_long nonblocking = 1;
321 if (listener->num_sockfds == MAX_LISTENER_HANDLES)
323 WLog_ERR(TAG,
"too many listening sockets");
327 if (strnlen(path,
sizeof(addr.sun_path)) >=
sizeof(addr.sun_path))
329 WLog_ERR(TAG,
"socket path too long: %s", path);
333 SOCKET sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
335 if (sockfd == INVALID_SOCKET)
337 WLog_ERR(TAG,
"socket(AF_UNIX) failed: %d (Windows 10 1803 or later is needed)",
342 (void)ioctlsocket(sockfd, FIONBIO, &nonblocking);
343 addr.sun_family = AF_UNIX;
344 strncpy(addr.sun_path, path,
sizeof(addr.sun_path) - 1);
346 (void)DeleteFileA(path);
348 if (_bind(sockfd, (
struct sockaddr*)&addr,
sizeof(addr)) != 0)
350 WLog_ERR(TAG,
"bind(%s) failed: %d", path, WSAGetLastError());
355 if (_listen(sockfd, 10) != 0)
357 WLog_ERR(TAG,
"listen(%s) failed: %d", path, WSAGetLastError());
362 HANDLE hevent = WSACreateEvent();
366 WLog_ERR(TAG,
"failed to create the socket's event");
371 WSAEventSelect(sockfd, hevent, FD_READ | FD_ACCEPT | FD_CLOSE);
372 listener->sockfds[listener->num_sockfds] = (int)sockfd;
373 listener->events[listener->num_sockfds] = hevent;
374 listener->num_sockfds++;
375 WLog_INFO(TAG,
"Listening on socket %s.", addr.sun_path);
380static BOOL freerdp_listener_open_from_socket(freerdp_listener* instance,
int fd)
383 rdpListener* listener = (rdpListener*)instance->listener;
385 if (listener->num_sockfds == MAX_LISTENER_HANDLES)
387 WLog_ERR(TAG,
"too many listening sockets");
391 if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
394 listener->sockfds[listener->num_sockfds] = fd;
395 listener->events[listener->num_sockfds] = WSACreateEvent();
397 if (!listener->events[listener->num_sockfds])
400 WSAEventSelect((SOCKET)fd, listener->events[listener->num_sockfds],
401 FD_READ | FD_ACCEPT | FD_CLOSE);
403 listener->num_sockfds++;
404 WLog_INFO(TAG,
"Listening on socket %d.", fd);
411static void freerdp_listener_close(freerdp_listener* instance)
413 rdpListener* listener = (rdpListener*)instance->listener;
415 for (
int i = 0; i < listener->num_sockfds; i++)
417 closesocket((SOCKET)listener->sockfds[i]);
418 (void)CloseHandle(listener->events[i]);
421 listener->num_sockfds = 0;
424#if defined(WITH_FREERDP_DEPRECATED)
425static BOOL freerdp_listener_get_fds(freerdp_listener* instance,
void** rfds,
int* rcount)
427 rdpListener* listener = (rdpListener*)instance->listener;
429 if (listener->num_sockfds < 1)
432 for (
int index = 0; index < listener->num_sockfds; index++)
434 rfds[*rcount] = (
void*)(
long)(listener->sockfds[index]);
442static DWORD freerdp_listener_get_event_handles(freerdp_listener* instance, HANDLE* events,
445 rdpListener* listener = (rdpListener*)instance->listener;
447 if (listener->num_sockfds < 1)
450 if (listener->num_sockfds > (INT64)nCount)
453 for (
int index = 0; index < listener->num_sockfds; index++)
455 events[index] = listener->events[index];
458 return WINPR_ASSERTING_INT_CAST(uint32_t, listener->num_sockfds);
461BOOL freerdp_peer_set_local_and_hostname(freerdp_peer* client,
462 const struct sockaddr_storage* peer_addr)
464 const void* sin_addr =
nullptr;
465 const BYTE localhost6_bytes[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
467 WINPR_ASSERT(client);
468 WINPR_ASSERT(peer_addr);
470 if (peer_addr->ss_family == AF_INET)
472 const UINT32* usin_addr = sin_addr = &(((
const struct sockaddr_in*)peer_addr)->sin_addr);
474 if ((*usin_addr) == 0x0100007f)
475 client->local = TRUE;
477 else if (peer_addr->ss_family == AF_INET6)
479 const struct sockaddr_in6* usin_addr = sin_addr =
480 &(((
const struct sockaddr_in6*)peer_addr)->sin6_addr);
482 if (memcmp(usin_addr, localhost6_bytes, 16) == 0)
483 client->local = TRUE;
486#if defined(HAVE_AF_VSOCK_H)
487 else if (peer_addr->ss_family == AF_UNIX || peer_addr->ss_family == AF_VSOCK)
489 else if (peer_addr->ss_family == AF_UNIX)
491 client->local = TRUE;
494 WLog_INFO(TAG,
"Accepting client from localhost");
497 inet_ntop(peer_addr->ss_family, sin_addr, client->hostname,
sizeof(client->hostname));
502static BOOL freerdp_check_and_create_client(freerdp_listener* instance,
int peer_sockfd,
503 const struct sockaddr_storage* peer_addr)
505 WINPR_ASSERT(instance);
506 WINPR_ASSERT(peer_sockfd >= 0);
507 WINPR_ASSERT(peer_addr);
509 const BOOL check = IFCALLRESULT(TRUE, instance->CheckPeerAcceptRestrictions, instance);
512 closesocket((SOCKET)peer_sockfd);
516 freerdp_peer* client = freerdp_peer_new(peer_sockfd);
519 closesocket((SOCKET)peer_sockfd);
523 if (!freerdp_peer_set_local_and_hostname(client, peer_addr))
525 freerdp_peer_free(client);
529 const BOOL peer_accepted = IFCALLRESULT(FALSE, instance->PeerAccepted, instance, client);
532 WLog_ERR(TAG,
"PeerAccepted callback failed");
533 freerdp_peer_free(client);
539static BOOL freerdp_listener_check_fds(freerdp_listener* instance)
541 rdpListener* listener = (rdpListener*)instance->listener;
543 if (listener->num_sockfds < 1)
546 for (
int i = 0; i < listener->num_sockfds; i++)
548 struct sockaddr_storage peer_addr = WINPR_C_ARRAY_INIT;
550 (void)WSAResetEvent(listener->events[i]);
551 int peer_addr_size =
sizeof(peer_addr);
553 _accept((SOCKET)listener->sockfds[i], (
struct sockaddr*)&peer_addr, &peer_addr_size);
555 if (peer_sockfd == (SOCKET)-1)
557 char buffer[128] = WINPR_C_ARRAY_INIT;
559 int wsa_error = WSAGetLastError();
562 if (wsa_error == WSAEWOULDBLOCK)
567 if (errno == EAGAIN || errno == EWOULDBLOCK)
571 WLog_WARN(TAG,
"accept failed with %s", winpr_strerror(errno, buffer,
sizeof(buffer)));
575 if (!freerdp_check_and_create_client(instance, (
int)peer_sockfd, &peer_addr))
582freerdp_listener* freerdp_listener_new(
void)
584 if (!utils_set_umask())
587 freerdp_listener* instance = (freerdp_listener*)calloc(1,
sizeof(freerdp_listener));
592 instance->Open = freerdp_listener_open;
593 instance->OpenLocal = freerdp_listener_open_local;
594 instance->OpenFromSocket = freerdp_listener_open_from_socket;
595#if defined(WITH_FREERDP_DEPRECATED)
596 instance->GetFileDescriptor = freerdp_listener_get_fds;
598 instance->GetEventHandles = freerdp_listener_get_event_handles;
599 instance->CheckFileDescriptor = freerdp_listener_check_fds;
600 instance->Close = freerdp_listener_close;
601 rdpListener* listener = (rdpListener*)calloc(1,
sizeof(rdpListener));
609 listener->instance = instance;
610 instance->listener = (
void*)listener;
614void freerdp_listener_free(freerdp_listener* instance)
618 free(instance->listener);