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 = { 0 };
245 struct timeval tv = { 0 };
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, NULL, NULL, timeout ? &tv : NULL);
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 = { 0 };
284 struct timeval tv = { 0 };
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, NULL, &rset, NULL, timeout ? &tv : NULL);
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 = NULL;
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 = NULL;
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 = NULL;
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, NULL);
423 free(ptr);
424 }
425
426 return 1;
427}
428
429BIO_METHOD* BIO_s_simple_socket(void)
430{
431 static BIO_METHOD* bio_methods = NULL;
432
433 if (bio_methods == NULL)
434 {
435 if (!(bio_methods = BIO_meth_new(BIO_TYPE_SIMPLE, "SimpleSocket")))
436 return NULL;
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] = { 0 };
466 WINPR_BIO_BUFFERED_SOCKET* ptr = (WINPR_BIO_BUFFERED_SOCKET*)BIO_get_data(bio);
467 BIO* next_bio = NULL;
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, NULL, 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 = NULL;
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 = NULL;
647
648 if (bio_methods == NULL)
649 {
650 if (!(bio_methods = BIO_meth_new(BIO_TYPE_BUFFERED, "BufferedSocket")))
651 return NULL;
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] = { 0 };
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 == NULL)
672 {
673 return NULL;
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 NULL;
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 NULL;
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 NULL;
698 }
699
700 if (pIPv6 != NULL)
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 = { 0 };
713 socklen_t length = sizeof(struct sockaddr_storage);
714
715 if (!freerdp_settings_set_string(settings, FreeRDP_ClientAddress, NULL))
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 != NULL;
723}
724
725char* freerdp_tcp_get_peer_address(SOCKET sockfd)
726{
727 struct sockaddr_storage saddr = { 0 };
728 socklen_t length = sizeof(struct sockaddr_storage);
729
730 if (getpeername((int)sockfd, (struct sockaddr*)&saddr, &length) != 0)
731 {
732 return NULL;
733 }
734
735 return freerdp_tcp_address_to_string(&saddr, NULL);
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 = { 0 };
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 = NULL;
772 char port_str[16];
773 int status = 0;
774 struct addrinfo hints = { 0 };
775 struct addrinfo* result = NULL;
776 hints.ai_family = AF_UNSPEC;
777 hints.ai_socktype = SOCK_STREAM;
778 hints.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 return NULL;
790
791 return result;
792}
793
794static BOOL freerdp_tcp_is_hostname_resolvable(rdpContext* context, const char* hostname)
795{
796 struct addrinfo* result = freerdp_tcp_resolve_host(hostname, -1, 0);
797
798 if (!result)
799 {
800 freerdp_set_last_error_if_not(context, FREERDP_ERROR_DNS_NAME_NOT_FOUND);
801
802 return FALSE;
803 }
804
805 freerdp_set_last_error_log(context, 0);
806 freeaddrinfo(result);
807 return TRUE;
808}
809
810static BOOL freerdp_tcp_connect_timeout(rdpContext* context, int sockfd, struct sockaddr* addr,
811 size_t addrlen, UINT32 timeout)
812{
813 BOOL rc = FALSE;
814 HANDLE handles[2] = { 0 };
815 DWORD count = 0;
816 u_long arg = 0;
817 DWORD tout = (timeout > 0) ? timeout : INFINITE;
818
819 handles[count] = CreateEvent(NULL, TRUE, FALSE, NULL);
820
821 if (!handles[count])
822 return FALSE;
823
824 const int wsastatus = WSAEventSelect((SOCKET)sockfd, handles[count++],
825 FD_READ | FD_WRITE | FD_CONNECT | FD_CLOSE);
826
827 if (wsastatus < 0)
828 {
829 WLog_ERR(TAG, "WSAEventSelect failed with %d", WSAGetLastError());
830 goto fail;
831 }
832
833 handles[count++] = utils_get_abort_event(context->rdp);
834
835 {
836 const int constatus =
837 _connect((SOCKET)sockfd, addr, WINPR_ASSERTING_INT_CAST(int, addrlen));
838 if (constatus < 0)
839 {
840 const int estatus = WSAGetLastError();
841
842 switch (estatus)
843 {
844 case WSAEINPROGRESS:
845 case WSAEWOULDBLOCK:
846 break;
847
848 default:
849 goto fail;
850 }
851 }
852 }
853
854 {
855 const DWORD wstatus = WaitForMultipleObjects(count, handles, FALSE, tout);
856 if (WAIT_OBJECT_0 != wstatus)
857 goto fail;
858 }
859
860 {
861 INT32 optval = 0;
862 socklen_t optlen = sizeof(optval);
863 if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) < 0)
864 goto fail;
865
866 if (optval != 0)
867 {
868 char ebuffer[256] = { 0 };
869 WLog_DBG(TAG, "connect failed with error: %s [%" PRId32 "]",
870 winpr_strerror(optval, ebuffer, sizeof(ebuffer)), optval);
871 goto fail;
872 }
873 }
874
875 {
876 const int status = WSAEventSelect((SOCKET)sockfd, handles[0], 0);
877 if (status < 0)
878 {
879 WLog_ERR(TAG, "WSAEventSelect failed with %d", WSAGetLastError());
880 goto fail;
881 }
882 }
883
884 if (_ioctlsocket((SOCKET)sockfd, FIONBIO, &arg) != 0)
885 goto fail;
886
887 rc = TRUE;
888fail:
889 (void)CloseHandle(handles[0]);
890 return rc;
891}
892
893typedef struct
894{
895 SOCKET s;
896 struct addrinfo* addr;
897 struct addrinfo* result;
898} t_peer;
899
900static void peer_free(t_peer* peer)
901{
902 if (peer->s != INVALID_SOCKET)
903 closesocket(peer->s);
904
905 freeaddrinfo(peer->addr);
906 memset(peer, 0, sizeof(t_peer));
907 peer->s = INVALID_SOCKET;
908}
909
910static int freerdp_tcp_connect_multi(rdpContext* context, char** hostnames, const UINT32* ports,
911 UINT32 count, UINT16 port, WINPR_ATTR_UNUSED UINT32 timeout)
912{
913 UINT32 sindex = count;
914 SOCKET sockfd = INVALID_SOCKET;
915 struct addrinfo* addr = NULL;
916 struct addrinfo* result = NULL;
917
918 HANDLE* events = (HANDLE*)calloc(count + 1, sizeof(HANDLE));
919 t_peer* peers = (t_peer*)calloc(count, sizeof(t_peer));
920
921 if (!peers || !events || (count < 1))
922 {
923 free(peers);
924 free((void*)events);
925 return -1;
926 }
927
928 for (UINT32 index = 0; index < count; index++)
929 {
930 int curPort = port;
931
932 if (ports)
933 curPort = WINPR_ASSERTING_INT_CAST(int, ports[index]);
934
935 result = freerdp_tcp_resolve_host(hostnames[index], curPort, 0);
936
937 if (!result)
938 continue;
939
940 addr = result;
941
942 if ((addr->ai_family == AF_INET6) && (addr->ai_next != 0))
943 {
944 while ((addr = addr->ai_next))
945 {
946 if (addr->ai_family == AF_INET)
947 break;
948 }
949
950 if (!addr)
951 addr = result;
952 }
953
954 peers[index].s = _socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
955
956 if (peers[index].s == INVALID_SOCKET)
957 {
958 freeaddrinfo(result);
959 continue;
960 }
961
962 peers[index].addr = addr;
963 peers[index].result = result;
964 }
965
966 for (UINT32 index = 0; index < count; index++)
967 {
968 sockfd = peers[index].s;
969 addr = peers[index].addr;
970
971 if ((sockfd == INVALID_SOCKET) || (!addr))
972 continue;
973
974 /* blocking tcp connect */
975 const int rc =
976 _connect(sockfd, addr->ai_addr, WINPR_ASSERTING_INT_CAST(int, addr->ai_addrlen));
977
978 if (rc >= 0)
979 {
980 /* connection success */
981 sindex = index;
982 break;
983 }
984 }
985
986 if (sindex < count)
987 {
988 sockfd = peers[sindex].s;
989 peers[sindex].s = INVALID_SOCKET;
990 }
991 else
992 freerdp_set_last_error_log(context, FREERDP_ERROR_CONNECT_CANCELLED);
993
994 for (UINT32 index = 0; index < count; index++)
995 peer_free(&peers[index]);
996
997 free(peers);
998 free((void*)events);
999 return (int)sockfd;
1000}
1001
1002BOOL freerdp_tcp_set_keep_alive_mode(const rdpSettings* settings, int sockfd)
1003{
1004 const BOOL keepalive = (freerdp_settings_get_bool(settings, FreeRDP_TcpKeepAlive));
1005 UINT32 optval = 0;
1006 socklen_t optlen = 0;
1007 optval = keepalive ? 1 : 0;
1008 optlen = sizeof(optval);
1009
1010 if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (void*)&optval, optlen) < 0)
1011 {
1012 WLog_WARN(TAG, "setsockopt() SOL_SOCKET, SO_KEEPALIVE");
1013 }
1014
1015#ifndef _WIN32
1016#ifdef TCP_KEEPIDLE
1017 optval = keepalive ? freerdp_settings_get_uint32(settings, FreeRDP_TcpKeepAliveDelay) : 0;
1018 optlen = sizeof(optval);
1019
1020 if (setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE, (void*)&optval, optlen) < 0)
1021 {
1022 WLog_WARN(TAG, "setsockopt() IPPROTO_TCP, TCP_KEEPIDLE");
1023 }
1024
1025#endif
1026#ifndef SOL_TCP
1027 /* "tcp" from /etc/protocols as getprotobyname(3C) */
1028#define SOL_TCP 6
1029#endif
1030#ifdef TCP_KEEPCNT
1031 optval = keepalive ? freerdp_settings_get_uint32(settings, FreeRDP_TcpKeepAliveRetries) : 0;
1032 optlen = sizeof(optval);
1033
1034 if (setsockopt(sockfd, SOL_TCP, TCP_KEEPCNT, (void*)&optval, optlen) < 0)
1035 {
1036 WLog_WARN(TAG, "setsockopt() SOL_TCP, TCP_KEEPCNT");
1037 }
1038
1039#endif
1040#ifdef TCP_KEEPINTVL
1041 optval = keepalive ? freerdp_settings_get_uint32(settings, FreeRDP_TcpKeepAliveInterval) : 0;
1042 optlen = sizeof(optval);
1043
1044 if (setsockopt(sockfd, SOL_TCP, TCP_KEEPINTVL, (void*)&optval, optlen) < 0)
1045 {
1046 WLog_WARN(TAG, "setsockopt() SOL_TCP, TCP_KEEPINTVL");
1047 }
1048
1049#endif
1050#endif
1051#if defined(__MACOSX__) || defined(__IOS__)
1052 optval = 1;
1053 optlen = sizeof(optval);
1054
1055 if (setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void*)&optval, optlen) < 0)
1056 {
1057 WLog_WARN(TAG, "setsockopt() SOL_SOCKET, SO_NOSIGPIPE");
1058 }
1059
1060#endif
1061#ifdef TCP_USER_TIMEOUT
1062 optval = freerdp_settings_get_uint32(settings, FreeRDP_TcpAckTimeout);
1063 optlen = sizeof(optval);
1064
1065 if (setsockopt(sockfd, SOL_TCP, TCP_USER_TIMEOUT, (void*)&optval, optlen) < 0)
1066 {
1067 WLog_WARN(TAG, "setsockopt() SOL_TCP, TCP_USER_TIMEOUT");
1068 }
1069
1070#endif
1071 return TRUE;
1072}
1073
1074int freerdp_tcp_connect(rdpContext* context, const char* hostname, int port, DWORD timeout)
1075{
1076 rdpTransport* transport = NULL;
1077 if (!context || !context->rdp)
1078 return -1;
1079 transport = context->rdp->transport;
1080 if (!transport)
1081 return -1;
1082 return transport_tcp_connect(context->rdp->transport, hostname, port, timeout);
1083}
1084
1085static struct addrinfo* reorder_addrinfo_by_preference(rdpContext* context, struct addrinfo* addr)
1086{
1087 WINPR_ASSERT(context);
1088 WINPR_ASSERT(addr);
1089
1090 const BOOL preferIPv6 =
1091 freerdp_settings_get_bool(context->settings, FreeRDP_PreferIPv6OverIPv4);
1092 if (!preferIPv6)
1093 return addr;
1094
1095 struct addrinfo* ipv6Head = NULL;
1096 struct addrinfo* ipv6Tail = NULL;
1097 struct addrinfo* otherHead = NULL;
1098 struct addrinfo* otherTail = NULL;
1099
1100 /* Partition the list into IPv6 and other addresses */
1101 while (addr)
1102 {
1103 struct addrinfo* next = addr->ai_next;
1104 addr->ai_next = NULL;
1105
1106 if (addr->ai_family == AF_INET6)
1107 {
1108 if (!ipv6Head)
1109 ipv6Head = addr;
1110 else
1111 ipv6Tail->ai_next = addr;
1112 ipv6Tail = addr;
1113 }
1114 else
1115 {
1116 if (!otherHead)
1117 otherHead = addr;
1118 else
1119 otherTail->ai_next = addr;
1120 otherTail = addr;
1121 }
1122 addr = next;
1123 }
1124
1125 /* Concatenate the lists */
1126 if (ipv6Tail)
1127 ipv6Tail->ai_next = otherHead;
1128
1129 return ipv6Head ? ipv6Head : otherHead;
1130}
1131
1132static int get_next_addrinfo(rdpContext* context, struct addrinfo* input, struct addrinfo** result,
1133 UINT32 errorCode)
1134{
1135 WINPR_ASSERT(context);
1136 WINPR_ASSERT(result);
1137
1138 struct addrinfo* addr = input;
1139 if (!addr)
1140 goto fail;
1141
1142 /* We want to force IPvX, abort if not detected */
1143 {
1144 const UINT32 IPvX = freerdp_settings_get_uint32(context->settings, FreeRDP_ForceIPvX);
1145 switch (IPvX)
1146 {
1147 case 4:
1148 case 6:
1149 {
1150 const int family = (IPvX == 4) ? AF_INET : AF_INET6;
1151 while (addr && (addr->ai_family != family))
1152 addr = addr->ai_next;
1153 }
1154 break;
1155 default:
1156 break;
1157 }
1158 }
1159
1160 if (!addr)
1161 goto fail;
1162
1163 *result = addr;
1164 return 0;
1165
1166fail:
1167 freerdp_set_last_error_if_not(context, errorCode);
1168 *result = NULL;
1169 return -1;
1170}
1171
1172static int freerdp_vsock_connect(rdpContext* context, const char* hostname, int port)
1173{
1174#if defined(HAVE_AF_VSOCK_H)
1175 int sockfd = socket(AF_VSOCK, SOCK_STREAM, 0);
1176 if (sockfd < 0)
1177 {
1178 char buffer[256] = { 0 };
1179 WLog_WARN(TAG, "socket(AF_VSOCK, SOCK_STREAM, 0) failed with %s",
1180 winpr_strerror(errno, buffer, sizeof(buffer)));
1181 freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
1182 return -1;
1183 }
1184
1185 struct sockaddr_vm addr = { 0 };
1186
1187 addr.svm_family = AF_VSOCK;
1188 addr.svm_port = WINPR_ASSERTING_INT_CAST(typeof(addr.svm_port), port);
1189
1190 errno = 0;
1191 char* ptr = NULL;
1192 unsigned long val = strtoul(hostname, &ptr, 10);
1193 if (errno || (val > UINT32_MAX))
1194 {
1195 char ebuffer[256] = { 0 };
1196 WLog_ERR(TAG, "could not extract port from '%s', value=%lu, error=%s", hostname, val,
1197 winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
1198 close(sockfd);
1199 return -1;
1200 }
1201 addr.svm_cid = WINPR_ASSERTING_INT_CAST(typeof(addr.svm_cid), val);
1202 if (addr.svm_cid == 2)
1203 {
1204 addr.svm_flags = VMADDR_FLAG_TO_HOST;
1205 }
1206 if ((connect(sockfd, (struct sockaddr*)&addr, sizeof(struct sockaddr_vm))) == -1)
1207 {
1208 WLog_ERR(TAG, "failed to connect to %s", hostname);
1209 close(sockfd);
1210 return -1;
1211 }
1212 return sockfd;
1213#else
1214 WLog_ERR(TAG, "Compiled without AF_VSOCK, '%s' not supported", hostname);
1215 return -1;
1216#endif
1217}
1218
1219static void log_connection_address(const char* hostname, struct addrinfo* addr)
1220{
1221 WINPR_ASSERT(addr);
1222
1223 char* peerAddress =
1224 freerdp_tcp_address_to_string((const struct sockaddr_storage*)addr->ai_addr, NULL);
1225 if (peerAddress)
1226 WLog_DBG(TAG, "resolved %s: try to connect to %s", hostname, peerAddress);
1227 free(peerAddress);
1228}
1229
1230static int freerdp_host_connect(rdpContext* context, const char* hostname, int port, DWORD timeout)
1231{
1232 int sockfd = -1;
1233 struct addrinfo* addr = NULL;
1234 struct addrinfo* result = freerdp_tcp_resolve_host(hostname, port, 0);
1235
1236 if (!result)
1237 {
1238 freerdp_set_last_error_if_not(context, FREERDP_ERROR_DNS_NAME_NOT_FOUND);
1239 return -1;
1240 }
1241 freerdp_set_last_error_log(context, 0);
1242
1243 /* By default we take the first returned entry.
1244 * If PreferIPv6OverIPv4 = TRUE we reorder addresses by preference:
1245 * IPv6 addresses come first, then other addresses.
1246 */
1247 result = reorder_addrinfo_by_preference(context, result);
1248
1249 const int rc = get_next_addrinfo(context, result, &addr, FREERDP_ERROR_DNS_NAME_NOT_FOUND);
1250 if (rc < 0)
1251 goto fail;
1252
1253 do
1254 {
1255 sockfd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
1256 if (sockfd >= 0)
1257 {
1258 log_connection_address(hostname, addr);
1259
1260 if (!freerdp_tcp_connect_timeout(context, sockfd, addr->ai_addr, addr->ai_addrlen,
1261 timeout))
1262 {
1263 close(sockfd);
1264 sockfd = -1;
1265 }
1266 }
1267
1268 if (sockfd < 0)
1269 {
1270 const int lrc =
1271 get_next_addrinfo(context, addr->ai_next, &addr, FREERDP_ERROR_CONNECT_FAILED);
1272 if (lrc < 0)
1273 goto fail;
1274 }
1275 } while (sockfd < 0);
1276
1277fail:
1278 freeaddrinfo(result);
1279 return sockfd;
1280}
1281
1282int freerdp_tcp_default_connect(rdpContext* context, rdpSettings* settings, const char* hostname,
1283 int port, DWORD timeout)
1284{
1285 int sockfd = -1;
1286 BOOL ipcSocket = FALSE;
1287 BOOL useExternalDefinedSocket = FALSE;
1288
1289 if (!hostname)
1290 {
1291 freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
1292
1293 return -1;
1294 }
1295
1296 if (hostname[0] == '/')
1297 ipcSocket = TRUE;
1298
1299 if (hostname[0] == '|')
1300 useExternalDefinedSocket = TRUE;
1301
1302 const char* vsock = utils_is_vsock(hostname);
1303 if (ipcSocket)
1304 {
1305 sockfd = freerdp_uds_connect(hostname);
1306
1307 if (sockfd < 0)
1308 {
1309 freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
1310 return -1;
1311 }
1312 }
1313 else if (useExternalDefinedSocket)
1314 sockfd = port;
1315 else if (vsock)
1316 sockfd = freerdp_vsock_connect(context, vsock, port);
1317 else
1318 {
1319 if (!settings->GatewayEnabled)
1320 {
1321 if (!freerdp_tcp_is_hostname_resolvable(context, hostname) ||
1322 settings->RemoteAssistanceMode)
1323 {
1324 if (settings->TargetNetAddressCount > 0)
1325 {
1326 WINPR_ASSERT(port <= UINT16_MAX);
1327 sockfd = freerdp_tcp_connect_multi(
1328 context, settings->TargetNetAddresses, settings->TargetNetPorts,
1329 settings->TargetNetAddressCount, (UINT16)port, timeout);
1330 }
1331 }
1332 }
1333
1334 if (sockfd <= 0)
1335 sockfd = freerdp_host_connect(context, hostname, port, timeout);
1336 }
1337
1338 if (!vsock)
1339 {
1340 if (!freerdp_tcp_get_ip_address(settings, sockfd))
1341 {
1342 if (!useExternalDefinedSocket)
1343 close(sockfd);
1344
1345 freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
1346
1347 WLog_ERR(TAG, "Couldn't get socket ip address");
1348 return -1;
1349 }
1350 }
1351
1352 if (!ipcSocket && !useExternalDefinedSocket)
1353 {
1354 (void)freerdp_tcp_set_nodelay(WLog_Get(TAG), WLOG_ERROR, sockfd);
1355 }
1356
1357 /* receive buffer must be a least 32 K */
1358 UINT32 optval = 1;
1359 socklen_t optlen = sizeof(optval);
1360 if (getsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (void*)&optval, &optlen) == 0)
1361 {
1362 if (optval < (1024 * 32))
1363 {
1364 optval = 1024 * 32;
1365 optlen = sizeof(optval);
1366
1367 if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (void*)&optval, optlen) < 0)
1368 {
1369 close(sockfd);
1370
1371 freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
1372
1373 WLog_ERR(TAG, "unable to set receive buffer len");
1374 return -1;
1375 }
1376 }
1377 }
1378
1379 if (!ipcSocket && !useExternalDefinedSocket)
1380 {
1381 if (!freerdp_tcp_set_keep_alive_mode(settings, sockfd))
1382 {
1383 close(sockfd);
1384
1385 freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
1386
1387 WLog_ERR(TAG, "Couldn't set keep alive mode.");
1388 return -1;
1389 }
1390 }
1391
1392 if (WaitForSingleObject(utils_get_abort_event(context->rdp), 0) == WAIT_OBJECT_0)
1393 {
1394 close(sockfd);
1395 return -1;
1396 }
1397
1398 return sockfd;
1399}
1400
1401struct rdp_tcp_layer
1402{
1403 int sockfd;
1404 HANDLE hEvent;
1405};
1406typedef struct rdp_tcp_layer rdpTcpLayer;
1407
1408static int freerdp_tcp_layer_read(void* userContext, void* data, int bytes)
1409{
1410 if (!userContext)
1411 return -1;
1412 if (!data || !bytes)
1413 return 0;
1414
1415 rdpTcpLayer* tcpLayer = (rdpTcpLayer*)userContext;
1416
1417 (void)WSAResetEvent(tcpLayer->hEvent);
1418 const int status = _recv((SOCKET)tcpLayer->sockfd, data, bytes, 0);
1419
1420 if (status > 0)
1421 return status;
1422
1423 const int error = WSAGetLastError();
1424
1425 if ((error == WSAEWOULDBLOCK) || (error == WSAEINTR) || (error == WSAEINPROGRESS) ||
1426 (error == WSAEALREADY))
1427 errno = EAGAIN;
1428
1429 return status;
1430}
1431
1432static int freerdp_tcp_layer_write(void* userContext, const void* data, int bytes)
1433{
1434 if (!userContext)
1435 return -1;
1436 if (!data || !bytes)
1437 return 0;
1438
1439 rdpTcpLayer* tcpLayer = (rdpTcpLayer*)userContext;
1440
1441 const int status = _send((SOCKET)tcpLayer->sockfd, data, bytes, 0);
1442 if (status > 0)
1443 return status;
1444
1445 const int error = WSAGetLastError();
1446
1447 if ((error == WSAEWOULDBLOCK) || (error == WSAEINTR) || (error == WSAEINPROGRESS) ||
1448 (error == WSAEALREADY))
1449 errno = EAGAIN;
1450
1451 return status;
1452}
1453
1454static BOOL freerdp_tcp_layer_close(void* userContext)
1455{
1456 if (!userContext)
1457 return FALSE;
1458
1459 rdpTcpLayer* tcpLayer = (rdpTcpLayer*)userContext;
1460
1461 if (tcpLayer->sockfd >= 0)
1462 closesocket((SOCKET)tcpLayer->sockfd);
1463 if (tcpLayer->hEvent)
1464 (void)CloseHandle(tcpLayer->hEvent);
1465
1466 return TRUE;
1467}
1468
1469static BOOL freerdp_tcp_layer_wait(void* userContext, BOOL waitWrite, DWORD timeout)
1470{
1471 if (!userContext)
1472 return FALSE;
1473
1474 rdpTcpLayer* tcpLayer = (rdpTcpLayer*)userContext;
1475
1476 int status = -1;
1477 int sockfd = tcpLayer->sockfd;
1478#ifdef WINPR_HAVE_POLL_H
1479 struct pollfd pollset = { 0 };
1480 pollset.fd = sockfd;
1481 pollset.events = waitWrite ? POLLOUT : POLLIN;
1482
1483 do
1484 {
1485 status = poll(&pollset, 1, (int)timeout);
1486 } while ((status < 0) && (errno == EINTR));
1487
1488#else
1489 fd_set rset = { 0 };
1490 struct timeval tv = { 0 };
1491 FD_ZERO(&rset);
1492 FD_SET(sockfd, &rset);
1493
1494 if (timeout)
1495 {
1496 tv.tv_sec = timeout / 1000;
1497 tv.tv_usec = (timeout % 1000) * 1000;
1498 }
1499
1500 do
1501 {
1502 if (waitWrite)
1503 status = select(sockfd + 1, NULL, &rset, NULL, timeout ? &tv : NULL);
1504 else
1505 status = select(sockfd + 1, &rset, NULL, NULL, timeout ? &tv : NULL);
1506 } while ((status < 0) && (errno == EINTR));
1507
1508#endif
1509
1510 return status != 0;
1511}
1512
1513static HANDLE freerdp_tcp_layer_get_event(void* userContext)
1514{
1515 if (!userContext)
1516 return NULL;
1517
1518 rdpTcpLayer* tcpLayer = (rdpTcpLayer*)userContext;
1519
1520 return tcpLayer->hEvent;
1521}
1522
1523rdpTransportLayer* freerdp_tcp_connect_layer(rdpContext* context, const char* hostname, int port,
1524 DWORD timeout)
1525{
1526 WINPR_ASSERT(context);
1527
1528 const rdpSettings* settings = context->settings;
1529 WINPR_ASSERT(settings);
1530
1531 rdpTransportLayer* layer = NULL;
1532 rdpTcpLayer* tcpLayer = NULL;
1533
1534 int sockfd = freerdp_tcp_connect(context, hostname, port, timeout);
1535 if (sockfd < 0)
1536 goto fail;
1537 if (!freerdp_tcp_set_keep_alive_mode(settings, sockfd))
1538 goto fail;
1539
1540 layer = transport_layer_new(freerdp_get_transport(context), sizeof(rdpTcpLayer));
1541 if (!layer)
1542 goto fail;
1543
1544 layer->Read = freerdp_tcp_layer_read;
1545 layer->Write = freerdp_tcp_layer_write;
1546 layer->Close = freerdp_tcp_layer_close;
1547 layer->Wait = freerdp_tcp_layer_wait;
1548 layer->GetEvent = freerdp_tcp_layer_get_event;
1549
1550 tcpLayer = (rdpTcpLayer*)layer->userContext;
1551 WINPR_ASSERT(tcpLayer);
1552
1553 tcpLayer->sockfd = -1;
1554 tcpLayer->hEvent = WSACreateEvent();
1555 if (!tcpLayer->hEvent)
1556 goto fail;
1557
1558 /* WSAEventSelect automatically sets the socket in non-blocking mode */
1559 if (WSAEventSelect((SOCKET)sockfd, tcpLayer->hEvent, FD_READ | FD_ACCEPT | FD_CLOSE))
1560 {
1561 WLog_ERR(TAG, "WSAEventSelect returned 0x%08x", (unsigned)WSAGetLastError());
1562 goto fail;
1563 }
1564
1565 tcpLayer->sockfd = sockfd;
1566
1567 return layer;
1568
1569fail:
1570 if (sockfd >= 0)
1571 closesocket((SOCKET)sockfd);
1572 transport_layer_free(layer);
1573 return NULL;
1574}
1575
1576BOOL freerdp_tcp_set_nodelay(wLog* log, DWORD level, int sockfd)
1577{
1578 WINPR_ASSERT(log);
1579
1580 int type = -1;
1581 socklen_t typelen = sizeof(type);
1582 char* ptype = (char*)&type;
1583 const int rc = getsockopt(sockfd, SOL_SOCKET, SO_TYPE, ptype, &typelen);
1584 if (rc < 0)
1585 {
1586 char buffer[128] = { 0 };
1587 WLog_Print(log, level, "can't get SOL_SOCKET|SO_TYPE (%s)",
1588 winpr_strerror(errno, buffer, sizeof(buffer)));
1589 return FALSE;
1590 }
1591 else if (type == SOCK_STREAM)
1592 {
1593 int option_value = -1;
1594 const socklen_t option_len = sizeof(option_value);
1595 const int sr =
1596 setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (void*)&option_value, option_len);
1597 if (sr < 0)
1598 {
1599 /* local unix sockets don't have the TCP_NODELAY implemented, so don't make this
1600 * error fatal */
1601 char buffer[128] = { 0 };
1602 WLog_Print(log, level, "can't set TCP_NODELAY (%s)",
1603 winpr_strerror(errno, buffer, sizeof(buffer)));
1604 return FALSE;
1605 }
1606 }
1607 else
1608 {
1609 WLog_Print(log, level, "Socket SOL_SOCKET|SO_TYPE %d unsupported", type);
1610 return FALSE;
1611 }
1612 return TRUE;
1613}
FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
FREERDP_API BOOL freerdp_settings_set_string(rdpSettings *settings, FreeRDP_Settings_Keys_String id, const char *param)
Sets a string settings value. The param is copied.
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