21#include <freerdp/config.h>
30#include <winpr/platform.h>
31#include <winpr/winsock.h>
41#include <sys/socket.h>
42#include <netinet/in.h>
43#include <netinet/tcp.h>
48#ifdef WINPR_HAVE_POLL_H
52#include <sys/select.h>
55#if defined(__FreeBSD__) || defined(__OpenBSD__)
57#define SOL_TCP IPPROTO_TCP
63#define SOL_TCP IPPROTO_TCP
66#define TCP_KEEPIDLE TCP_KEEPALIVE
72#include <winpr/windows.h>
76#define SHUT_RDWR SD_BOTH
77#define close(_fd) closesocket(_fd)
81#include <freerdp/log.h>
83#include <winpr/stream.h>
86#include "../crypto/opensslcompat.h"
88#if defined(HAVE_AF_VSOCK_H)
90#include <linux/vm_sockets.h>
93#define TAG FREERDP_TAG("core")
101} WINPR_BIO_SIMPLE_SOCKET;
103static int transport_bio_simple_init(BIO* bio, SOCKET socket,
int shutdown);
104static int transport_bio_simple_uninit(BIO* bio);
106static int transport_bio_simple_write(BIO* bio,
const char* buf,
int size)
110 WINPR_BIO_SIMPLE_SOCKET* ptr = (WINPR_BIO_SIMPLE_SOCKET*)BIO_get_data(bio);
115 BIO_clear_flags(bio, BIO_FLAGS_WRITE);
116 status = _send(ptr->socket, buf, size, 0);
120 error = WSAGetLastError();
122 if ((error == WSAEWOULDBLOCK) || (error == WSAEINTR) || (error == WSAEINPROGRESS) ||
123 (error == WSAEALREADY))
125 BIO_set_flags(bio, (BIO_FLAGS_WRITE | BIO_FLAGS_SHOULD_RETRY));
129 BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
136static int transport_bio_simple_read(BIO* bio,
char* buf,
int size)
140 WINPR_BIO_SIMPLE_SOCKET* ptr = (WINPR_BIO_SIMPLE_SOCKET*)BIO_get_data(bio);
145 BIO_clear_flags(bio, BIO_FLAGS_READ);
146 (void)WSAResetEvent(ptr->hEvent);
147 status = _recv(ptr->socket, buf, size, 0);
156 BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
160 error = WSAGetLastError();
162 if ((error == WSAEWOULDBLOCK) || (error == WSAEINTR) || (error == WSAEINPROGRESS) ||
163 (error == WSAEALREADY))
165 BIO_set_flags(bio, (BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY));
169 BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
175static int transport_bio_simple_puts(WINPR_ATTR_UNUSED BIO* bio, WINPR_ATTR_UNUSED
const char* str)
180static int transport_bio_simple_gets(WINPR_ATTR_UNUSED BIO* bio, WINPR_ATTR_UNUSED
char* str,
181 WINPR_ATTR_UNUSED
int size)
186static long transport_bio_simple_ctrl(BIO* bio,
int cmd,
long arg1,
void* arg2)
189 WINPR_BIO_SIMPLE_SOCKET* ptr = (WINPR_BIO_SIMPLE_SOCKET*)BIO_get_data(bio);
193 case BIO_C_SET_SOCKET:
194 transport_bio_simple_uninit(bio);
195 transport_bio_simple_init(bio, (SOCKET)arg2, (
int)arg1);
197 case BIO_C_GET_SOCKET:
198 if (!BIO_get_init(bio) || !arg2)
201 *((SOCKET*)arg2) = ptr->socket;
203 case BIO_C_GET_EVENT:
204 if (!BIO_get_init(bio) || !arg2)
207 *((HANDLE*)arg2) = ptr->hEvent;
209 case BIO_C_SET_NONBLOCK:
213 flags = fcntl((
int)ptr->socket, F_GETFL);
219 (void)fcntl((
int)ptr->socket, F_SETFL, flags | O_NONBLOCK);
221 (
void)fcntl((
int)ptr->socket, F_SETFL, flags & ~(O_NONBLOCK));
228 case BIO_C_WAIT_READ:
230 int timeout = (int)arg1;
231 int sockfd = (int)ptr->socket;
232#ifdef WINPR_HAVE_POLL_H
233 struct pollfd pollset;
235 pollset.events = POLLIN;
240 status = poll(&pollset, 1, timeout);
241 }
while ((status < 0) && (errno == EINTR));
244 fd_set rset = WINPR_C_ARRAY_INIT;
245 struct timeval tv = WINPR_C_ARRAY_INIT;
247 FD_SET(sockfd, &rset);
251 tv.tv_sec = timeout / 1000;
252 tv.tv_usec = (timeout % 1000) * 1000;
257 status = select(sockfd + 1, &rset,
nullptr,
nullptr, timeout ? &tv : nullptr);
258 }
while ((status < 0) && (errno == EINTR));
267 case BIO_C_WAIT_WRITE:
269 int timeout = (int)arg1;
270 int sockfd = (int)ptr->socket;
271#ifdef WINPR_HAVE_POLL_H
272 struct pollfd pollset;
274 pollset.events = POLLOUT;
279 status = poll(&pollset, 1, timeout);
280 }
while ((status < 0) && (errno == EINTR));
283 fd_set rset = WINPR_C_ARRAY_INIT;
284 struct timeval tv = WINPR_C_ARRAY_INIT;
286 FD_SET(sockfd, &rset);
290 tv.tv_sec = timeout / 1000;
291 tv.tv_usec = (timeout % 1000) * 1000;
296 status = select(sockfd + 1,
nullptr, &rset,
nullptr, timeout ? &tv : nullptr);
297 }
while ((status < 0) && (errno == EINTR));
309 transport_bio_simple_uninit(bio);
310 transport_bio_simple_init(bio, (SOCKET) * ((
int*)arg2), (
int)arg1);
317 if (BIO_get_init(bio))
320 *((
int*)arg2) = (int)ptr->socket;
322 status = (int)ptr->socket;
327 case BIO_CTRL_GET_CLOSE:
328 status = BIO_get_shutdown(bio);
331 case BIO_CTRL_SET_CLOSE:
332 BIO_set_shutdown(bio, (
int)arg1);
349static int transport_bio_simple_init(BIO* bio, SOCKET socket,
int shutdown)
351 WINPR_BIO_SIMPLE_SOCKET* ptr = (WINPR_BIO_SIMPLE_SOCKET*)BIO_get_data(bio);
352 ptr->socket = socket;
353 BIO_set_shutdown(bio, shutdown);
354 BIO_set_flags(bio, BIO_FLAGS_SHOULD_RETRY);
355 BIO_set_init(bio, 1);
356 ptr->hEvent = WSACreateEvent();
362 if (WSAEventSelect(ptr->socket, ptr->hEvent, FD_READ | FD_ACCEPT | FD_CLOSE))
364 WLog_ERR(TAG,
"WSAEventSelect returned 0x%08x",
365 WINPR_CXX_COMPAT_CAST(
unsigned, WSAGetLastError()));
372static int transport_bio_simple_uninit(BIO* bio)
374 WINPR_BIO_SIMPLE_SOCKET* ptr = (WINPR_BIO_SIMPLE_SOCKET*)BIO_get_data(bio);
376 if (BIO_get_shutdown(bio))
378 if (BIO_get_init(bio) && ptr)
380 _shutdown(ptr->socket, SD_BOTH);
381 closesocket(ptr->socket);
386 if (ptr && ptr->hEvent)
388 (void)CloseHandle(ptr->hEvent);
389 ptr->hEvent =
nullptr;
392 BIO_set_init(bio, 0);
393 BIO_set_flags(bio, 0);
397static int transport_bio_simple_new(BIO* bio)
399 WINPR_BIO_SIMPLE_SOCKET* ptr =
nullptr;
400 BIO_set_flags(bio, BIO_FLAGS_SHOULD_RETRY);
401 ptr = (WINPR_BIO_SIMPLE_SOCKET*)calloc(1,
sizeof(WINPR_BIO_SIMPLE_SOCKET));
406 BIO_set_data(bio, ptr);
410static int transport_bio_simple_free(BIO* bio)
412 WINPR_BIO_SIMPLE_SOCKET* ptr =
nullptr;
417 transport_bio_simple_uninit(bio);
418 ptr = (WINPR_BIO_SIMPLE_SOCKET*)BIO_get_data(bio);
422 BIO_set_data(bio,
nullptr);
429static BOOL CALLBACK bio_register(WINPR_ATTR_UNUSED
PINIT_ONCE InitOnce, PVOID Parameter,
430 WINPR_ATTR_UNUSED PVOID* Context)
432 BIO_METHOD** methods = (BIO_METHOD**)Parameter;
433 WINPR_ASSERT(methods);
435 BIO_METHOD* bio_methods = BIO_meth_new(BIO_TYPE_SIMPLE,
"SimpleSocket");
436 *methods = bio_methods;
440 BIO_meth_set_write(bio_methods, transport_bio_simple_write);
441 BIO_meth_set_read(bio_methods, transport_bio_simple_read);
442 BIO_meth_set_puts(bio_methods, transport_bio_simple_puts);
443 BIO_meth_set_gets(bio_methods, transport_bio_simple_gets);
444 BIO_meth_set_ctrl(bio_methods, transport_bio_simple_ctrl);
445 BIO_meth_set_create(bio_methods, transport_bio_simple_new);
446 BIO_meth_set_destroy(bio_methods, transport_bio_simple_free);
450const BIO_METHOD* BIO_s_simple_socket(
void)
452 static BIO_METHOD* bio_methods =
nullptr;
453 static INIT_ONCE once = INIT_ONCE_STATIC_INIT;
454 if (!InitOnceExecuteOnce(&once, bio_register, (
void*)&bio_methods,
nullptr))
467} WINPR_BIO_BUFFERED_SOCKET;
469static int transport_bio_buffered_write(BIO* bio,
const char* buf,
int num)
473 size_t committedBytes = 0;
474 DataChunk chunks[2] = WINPR_C_ARRAY_INIT;
475 WINPR_BIO_BUFFERED_SOCKET* ptr = (WINPR_BIO_BUFFERED_SOCKET*)BIO_get_data(bio);
476 BIO* next_bio =
nullptr;
483 ptr->writeBlocked = FALSE;
484 BIO_clear_flags(bio, BIO_FLAGS_WRITE);
489 if (buf && (num > 0) && !ringbuffer_write(&ptr->xmitBuffer, (
const BYTE*)buf, (
size_t)num))
491 WLog_ERR(TAG,
"an error occurred when writing (num: %d)", num);
495 nchunks = ringbuffer_peek(&ptr->xmitBuffer, chunks, ringbuffer_used(&ptr->xmitBuffer));
496 next_bio = BIO_next(bio);
498 for (
int i = 0; i < nchunks; i++)
500 while (chunks[i].size)
504 const size_t wr = MIN(INT32_MAX, chunks[i].size);
505 const int status = BIO_write(next_bio, chunks[i].data, (
int)wr);
509 if (!BIO_should_retry(next_bio))
511 BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
516 if (BIO_should_write(next_bio))
518 BIO_set_flags(bio, BIO_FLAGS_WRITE);
519 ptr->writeBlocked = TRUE;
525 committedBytes += (size_t)status;
526 chunks[i].size -= (size_t)status;
527 chunks[i].data += status;
533 ringbuffer_commit_read_bytes(&ptr->xmitBuffer, committedBytes);
537static int transport_bio_buffered_read(BIO* bio,
char* buf,
int size)
540 WINPR_BIO_BUFFERED_SOCKET* ptr = (WINPR_BIO_BUFFERED_SOCKET*)BIO_get_data(bio);
541 BIO* next_bio = BIO_next(bio);
542 ptr->readBlocked = FALSE;
543 BIO_clear_flags(bio, BIO_FLAGS_READ);
545 status = BIO_read(next_bio, buf, size);
549 if (!BIO_should_retry(next_bio))
551 BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
555 BIO_set_flags(bio, BIO_FLAGS_SHOULD_RETRY);
557 if (BIO_should_read(next_bio))
559 BIO_set_flags(bio, BIO_FLAGS_READ);
560 ptr->readBlocked = TRUE;
569static int transport_bio_buffered_puts(WINPR_ATTR_UNUSED BIO* bio,
570 WINPR_ATTR_UNUSED
const char* str)
575static int transport_bio_buffered_gets(WINPR_ATTR_UNUSED BIO* bio, WINPR_ATTR_UNUSED
char* str,
576 WINPR_ATTR_UNUSED
int size)
581static long transport_bio_buffered_ctrl(BIO* bio,
int cmd,
long arg1,
void* arg2)
584 WINPR_BIO_BUFFERED_SOCKET* ptr = (WINPR_BIO_BUFFERED_SOCKET*)BIO_get_data(bio);
589 if (!ringbuffer_used(&ptr->xmitBuffer))
592 status = (transport_bio_buffered_write(bio,
nullptr, 0) >= 0) ? 1 : -1;
596 case BIO_CTRL_WPENDING:
597 status = WINPR_ASSERTING_INT_CAST(
long, ringbuffer_used(&ptr->xmitBuffer));
600 case BIO_CTRL_PENDING:
604 case BIO_C_READ_BLOCKED:
605 status = (int)ptr->readBlocked;
608 case BIO_C_WRITE_BLOCKED:
609 status = (int)ptr->writeBlocked;
613 status = BIO_ctrl(BIO_next(bio), cmd, arg1, arg2);
620static int transport_bio_buffered_new(BIO* bio)
622 WINPR_BIO_BUFFERED_SOCKET* ptr =
nullptr;
623 BIO_set_init(bio, 1);
624 BIO_set_flags(bio, BIO_FLAGS_SHOULD_RETRY);
625 ptr = (WINPR_BIO_BUFFERED_SOCKET*)calloc(1,
sizeof(WINPR_BIO_BUFFERED_SOCKET));
630 BIO_set_data(bio, (
void*)ptr);
632 if (!ringbuffer_init(&ptr->xmitBuffer, 0x10000))
641static int transport_bio_buffered_free(BIO* bio)
643 WINPR_BIO_BUFFERED_SOCKET* ptr = (WINPR_BIO_BUFFERED_SOCKET*)BIO_get_data(bio);
648 ringbuffer_destroy(&ptr->xmitBuffer);
653static BOOL CALLBACK bio_socket_register(WINPR_ATTR_UNUSED
PINIT_ONCE InitOnce, PVOID Parameter,
654 WINPR_ATTR_UNUSED PVOID* Context)
656 BIO_METHOD** methods = (BIO_METHOD**)Parameter;
657 WINPR_ASSERT(methods);
659 BIO_METHOD* bio_methods = BIO_meth_new(BIO_TYPE_BUFFERED,
"BufferedSocket");
660 *methods = bio_methods;
663 BIO_meth_set_write(bio_methods, transport_bio_buffered_write);
664 BIO_meth_set_read(bio_methods, transport_bio_buffered_read);
665 BIO_meth_set_puts(bio_methods, transport_bio_buffered_puts);
666 BIO_meth_set_gets(bio_methods, transport_bio_buffered_gets);
667 BIO_meth_set_ctrl(bio_methods, transport_bio_buffered_ctrl);
668 BIO_meth_set_create(bio_methods, transport_bio_buffered_new);
669 BIO_meth_set_destroy(bio_methods, transport_bio_buffered_free);
673const BIO_METHOD* BIO_s_buffered_socket(
void)
675 static BIO_METHOD* bio_methods =
nullptr;
676 static INIT_ONCE once = INIT_ONCE_STATIC_INIT;
677 if (!InitOnceExecuteOnce(&once, bio_socket_register, (
void*)&bio_methods,
nullptr))
682char* freerdp_tcp_address_to_string(
const struct sockaddr_storage* addr, BOOL* pIPv6)
684 char ipAddress[INET6_ADDRSTRLEN + 1] = WINPR_C_ARRAY_INIT;
685 const struct sockaddr_in6* sockaddr_ipv6 = (
const struct sockaddr_in6*)addr;
686 const struct sockaddr_in* sockaddr_ipv4 = (
const struct sockaddr_in*)addr;
693 switch (sockaddr_ipv4->sin_family)
696 if (!inet_ntop(sockaddr_ipv4->sin_family, &sockaddr_ipv4->sin_addr, ipAddress,
703 if (!inet_ntop(sockaddr_ipv6->sin6_family, &sockaddr_ipv6->sin6_addr, ipAddress,
710 (void)sprintf_s(ipAddress, ARRAYSIZE(ipAddress),
"127.0.0.1");
717 if (pIPv6 !=
nullptr)
719 *pIPv6 = (sockaddr_ipv4->sin_family == AF_INET6);
722 return _strdup(ipAddress);
725static bool freerdp_tcp_get_ip_address(rdpSettings* settings,
int sockfd)
727 WINPR_ASSERT(settings);
729 struct sockaddr_storage saddr = WINPR_C_ARRAY_INIT;
730 socklen_t length =
sizeof(
struct sockaddr_storage);
736 if (getsockname(sockfd, (
struct sockaddr*)&saddr, &length) != 0)
738 settings->ClientAddress = freerdp_tcp_address_to_string(&saddr, &settings->IPv6Enabled);
739 return settings->ClientAddress !=
nullptr;
742char* freerdp_tcp_get_peer_address(SOCKET sockfd)
744 struct sockaddr_storage saddr = WINPR_C_ARRAY_INIT;
745 socklen_t length =
sizeof(
struct sockaddr_storage);
747 if (getpeername((
int)sockfd, (
struct sockaddr*)&saddr, &length) != 0)
752 return freerdp_tcp_address_to_string(&saddr,
nullptr);
755static int freerdp_uds_connect(
const char* path)
760 struct sockaddr_un addr = WINPR_C_ARRAY_INIT;
761 sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
765 WLog_ERR(TAG,
"socket");
769 addr.sun_family = AF_UNIX;
770 strncpy(addr.sun_path, path,
sizeof(addr.sun_path) - 1);
771 status = connect(sockfd, (
struct sockaddr*)&addr,
sizeof(addr));
775 WLog_ERR(TAG,
"connect");
786struct addrinfo* freerdp_tcp_resolve_host(
const char* hostname,
int port,
int ai_flags)
788 char* service =
nullptr;
789 char port_str[16] = WINPR_C_ARRAY_INIT;
792 struct addrinfo* result =
nullptr;
793 struct addrinfo hints = { .ai_family = AF_UNSPEC,
794 .ai_socktype = SOCK_STREAM,
795 .ai_flags = ai_flags };
799 (void)sprintf_s(port_str,
sizeof(port_str) - 1,
"%d", port);
803 status = getaddrinfo(hostname, service, &hints, &result);
807 WLog_WARN(TAG,
"getaddrinfo(%s) failed with %s", hostname, gai_strerror(status));
814static BOOL freerdp_tcp_is_hostname_resolvable(rdpContext* context,
const char* hostname)
816 struct addrinfo* result = freerdp_tcp_resolve_host(hostname, -1, 0);
820 freerdp_set_last_error_if_not(context, FREERDP_ERROR_DNS_NAME_NOT_FOUND);
825 freerdp_set_last_error_log(context, 0);
826 freeaddrinfo(result);
830static BOOL freerdp_tcp_connect_timeout(rdpContext* context,
int sockfd,
struct sockaddr* addr,
831 size_t addrlen, UINT32 timeout)
834 HANDLE handles[2] = WINPR_C_ARRAY_INIT;
837 DWORD tout = (timeout > 0) ? timeout : INFINITE;
839 handles[count] = CreateEvent(
nullptr, TRUE, FALSE,
nullptr);
844 const int wsastatus = WSAEventSelect((SOCKET)sockfd, handles[count++],
845 FD_READ | FD_WRITE | FD_CONNECT | FD_CLOSE);
849 WLog_ERR(TAG,
"WSAEventSelect failed with %d", WSAGetLastError());
853 handles[count++] = utils_get_abort_event(context->rdp);
856 const int constatus =
857 _connect((SOCKET)sockfd, addr, WINPR_ASSERTING_INT_CAST(
int, addrlen));
860 const int estatus = WSAGetLastError();
875 const DWORD wstatus = WaitForMultipleObjects(count, handles, FALSE, tout);
876 if (WAIT_OBJECT_0 != wstatus)
881 const int status = WSAEventSelect((SOCKET)sockfd, handles[0], 0);
884 WLog_ERR(TAG,
"WSAEventSelect failed with %d", WSAGetLastError());
889 if (_ioctlsocket((SOCKET)sockfd, FIONBIO, &arg) != 0)
896 socklen_t optlen =
sizeof(optval);
897 if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (
void*)&optval, &optlen) >= 0)
901 char ebuffer[256] = WINPR_C_ARRAY_INIT;
902 char hostname[512] = WINPR_C_ARRAY_INIT;
903 char serv[512] = WINPR_C_ARRAY_INIT;
905 getnameinfo(addr, WINPR_ASSERTING_INT_CAST(socklen_t, addrlen), hostname,
906 WINPR_ASSERTING_INT_CAST(socklen_t,
sizeof(hostname)), serv,
907 WINPR_ASSERTING_INT_CAST(socklen_t,
sizeof(serv)),
908 NI_NUMERICHOST | NI_NUMERICSERV);
909 WLog_WARN(TAG,
"connect to %s:%s failed with error: %s [%" PRId32
"]", hostname, serv,
910 winpr_strerror(optval, ebuffer,
sizeof(ebuffer)), optval);
916 (void)CloseHandle(handles[0]);
923 struct addrinfo* addr;
924 struct addrinfo* result;
927static void peer_free(t_peer* peer)
929 if (peer->s != INVALID_SOCKET)
930 closesocket(peer->s);
932 freeaddrinfo(peer->addr);
933 memset(peer, 0,
sizeof(t_peer));
934 peer->s = INVALID_SOCKET;
937static int freerdp_tcp_connect_multi(rdpContext* context,
char** hostnames,
const UINT32* ports,
938 UINT32 count, UINT16 port, WINPR_ATTR_UNUSED UINT32 timeout)
940 UINT32 sindex = count;
941 SOCKET sockfd = INVALID_SOCKET;
942 struct addrinfo* addr =
nullptr;
943 struct addrinfo* result =
nullptr;
945 HANDLE* events = (HANDLE*)calloc(count + 1,
sizeof(HANDLE));
946 t_peer* peers = (t_peer*)calloc(count,
sizeof(t_peer));
948 if (!peers || !events || (count < 1))
955 for (UINT32 index = 0; index < count; index++)
960 curPort = WINPR_ASSERTING_INT_CAST(
int, ports[index]);
962 result = freerdp_tcp_resolve_host(hostnames[index], curPort, 0);
969 if ((addr->ai_family == AF_INET6) && (addr->ai_next !=
nullptr))
971 while ((addr = addr->ai_next))
973 if (addr->ai_family == AF_INET)
981 peers[index].s = _socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
983 if (peers[index].s == INVALID_SOCKET)
985 freeaddrinfo(result);
989 peers[index].addr = addr;
990 peers[index].result = result;
993 for (UINT32 index = 0; index < count; index++)
995 sockfd = peers[index].s;
996 addr = peers[index].addr;
998 if ((sockfd == INVALID_SOCKET) || (!addr))
1003 _connect(sockfd, addr->ai_addr, WINPR_ASSERTING_INT_CAST(
int, addr->ai_addrlen));
1015 sockfd = peers[sindex].s;
1016 peers[sindex].s = INVALID_SOCKET;
1019 freerdp_set_last_error_log(context, FREERDP_ERROR_CONNECT_CANCELLED);
1021 for (UINT32 index = 0; index < count; index++)
1022 peer_free(&peers[index]);
1025 free((
void*)events);
1029BOOL freerdp_tcp_set_keep_alive_mode(
const rdpSettings* settings,
int sockfd)
1033 socklen_t optlen = 0;
1037 socklen_t xoptlen =
sizeof(xoptval);
1038 const int rc = getsockopt(sockfd, SOL_SOCKET, SO_TYPE, (
void*)&xoptval, &xoptlen);
1041 isTcp = xoptval == SOCK_STREAM;
1043 optval = keepalive ? 1 : 0;
1044 optlen =
sizeof(optval);
1046 if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (
void*)&optval, optlen) < 0)
1048 WLog_WARN(TAG,
"setsockopt() SOL_SOCKET, SO_KEEPALIVE");
1057 optlen =
sizeof(optval);
1059 if (setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE, (
void*)&optval, optlen) < 0)
1061 WLog_WARN(TAG,
"setsockopt() IPPROTO_TCP, TCP_KEEPIDLE");
1071 optlen =
sizeof(optval);
1073 if (setsockopt(sockfd, SOL_TCP, TCP_KEEPCNT, (
void*)&optval, optlen) < 0)
1075 WLog_WARN(TAG,
"setsockopt() SOL_TCP, TCP_KEEPCNT");
1081 optlen =
sizeof(optval);
1083 if (setsockopt(sockfd, SOL_TCP, TCP_KEEPINTVL, (
void*)&optval, optlen) < 0)
1085 WLog_WARN(TAG,
"setsockopt() SOL_TCP, TCP_KEEPINTVL");
1090#if defined(__MACOSX__) || defined(__IOS__)
1092 optlen =
sizeof(optval);
1094 if (setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (
void*)&optval, optlen) < 0)
1096 WLog_WARN(TAG,
"setsockopt() SOL_SOCKET, SO_NOSIGPIPE");
1100#ifdef TCP_USER_TIMEOUT
1102 optlen =
sizeof(optval);
1104 if (setsockopt(sockfd, SOL_TCP, TCP_USER_TIMEOUT, (
void*)&optval, optlen) < 0)
1106 WLog_WARN(TAG,
"setsockopt() SOL_TCP, TCP_USER_TIMEOUT");
1113int freerdp_tcp_connect(rdpContext* context,
const char* hostname,
int port, DWORD timeout)
1115 rdpTransport* transport =
nullptr;
1116 if (!context || !context->rdp)
1118 transport = context->rdp->transport;
1121 return transport_tcp_connect(context->rdp->transport, hostname, port, timeout);
1124static struct addrinfo* reorder_addrinfo_by_preference(rdpContext* context,
struct addrinfo* addr)
1126 WINPR_ASSERT(context);
1129 const BOOL preferIPv6 =
1134 struct addrinfo* ipv6Head =
nullptr;
1135 struct addrinfo* ipv6Tail =
nullptr;
1136 struct addrinfo* otherHead =
nullptr;
1137 struct addrinfo* otherTail =
nullptr;
1142 struct addrinfo* next = addr->ai_next;
1143 addr->ai_next =
nullptr;
1145 if (addr->ai_family == AF_INET6)
1150 ipv6Tail->ai_next = addr;
1158 otherTail->ai_next = addr;
1166 ipv6Tail->ai_next = otherHead;
1168 return ipv6Head ? ipv6Head : otherHead;
1171static int get_next_addrinfo(rdpContext* context,
struct addrinfo* input,
struct addrinfo** result,
1174 WINPR_ASSERT(context);
1175 WINPR_ASSERT(result);
1177 struct addrinfo* addr = input;
1189 const int family = (IPvX == 4) ? AF_INET : AF_INET6;
1190 while (addr && (addr->ai_family != family))
1191 addr = addr->ai_next;
1206 freerdp_set_last_error_if_not(context, errorCode);
1211static int freerdp_vsock_connect(rdpContext* context,
const char* hostname,
int port)
1213#if defined(HAVE_AF_VSOCK_H)
1214 int sockfd = socket(AF_VSOCK, SOCK_STREAM, 0);
1217 char buffer[256] = WINPR_C_ARRAY_INIT;
1218 WLog_WARN(TAG,
"socket(AF_VSOCK, SOCK_STREAM, 0) failed with %s",
1219 winpr_strerror(errno, buffer,
sizeof(buffer)));
1220 freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
1224 struct sockaddr_vm addr = WINPR_C_ARRAY_INIT;
1226 addr.svm_family = AF_VSOCK;
1227 addr.svm_port = WINPR_ASSERTING_INT_CAST(typeof(addr.svm_port), port);
1230 char* ptr =
nullptr;
1231 unsigned long val = strtoul(hostname, &ptr, 10);
1232 if (errno || (val > UINT32_MAX))
1234 char ebuffer[256] = WINPR_C_ARRAY_INIT;
1235 WLog_ERR(TAG,
"could not extract port from '%s', value=%lu, error=%s", hostname, val,
1236 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)));
1240 addr.svm_cid = WINPR_ASSERTING_INT_CAST(typeof(addr.svm_cid), val);
1241 if (addr.svm_cid == 2)
1243 addr.svm_flags = VMADDR_FLAG_TO_HOST;
1245 if ((connect(sockfd, (
struct sockaddr*)&addr,
sizeof(
struct sockaddr_vm))) == -1)
1247 WLog_ERR(TAG,
"failed to connect to %s", hostname);
1253 WLog_ERR(TAG,
"Compiled without AF_VSOCK, '%s' not supported", hostname);
1258static void log_connection_address(
const char* hostname,
struct addrinfo* addr)
1262 char* peerAddress = freerdp_tcp_address_to_string(
1263 WINPR_PACKED_ALIGN_CAST(
const struct sockaddr_storage*, addr->ai_addr),
nullptr);
1265 WLog_DBG(TAG,
"resolved %s: try to connect to %s", hostname, peerAddress);
1269static int freerdp_host_connect(rdpContext* context,
const char* hostname,
int port, DWORD timeout)
1272 struct addrinfo* addr =
nullptr;
1273 struct addrinfo* result = freerdp_tcp_resolve_host(hostname, port, 0);
1277 freerdp_set_last_error_if_not(context, FREERDP_ERROR_DNS_NAME_NOT_FOUND);
1280 freerdp_set_last_error_log(context, 0);
1286 result = reorder_addrinfo_by_preference(context, result);
1288 const int rc = get_next_addrinfo(context, result, &addr, FREERDP_ERROR_DNS_NAME_NOT_FOUND);
1294 sockfd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
1297 log_connection_address(hostname, addr);
1299 if (!freerdp_tcp_connect_timeout(context, sockfd, addr->ai_addr, addr->ai_addrlen,
1310 get_next_addrinfo(context, addr->ai_next, &addr, FREERDP_ERROR_CONNECT_FAILED);
1314 }
while (sockfd < 0);
1317 freeaddrinfo(result);
1321int freerdp_tcp_default_connect(rdpContext* context, rdpSettings* settings,
const char* hostname,
1322 int port, DWORD timeout)
1325 BOOL ipcSocket = FALSE;
1326 BOOL useExternalDefinedSocket = FALSE;
1330 freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
1335 if (hostname[0] ==
'/')
1338 if (hostname[0] ==
'|')
1339 useExternalDefinedSocket = TRUE;
1341 const char* vsock = utils_is_vsock(hostname);
1344 sockfd = freerdp_uds_connect(hostname);
1348 freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
1352 else if (useExternalDefinedSocket)
1355 sockfd = freerdp_vsock_connect(context, vsock, port);
1358 if (!settings->GatewayEnabled)
1360 if (!freerdp_tcp_is_hostname_resolvable(context, hostname) ||
1361 settings->RemoteAssistanceMode)
1363 if (settings->TargetNetAddressCount > 0)
1365 WINPR_ASSERT(port <= UINT16_MAX);
1366 sockfd = freerdp_tcp_connect_multi(
1367 context, settings->TargetNetAddresses, settings->TargetNetPorts,
1368 settings->TargetNetAddressCount, (UINT16)port, timeout);
1374 sockfd = freerdp_host_connect(context, hostname, port, timeout);
1379 if (!freerdp_tcp_get_ip_address(settings, sockfd))
1381 if (!useExternalDefinedSocket)
1384 freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
1386 WLog_ERR(TAG,
"Couldn't get socket ip address");
1391 if (!ipcSocket && !useExternalDefinedSocket)
1393 (void)freerdp_tcp_set_nodelay(WLog_Get(TAG), WLOG_ERROR, sockfd);
1398 socklen_t optlen =
sizeof(optval);
1399 if (getsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (
void*)&optval, &optlen) == 0)
1401 if (optval < (1024 * 32))
1404 optlen =
sizeof(optval);
1406 if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (
void*)&optval, optlen) < 0)
1410 freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
1412 WLog_ERR(TAG,
"unable to set receive buffer len");
1418 if (!ipcSocket && !useExternalDefinedSocket)
1420 if (!freerdp_tcp_set_keep_alive_mode(settings, sockfd))
1424 freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
1426 WLog_ERR(TAG,
"Couldn't set keep alive mode.");
1431 if (WaitForSingleObject(utils_get_abort_event(context->rdp), 0) == WAIT_OBJECT_0)
1445typedef struct rdp_tcp_layer rdpTcpLayer;
1447static int freerdp_tcp_layer_read(
void* userContext,
void* data,
int bytes)
1451 if (!data || !bytes)
1454 rdpTcpLayer* tcpLayer = (rdpTcpLayer*)userContext;
1456 (void)WSAResetEvent(tcpLayer->hEvent);
1457 const int status = _recv((SOCKET)tcpLayer->sockfd, data, bytes, 0);
1462 const int error = WSAGetLastError();
1464 if ((error == WSAEWOULDBLOCK) || (error == WSAEINTR) || (error == WSAEINPROGRESS) ||
1465 (error == WSAEALREADY))
1471static int freerdp_tcp_layer_write(
void* userContext,
const void* data,
int bytes)
1475 if (!data || !bytes)
1478 rdpTcpLayer* tcpLayer = (rdpTcpLayer*)userContext;
1480 const int status = _send((SOCKET)tcpLayer->sockfd, data, bytes, 0);
1484 const int error = WSAGetLastError();
1486 if ((error == WSAEWOULDBLOCK) || (error == WSAEINTR) || (error == WSAEINPROGRESS) ||
1487 (error == WSAEALREADY))
1493static BOOL freerdp_tcp_layer_close(
void* userContext)
1498 rdpTcpLayer* tcpLayer = (rdpTcpLayer*)userContext;
1500 if (tcpLayer->sockfd >= 0)
1501 closesocket((SOCKET)tcpLayer->sockfd);
1502 if (tcpLayer->hEvent)
1503 (void)CloseHandle(tcpLayer->hEvent);
1508static BOOL freerdp_tcp_layer_wait(
void* userContext, BOOL waitWrite, DWORD timeout)
1513 rdpTcpLayer* tcpLayer = (rdpTcpLayer*)userContext;
1516 int sockfd = tcpLayer->sockfd;
1517#ifdef WINPR_HAVE_POLL_H
1518 struct pollfd pollset = WINPR_C_ARRAY_INIT;
1519 pollset.fd = sockfd;
1520 pollset.events = waitWrite ? POLLOUT : POLLIN;
1524 status = poll(&pollset, 1, (
int)timeout);
1525 }
while ((status < 0) && (errno == EINTR));
1528 fd_set rset = WINPR_C_ARRAY_INIT;
1529 struct timeval tv = WINPR_C_ARRAY_INIT;
1531 FD_SET(sockfd, &rset);
1535 tv.tv_sec = timeout / 1000;
1536 tv.tv_usec = (timeout % 1000) * 1000;
1542 status = select(sockfd + 1,
nullptr, &rset,
nullptr, timeout ? &tv : nullptr);
1544 status = select(sockfd + 1, &rset,
nullptr,
nullptr, timeout ? &tv : nullptr);
1545 }
while ((status < 0) && (errno == EINTR));
1552static HANDLE freerdp_tcp_layer_get_event(
void* userContext)
1557 rdpTcpLayer* tcpLayer = (rdpTcpLayer*)userContext;
1559 return tcpLayer->hEvent;
1562rdpTransportLayer* freerdp_tcp_connect_layer(rdpContext* context,
const char* hostname,
int port,
1565 WINPR_ASSERT(context);
1567 const rdpSettings* settings = context->settings;
1568 WINPR_ASSERT(settings);
1571 rdpTcpLayer* tcpLayer =
nullptr;
1573 int sockfd = freerdp_tcp_connect(context, hostname, port, timeout);
1576 if (!freerdp_tcp_set_keep_alive_mode(settings, sockfd))
1579 layer = transport_layer_new(freerdp_get_transport(context),
sizeof(rdpTcpLayer));
1583 layer->Read = freerdp_tcp_layer_read;
1584 layer->Write = freerdp_tcp_layer_write;
1585 layer->Close = freerdp_tcp_layer_close;
1586 layer->Wait = freerdp_tcp_layer_wait;
1587 layer->GetEvent = freerdp_tcp_layer_get_event;
1589 tcpLayer = (rdpTcpLayer*)layer->userContext;
1590 WINPR_ASSERT(tcpLayer);
1592 tcpLayer->sockfd = -1;
1593 tcpLayer->hEvent = WSACreateEvent();
1594 if (!tcpLayer->hEvent)
1598 if (WSAEventSelect((SOCKET)sockfd, tcpLayer->hEvent, FD_READ | FD_ACCEPT | FD_CLOSE))
1600 WLog_ERR(TAG,
"WSAEventSelect returned 0x%08x", (
unsigned)WSAGetLastError());
1604 tcpLayer->sockfd = sockfd;
1610 closesocket((SOCKET)sockfd);
1611 transport_layer_free(layer);
1615BOOL freerdp_tcp_set_nodelay(wLog* log, DWORD level,
int sockfd)
1620 socklen_t typelen =
sizeof(type);
1621 char* ptype = (
char*)&type;
1622 const int rc = getsockopt(sockfd, SOL_SOCKET, SO_TYPE, ptype, &typelen);
1625 char buffer[128] = WINPR_C_ARRAY_INIT;
1626 WLog_Print(log, level,
"can't get SOL_SOCKET|SO_TYPE (%s)",
1627 winpr_strerror(errno, buffer,
sizeof(buffer)));
1630 else if (type == SOCK_STREAM)
1632 int option_value = -1;
1633 const socklen_t option_len =
sizeof(option_value);
1635 setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (
void*)&option_value, option_len);
1640 char buffer[128] = WINPR_C_ARRAY_INIT;
1641 WLog_Print(log, level,
"can't set TCP_NODELAY (%s)",
1642 winpr_strerror(errno, buffer,
sizeof(buffer)));
1648 WLog_Print(log, level,
"Socket SOL_SOCKET|SO_TYPE %d unsupported", type);
WINPR_ATTR_NODISCARD FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_string(rdpSettings *settings, FreeRDP_Settings_Keys_String id, const char *val)
Sets a string settings value. The param is copied.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.
a piece of data in the ring buffer, exactly like a glibc iovec