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, &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 optval = keepalive ? 1 : 0;
1017 optlen = sizeof(optval);
1018
1019 if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (void*)&optval, optlen) < 0)
1020 {
1021 WLog_WARN(TAG, "setsockopt() SOL_SOCKET, SO_KEEPALIVE");
1022 }
1023
1024#ifndef _WIN32
1025#ifdef TCP_KEEPIDLE
1026 optval = keepalive ? freerdp_settings_get_uint32(settings, FreeRDP_TcpKeepAliveDelay) : 0;
1027 optlen = sizeof(optval);
1028
1029 if (setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE, (void*)&optval, optlen) < 0)
1030 {
1031 WLog_WARN(TAG, "setsockopt() IPPROTO_TCP, TCP_KEEPIDLE");
1032 }
1033
1034#endif
1035#ifndef SOL_TCP
1036 /* "tcp" from /etc/protocols as getprotobyname(3C) */
1037#define SOL_TCP 6
1038#endif
1039#ifdef TCP_KEEPCNT
1040 optval = keepalive ? freerdp_settings_get_uint32(settings, FreeRDP_TcpKeepAliveRetries) : 0;
1041 optlen = sizeof(optval);
1042
1043 if (setsockopt(sockfd, SOL_TCP, TCP_KEEPCNT, (void*)&optval, optlen) < 0)
1044 {
1045 WLog_WARN(TAG, "setsockopt() SOL_TCP, TCP_KEEPCNT");
1046 }
1047
1048#endif
1049#ifdef TCP_KEEPINTVL
1050 optval = keepalive ? freerdp_settings_get_uint32(settings, FreeRDP_TcpKeepAliveInterval) : 0;
1051 optlen = sizeof(optval);
1052
1053 if (setsockopt(sockfd, SOL_TCP, TCP_KEEPINTVL, (void*)&optval, optlen) < 0)
1054 {
1055 WLog_WARN(TAG, "setsockopt() SOL_TCP, TCP_KEEPINTVL");
1056 }
1057
1058#endif
1059#endif
1060#if defined(__MACOSX__) || defined(__IOS__)
1061 optval = 1;
1062 optlen = sizeof(optval);
1063
1064 if (setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void*)&optval, optlen) < 0)
1065 {
1066 WLog_WARN(TAG, "setsockopt() SOL_SOCKET, SO_NOSIGPIPE");
1067 }
1068
1069#endif
1070#ifdef TCP_USER_TIMEOUT
1071 optval = freerdp_settings_get_uint32(settings, FreeRDP_TcpAckTimeout);
1072 optlen = sizeof(optval);
1073
1074 if (setsockopt(sockfd, SOL_TCP, TCP_USER_TIMEOUT, (void*)&optval, optlen) < 0)
1075 {
1076 WLog_WARN(TAG, "setsockopt() SOL_TCP, TCP_USER_TIMEOUT");
1077 }
1078
1079#endif
1080 return TRUE;
1081}
1082
1083int freerdp_tcp_connect(rdpContext* context, const char* hostname, int port, DWORD timeout)
1084{
1085 rdpTransport* transport = nullptr;
1086 if (!context || !context->rdp)
1087 return -1;
1088 transport = context->rdp->transport;
1089 if (!transport)
1090 return -1;
1091 return transport_tcp_connect(context->rdp->transport, hostname, port, timeout);
1092}
1093
1094static struct addrinfo* reorder_addrinfo_by_preference(rdpContext* context, struct addrinfo* addr)
1095{
1096 WINPR_ASSERT(context);
1097 WINPR_ASSERT(addr);
1098
1099 const BOOL preferIPv6 =
1100 freerdp_settings_get_bool(context->settings, FreeRDP_PreferIPv6OverIPv4);
1101 if (!preferIPv6)
1102 return addr;
1103
1104 struct addrinfo* ipv6Head = nullptr;
1105 struct addrinfo* ipv6Tail = nullptr;
1106 struct addrinfo* otherHead = nullptr;
1107 struct addrinfo* otherTail = nullptr;
1108
1109 /* Partition the list into IPv6 and other addresses */
1110 while (addr)
1111 {
1112 struct addrinfo* next = addr->ai_next;
1113 addr->ai_next = nullptr;
1114
1115 if (addr->ai_family == AF_INET6)
1116 {
1117 if (!ipv6Head)
1118 ipv6Head = addr;
1119 else
1120 ipv6Tail->ai_next = addr;
1121 ipv6Tail = addr;
1122 }
1123 else
1124 {
1125 if (!otherHead)
1126 otherHead = addr;
1127 else
1128 otherTail->ai_next = addr;
1129 otherTail = addr;
1130 }
1131 addr = next;
1132 }
1133
1134 /* Concatenate the lists */
1135 if (ipv6Tail)
1136 ipv6Tail->ai_next = otherHead;
1137
1138 return ipv6Head ? ipv6Head : otherHead;
1139}
1140
1141static int get_next_addrinfo(rdpContext* context, struct addrinfo* input, struct addrinfo** result,
1142 UINT32 errorCode)
1143{
1144 WINPR_ASSERT(context);
1145 WINPR_ASSERT(result);
1146
1147 struct addrinfo* addr = input;
1148 if (!addr)
1149 goto fail;
1150
1151 /* We want to force IPvX, abort if not detected */
1152 {
1153 const UINT32 IPvX = freerdp_settings_get_uint32(context->settings, FreeRDP_ForceIPvX);
1154 switch (IPvX)
1155 {
1156 case 4:
1157 case 6:
1158 {
1159 const int family = (IPvX == 4) ? AF_INET : AF_INET6;
1160 while (addr && (addr->ai_family != family))
1161 addr = addr->ai_next;
1162 }
1163 break;
1164 default:
1165 break;
1166 }
1167 }
1168
1169 if (!addr)
1170 goto fail;
1171
1172 *result = addr;
1173 return 0;
1174
1175fail:
1176 freerdp_set_last_error_if_not(context, errorCode);
1177 *result = nullptr;
1178 return -1;
1179}
1180
1181static int freerdp_vsock_connect(rdpContext* context, const char* hostname, int port)
1182{
1183#if defined(HAVE_AF_VSOCK_H)
1184 int sockfd = socket(AF_VSOCK, SOCK_STREAM, 0);
1185 if (sockfd < 0)
1186 {
1187 char buffer[256] = WINPR_C_ARRAY_INIT;
1188 WLog_WARN(TAG, "socket(AF_VSOCK, SOCK_STREAM, 0) failed with %s",
1189 winpr_strerror(errno, buffer, sizeof(buffer)));
1190 freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
1191 return -1;
1192 }
1193
1194 struct sockaddr_vm addr = WINPR_C_ARRAY_INIT;
1195
1196 addr.svm_family = AF_VSOCK;
1197 addr.svm_port = WINPR_ASSERTING_INT_CAST(typeof(addr.svm_port), port);
1198
1199 errno = 0;
1200 char* ptr = nullptr;
1201 unsigned long val = strtoul(hostname, &ptr, 10);
1202 if (errno || (val > UINT32_MAX))
1203 {
1204 char ebuffer[256] = WINPR_C_ARRAY_INIT;
1205 WLog_ERR(TAG, "could not extract port from '%s', value=%lu, error=%s", hostname, val,
1206 winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
1207 close(sockfd);
1208 return -1;
1209 }
1210 addr.svm_cid = WINPR_ASSERTING_INT_CAST(typeof(addr.svm_cid), val);
1211 if (addr.svm_cid == 2)
1212 {
1213 addr.svm_flags = VMADDR_FLAG_TO_HOST;
1214 }
1215 if ((connect(sockfd, (struct sockaddr*)&addr, sizeof(struct sockaddr_vm))) == -1)
1216 {
1217 WLog_ERR(TAG, "failed to connect to %s", hostname);
1218 close(sockfd);
1219 return -1;
1220 }
1221 return sockfd;
1222#else
1223 WLog_ERR(TAG, "Compiled without AF_VSOCK, '%s' not supported", hostname);
1224 return -1;
1225#endif
1226}
1227
1228static void log_connection_address(const char* hostname, struct addrinfo* addr)
1229{
1230 WINPR_ASSERT(addr);
1231
1232 char* peerAddress =
1233 freerdp_tcp_address_to_string((const struct sockaddr_storage*)addr->ai_addr, nullptr);
1234 if (peerAddress)
1235 WLog_DBG(TAG, "resolved %s: try to connect to %s", hostname, peerAddress);
1236 free(peerAddress);
1237}
1238
1239static int freerdp_host_connect(rdpContext* context, const char* hostname, int port, DWORD timeout)
1240{
1241 int sockfd = -1;
1242 struct addrinfo* addr = nullptr;
1243 struct addrinfo* result = freerdp_tcp_resolve_host(hostname, port, 0);
1244
1245 if (!result)
1246 {
1247 freerdp_set_last_error_if_not(context, FREERDP_ERROR_DNS_NAME_NOT_FOUND);
1248 return -1;
1249 }
1250 freerdp_set_last_error_log(context, 0);
1251
1252 /* By default we take the first returned entry.
1253 * If PreferIPv6OverIPv4 = TRUE we reorder addresses by preference:
1254 * IPv6 addresses come first, then other addresses.
1255 */
1256 result = reorder_addrinfo_by_preference(context, result);
1257
1258 const int rc = get_next_addrinfo(context, result, &addr, FREERDP_ERROR_DNS_NAME_NOT_FOUND);
1259 if (rc < 0)
1260 goto fail;
1261
1262 do
1263 {
1264 sockfd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
1265 if (sockfd >= 0)
1266 {
1267 log_connection_address(hostname, addr);
1268
1269 if (!freerdp_tcp_connect_timeout(context, sockfd, addr->ai_addr, addr->ai_addrlen,
1270 timeout))
1271 {
1272 close(sockfd);
1273 sockfd = -1;
1274 }
1275 }
1276
1277 if (sockfd < 0)
1278 {
1279 const int lrc =
1280 get_next_addrinfo(context, addr->ai_next, &addr, FREERDP_ERROR_CONNECT_FAILED);
1281 if (lrc < 0)
1282 goto fail;
1283 }
1284 } while (sockfd < 0);
1285
1286fail:
1287 freeaddrinfo(result);
1288 return sockfd;
1289}
1290
1291int freerdp_tcp_default_connect(rdpContext* context, rdpSettings* settings, const char* hostname,
1292 int port, DWORD timeout)
1293{
1294 int sockfd = -1;
1295 BOOL ipcSocket = FALSE;
1296 BOOL useExternalDefinedSocket = FALSE;
1297
1298 if (!hostname)
1299 {
1300 freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
1301
1302 return -1;
1303 }
1304
1305 if (hostname[0] == '/')
1306 ipcSocket = TRUE;
1307
1308 if (hostname[0] == '|')
1309 useExternalDefinedSocket = TRUE;
1310
1311 const char* vsock = utils_is_vsock(hostname);
1312 if (ipcSocket)
1313 {
1314 sockfd = freerdp_uds_connect(hostname);
1315
1316 if (sockfd < 0)
1317 {
1318 freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
1319 return -1;
1320 }
1321 }
1322 else if (useExternalDefinedSocket)
1323 sockfd = port;
1324 else if (vsock)
1325 sockfd = freerdp_vsock_connect(context, vsock, port);
1326 else
1327 {
1328 if (!settings->GatewayEnabled)
1329 {
1330 if (!freerdp_tcp_is_hostname_resolvable(context, hostname) ||
1331 settings->RemoteAssistanceMode)
1332 {
1333 if (settings->TargetNetAddressCount > 0)
1334 {
1335 WINPR_ASSERT(port <= UINT16_MAX);
1336 sockfd = freerdp_tcp_connect_multi(
1337 context, settings->TargetNetAddresses, settings->TargetNetPorts,
1338 settings->TargetNetAddressCount, (UINT16)port, timeout);
1339 }
1340 }
1341 }
1342
1343 if (sockfd <= 0)
1344 sockfd = freerdp_host_connect(context, hostname, port, timeout);
1345 }
1346
1347 if (!vsock)
1348 {
1349 if (!freerdp_tcp_get_ip_address(settings, sockfd))
1350 {
1351 if (!useExternalDefinedSocket)
1352 close(sockfd);
1353
1354 freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
1355
1356 WLog_ERR(TAG, "Couldn't get socket ip address");
1357 return -1;
1358 }
1359 }
1360
1361 if (!ipcSocket && !useExternalDefinedSocket)
1362 {
1363 (void)freerdp_tcp_set_nodelay(WLog_Get(TAG), WLOG_ERROR, sockfd);
1364 }
1365
1366 /* receive buffer must be a least 32 K */
1367 UINT32 optval = 1;
1368 socklen_t optlen = sizeof(optval);
1369 if (getsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (void*)&optval, &optlen) == 0)
1370 {
1371 if (optval < (1024 * 32))
1372 {
1373 optval = 1024 * 32;
1374 optlen = sizeof(optval);
1375
1376 if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (void*)&optval, optlen) < 0)
1377 {
1378 close(sockfd);
1379
1380 freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
1381
1382 WLog_ERR(TAG, "unable to set receive buffer len");
1383 return -1;
1384 }
1385 }
1386 }
1387
1388 if (!ipcSocket && !useExternalDefinedSocket)
1389 {
1390 if (!freerdp_tcp_set_keep_alive_mode(settings, sockfd))
1391 {
1392 close(sockfd);
1393
1394 freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
1395
1396 WLog_ERR(TAG, "Couldn't set keep alive mode.");
1397 return -1;
1398 }
1399 }
1400
1401 if (WaitForSingleObject(utils_get_abort_event(context->rdp), 0) == WAIT_OBJECT_0)
1402 {
1403 close(sockfd);
1404 return -1;
1405 }
1406
1407 return sockfd;
1408}
1409
1410struct rdp_tcp_layer
1411{
1412 int sockfd;
1413 HANDLE hEvent;
1414};
1415typedef struct rdp_tcp_layer rdpTcpLayer;
1416
1417static int freerdp_tcp_layer_read(void* userContext, void* data, int bytes)
1418{
1419 if (!userContext)
1420 return -1;
1421 if (!data || !bytes)
1422 return 0;
1423
1424 rdpTcpLayer* tcpLayer = (rdpTcpLayer*)userContext;
1425
1426 (void)WSAResetEvent(tcpLayer->hEvent);
1427 const int status = _recv((SOCKET)tcpLayer->sockfd, data, bytes, 0);
1428
1429 if (status > 0)
1430 return status;
1431
1432 const int error = WSAGetLastError();
1433
1434 if ((error == WSAEWOULDBLOCK) || (error == WSAEINTR) || (error == WSAEINPROGRESS) ||
1435 (error == WSAEALREADY))
1436 errno = EAGAIN;
1437
1438 return status;
1439}
1440
1441static int freerdp_tcp_layer_write(void* userContext, const void* data, int bytes)
1442{
1443 if (!userContext)
1444 return -1;
1445 if (!data || !bytes)
1446 return 0;
1447
1448 rdpTcpLayer* tcpLayer = (rdpTcpLayer*)userContext;
1449
1450 const int status = _send((SOCKET)tcpLayer->sockfd, data, bytes, 0);
1451 if (status > 0)
1452 return status;
1453
1454 const int error = WSAGetLastError();
1455
1456 if ((error == WSAEWOULDBLOCK) || (error == WSAEINTR) || (error == WSAEINPROGRESS) ||
1457 (error == WSAEALREADY))
1458 errno = EAGAIN;
1459
1460 return status;
1461}
1462
1463static BOOL freerdp_tcp_layer_close(void* userContext)
1464{
1465 if (!userContext)
1466 return FALSE;
1467
1468 rdpTcpLayer* tcpLayer = (rdpTcpLayer*)userContext;
1469
1470 if (tcpLayer->sockfd >= 0)
1471 closesocket((SOCKET)tcpLayer->sockfd);
1472 if (tcpLayer->hEvent)
1473 (void)CloseHandle(tcpLayer->hEvent);
1474
1475 return TRUE;
1476}
1477
1478static BOOL freerdp_tcp_layer_wait(void* userContext, BOOL waitWrite, DWORD timeout)
1479{
1480 if (!userContext)
1481 return FALSE;
1482
1483 rdpTcpLayer* tcpLayer = (rdpTcpLayer*)userContext;
1484
1485 int status = -1;
1486 int sockfd = tcpLayer->sockfd;
1487#ifdef WINPR_HAVE_POLL_H
1488 struct pollfd pollset = WINPR_C_ARRAY_INIT;
1489 pollset.fd = sockfd;
1490 pollset.events = waitWrite ? POLLOUT : POLLIN;
1491
1492 do
1493 {
1494 status = poll(&pollset, 1, (int)timeout);
1495 } while ((status < 0) && (errno == EINTR));
1496
1497#else
1498 fd_set rset = WINPR_C_ARRAY_INIT;
1499 struct timeval tv = WINPR_C_ARRAY_INIT;
1500 FD_ZERO(&rset);
1501 FD_SET(sockfd, &rset);
1502
1503 if (timeout)
1504 {
1505 tv.tv_sec = timeout / 1000;
1506 tv.tv_usec = (timeout % 1000) * 1000;
1507 }
1508
1509 do
1510 {
1511 if (waitWrite)
1512 status = select(sockfd + 1, nullptr, &rset, nullptr, timeout ? &tv : nullptr);
1513 else
1514 status = select(sockfd + 1, &rset, nullptr, nullptr, timeout ? &tv : nullptr);
1515 } while ((status < 0) && (errno == EINTR));
1516
1517#endif
1518
1519 return status != 0;
1520}
1521
1522static HANDLE freerdp_tcp_layer_get_event(void* userContext)
1523{
1524 if (!userContext)
1525 return nullptr;
1526
1527 rdpTcpLayer* tcpLayer = (rdpTcpLayer*)userContext;
1528
1529 return tcpLayer->hEvent;
1530}
1531
1532rdpTransportLayer* freerdp_tcp_connect_layer(rdpContext* context, const char* hostname, int port,
1533 DWORD timeout)
1534{
1535 WINPR_ASSERT(context);
1536
1537 const rdpSettings* settings = context->settings;
1538 WINPR_ASSERT(settings);
1539
1540 rdpTransportLayer* layer = nullptr;
1541 rdpTcpLayer* tcpLayer = nullptr;
1542
1543 int sockfd = freerdp_tcp_connect(context, hostname, port, timeout);
1544 if (sockfd < 0)
1545 goto fail;
1546 if (!freerdp_tcp_set_keep_alive_mode(settings, sockfd))
1547 goto fail;
1548
1549 layer = transport_layer_new(freerdp_get_transport(context), sizeof(rdpTcpLayer));
1550 if (!layer)
1551 goto fail;
1552
1553 layer->Read = freerdp_tcp_layer_read;
1554 layer->Write = freerdp_tcp_layer_write;
1555 layer->Close = freerdp_tcp_layer_close;
1556 layer->Wait = freerdp_tcp_layer_wait;
1557 layer->GetEvent = freerdp_tcp_layer_get_event;
1558
1559 tcpLayer = (rdpTcpLayer*)layer->userContext;
1560 WINPR_ASSERT(tcpLayer);
1561
1562 tcpLayer->sockfd = -1;
1563 tcpLayer->hEvent = WSACreateEvent();
1564 if (!tcpLayer->hEvent)
1565 goto fail;
1566
1567 /* WSAEventSelect automatically sets the socket in non-blocking mode */
1568 if (WSAEventSelect((SOCKET)sockfd, tcpLayer->hEvent, FD_READ | FD_ACCEPT | FD_CLOSE))
1569 {
1570 WLog_ERR(TAG, "WSAEventSelect returned 0x%08x", (unsigned)WSAGetLastError());
1571 goto fail;
1572 }
1573
1574 tcpLayer->sockfd = sockfd;
1575
1576 return layer;
1577
1578fail:
1579 if (sockfd >= 0)
1580 closesocket((SOCKET)sockfd);
1581 transport_layer_free(layer);
1582 return nullptr;
1583}
1584
1585BOOL freerdp_tcp_set_nodelay(wLog* log, DWORD level, int sockfd)
1586{
1587 WINPR_ASSERT(log);
1588
1589 int type = -1;
1590 socklen_t typelen = sizeof(type);
1591 char* ptype = (char*)&type;
1592 const int rc = getsockopt(sockfd, SOL_SOCKET, SO_TYPE, ptype, &typelen);
1593 if (rc < 0)
1594 {
1595 char buffer[128] = WINPR_C_ARRAY_INIT;
1596 WLog_Print(log, level, "can't get SOL_SOCKET|SO_TYPE (%s)",
1597 winpr_strerror(errno, buffer, sizeof(buffer)));
1598 return FALSE;
1599 }
1600 else if (type == SOCK_STREAM)
1601 {
1602 int option_value = -1;
1603 const socklen_t option_len = sizeof(option_value);
1604 const int sr =
1605 setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (void*)&option_value, option_len);
1606 if (sr < 0)
1607 {
1608 /* local unix sockets don't have the TCP_NODELAY implemented, so don't make this
1609 * error fatal */
1610 char buffer[128] = WINPR_C_ARRAY_INIT;
1611 WLog_Print(log, level, "can't set TCP_NODELAY (%s)",
1612 winpr_strerror(errno, buffer, sizeof(buffer)));
1613 return FALSE;
1614 }
1615 }
1616 else
1617 {
1618 WLog_Print(log, level, "Socket SOL_SOCKET|SO_TYPE %d unsupported", type);
1619 return FALSE;
1620 }
1621 return TRUE;
1622}
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