FreeRDP
Loading...
Searching...
No Matches
tcp.c
1
21#include <freerdp/config.h>
22
23#include "settings.h"
24
25#include <time.h>
26#include <errno.h>
27#include <fcntl.h>
28
29#include <winpr/crt.h>
30#include <winpr/platform.h>
31#include <winpr/winsock.h>
32
33#include "rdp.h"
34#include "utils.h"
35
36#if !defined(_WIN32)
37
38#include <netdb.h>
39#include <unistd.h>
40#include <sys/ioctl.h>
41#include <sys/socket.h>
42#include <netinet/in.h>
43#include <netinet/tcp.h>
44#include <net/if.h>
45#include <sys/types.h>
46#include <arpa/inet.h>
47
48#ifdef WINPR_HAVE_POLL_H
49#include <poll.h>
50#else
51#include <time.h>
52#include <sys/select.h>
53#endif
54
55#if defined(__FreeBSD__) || defined(__OpenBSD__)
56#ifndef SOL_TCP
57#define SOL_TCP IPPROTO_TCP
58#endif
59#endif
60
61#ifdef __APPLE__
62#ifndef SOL_TCP
63#define SOL_TCP IPPROTO_TCP
64#endif
65#ifndef TCP_KEEPIDLE
66#define TCP_KEEPIDLE TCP_KEEPALIVE
67#endif
68#endif
69
70#else
71
72#include <winpr/windows.h>
73
74#include <winpr/crt.h>
75
76#define SHUT_RDWR SD_BOTH
77#define close(_fd) closesocket(_fd)
78
79#endif
80
81#include <freerdp/log.h>
82
83#include <winpr/stream.h>
84
85#include "tcp.h"
86#include "../crypto/opensslcompat.h"
87
88#if defined(HAVE_AF_VSOCK_H)
89#include <ctype.h>
90#include <linux/vm_sockets.h>
91#endif
92
93#define TAG FREERDP_TAG("core")
94
95/* Simple Socket BIO */
96
97typedef struct
98{
99 SOCKET socket;
100 HANDLE hEvent;
101} WINPR_BIO_SIMPLE_SOCKET;
102
103static int transport_bio_simple_init(BIO* bio, SOCKET socket, int shutdown);
104static int transport_bio_simple_uninit(BIO* bio);
105
106static int transport_bio_simple_write(BIO* bio, const char* buf, int size)
107{
108 int error = 0;
109 int status = 0;
110 WINPR_BIO_SIMPLE_SOCKET* ptr = (WINPR_BIO_SIMPLE_SOCKET*)BIO_get_data(bio);
111
112 if (!buf)
113 return 0;
114
115 BIO_clear_flags(bio, BIO_FLAGS_WRITE);
116 status = _send(ptr->socket, buf, size, 0);
117
118 if (status <= 0)
119 {
120 error = WSAGetLastError();
121
122 if ((error == WSAEWOULDBLOCK) || (error == WSAEINTR) || (error == WSAEINPROGRESS) ||
123 (error == WSAEALREADY))
124 {
125 BIO_set_flags(bio, (BIO_FLAGS_WRITE | BIO_FLAGS_SHOULD_RETRY));
126 }
127 else
128 {
129 BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
130 }
131 }
132
133 return status;
134}
135
136static int transport_bio_simple_read(BIO* bio, char* buf, int size)
137{
138 int error = 0;
139 int status = 0;
140 WINPR_BIO_SIMPLE_SOCKET* ptr = (WINPR_BIO_SIMPLE_SOCKET*)BIO_get_data(bio);
141
142 if (!buf)
143 return 0;
144
145 BIO_clear_flags(bio, BIO_FLAGS_READ);
146 (void)WSAResetEvent(ptr->hEvent);
147 status = _recv(ptr->socket, buf, size, 0);
148
149 if (status > 0)
150 {
151 return status;
152 }
153
154 if (status == 0)
155 {
156 BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
157 return 0;
158 }
159
160 error = WSAGetLastError();
161
162 if ((error == WSAEWOULDBLOCK) || (error == WSAEINTR) || (error == WSAEINPROGRESS) ||
163 (error == WSAEALREADY))
164 {
165 BIO_set_flags(bio, (BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY));
166 }
167 else
168 {
169 BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
170 }
171
172 return -1;
173}
174
175static int transport_bio_simple_puts(WINPR_ATTR_UNUSED BIO* bio, WINPR_ATTR_UNUSED const char* str)
176{
177 return -2;
178}
179
180static int transport_bio_simple_gets(WINPR_ATTR_UNUSED BIO* bio, WINPR_ATTR_UNUSED char* str,
181 WINPR_ATTR_UNUSED int size)
182{
183 return 1;
184}
185
186static long transport_bio_simple_ctrl(BIO* bio, int cmd, long arg1, void* arg2)
187{
188 int status = -1;
189 WINPR_BIO_SIMPLE_SOCKET* ptr = (WINPR_BIO_SIMPLE_SOCKET*)BIO_get_data(bio);
190
191 switch (cmd)
192 {
193 case BIO_C_SET_SOCKET:
194 transport_bio_simple_uninit(bio);
195 transport_bio_simple_init(bio, (SOCKET)arg2, (int)arg1);
196 return 1;
197 case BIO_C_GET_SOCKET:
198 if (!BIO_get_init(bio) || !arg2)
199 return 0;
200
201 *((SOCKET*)arg2) = ptr->socket;
202 return 1;
203 case BIO_C_GET_EVENT:
204 if (!BIO_get_init(bio) || !arg2)
205 return 0;
206
207 *((HANDLE*)arg2) = ptr->hEvent;
208 return 1;
209 case BIO_C_SET_NONBLOCK:
210 {
211#ifndef _WIN32
212 int flags = 0;
213 flags = fcntl((int)ptr->socket, F_GETFL);
214
215 if (flags == -1)
216 return 0;
217
218 if (arg1)
219 (void)fcntl((int)ptr->socket, F_SETFL, flags | O_NONBLOCK);
220 else
221 (void)fcntl((int)ptr->socket, F_SETFL, flags & ~(O_NONBLOCK));
222
223#else
224 /* the internal socket is always non-blocking */
225#endif
226 return 1;
227 }
228 case BIO_C_WAIT_READ:
229 {
230 int timeout = (int)arg1;
231 int sockfd = (int)ptr->socket;
232#ifdef WINPR_HAVE_POLL_H
233 struct pollfd pollset;
234 pollset.fd = sockfd;
235 pollset.events = POLLIN;
236 pollset.revents = 0;
237
238 do
239 {
240 status = poll(&pollset, 1, timeout);
241 } while ((status < 0) && (errno == EINTR));
242
243#else
244 fd_set rset = WINPR_C_ARRAY_INIT;
245 struct timeval tv = WINPR_C_ARRAY_INIT;
246 FD_ZERO(&rset);
247 FD_SET(sockfd, &rset);
248
249 if (timeout)
250 {
251 tv.tv_sec = timeout / 1000;
252 tv.tv_usec = (timeout % 1000) * 1000;
253 }
254
255 do
256 {
257 status = select(sockfd + 1, &rset, nullptr, nullptr, timeout ? &tv : nullptr);
258 } while ((status < 0) && (errno == EINTR));
259
260#endif
261 /* Convert timeout to error return */
262 if (status == 0)
263 errno = ETIMEDOUT;
264 }
265 break;
266
267 case BIO_C_WAIT_WRITE:
268 {
269 int timeout = (int)arg1;
270 int sockfd = (int)ptr->socket;
271#ifdef WINPR_HAVE_POLL_H
272 struct pollfd pollset;
273 pollset.fd = sockfd;
274 pollset.events = POLLOUT;
275 pollset.revents = 0;
276
277 do
278 {
279 status = poll(&pollset, 1, timeout);
280 } while ((status < 0) && (errno == EINTR));
281
282#else
283 fd_set rset = WINPR_C_ARRAY_INIT;
284 struct timeval tv = WINPR_C_ARRAY_INIT;
285 FD_ZERO(&rset);
286 FD_SET(sockfd, &rset);
287
288 if (timeout)
289 {
290 tv.tv_sec = timeout / 1000;
291 tv.tv_usec = (timeout % 1000) * 1000;
292 }
293
294 do
295 {
296 status = select(sockfd + 1, nullptr, &rset, nullptr, timeout ? &tv : nullptr);
297 } while ((status < 0) && (errno == EINTR));
298
299#endif
300 /* Convert timeout to error return */
301 if (status == 0)
302 errno = ETIMEDOUT;
303 }
304 break;
305
306 case BIO_C_SET_FD:
307 if (arg2)
308 {
309 transport_bio_simple_uninit(bio);
310 transport_bio_simple_init(bio, (SOCKET) * ((int*)arg2), (int)arg1);
311 status = 1;
312 }
313
314 break;
315
316 case BIO_C_GET_FD:
317 if (BIO_get_init(bio))
318 {
319 if (arg2)
320 *((int*)arg2) = (int)ptr->socket;
321
322 status = (int)ptr->socket;
323 }
324
325 break;
326
327 case BIO_CTRL_GET_CLOSE:
328 status = BIO_get_shutdown(bio);
329 break;
330
331 case BIO_CTRL_SET_CLOSE:
332 BIO_set_shutdown(bio, (int)arg1);
333 status = 1;
334 break;
335
336 case BIO_CTRL_FLUSH:
337 case BIO_CTRL_DUP:
338 status = 1;
339 break;
340
341 default:
342 status = 0;
343 break;
344 }
345
346 return status;
347}
348
349static int transport_bio_simple_init(BIO* bio, SOCKET socket, int shutdown)
350{
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();
357
358 if (!ptr->hEvent)
359 return 0;
360
361 /* WSAEventSelect automatically sets the socket in non-blocking mode */
362 if (WSAEventSelect(ptr->socket, ptr->hEvent, FD_READ | FD_ACCEPT | FD_CLOSE))
363 {
364 WLog_ERR(TAG, "WSAEventSelect returned 0x%08x",
365 WINPR_CXX_COMPAT_CAST(unsigned, WSAGetLastError()));
366 return 0;
367 }
368
369 return 1;
370}
371
372static int transport_bio_simple_uninit(BIO* bio)
373{
374 WINPR_BIO_SIMPLE_SOCKET* ptr = (WINPR_BIO_SIMPLE_SOCKET*)BIO_get_data(bio);
375
376 if (BIO_get_shutdown(bio))
377 {
378 if (BIO_get_init(bio) && ptr)
379 {
380 _shutdown(ptr->socket, SD_BOTH);
381 closesocket(ptr->socket);
382 ptr->socket = 0;
383 }
384 }
385
386 if (ptr && ptr->hEvent)
387 {
388 (void)CloseHandle(ptr->hEvent);
389 ptr->hEvent = nullptr;
390 }
391
392 BIO_set_init(bio, 0);
393 BIO_set_flags(bio, 0);
394 return 1;
395}
396
397static int transport_bio_simple_new(BIO* bio)
398{
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));
402
403 if (!ptr)
404 return 0;
405
406 BIO_set_data(bio, ptr);
407 return 1;
408}
409
410static int transport_bio_simple_free(BIO* bio)
411{
412 WINPR_BIO_SIMPLE_SOCKET* ptr = nullptr;
413
414 if (!bio)
415 return 0;
416
417 transport_bio_simple_uninit(bio);
418 ptr = (WINPR_BIO_SIMPLE_SOCKET*)BIO_get_data(bio);
419
420 if (ptr)
421 {
422 BIO_set_data(bio, nullptr);
423 free(ptr);
424 }
425
426 return 1;
427}
428
429BIO_METHOD* BIO_s_simple_socket(void)
430{
431 static BIO_METHOD* bio_methods = nullptr;
432
433 if (bio_methods == nullptr)
434 {
435 if (!(bio_methods = BIO_meth_new(BIO_TYPE_SIMPLE, "SimpleSocket")))
436 return nullptr;
437
438 BIO_meth_set_write(bio_methods, transport_bio_simple_write);
439 BIO_meth_set_read(bio_methods, transport_bio_simple_read);
440 BIO_meth_set_puts(bio_methods, transport_bio_simple_puts);
441 BIO_meth_set_gets(bio_methods, transport_bio_simple_gets);
442 BIO_meth_set_ctrl(bio_methods, transport_bio_simple_ctrl);
443 BIO_meth_set_create(bio_methods, transport_bio_simple_new);
444 BIO_meth_set_destroy(bio_methods, transport_bio_simple_free);
445 }
446
447 return bio_methods;
448}
449
450/* Buffered Socket BIO */
451
452typedef struct
453{
454 BIO* bufferedBio;
455 BOOL readBlocked;
456 BOOL writeBlocked;
457 RingBuffer xmitBuffer;
458} WINPR_BIO_BUFFERED_SOCKET;
459
460static int transport_bio_buffered_write(BIO* bio, const char* buf, int num)
461{
462 int ret = num;
463 int nchunks = 0;
464 size_t committedBytes = 0;
465 DataChunk chunks[2] = WINPR_C_ARRAY_INIT;
466 WINPR_BIO_BUFFERED_SOCKET* ptr = (WINPR_BIO_BUFFERED_SOCKET*)BIO_get_data(bio);
467 BIO* next_bio = nullptr;
468
469 WINPR_ASSERT(bio);
470 WINPR_ASSERT(ptr);
471 if (num < 0)
472 return num;
473
474 ptr->writeBlocked = FALSE;
475 BIO_clear_flags(bio, BIO_FLAGS_WRITE);
476
477 /* we directly append extra bytes in the xmit buffer, this could be prevented
478 * but for now it makes the code more simple.
479 */
480 if (buf && (num > 0) && !ringbuffer_write(&ptr->xmitBuffer, (const BYTE*)buf, (size_t)num))
481 {
482 WLog_ERR(TAG, "an error occurred when writing (num: %d)", num);
483 return -1;
484 }
485
486 nchunks = ringbuffer_peek(&ptr->xmitBuffer, chunks, ringbuffer_used(&ptr->xmitBuffer));
487 next_bio = BIO_next(bio);
488
489 for (int i = 0; i < nchunks; i++)
490 {
491 while (chunks[i].size)
492 {
493 ERR_clear_error();
494
495 const size_t wr = MIN(INT32_MAX, chunks[i].size);
496 const int status = BIO_write(next_bio, chunks[i].data, (int)wr);
497
498 if (status <= 0)
499 {
500 if (!BIO_should_retry(next_bio))
501 {
502 BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
503 ret = -1; /* fatal error */
504 goto out;
505 }
506
507 if (BIO_should_write(next_bio))
508 {
509 BIO_set_flags(bio, BIO_FLAGS_WRITE);
510 ptr->writeBlocked = TRUE;
511 goto out; /* EWOULDBLOCK */
512 }
513 }
514 else
515 {
516 committedBytes += (size_t)status;
517 chunks[i].size -= (size_t)status;
518 chunks[i].data += status;
519 }
520 }
521 }
522
523out:
524 ringbuffer_commit_read_bytes(&ptr->xmitBuffer, committedBytes);
525 return ret;
526}
527
528static int transport_bio_buffered_read(BIO* bio, char* buf, int size)
529{
530 int status = 0;
531 WINPR_BIO_BUFFERED_SOCKET* ptr = (WINPR_BIO_BUFFERED_SOCKET*)BIO_get_data(bio);
532 BIO* next_bio = BIO_next(bio);
533 ptr->readBlocked = FALSE;
534 BIO_clear_flags(bio, BIO_FLAGS_READ);
535 ERR_clear_error();
536 status = BIO_read(next_bio, buf, size);
537
538 if (status <= 0)
539 {
540 if (!BIO_should_retry(next_bio))
541 {
542 BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
543 goto out;
544 }
545
546 BIO_set_flags(bio, BIO_FLAGS_SHOULD_RETRY);
547
548 if (BIO_should_read(next_bio))
549 {
550 BIO_set_flags(bio, BIO_FLAGS_READ);
551 ptr->readBlocked = TRUE;
552 goto out;
553 }
554 }
555
556out:
557 return status;
558}
559
560static int transport_bio_buffered_puts(WINPR_ATTR_UNUSED BIO* bio,
561 WINPR_ATTR_UNUSED const char* str)
562{
563 return 1;
564}
565
566static int transport_bio_buffered_gets(WINPR_ATTR_UNUSED BIO* bio, WINPR_ATTR_UNUSED char* str,
567 WINPR_ATTR_UNUSED int size)
568{
569 return 1;
570}
571
572static long transport_bio_buffered_ctrl(BIO* bio, int cmd, long arg1, void* arg2)
573{
574 long status = -1;
575 WINPR_BIO_BUFFERED_SOCKET* ptr = (WINPR_BIO_BUFFERED_SOCKET*)BIO_get_data(bio);
576
577 switch (cmd)
578 {
579 case BIO_CTRL_FLUSH:
580 if (!ringbuffer_used(&ptr->xmitBuffer))
581 status = 1;
582 else
583 status = (transport_bio_buffered_write(bio, nullptr, 0) >= 0) ? 1 : -1;
584
585 break;
586
587 case BIO_CTRL_WPENDING:
588 status = WINPR_ASSERTING_INT_CAST(long, ringbuffer_used(&ptr->xmitBuffer));
589 break;
590
591 case BIO_CTRL_PENDING:
592 status = 0;
593 break;
594
595 case BIO_C_READ_BLOCKED:
596 status = (int)ptr->readBlocked;
597 break;
598
599 case BIO_C_WRITE_BLOCKED:
600 status = (int)ptr->writeBlocked;
601 break;
602
603 default:
604 status = BIO_ctrl(BIO_next(bio), cmd, arg1, arg2);
605 break;
606 }
607
608 return status;
609}
610
611static int transport_bio_buffered_new(BIO* bio)
612{
613 WINPR_BIO_BUFFERED_SOCKET* ptr = nullptr;
614 BIO_set_init(bio, 1);
615 BIO_set_flags(bio, BIO_FLAGS_SHOULD_RETRY);
616 ptr = (WINPR_BIO_BUFFERED_SOCKET*)calloc(1, sizeof(WINPR_BIO_BUFFERED_SOCKET));
617
618 if (!ptr)
619 return -1;
620
621 BIO_set_data(bio, (void*)ptr);
622
623 if (!ringbuffer_init(&ptr->xmitBuffer, 0x10000))
624 return -1;
625
626 return 1;
627}
628
629/* Free the buffered BIO.
630 * Do not free other elements in the BIO stack,
631 * let BIO_free_all handle that. */
632static int transport_bio_buffered_free(BIO* bio)
633{
634 WINPR_BIO_BUFFERED_SOCKET* ptr = (WINPR_BIO_BUFFERED_SOCKET*)BIO_get_data(bio);
635
636 if (!ptr)
637 return 0;
638
639 ringbuffer_destroy(&ptr->xmitBuffer);
640 free(ptr);
641 return 1;
642}
643
644BIO_METHOD* BIO_s_buffered_socket(void)
645{
646 static BIO_METHOD* bio_methods = nullptr;
647
648 if (bio_methods == nullptr)
649 {
650 if (!(bio_methods = BIO_meth_new(BIO_TYPE_BUFFERED, "BufferedSocket")))
651 return nullptr;
652
653 BIO_meth_set_write(bio_methods, transport_bio_buffered_write);
654 BIO_meth_set_read(bio_methods, transport_bio_buffered_read);
655 BIO_meth_set_puts(bio_methods, transport_bio_buffered_puts);
656 BIO_meth_set_gets(bio_methods, transport_bio_buffered_gets);
657 BIO_meth_set_ctrl(bio_methods, transport_bio_buffered_ctrl);
658 BIO_meth_set_create(bio_methods, transport_bio_buffered_new);
659 BIO_meth_set_destroy(bio_methods, transport_bio_buffered_free);
660 }
661
662 return bio_methods;
663}
664
665char* freerdp_tcp_address_to_string(const struct sockaddr_storage* addr, BOOL* pIPv6)
666{
667 char ipAddress[INET6_ADDRSTRLEN + 1] = WINPR_C_ARRAY_INIT;
668 const struct sockaddr_in6* sockaddr_ipv6 = (const struct sockaddr_in6*)addr;
669 const struct sockaddr_in* sockaddr_ipv4 = (const struct sockaddr_in*)addr;
670
671 if (addr == nullptr)
672 {
673 return nullptr;
674 }
675
676 switch (sockaddr_ipv4->sin_family)
677 {
678 case AF_INET:
679 if (!inet_ntop(sockaddr_ipv4->sin_family, &sockaddr_ipv4->sin_addr, ipAddress,
680 sizeof(ipAddress)))
681 return nullptr;
682
683 break;
684
685 case AF_INET6:
686 if (!inet_ntop(sockaddr_ipv6->sin6_family, &sockaddr_ipv6->sin6_addr, ipAddress,
687 sizeof(ipAddress)))
688 return nullptr;
689
690 break;
691
692 case AF_UNIX:
693 (void)sprintf_s(ipAddress, ARRAYSIZE(ipAddress), "127.0.0.1");
694 break;
695
696 default:
697 return nullptr;
698 }
699
700 if (pIPv6 != nullptr)
701 {
702 *pIPv6 = (sockaddr_ipv4->sin_family == AF_INET6);
703 }
704
705 return _strdup(ipAddress);
706}
707
708static bool freerdp_tcp_get_ip_address(rdpSettings* settings, int sockfd)
709{
710 WINPR_ASSERT(settings);
711
712 struct sockaddr_storage saddr = WINPR_C_ARRAY_INIT;
713 socklen_t length = sizeof(struct sockaddr_storage);
714
715 if (!freerdp_settings_set_string(settings, FreeRDP_ClientAddress, nullptr))
716 return false;
717 if (sockfd < 0)
718 return false;
719 if (getsockname(sockfd, (struct sockaddr*)&saddr, &length) != 0)
720 return false;
721 settings->ClientAddress = freerdp_tcp_address_to_string(&saddr, &settings->IPv6Enabled);
722 return settings->ClientAddress != nullptr;
723}
724
725char* freerdp_tcp_get_peer_address(SOCKET sockfd)
726{
727 struct sockaddr_storage saddr = WINPR_C_ARRAY_INIT;
728 socklen_t length = sizeof(struct sockaddr_storage);
729
730 if (getpeername((int)sockfd, (struct sockaddr*)&saddr, &length) != 0)
731 {
732 return nullptr;
733 }
734
735 return freerdp_tcp_address_to_string(&saddr, nullptr);
736}
737
738static int freerdp_uds_connect(const char* path)
739{
740#ifndef _WIN32
741 int status = 0;
742 int sockfd = 0;
743 struct sockaddr_un addr = WINPR_C_ARRAY_INIT;
744 sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
745
746 if (sockfd == -1)
747 {
748 WLog_ERR(TAG, "socket");
749 return -1;
750 }
751
752 addr.sun_family = AF_UNIX;
753 strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
754 status = connect(sockfd, (struct sockaddr*)&addr, sizeof(addr));
755
756 if (status < 0)
757 {
758 WLog_ERR(TAG, "connect");
759 close(sockfd);
760 return -1;
761 }
762
763 return sockfd;
764#else /* ifndef _WIN32 */
765 return -1;
766#endif
767}
768
769struct addrinfo* freerdp_tcp_resolve_host(const char* hostname, int port, int ai_flags)
770{
771 char* service = nullptr;
772 char port_str[16] = WINPR_C_ARRAY_INIT;
773 int status = 0;
774
775 struct addrinfo* result = nullptr;
776 struct addrinfo hints = { .ai_family = AF_UNSPEC,
777 .ai_socktype = SOCK_STREAM,
778 .ai_flags = ai_flags };
779
780 if (port >= 0)
781 {
782 (void)sprintf_s(port_str, sizeof(port_str) - 1, "%d", port);
783 service = port_str;
784 }
785
786 status = getaddrinfo(hostname, service, &hints, &result);
787
788 if (status)
789 {
790 WLog_WARN(TAG, "getaddrinfo(%s) failed with %s", hostname, gai_strerror(status));
791 return nullptr;
792 }
793
794 return result;
795}
796
797static BOOL freerdp_tcp_is_hostname_resolvable(rdpContext* context, const char* hostname)
798{
799 struct addrinfo* result = freerdp_tcp_resolve_host(hostname, -1, 0);
800
801 if (!result)
802 {
803 freerdp_set_last_error_if_not(context, FREERDP_ERROR_DNS_NAME_NOT_FOUND);
804
805 return FALSE;
806 }
807
808 freerdp_set_last_error_log(context, 0);
809 freeaddrinfo(result);
810 return TRUE;
811}
812
813static BOOL freerdp_tcp_connect_timeout(rdpContext* context, int sockfd, struct sockaddr* addr,
814 size_t addrlen, UINT32 timeout)
815{
816 BOOL rc = FALSE;
817 HANDLE handles[2] = WINPR_C_ARRAY_INIT;
818 DWORD count = 0;
819 u_long arg = 0;
820 DWORD tout = (timeout > 0) ? timeout : INFINITE;
821
822 handles[count] = CreateEvent(nullptr, TRUE, FALSE, nullptr);
823
824 if (!handles[count])
825 return FALSE;
826
827 const int wsastatus = WSAEventSelect((SOCKET)sockfd, handles[count++],
828 FD_READ | FD_WRITE | FD_CONNECT | FD_CLOSE);
829
830 if (wsastatus < 0)
831 {
832 WLog_ERR(TAG, "WSAEventSelect failed with %d", WSAGetLastError());
833 goto fail;
834 }
835
836 handles[count++] = utils_get_abort_event(context->rdp);
837
838 {
839 const int constatus =
840 _connect((SOCKET)sockfd, addr, WINPR_ASSERTING_INT_CAST(int, addrlen));
841 if (constatus < 0)
842 {
843 const int estatus = WSAGetLastError();
844
845 switch (estatus)
846 {
847 case WSAEINPROGRESS:
848 case WSAEWOULDBLOCK:
849 break;
850
851 default:
852 goto fail;
853 }
854 }
855 }
856
857 {
858 const DWORD wstatus = WaitForMultipleObjects(count, handles, FALSE, tout);
859 if (WAIT_OBJECT_0 != wstatus)
860 goto fail;
861 }
862
863 {
864 const int status = WSAEventSelect((SOCKET)sockfd, handles[0], 0);
865 if (status < 0)
866 {
867 WLog_ERR(TAG, "WSAEventSelect failed with %d", WSAGetLastError());
868 goto fail;
869 }
870 }
871
872 if (_ioctlsocket((SOCKET)sockfd, FIONBIO, &arg) != 0)
873 goto fail;
874
875 rc = TRUE;
876fail:
877{
878 INT32 optval = 0;
879 socklen_t optlen = sizeof(optval);
880 if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void*)&optval, &optlen) >= 0)
881 {
882 if (optval != 0)
883 {
884 char ebuffer[256] = WINPR_C_ARRAY_INIT;
885 char hostname[512] = WINPR_C_ARRAY_INIT;
886 char serv[512] = WINPR_C_ARRAY_INIT;
887
888 getnameinfo(addr, WINPR_ASSERTING_INT_CAST(socklen_t, addrlen), hostname,
889 WINPR_ASSERTING_INT_CAST(socklen_t, sizeof(hostname)), serv,
890 WINPR_ASSERTING_INT_CAST(socklen_t, sizeof(serv)), NI_NUMERICSERV);
891 WLog_WARN(TAG, "connect to %s:%s failed with error: %s [%" PRId32 "]", hostname, serv,
892 winpr_strerror(optval, ebuffer, sizeof(ebuffer)), optval);
893 rc = FALSE;
894 }
895 }
896}
897
898 (void)CloseHandle(handles[0]);
899 return rc;
900}
901
902typedef struct
903{
904 SOCKET s;
905 struct addrinfo* addr;
906 struct addrinfo* result;
907} t_peer;
908
909static void peer_free(t_peer* peer)
910{
911 if (peer->s != INVALID_SOCKET)
912 closesocket(peer->s);
913
914 freeaddrinfo(peer->addr);
915 memset(peer, 0, sizeof(t_peer));
916 peer->s = INVALID_SOCKET;
917}
918
919static int freerdp_tcp_connect_multi(rdpContext* context, char** hostnames, const UINT32* ports,
920 UINT32 count, UINT16 port, WINPR_ATTR_UNUSED UINT32 timeout)
921{
922 UINT32 sindex = count;
923 SOCKET sockfd = INVALID_SOCKET;
924 struct addrinfo* addr = nullptr;
925 struct addrinfo* result = nullptr;
926
927 HANDLE* events = (HANDLE*)calloc(count + 1, sizeof(HANDLE));
928 t_peer* peers = (t_peer*)calloc(count, sizeof(t_peer));
929
930 if (!peers || !events || (count < 1))
931 {
932 free(peers);
933 free((void*)events);
934 return -1;
935 }
936
937 for (UINT32 index = 0; index < count; index++)
938 {
939 int curPort = port;
940
941 if (ports)
942 curPort = WINPR_ASSERTING_INT_CAST(int, ports[index]);
943
944 result = freerdp_tcp_resolve_host(hostnames[index], curPort, 0);
945
946 if (!result)
947 continue;
948
949 addr = result;
950
951 if ((addr->ai_family == AF_INET6) && (addr->ai_next != nullptr))
952 {
953 while ((addr = addr->ai_next))
954 {
955 if (addr->ai_family == AF_INET)
956 break;
957 }
958
959 if (!addr)
960 addr = result;
961 }
962
963 peers[index].s = _socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
964
965 if (peers[index].s == INVALID_SOCKET)
966 {
967 freeaddrinfo(result);
968 continue;
969 }
970
971 peers[index].addr = addr;
972 peers[index].result = result;
973 }
974
975 for (UINT32 index = 0; index < count; index++)
976 {
977 sockfd = peers[index].s;
978 addr = peers[index].addr;
979
980 if ((sockfd == INVALID_SOCKET) || (!addr))
981 continue;
982
983 /* blocking tcp connect */
984 const int rc =
985 _connect(sockfd, addr->ai_addr, WINPR_ASSERTING_INT_CAST(int, addr->ai_addrlen));
986
987 if (rc >= 0)
988 {
989 /* connection success */
990 sindex = index;
991 break;
992 }
993 }
994
995 if (sindex < count)
996 {
997 sockfd = peers[sindex].s;
998 peers[sindex].s = INVALID_SOCKET;
999 }
1000 else
1001 freerdp_set_last_error_log(context, FREERDP_ERROR_CONNECT_CANCELLED);
1002
1003 for (UINT32 index = 0; index < count; index++)
1004 peer_free(&peers[index]);
1005
1006 free(peers);
1007 free((void*)events);
1008 return (int)sockfd;
1009}
1010
1011BOOL freerdp_tcp_set_keep_alive_mode(const rdpSettings* settings, int sockfd)
1012{
1013 const BOOL keepalive = (freerdp_settings_get_bool(settings, FreeRDP_TcpKeepAlive));
1014 UINT32 optval = 0;
1015 socklen_t optlen = 0;
1016 BOOL isTcp = FALSE;
1017
1018 int xoptval = 0;
1019 socklen_t xoptlen = sizeof(xoptval);
1020 const int rc = getsockopt(sockfd, SOL_SOCKET, SO_TYPE, (void*)&xoptval, &xoptlen);
1021
1022 if (rc == 0)
1023 isTcp = xoptval == SOCK_STREAM;
1024
1025 optval = keepalive ? 1 : 0;
1026 optlen = sizeof(optval);
1027
1028 if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (void*)&optval, optlen) < 0)
1029 {
1030 WLog_WARN(TAG, "setsockopt() SOL_SOCKET, SO_KEEPALIVE");
1031 }
1032
1033 if (!isTcp)
1034 return TRUE;
1035
1036#ifndef _WIN32
1037#ifdef TCP_KEEPIDLE
1038 optval = keepalive ? freerdp_settings_get_uint32(settings, FreeRDP_TcpKeepAliveDelay) : 0;
1039 optlen = sizeof(optval);
1040
1041 if (setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE, (void*)&optval, optlen) < 0)
1042 {
1043 WLog_WARN(TAG, "setsockopt() IPPROTO_TCP, TCP_KEEPIDLE");
1044 }
1045
1046#endif
1047#ifndef SOL_TCP
1048 /* "tcp" from /etc/protocols as getprotobyname(3C) */
1049#define SOL_TCP 6
1050#endif
1051#ifdef TCP_KEEPCNT
1052 optval = keepalive ? freerdp_settings_get_uint32(settings, FreeRDP_TcpKeepAliveRetries) : 0;
1053 optlen = sizeof(optval);
1054
1055 if (setsockopt(sockfd, SOL_TCP, TCP_KEEPCNT, (void*)&optval, optlen) < 0)
1056 {
1057 WLog_WARN(TAG, "setsockopt() SOL_TCP, TCP_KEEPCNT");
1058 }
1059
1060#endif
1061#ifdef TCP_KEEPINTVL
1062 optval = keepalive ? freerdp_settings_get_uint32(settings, FreeRDP_TcpKeepAliveInterval) : 0;
1063 optlen = sizeof(optval);
1064
1065 if (setsockopt(sockfd, SOL_TCP, TCP_KEEPINTVL, (void*)&optval, optlen) < 0)
1066 {
1067 WLog_WARN(TAG, "setsockopt() SOL_TCP, TCP_KEEPINTVL");
1068 }
1069
1070#endif
1071#endif
1072#if defined(__MACOSX__) || defined(__IOS__)
1073 optval = 1;
1074 optlen = sizeof(optval);
1075
1076 if (setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void*)&optval, optlen) < 0)
1077 {
1078 WLog_WARN(TAG, "setsockopt() SOL_SOCKET, SO_NOSIGPIPE");
1079 }
1080
1081#endif
1082#ifdef TCP_USER_TIMEOUT
1083 optval = freerdp_settings_get_uint32(settings, FreeRDP_TcpAckTimeout);
1084 optlen = sizeof(optval);
1085
1086 if (setsockopt(sockfd, SOL_TCP, TCP_USER_TIMEOUT, (void*)&optval, optlen) < 0)
1087 {
1088 WLog_WARN(TAG, "setsockopt() SOL_TCP, TCP_USER_TIMEOUT");
1089 }
1090
1091#endif
1092 return TRUE;
1093}
1094
1095int freerdp_tcp_connect(rdpContext* context, const char* hostname, int port, DWORD timeout)
1096{
1097 rdpTransport* transport = nullptr;
1098 if (!context || !context->rdp)
1099 return -1;
1100 transport = context->rdp->transport;
1101 if (!transport)
1102 return -1;
1103 return transport_tcp_connect(context->rdp->transport, hostname, port, timeout);
1104}
1105
1106static struct addrinfo* reorder_addrinfo_by_preference(rdpContext* context, struct addrinfo* addr)
1107{
1108 WINPR_ASSERT(context);
1109 WINPR_ASSERT(addr);
1110
1111 const BOOL preferIPv6 =
1112 freerdp_settings_get_bool(context->settings, FreeRDP_PreferIPv6OverIPv4);
1113 if (!preferIPv6)
1114 return addr;
1115
1116 struct addrinfo* ipv6Head = nullptr;
1117 struct addrinfo* ipv6Tail = nullptr;
1118 struct addrinfo* otherHead = nullptr;
1119 struct addrinfo* otherTail = nullptr;
1120
1121 /* Partition the list into IPv6 and other addresses */
1122 while (addr)
1123 {
1124 struct addrinfo* next = addr->ai_next;
1125 addr->ai_next = nullptr;
1126
1127 if (addr->ai_family == AF_INET6)
1128 {
1129 if (!ipv6Head)
1130 ipv6Head = addr;
1131 else
1132 ipv6Tail->ai_next = addr;
1133 ipv6Tail = addr;
1134 }
1135 else
1136 {
1137 if (!otherHead)
1138 otherHead = addr;
1139 else
1140 otherTail->ai_next = addr;
1141 otherTail = addr;
1142 }
1143 addr = next;
1144 }
1145
1146 /* Concatenate the lists */
1147 if (ipv6Tail)
1148 ipv6Tail->ai_next = otherHead;
1149
1150 return ipv6Head ? ipv6Head : otherHead;
1151}
1152
1153static int get_next_addrinfo(rdpContext* context, struct addrinfo* input, struct addrinfo** result,
1154 UINT32 errorCode)
1155{
1156 WINPR_ASSERT(context);
1157 WINPR_ASSERT(result);
1158
1159 struct addrinfo* addr = input;
1160 if (!addr)
1161 goto fail;
1162
1163 /* We want to force IPvX, abort if not detected */
1164 {
1165 const UINT32 IPvX = freerdp_settings_get_uint32(context->settings, FreeRDP_ForceIPvX);
1166 switch (IPvX)
1167 {
1168 case 4:
1169 case 6:
1170 {
1171 const int family = (IPvX == 4) ? AF_INET : AF_INET6;
1172 while (addr && (addr->ai_family != family))
1173 addr = addr->ai_next;
1174 }
1175 break;
1176 default:
1177 break;
1178 }
1179 }
1180
1181 if (!addr)
1182 goto fail;
1183
1184 *result = addr;
1185 return 0;
1186
1187fail:
1188 freerdp_set_last_error_if_not(context, errorCode);
1189 *result = nullptr;
1190 return -1;
1191}
1192
1193static int freerdp_vsock_connect(rdpContext* context, const char* hostname, int port)
1194{
1195#if defined(HAVE_AF_VSOCK_H)
1196 int sockfd = socket(AF_VSOCK, SOCK_STREAM, 0);
1197 if (sockfd < 0)
1198 {
1199 char buffer[256] = WINPR_C_ARRAY_INIT;
1200 WLog_WARN(TAG, "socket(AF_VSOCK, SOCK_STREAM, 0) failed with %s",
1201 winpr_strerror(errno, buffer, sizeof(buffer)));
1202 freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
1203 return -1;
1204 }
1205
1206 struct sockaddr_vm addr = WINPR_C_ARRAY_INIT;
1207
1208 addr.svm_family = AF_VSOCK;
1209 addr.svm_port = WINPR_ASSERTING_INT_CAST(typeof(addr.svm_port), port);
1210
1211 errno = 0;
1212 char* ptr = nullptr;
1213 unsigned long val = strtoul(hostname, &ptr, 10);
1214 if (errno || (val > UINT32_MAX))
1215 {
1216 char ebuffer[256] = WINPR_C_ARRAY_INIT;
1217 WLog_ERR(TAG, "could not extract port from '%s', value=%lu, error=%s", hostname, val,
1218 winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
1219 close(sockfd);
1220 return -1;
1221 }
1222 addr.svm_cid = WINPR_ASSERTING_INT_CAST(typeof(addr.svm_cid), val);
1223 if (addr.svm_cid == 2)
1224 {
1225 addr.svm_flags = VMADDR_FLAG_TO_HOST;
1226 }
1227 if ((connect(sockfd, (struct sockaddr*)&addr, sizeof(struct sockaddr_vm))) == -1)
1228 {
1229 WLog_ERR(TAG, "failed to connect to %s", hostname);
1230 close(sockfd);
1231 return -1;
1232 }
1233 return sockfd;
1234#else
1235 WLog_ERR(TAG, "Compiled without AF_VSOCK, '%s' not supported", hostname);
1236 return -1;
1237#endif
1238}
1239
1240static void log_connection_address(const char* hostname, struct addrinfo* addr)
1241{
1242 WINPR_ASSERT(addr);
1243
1244 char* peerAddress = freerdp_tcp_address_to_string(
1245 WINPR_PACKED_ALIGN_CAST(const struct sockaddr_storage*, addr->ai_addr), nullptr);
1246 if (peerAddress)
1247 WLog_DBG(TAG, "resolved %s: try to connect to %s", hostname, peerAddress);
1248 free(peerAddress);
1249}
1250
1251static int freerdp_host_connect(rdpContext* context, const char* hostname, int port, DWORD timeout)
1252{
1253 int sockfd = -1;
1254 struct addrinfo* addr = nullptr;
1255 struct addrinfo* result = freerdp_tcp_resolve_host(hostname, port, 0);
1256
1257 if (!result)
1258 {
1259 freerdp_set_last_error_if_not(context, FREERDP_ERROR_DNS_NAME_NOT_FOUND);
1260 return -1;
1261 }
1262 freerdp_set_last_error_log(context, 0);
1263
1264 /* By default we take the first returned entry.
1265 * If PreferIPv6OverIPv4 = TRUE we reorder addresses by preference:
1266 * IPv6 addresses come first, then other addresses.
1267 */
1268 result = reorder_addrinfo_by_preference(context, result);
1269
1270 const int rc = get_next_addrinfo(context, result, &addr, FREERDP_ERROR_DNS_NAME_NOT_FOUND);
1271 if (rc < 0)
1272 goto fail;
1273
1274 do
1275 {
1276 sockfd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
1277 if (sockfd >= 0)
1278 {
1279 log_connection_address(hostname, addr);
1280
1281 if (!freerdp_tcp_connect_timeout(context, sockfd, addr->ai_addr, addr->ai_addrlen,
1282 timeout))
1283 {
1284 close(sockfd);
1285 sockfd = -1;
1286 }
1287 }
1288
1289 if (sockfd < 0)
1290 {
1291 const int lrc =
1292 get_next_addrinfo(context, addr->ai_next, &addr, FREERDP_ERROR_CONNECT_FAILED);
1293 if (lrc < 0)
1294 goto fail;
1295 }
1296 } while (sockfd < 0);
1297
1298fail:
1299 freeaddrinfo(result);
1300 return sockfd;
1301}
1302
1303int freerdp_tcp_default_connect(rdpContext* context, rdpSettings* settings, const char* hostname,
1304 int port, DWORD timeout)
1305{
1306 int sockfd = -1;
1307 BOOL ipcSocket = FALSE;
1308 BOOL useExternalDefinedSocket = FALSE;
1309
1310 if (!hostname)
1311 {
1312 freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
1313
1314 return -1;
1315 }
1316
1317 if (hostname[0] == '/')
1318 ipcSocket = TRUE;
1319
1320 if (hostname[0] == '|')
1321 useExternalDefinedSocket = TRUE;
1322
1323 const char* vsock = utils_is_vsock(hostname);
1324 if (ipcSocket)
1325 {
1326 sockfd = freerdp_uds_connect(hostname);
1327
1328 if (sockfd < 0)
1329 {
1330 freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
1331 return -1;
1332 }
1333 }
1334 else if (useExternalDefinedSocket)
1335 sockfd = port;
1336 else if (vsock)
1337 sockfd = freerdp_vsock_connect(context, vsock, port);
1338 else
1339 {
1340 if (!settings->GatewayEnabled)
1341 {
1342 if (!freerdp_tcp_is_hostname_resolvable(context, hostname) ||
1343 settings->RemoteAssistanceMode)
1344 {
1345 if (settings->TargetNetAddressCount > 0)
1346 {
1347 WINPR_ASSERT(port <= UINT16_MAX);
1348 sockfd = freerdp_tcp_connect_multi(
1349 context, settings->TargetNetAddresses, settings->TargetNetPorts,
1350 settings->TargetNetAddressCount, (UINT16)port, timeout);
1351 }
1352 }
1353 }
1354
1355 if (sockfd <= 0)
1356 sockfd = freerdp_host_connect(context, hostname, port, timeout);
1357 }
1358
1359 if (!vsock)
1360 {
1361 if (!freerdp_tcp_get_ip_address(settings, sockfd))
1362 {
1363 if (!useExternalDefinedSocket)
1364 close(sockfd);
1365
1366 freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
1367
1368 WLog_ERR(TAG, "Couldn't get socket ip address");
1369 return -1;
1370 }
1371 }
1372
1373 if (!ipcSocket && !useExternalDefinedSocket)
1374 {
1375 (void)freerdp_tcp_set_nodelay(WLog_Get(TAG), WLOG_ERROR, sockfd);
1376 }
1377
1378 /* receive buffer must be a least 32 K */
1379 UINT32 optval = 1;
1380 socklen_t optlen = sizeof(optval);
1381 if (getsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (void*)&optval, &optlen) == 0)
1382 {
1383 if (optval < (1024 * 32))
1384 {
1385 optval = 1024 * 32;
1386 optlen = sizeof(optval);
1387
1388 if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (void*)&optval, optlen) < 0)
1389 {
1390 close(sockfd);
1391
1392 freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
1393
1394 WLog_ERR(TAG, "unable to set receive buffer len");
1395 return -1;
1396 }
1397 }
1398 }
1399
1400 if (!ipcSocket && !useExternalDefinedSocket)
1401 {
1402 if (!freerdp_tcp_set_keep_alive_mode(settings, sockfd))
1403 {
1404 close(sockfd);
1405
1406 freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
1407
1408 WLog_ERR(TAG, "Couldn't set keep alive mode.");
1409 return -1;
1410 }
1411 }
1412
1413 if (WaitForSingleObject(utils_get_abort_event(context->rdp), 0) == WAIT_OBJECT_0)
1414 {
1415 close(sockfd);
1416 return -1;
1417 }
1418
1419 return sockfd;
1420}
1421
1422struct rdp_tcp_layer
1423{
1424 int sockfd;
1425 HANDLE hEvent;
1426};
1427typedef struct rdp_tcp_layer rdpTcpLayer;
1428
1429static int freerdp_tcp_layer_read(void* userContext, void* data, int bytes)
1430{
1431 if (!userContext)
1432 return -1;
1433 if (!data || !bytes)
1434 return 0;
1435
1436 rdpTcpLayer* tcpLayer = (rdpTcpLayer*)userContext;
1437
1438 (void)WSAResetEvent(tcpLayer->hEvent);
1439 const int status = _recv((SOCKET)tcpLayer->sockfd, data, bytes, 0);
1440
1441 if (status > 0)
1442 return status;
1443
1444 const int error = WSAGetLastError();
1445
1446 if ((error == WSAEWOULDBLOCK) || (error == WSAEINTR) || (error == WSAEINPROGRESS) ||
1447 (error == WSAEALREADY))
1448 errno = EAGAIN;
1449
1450 return status;
1451}
1452
1453static int freerdp_tcp_layer_write(void* userContext, const void* data, int bytes)
1454{
1455 if (!userContext)
1456 return -1;
1457 if (!data || !bytes)
1458 return 0;
1459
1460 rdpTcpLayer* tcpLayer = (rdpTcpLayer*)userContext;
1461
1462 const int status = _send((SOCKET)tcpLayer->sockfd, data, bytes, 0);
1463 if (status > 0)
1464 return status;
1465
1466 const int error = WSAGetLastError();
1467
1468 if ((error == WSAEWOULDBLOCK) || (error == WSAEINTR) || (error == WSAEINPROGRESS) ||
1469 (error == WSAEALREADY))
1470 errno = EAGAIN;
1471
1472 return status;
1473}
1474
1475static BOOL freerdp_tcp_layer_close(void* userContext)
1476{
1477 if (!userContext)
1478 return FALSE;
1479
1480 rdpTcpLayer* tcpLayer = (rdpTcpLayer*)userContext;
1481
1482 if (tcpLayer->sockfd >= 0)
1483 closesocket((SOCKET)tcpLayer->sockfd);
1484 if (tcpLayer->hEvent)
1485 (void)CloseHandle(tcpLayer->hEvent);
1486
1487 return TRUE;
1488}
1489
1490static BOOL freerdp_tcp_layer_wait(void* userContext, BOOL waitWrite, DWORD timeout)
1491{
1492 if (!userContext)
1493 return FALSE;
1494
1495 rdpTcpLayer* tcpLayer = (rdpTcpLayer*)userContext;
1496
1497 int status = -1;
1498 int sockfd = tcpLayer->sockfd;
1499#ifdef WINPR_HAVE_POLL_H
1500 struct pollfd pollset = WINPR_C_ARRAY_INIT;
1501 pollset.fd = sockfd;
1502 pollset.events = waitWrite ? POLLOUT : POLLIN;
1503
1504 do
1505 {
1506 status = poll(&pollset, 1, (int)timeout);
1507 } while ((status < 0) && (errno == EINTR));
1508
1509#else
1510 fd_set rset = WINPR_C_ARRAY_INIT;
1511 struct timeval tv = WINPR_C_ARRAY_INIT;
1512 FD_ZERO(&rset);
1513 FD_SET(sockfd, &rset);
1514
1515 if (timeout)
1516 {
1517 tv.tv_sec = timeout / 1000;
1518 tv.tv_usec = (timeout % 1000) * 1000;
1519 }
1520
1521 do
1522 {
1523 if (waitWrite)
1524 status = select(sockfd + 1, nullptr, &rset, nullptr, timeout ? &tv : nullptr);
1525 else
1526 status = select(sockfd + 1, &rset, nullptr, nullptr, timeout ? &tv : nullptr);
1527 } while ((status < 0) && (errno == EINTR));
1528
1529#endif
1530
1531 return status != 0;
1532}
1533
1534static HANDLE freerdp_tcp_layer_get_event(void* userContext)
1535{
1536 if (!userContext)
1537 return nullptr;
1538
1539 rdpTcpLayer* tcpLayer = (rdpTcpLayer*)userContext;
1540
1541 return tcpLayer->hEvent;
1542}
1543
1544rdpTransportLayer* freerdp_tcp_connect_layer(rdpContext* context, const char* hostname, int port,
1545 DWORD timeout)
1546{
1547 WINPR_ASSERT(context);
1548
1549 const rdpSettings* settings = context->settings;
1550 WINPR_ASSERT(settings);
1551
1552 rdpTransportLayer* layer = nullptr;
1553 rdpTcpLayer* tcpLayer = nullptr;
1554
1555 int sockfd = freerdp_tcp_connect(context, hostname, port, timeout);
1556 if (sockfd < 0)
1557 goto fail;
1558 if (!freerdp_tcp_set_keep_alive_mode(settings, sockfd))
1559 goto fail;
1560
1561 layer = transport_layer_new(freerdp_get_transport(context), sizeof(rdpTcpLayer));
1562 if (!layer)
1563 goto fail;
1564
1565 layer->Read = freerdp_tcp_layer_read;
1566 layer->Write = freerdp_tcp_layer_write;
1567 layer->Close = freerdp_tcp_layer_close;
1568 layer->Wait = freerdp_tcp_layer_wait;
1569 layer->GetEvent = freerdp_tcp_layer_get_event;
1570
1571 tcpLayer = (rdpTcpLayer*)layer->userContext;
1572 WINPR_ASSERT(tcpLayer);
1573
1574 tcpLayer->sockfd = -1;
1575 tcpLayer->hEvent = WSACreateEvent();
1576 if (!tcpLayer->hEvent)
1577 goto fail;
1578
1579 /* WSAEventSelect automatically sets the socket in non-blocking mode */
1580 if (WSAEventSelect((SOCKET)sockfd, tcpLayer->hEvent, FD_READ | FD_ACCEPT | FD_CLOSE))
1581 {
1582 WLog_ERR(TAG, "WSAEventSelect returned 0x%08x", (unsigned)WSAGetLastError());
1583 goto fail;
1584 }
1585
1586 tcpLayer->sockfd = sockfd;
1587
1588 return layer;
1589
1590fail:
1591 if (sockfd >= 0)
1592 closesocket((SOCKET)sockfd);
1593 transport_layer_free(layer);
1594 return nullptr;
1595}
1596
1597BOOL freerdp_tcp_set_nodelay(wLog* log, DWORD level, int sockfd)
1598{
1599 WINPR_ASSERT(log);
1600
1601 int type = -1;
1602 socklen_t typelen = sizeof(type);
1603 char* ptype = (char*)&type;
1604 const int rc = getsockopt(sockfd, SOL_SOCKET, SO_TYPE, ptype, &typelen);
1605 if (rc < 0)
1606 {
1607 char buffer[128] = WINPR_C_ARRAY_INIT;
1608 WLog_Print(log, level, "can't get SOL_SOCKET|SO_TYPE (%s)",
1609 winpr_strerror(errno, buffer, sizeof(buffer)));
1610 return FALSE;
1611 }
1612 else if (type == SOCK_STREAM)
1613 {
1614 int option_value = -1;
1615 const socklen_t option_len = sizeof(option_value);
1616 const int sr =
1617 setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (void*)&option_value, option_len);
1618 if (sr < 0)
1619 {
1620 /* local unix sockets don't have the TCP_NODELAY implemented, so don't make this
1621 * error fatal */
1622 char buffer[128] = WINPR_C_ARRAY_INIT;
1623 WLog_Print(log, level, "can't set TCP_NODELAY (%s)",
1624 winpr_strerror(errno, buffer, sizeof(buffer)));
1625 return FALSE;
1626 }
1627 }
1628 else
1629 {
1630 WLog_Print(log, level, "Socket SOL_SOCKET|SO_TYPE %d unsupported", type);
1631 return FALSE;
1632 }
1633 return TRUE;
1634}
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
Definition ringbuffer.h:44
ring buffer meta data
Definition ringbuffer.h:33