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", WSAGetLastError());
365 return 0;
366 }
367
368 return 1;
369}
370
371static int transport_bio_simple_uninit(BIO* bio)
372{
373 WINPR_BIO_SIMPLE_SOCKET* ptr = (WINPR_BIO_SIMPLE_SOCKET*)BIO_get_data(bio);
374
375 if (BIO_get_shutdown(bio))
376 {
377 if (BIO_get_init(bio) && ptr)
378 {
379 _shutdown(ptr->socket, SD_BOTH);
380 closesocket(ptr->socket);
381 ptr->socket = 0;
382 }
383 }
384
385 if (ptr && ptr->hEvent)
386 {
387 (void)CloseHandle(ptr->hEvent);
388 ptr->hEvent = NULL;
389 }
390
391 BIO_set_init(bio, 0);
392 BIO_set_flags(bio, 0);
393 return 1;
394}
395
396static int transport_bio_simple_new(BIO* bio)
397{
398 WINPR_BIO_SIMPLE_SOCKET* ptr = NULL;
399 BIO_set_flags(bio, BIO_FLAGS_SHOULD_RETRY);
400 ptr = (WINPR_BIO_SIMPLE_SOCKET*)calloc(1, sizeof(WINPR_BIO_SIMPLE_SOCKET));
401
402 if (!ptr)
403 return 0;
404
405 BIO_set_data(bio, ptr);
406 return 1;
407}
408
409static int transport_bio_simple_free(BIO* bio)
410{
411 WINPR_BIO_SIMPLE_SOCKET* ptr = NULL;
412
413 if (!bio)
414 return 0;
415
416 transport_bio_simple_uninit(bio);
417 ptr = (WINPR_BIO_SIMPLE_SOCKET*)BIO_get_data(bio);
418
419 if (ptr)
420 {
421 BIO_set_data(bio, NULL);
422 free(ptr);
423 }
424
425 return 1;
426}
427
428BIO_METHOD* BIO_s_simple_socket(void)
429{
430 static BIO_METHOD* bio_methods = NULL;
431
432 if (bio_methods == NULL)
433 {
434 if (!(bio_methods = BIO_meth_new(BIO_TYPE_SIMPLE, "SimpleSocket")))
435 return NULL;
436
437 BIO_meth_set_write(bio_methods, transport_bio_simple_write);
438 BIO_meth_set_read(bio_methods, transport_bio_simple_read);
439 BIO_meth_set_puts(bio_methods, transport_bio_simple_puts);
440 BIO_meth_set_gets(bio_methods, transport_bio_simple_gets);
441 BIO_meth_set_ctrl(bio_methods, transport_bio_simple_ctrl);
442 BIO_meth_set_create(bio_methods, transport_bio_simple_new);
443 BIO_meth_set_destroy(bio_methods, transport_bio_simple_free);
444 }
445
446 return bio_methods;
447}
448
449/* Buffered Socket BIO */
450
451typedef struct
452{
453 BIO* bufferedBio;
454 BOOL readBlocked;
455 BOOL writeBlocked;
456 RingBuffer xmitBuffer;
457} WINPR_BIO_BUFFERED_SOCKET;
458
459static int transport_bio_buffered_write(BIO* bio, const char* buf, int num)
460{
461 int ret = num;
462 int nchunks = 0;
463 size_t committedBytes = 0;
464 DataChunk chunks[2] = { 0 };
465 WINPR_BIO_BUFFERED_SOCKET* ptr = (WINPR_BIO_BUFFERED_SOCKET*)BIO_get_data(bio);
466 BIO* next_bio = NULL;
467
468 WINPR_ASSERT(bio);
469 WINPR_ASSERT(ptr);
470 if (num < 0)
471 return num;
472
473 ptr->writeBlocked = FALSE;
474 BIO_clear_flags(bio, BIO_FLAGS_WRITE);
475
476 /* we directly append extra bytes in the xmit buffer, this could be prevented
477 * but for now it makes the code more simple.
478 */
479 if (buf && (num > 0) && !ringbuffer_write(&ptr->xmitBuffer, (const BYTE*)buf, (size_t)num))
480 {
481 WLog_ERR(TAG, "an error occurred when writing (num: %d)", num);
482 return -1;
483 }
484
485 nchunks = ringbuffer_peek(&ptr->xmitBuffer, chunks, ringbuffer_used(&ptr->xmitBuffer));
486 next_bio = BIO_next(bio);
487
488 for (int i = 0; i < nchunks; i++)
489 {
490 while (chunks[i].size)
491 {
492 ERR_clear_error();
493
494 const size_t wr = MIN(INT32_MAX, chunks[i].size);
495 const int status = BIO_write(next_bio, chunks[i].data, (int)wr);
496
497 if (status <= 0)
498 {
499 if (!BIO_should_retry(next_bio))
500 {
501 BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
502 ret = -1; /* fatal error */
503 goto out;
504 }
505
506 if (BIO_should_write(next_bio))
507 {
508 BIO_set_flags(bio, BIO_FLAGS_WRITE);
509 ptr->writeBlocked = TRUE;
510 goto out; /* EWOULDBLOCK */
511 }
512 }
513 else
514 {
515 committedBytes += (size_t)status;
516 chunks[i].size -= (size_t)status;
517 chunks[i].data += status;
518 }
519 }
520 }
521
522out:
523 ringbuffer_commit_read_bytes(&ptr->xmitBuffer, committedBytes);
524 return ret;
525}
526
527static int transport_bio_buffered_read(BIO* bio, char* buf, int size)
528{
529 int status = 0;
530 WINPR_BIO_BUFFERED_SOCKET* ptr = (WINPR_BIO_BUFFERED_SOCKET*)BIO_get_data(bio);
531 BIO* next_bio = BIO_next(bio);
532 ptr->readBlocked = FALSE;
533 BIO_clear_flags(bio, BIO_FLAGS_READ);
534 ERR_clear_error();
535 status = BIO_read(next_bio, buf, size);
536
537 if (status <= 0)
538 {
539 if (!BIO_should_retry(next_bio))
540 {
541 BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
542 goto out;
543 }
544
545 BIO_set_flags(bio, BIO_FLAGS_SHOULD_RETRY);
546
547 if (BIO_should_read(next_bio))
548 {
549 BIO_set_flags(bio, BIO_FLAGS_READ);
550 ptr->readBlocked = TRUE;
551 goto out;
552 }
553 }
554
555out:
556 return status;
557}
558
559static int transport_bio_buffered_puts(WINPR_ATTR_UNUSED BIO* bio,
560 WINPR_ATTR_UNUSED const char* str)
561{
562 return 1;
563}
564
565static int transport_bio_buffered_gets(WINPR_ATTR_UNUSED BIO* bio, WINPR_ATTR_UNUSED char* str,
566 WINPR_ATTR_UNUSED int size)
567{
568 return 1;
569}
570
571static long transport_bio_buffered_ctrl(BIO* bio, int cmd, long arg1, void* arg2)
572{
573 long status = -1;
574 WINPR_BIO_BUFFERED_SOCKET* ptr = (WINPR_BIO_BUFFERED_SOCKET*)BIO_get_data(bio);
575
576 switch (cmd)
577 {
578 case BIO_CTRL_FLUSH:
579 if (!ringbuffer_used(&ptr->xmitBuffer))
580 status = 1;
581 else
582 status = (transport_bio_buffered_write(bio, NULL, 0) >= 0) ? 1 : -1;
583
584 break;
585
586 case BIO_CTRL_WPENDING:
587 status = WINPR_ASSERTING_INT_CAST(long, ringbuffer_used(&ptr->xmitBuffer));
588 break;
589
590 case BIO_CTRL_PENDING:
591 status = 0;
592 break;
593
594 case BIO_C_READ_BLOCKED:
595 status = (int)ptr->readBlocked;
596 break;
597
598 case BIO_C_WRITE_BLOCKED:
599 status = (int)ptr->writeBlocked;
600 break;
601
602 default:
603 status = BIO_ctrl(BIO_next(bio), cmd, arg1, arg2);
604 break;
605 }
606
607 return status;
608}
609
610static int transport_bio_buffered_new(BIO* bio)
611{
612 WINPR_BIO_BUFFERED_SOCKET* ptr = NULL;
613 BIO_set_init(bio, 1);
614 BIO_set_flags(bio, BIO_FLAGS_SHOULD_RETRY);
615 ptr = (WINPR_BIO_BUFFERED_SOCKET*)calloc(1, sizeof(WINPR_BIO_BUFFERED_SOCKET));
616
617 if (!ptr)
618 return -1;
619
620 BIO_set_data(bio, (void*)ptr);
621
622 if (!ringbuffer_init(&ptr->xmitBuffer, 0x10000))
623 return -1;
624
625 return 1;
626}
627
628/* Free the buffered BIO.
629 * Do not free other elements in the BIO stack,
630 * let BIO_free_all handle that. */
631static int transport_bio_buffered_free(BIO* bio)
632{
633 WINPR_BIO_BUFFERED_SOCKET* ptr = (WINPR_BIO_BUFFERED_SOCKET*)BIO_get_data(bio);
634
635 if (!ptr)
636 return 0;
637
638 ringbuffer_destroy(&ptr->xmitBuffer);
639 free(ptr);
640 return 1;
641}
642
643BIO_METHOD* BIO_s_buffered_socket(void)
644{
645 static BIO_METHOD* bio_methods = NULL;
646
647 if (bio_methods == NULL)
648 {
649 if (!(bio_methods = BIO_meth_new(BIO_TYPE_BUFFERED, "BufferedSocket")))
650 return NULL;
651
652 BIO_meth_set_write(bio_methods, transport_bio_buffered_write);
653 BIO_meth_set_read(bio_methods, transport_bio_buffered_read);
654 BIO_meth_set_puts(bio_methods, transport_bio_buffered_puts);
655 BIO_meth_set_gets(bio_methods, transport_bio_buffered_gets);
656 BIO_meth_set_ctrl(bio_methods, transport_bio_buffered_ctrl);
657 BIO_meth_set_create(bio_methods, transport_bio_buffered_new);
658 BIO_meth_set_destroy(bio_methods, transport_bio_buffered_free);
659 }
660
661 return bio_methods;
662}
663
664char* freerdp_tcp_address_to_string(const struct sockaddr_storage* addr, BOOL* pIPv6)
665{
666 char ipAddress[INET6_ADDRSTRLEN + 1] = { 0 };
667 const struct sockaddr_in6* sockaddr_ipv6 = (const struct sockaddr_in6*)addr;
668 const struct sockaddr_in* sockaddr_ipv4 = (const struct sockaddr_in*)addr;
669
670 if (addr == NULL)
671 {
672 return NULL;
673 }
674
675 switch (sockaddr_ipv4->sin_family)
676 {
677 case AF_INET:
678 if (!inet_ntop(sockaddr_ipv4->sin_family, &sockaddr_ipv4->sin_addr, ipAddress,
679 sizeof(ipAddress)))
680 return NULL;
681
682 break;
683
684 case AF_INET6:
685 if (!inet_ntop(sockaddr_ipv6->sin6_family, &sockaddr_ipv6->sin6_addr, ipAddress,
686 sizeof(ipAddress)))
687 return NULL;
688
689 break;
690
691 case AF_UNIX:
692 (void)sprintf_s(ipAddress, ARRAYSIZE(ipAddress), "127.0.0.1");
693 break;
694
695 default:
696 return NULL;
697 }
698
699 if (pIPv6 != NULL)
700 {
701 *pIPv6 = (sockaddr_ipv4->sin_family == AF_INET6);
702 }
703
704 return _strdup(ipAddress);
705}
706
707static bool freerdp_tcp_get_ip_address(rdpSettings* settings, int sockfd)
708{
709 WINPR_ASSERT(settings);
710
711 struct sockaddr_storage saddr = { 0 };
712 socklen_t length = sizeof(struct sockaddr_storage);
713
714 if (!freerdp_settings_set_string(settings, FreeRDP_ClientAddress, NULL))
715 return false;
716 if (sockfd < 0)
717 return false;
718 if (getsockname(sockfd, (struct sockaddr*)&saddr, &length) != 0)
719 return false;
720 settings->ClientAddress = freerdp_tcp_address_to_string(&saddr, &settings->IPv6Enabled);
721 return settings->ClientAddress != NULL;
722}
723
724char* freerdp_tcp_get_peer_address(SOCKET sockfd)
725{
726 struct sockaddr_storage saddr = { 0 };
727 socklen_t length = sizeof(struct sockaddr_storage);
728
729 if (getpeername((int)sockfd, (struct sockaddr*)&saddr, &length) != 0)
730 {
731 return NULL;
732 }
733
734 return freerdp_tcp_address_to_string(&saddr, NULL);
735}
736
737static int freerdp_uds_connect(const char* path)
738{
739#ifndef _WIN32
740 int status = 0;
741 int sockfd = 0;
742 struct sockaddr_un addr = { 0 };
743 sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
744
745 if (sockfd == -1)
746 {
747 WLog_ERR(TAG, "socket");
748 return -1;
749 }
750
751 addr.sun_family = AF_UNIX;
752 strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
753 status = connect(sockfd, (struct sockaddr*)&addr, sizeof(addr));
754
755 if (status < 0)
756 {
757 WLog_ERR(TAG, "connect");
758 close(sockfd);
759 return -1;
760 }
761
762 return sockfd;
763#else /* ifndef _WIN32 */
764 return -1;
765#endif
766}
767
768struct addrinfo* freerdp_tcp_resolve_host(const char* hostname, int port, int ai_flags)
769{
770 char* service = NULL;
771 char port_str[16];
772 int status = 0;
773 struct addrinfo hints = { 0 };
774 struct addrinfo* result = NULL;
775 hints.ai_family = AF_UNSPEC;
776 hints.ai_socktype = SOCK_STREAM;
777 hints.ai_flags = ai_flags;
778
779 if (port >= 0)
780 {
781 (void)sprintf_s(port_str, sizeof(port_str) - 1, "%d", port);
782 service = port_str;
783 }
784
785 status = getaddrinfo(hostname, service, &hints, &result);
786
787 if (status)
788 return NULL;
789
790 return result;
791}
792
793static BOOL freerdp_tcp_is_hostname_resolvable(rdpContext* context, const char* hostname)
794{
795 struct addrinfo* result = freerdp_tcp_resolve_host(hostname, -1, 0);
796
797 if (!result)
798 {
799 freerdp_set_last_error_if_not(context, FREERDP_ERROR_DNS_NAME_NOT_FOUND);
800
801 return FALSE;
802 }
803
804 freerdp_set_last_error_log(context, 0);
805 freeaddrinfo(result);
806 return TRUE;
807}
808
809static BOOL freerdp_tcp_connect_timeout(rdpContext* context, int sockfd, struct sockaddr* addr,
810 socklen_t addrlen, UINT32 timeout)
811{
812 BOOL rc = FALSE;
813 HANDLE handles[2] = { 0 };
814 DWORD count = 0;
815 u_long arg = 0;
816 DWORD tout = (timeout > 0) ? timeout : INFINITE;
817
818 handles[count] = CreateEvent(NULL, TRUE, FALSE, NULL);
819
820 if (!handles[count])
821 return FALSE;
822
823 const int wsastatus = WSAEventSelect((SOCKET)sockfd, handles[count++],
824 FD_READ | FD_WRITE | FD_CONNECT | FD_CLOSE);
825
826 if (wsastatus < 0)
827 {
828 WLog_ERR(TAG, "WSAEventSelect failed with %d", WSAGetLastError());
829 goto fail;
830 }
831
832 handles[count++] = utils_get_abort_event(context->rdp);
833
834 {
835 const int constatus =
836 _connect((SOCKET)sockfd, addr, WINPR_ASSERTING_INT_CAST(int, addrlen));
837 if (constatus < 0)
838 {
839 const int estatus = WSAGetLastError();
840
841 switch (estatus)
842 {
843 case WSAEINPROGRESS:
844 case WSAEWOULDBLOCK:
845 break;
846
847 default:
848 goto fail;
849 }
850 }
851 }
852
853 {
854 const DWORD wstatus = WaitForMultipleObjects(count, handles, FALSE, tout);
855 if (WAIT_OBJECT_0 != wstatus)
856 goto fail;
857 }
858
859 {
860 INT32 optval = 0;
861 socklen_t optlen = sizeof(optval);
862 if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) < 0)
863 goto fail;
864
865 if (optval != 0)
866 {
867 char ebuffer[256] = { 0 };
868 WLog_DBG(TAG, "connect failed with error: %s [%" PRIu32 "]",
869 winpr_strerror(optval, ebuffer, sizeof(ebuffer)), optval);
870 goto fail;
871 }
872 }
873
874 {
875 const int status = WSAEventSelect((SOCKET)sockfd, handles[0], 0);
876 if (status < 0)
877 {
878 WLog_ERR(TAG, "WSAEventSelect failed with %d", WSAGetLastError());
879 goto fail;
880 }
881 }
882
883 if (_ioctlsocket((SOCKET)sockfd, FIONBIO, &arg) != 0)
884 goto fail;
885
886 rc = TRUE;
887fail:
888 (void)CloseHandle(handles[0]);
889 return rc;
890}
891
892typedef struct
893{
894 SOCKET s;
895 struct addrinfo* addr;
896 struct addrinfo* result;
897} t_peer;
898
899static void peer_free(t_peer* peer)
900{
901 if (peer->s != INVALID_SOCKET)
902 closesocket(peer->s);
903
904 freeaddrinfo(peer->addr);
905 memset(peer, 0, sizeof(t_peer));
906 peer->s = INVALID_SOCKET;
907}
908
909static int freerdp_tcp_connect_multi(rdpContext* context, char** hostnames, const UINT32* ports,
910 UINT32 count, UINT16 port, WINPR_ATTR_UNUSED UINT32 timeout)
911{
912 UINT32 sindex = count;
913 SOCKET sockfd = INVALID_SOCKET;
914 struct addrinfo* addr = NULL;
915 struct addrinfo* result = NULL;
916
917 HANDLE* events = (HANDLE*)calloc(count + 1, sizeof(HANDLE));
918 t_peer* peers = (t_peer*)calloc(count, sizeof(t_peer));
919
920 if (!peers || !events || (count < 1))
921 {
922 free(peers);
923 free((void*)events);
924 return -1;
925 }
926
927 for (UINT32 index = 0; index < count; index++)
928 {
929 int curPort = port;
930
931 if (ports)
932 curPort = WINPR_ASSERTING_INT_CAST(int, ports[index]);
933
934 result = freerdp_tcp_resolve_host(hostnames[index], curPort, 0);
935
936 if (!result)
937 continue;
938
939 addr = result;
940
941 if ((addr->ai_family == AF_INET6) && (addr->ai_next != 0))
942 {
943 while ((addr = addr->ai_next))
944 {
945 if (addr->ai_family == AF_INET)
946 break;
947 }
948
949 if (!addr)
950 addr = result;
951 }
952
953 peers[index].s = _socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
954
955 if (peers[index].s == INVALID_SOCKET)
956 {
957 freeaddrinfo(result);
958 continue;
959 }
960
961 peers[index].addr = addr;
962 peers[index].result = result;
963 }
964
965 for (UINT32 index = 0; index < count; index++)
966 {
967 sockfd = peers[index].s;
968 addr = peers[index].addr;
969
970 if ((sockfd == INVALID_SOCKET) || (!addr))
971 continue;
972
973 /* blocking tcp connect */
974 const int rc =
975 _connect(sockfd, addr->ai_addr, WINPR_ASSERTING_INT_CAST(int, addr->ai_addrlen));
976
977 if (rc >= 0)
978 {
979 /* connection success */
980 sindex = index;
981 break;
982 }
983 }
984
985 if (sindex < count)
986 {
987 sockfd = peers[sindex].s;
988 peers[sindex].s = INVALID_SOCKET;
989 }
990 else
991 freerdp_set_last_error_log(context, FREERDP_ERROR_CONNECT_CANCELLED);
992
993 for (UINT32 index = 0; index < count; index++)
994 peer_free(&peers[index]);
995
996 free(peers);
997 free((void*)events);
998 return (int)sockfd;
999}
1000
1001BOOL freerdp_tcp_set_keep_alive_mode(const rdpSettings* settings, int sockfd)
1002{
1003 const BOOL keepalive = (freerdp_settings_get_bool(settings, FreeRDP_TcpKeepAlive));
1004 UINT32 optval = 0;
1005 socklen_t optlen = 0;
1006 optval = keepalive ? 1 : 0;
1007 optlen = sizeof(optval);
1008
1009 if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (void*)&optval, optlen) < 0)
1010 {
1011 WLog_WARN(TAG, "setsockopt() SOL_SOCKET, SO_KEEPALIVE");
1012 }
1013
1014#ifndef _WIN32
1015#ifdef TCP_KEEPIDLE
1016 optval = keepalive ? freerdp_settings_get_uint32(settings, FreeRDP_TcpKeepAliveDelay) : 0;
1017 optlen = sizeof(optval);
1018
1019 if (setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE, (void*)&optval, optlen) < 0)
1020 {
1021 WLog_WARN(TAG, "setsockopt() IPPROTO_TCP, TCP_KEEPIDLE");
1022 }
1023
1024#endif
1025#ifndef SOL_TCP
1026 /* "tcp" from /etc/protocols as getprotobyname(3C) */
1027#define SOL_TCP 6
1028#endif
1029#ifdef TCP_KEEPCNT
1030 optval = keepalive ? freerdp_settings_get_uint32(settings, FreeRDP_TcpKeepAliveRetries) : 0;
1031 optlen = sizeof(optval);
1032
1033 if (setsockopt(sockfd, SOL_TCP, TCP_KEEPCNT, (void*)&optval, optlen) < 0)
1034 {
1035 WLog_WARN(TAG, "setsockopt() SOL_TCP, TCP_KEEPCNT");
1036 }
1037
1038#endif
1039#ifdef TCP_KEEPINTVL
1040 optval = keepalive ? freerdp_settings_get_uint32(settings, FreeRDP_TcpKeepAliveInterval) : 0;
1041 optlen = sizeof(optval);
1042
1043 if (setsockopt(sockfd, SOL_TCP, TCP_KEEPINTVL, (void*)&optval, optlen) < 0)
1044 {
1045 WLog_WARN(TAG, "setsockopt() SOL_TCP, TCP_KEEPINTVL");
1046 }
1047
1048#endif
1049#endif
1050#if defined(__MACOSX__) || defined(__IOS__)
1051 optval = 1;
1052 optlen = sizeof(optval);
1053
1054 if (setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void*)&optval, optlen) < 0)
1055 {
1056 WLog_WARN(TAG, "setsockopt() SOL_SOCKET, SO_NOSIGPIPE");
1057 }
1058
1059#endif
1060#ifdef TCP_USER_TIMEOUT
1061 optval = freerdp_settings_get_uint32(settings, FreeRDP_TcpAckTimeout);
1062 optlen = sizeof(optval);
1063
1064 if (setsockopt(sockfd, SOL_TCP, TCP_USER_TIMEOUT, (void*)&optval, optlen) < 0)
1065 {
1066 WLog_WARN(TAG, "setsockopt() SOL_TCP, TCP_USER_TIMEOUT");
1067 }
1068
1069#endif
1070 return TRUE;
1071}
1072
1073int freerdp_tcp_connect(rdpContext* context, const char* hostname, int port, DWORD timeout)
1074{
1075 rdpTransport* transport = NULL;
1076 if (!context || !context->rdp)
1077 return -1;
1078 transport = context->rdp->transport;
1079 if (!transport)
1080 return -1;
1081 return transport_tcp_connect(context->rdp->transport, hostname, port, timeout);
1082}
1083
1084static struct addrinfo* reorder_addrinfo_by_preference(rdpContext* context, struct addrinfo* addr)
1085{
1086 WINPR_ASSERT(context);
1087 WINPR_ASSERT(addr);
1088
1089 const BOOL preferIPv6 =
1090 freerdp_settings_get_bool(context->settings, FreeRDP_PreferIPv6OverIPv4);
1091 if (!preferIPv6)
1092 return addr;
1093
1094 struct addrinfo* ipv6Head = NULL;
1095 struct addrinfo* ipv6Tail = NULL;
1096 struct addrinfo* otherHead = NULL;
1097 struct addrinfo* otherTail = NULL;
1098
1099 /* Partition the list into IPv6 and other addresses */
1100 while (addr)
1101 {
1102 struct addrinfo* next = addr->ai_next;
1103 addr->ai_next = NULL;
1104
1105 if (addr->ai_family == AF_INET6)
1106 {
1107 if (!ipv6Head)
1108 ipv6Head = addr;
1109 else
1110 ipv6Tail->ai_next = addr;
1111 ipv6Tail = addr;
1112 }
1113 else
1114 {
1115 if (!otherHead)
1116 otherHead = addr;
1117 else
1118 otherTail->ai_next = addr;
1119 otherTail = addr;
1120 }
1121 addr = next;
1122 }
1123
1124 /* Concatenate the lists */
1125 if (ipv6Tail)
1126 ipv6Tail->ai_next = otherHead;
1127
1128 return ipv6Head ? ipv6Head : otherHead;
1129}
1130
1131static int get_next_addrinfo(rdpContext* context, struct addrinfo* input, struct addrinfo** result,
1132 UINT32 errorCode)
1133{
1134 WINPR_ASSERT(context);
1135 WINPR_ASSERT(result);
1136
1137 struct addrinfo* addr = input;
1138 if (!addr)
1139 goto fail;
1140
1141 /* We want to force IPvX, abort if not detected */
1142 {
1143 const UINT32 IPvX = freerdp_settings_get_uint32(context->settings, FreeRDP_ForceIPvX);
1144 switch (IPvX)
1145 {
1146 case 4:
1147 case 6:
1148 {
1149 const int family = (IPvX == 4) ? AF_INET : AF_INET6;
1150 while (addr && (addr->ai_family != family))
1151 addr = addr->ai_next;
1152 }
1153 break;
1154 default:
1155 break;
1156 }
1157 }
1158
1159 if (!addr)
1160 goto fail;
1161
1162 *result = addr;
1163 return 0;
1164
1165fail:
1166 freerdp_set_last_error_if_not(context, errorCode);
1167 *result = NULL;
1168 return -1;
1169}
1170
1171static int freerdp_vsock_connect(rdpContext* context, const char* hostname, int port)
1172{
1173#if defined(HAVE_AF_VSOCK_H)
1174 int sockfd = socket(AF_VSOCK, SOCK_STREAM, 0);
1175 if (sockfd < 0)
1176 {
1177 char buffer[256] = { 0 };
1178 WLog_WARN(TAG, "socket(AF_VSOCK, SOCK_STREAM, 0) failed with %s [%d]",
1179 winpr_strerror(errno, buffer, sizeof(buffer)));
1180 freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
1181 return -1;
1182 }
1183
1184 struct sockaddr_vm addr = { 0 };
1185
1186 addr.svm_family = AF_VSOCK;
1187 addr.svm_port = WINPR_ASSERTING_INT_CAST(typeof(addr.svm_port), port);
1188
1189 errno = 0;
1190 char* ptr = NULL;
1191 unsigned long val = strtoul(hostname, &ptr, 10);
1192 if (errno || (val > UINT32_MAX))
1193 {
1194 char ebuffer[256] = { 0 };
1195 WLog_ERR(TAG, "could not extract port from '%s', value=%ul, error=%s", hostname, val,
1196 winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
1197 close(sockfd);
1198 return -1;
1199 }
1200 addr.svm_cid = WINPR_ASSERTING_INT_CAST(typeof(addr.svm_cid), val);
1201 if (addr.svm_cid == 2)
1202 {
1203 addr.svm_flags = VMADDR_FLAG_TO_HOST;
1204 }
1205 if ((connect(sockfd, (struct sockaddr*)&addr, sizeof(struct sockaddr_vm))) == -1)
1206 {
1207 WLog_ERR(TAG, "failed to connect to %s", hostname);
1208 close(sockfd);
1209 return -1;
1210 }
1211 return sockfd;
1212#else
1213 WLog_ERR(TAG, "Compiled without AF_VSOCK, '%s' not supported", hostname);
1214 return -1;
1215#endif
1216}
1217
1218static void log_connection_address(const char* hostname, struct addrinfo* addr)
1219{
1220 WINPR_ASSERT(addr);
1221
1222 char* peerAddress =
1223 freerdp_tcp_address_to_string((const struct sockaddr_storage*)addr->ai_addr, NULL);
1224 if (peerAddress)
1225 WLog_DBG(TAG, "resolved %s: try to connect to %s", hostname, peerAddress);
1226 free(peerAddress);
1227}
1228
1229static int freerdp_host_connect(rdpContext* context, const char* hostname, int port, DWORD timeout)
1230{
1231 int sockfd = -1;
1232 struct addrinfo* addr = NULL;
1233 struct addrinfo* result = freerdp_tcp_resolve_host(hostname, port, 0);
1234
1235 if (!result)
1236 {
1237 freerdp_set_last_error_if_not(context, FREERDP_ERROR_DNS_NAME_NOT_FOUND);
1238 return -1;
1239 }
1240 freerdp_set_last_error_log(context, 0);
1241
1242 /* By default we take the first returned entry.
1243 * If PreferIPv6OverIPv4 = TRUE we reorder addresses by preference:
1244 * IPv6 addresses come first, then other addresses.
1245 */
1246 result = reorder_addrinfo_by_preference(context, result);
1247
1248 const int rc = get_next_addrinfo(context, result, &addr, FREERDP_ERROR_DNS_NAME_NOT_FOUND);
1249 if (rc < 0)
1250 goto fail;
1251
1252 do
1253 {
1254 sockfd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
1255 if (sockfd >= 0)
1256 {
1257 log_connection_address(hostname, addr);
1258
1259 if (!freerdp_tcp_connect_timeout(context, sockfd, addr->ai_addr, addr->ai_addrlen,
1260 timeout))
1261 {
1262 close(sockfd);
1263 sockfd = -1;
1264 }
1265 }
1266
1267 if (sockfd < 0)
1268 {
1269 const int lrc =
1270 get_next_addrinfo(context, addr->ai_next, &addr, FREERDP_ERROR_CONNECT_FAILED);
1271 if (lrc < 0)
1272 goto fail;
1273 }
1274 } while (sockfd < 0);
1275
1276fail:
1277 freeaddrinfo(result);
1278 return sockfd;
1279}
1280
1281int freerdp_tcp_default_connect(rdpContext* context, rdpSettings* settings, const char* hostname,
1282 int port, DWORD timeout)
1283{
1284 int sockfd = -1;
1285 BOOL ipcSocket = FALSE;
1286 BOOL useExternalDefinedSocket = FALSE;
1287
1288 if (!hostname)
1289 {
1290 freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
1291
1292 return -1;
1293 }
1294
1295 if (hostname[0] == '/')
1296 ipcSocket = TRUE;
1297
1298 if (hostname[0] == '|')
1299 useExternalDefinedSocket = TRUE;
1300
1301 const char* vsock = utils_is_vsock(hostname);
1302 if (ipcSocket)
1303 {
1304 sockfd = freerdp_uds_connect(hostname);
1305
1306 if (sockfd < 0)
1307 {
1308 freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
1309 return -1;
1310 }
1311 }
1312 else if (useExternalDefinedSocket)
1313 sockfd = port;
1314 else if (vsock)
1315 sockfd = freerdp_vsock_connect(context, vsock, port);
1316 else
1317 {
1318 if (!settings->GatewayEnabled)
1319 {
1320 if (!freerdp_tcp_is_hostname_resolvable(context, hostname) ||
1321 settings->RemoteAssistanceMode)
1322 {
1323 if (settings->TargetNetAddressCount > 0)
1324 {
1325 WINPR_ASSERT(port <= UINT16_MAX);
1326 sockfd = freerdp_tcp_connect_multi(
1327 context, settings->TargetNetAddresses, settings->TargetNetPorts,
1328 settings->TargetNetAddressCount, (UINT16)port, timeout);
1329 }
1330 }
1331 }
1332
1333 if (sockfd <= 0)
1334 sockfd = freerdp_host_connect(context, hostname, port, timeout);
1335 }
1336
1337 if (!vsock)
1338 {
1339 if (!freerdp_tcp_get_ip_address(settings, sockfd))
1340 {
1341 if (!useExternalDefinedSocket)
1342 close(sockfd);
1343
1344 freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
1345
1346 WLog_ERR(TAG, "Couldn't get socket ip address");
1347 return -1;
1348 }
1349 }
1350
1351 if (!ipcSocket && !useExternalDefinedSocket)
1352 {
1353 (void)freerdp_tcp_set_nodelay(WLog_Get(TAG), WLOG_ERROR, sockfd);
1354 }
1355
1356 /* receive buffer must be a least 32 K */
1357 UINT32 optval = 1;
1358 socklen_t optlen = sizeof(optval);
1359 if (getsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (void*)&optval, &optlen) == 0)
1360 {
1361 if (optval < (1024 * 32))
1362 {
1363 optval = 1024 * 32;
1364 optlen = sizeof(optval);
1365
1366 if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (void*)&optval, optlen) < 0)
1367 {
1368 close(sockfd);
1369
1370 freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
1371
1372 WLog_ERR(TAG, "unable to set receive buffer len");
1373 return -1;
1374 }
1375 }
1376 }
1377
1378 if (!ipcSocket && !useExternalDefinedSocket)
1379 {
1380 if (!freerdp_tcp_set_keep_alive_mode(settings, sockfd))
1381 {
1382 close(sockfd);
1383
1384 freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
1385
1386 WLog_ERR(TAG, "Couldn't set keep alive mode.");
1387 return -1;
1388 }
1389 }
1390
1391 if (WaitForSingleObject(utils_get_abort_event(context->rdp), 0) == WAIT_OBJECT_0)
1392 {
1393 close(sockfd);
1394 return -1;
1395 }
1396
1397 return sockfd;
1398}
1399
1400struct rdp_tcp_layer
1401{
1402 int sockfd;
1403 HANDLE hEvent;
1404};
1405typedef struct rdp_tcp_layer rdpTcpLayer;
1406
1407static int freerdp_tcp_layer_read(void* userContext, void* data, int bytes)
1408{
1409 if (!userContext)
1410 return -1;
1411 if (!data || !bytes)
1412 return 0;
1413
1414 rdpTcpLayer* tcpLayer = (rdpTcpLayer*)userContext;
1415
1416 (void)WSAResetEvent(tcpLayer->hEvent);
1417 const int status = _recv((SOCKET)tcpLayer->sockfd, data, bytes, 0);
1418
1419 if (status > 0)
1420 return status;
1421
1422 const int error = WSAGetLastError();
1423
1424 if ((error == WSAEWOULDBLOCK) || (error == WSAEINTR) || (error == WSAEINPROGRESS) ||
1425 (error == WSAEALREADY))
1426 errno = EAGAIN;
1427
1428 return status;
1429}
1430
1431static int freerdp_tcp_layer_write(void* userContext, const void* data, int bytes)
1432{
1433 if (!userContext)
1434 return -1;
1435 if (!data || !bytes)
1436 return 0;
1437
1438 rdpTcpLayer* tcpLayer = (rdpTcpLayer*)userContext;
1439
1440 const int status = _send((SOCKET)tcpLayer->sockfd, data, bytes, 0);
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 BOOL freerdp_tcp_layer_close(void* userContext)
1454{
1455 if (!userContext)
1456 return FALSE;
1457
1458 rdpTcpLayer* tcpLayer = (rdpTcpLayer*)userContext;
1459
1460 if (tcpLayer->sockfd >= 0)
1461 closesocket((SOCKET)tcpLayer->sockfd);
1462 if (tcpLayer->hEvent)
1463 (void)CloseHandle(tcpLayer->hEvent);
1464
1465 return TRUE;
1466}
1467
1468static BOOL freerdp_tcp_layer_wait(void* userContext, BOOL waitWrite, DWORD timeout)
1469{
1470 if (!userContext)
1471 return FALSE;
1472
1473 rdpTcpLayer* tcpLayer = (rdpTcpLayer*)userContext;
1474
1475 int status = -1;
1476 int sockfd = tcpLayer->sockfd;
1477#ifdef WINPR_HAVE_POLL_H
1478 struct pollfd pollset = { 0 };
1479 pollset.fd = sockfd;
1480 pollset.events = waitWrite ? POLLOUT : POLLIN;
1481
1482 do
1483 {
1484 status = poll(&pollset, 1, (int)timeout);
1485 } while ((status < 0) && (errno == EINTR));
1486
1487#else
1488 fd_set rset = { 0 };
1489 struct timeval tv = { 0 };
1490 FD_ZERO(&rset);
1491 FD_SET(sockfd, &rset);
1492
1493 if (timeout)
1494 {
1495 tv.tv_sec = timeout / 1000;
1496 tv.tv_usec = (timeout % 1000) * 1000;
1497 }
1498
1499 do
1500 {
1501 if (waitWrite)
1502 status = select(sockfd + 1, NULL, &rset, NULL, timeout ? &tv : NULL);
1503 else
1504 status = select(sockfd + 1, &rset, NULL, NULL, timeout ? &tv : NULL);
1505 } while ((status < 0) && (errno == EINTR));
1506
1507#endif
1508
1509 return status != 0;
1510}
1511
1512static HANDLE freerdp_tcp_layer_get_event(void* userContext)
1513{
1514 if (!userContext)
1515 return NULL;
1516
1517 rdpTcpLayer* tcpLayer = (rdpTcpLayer*)userContext;
1518
1519 return tcpLayer->hEvent;
1520}
1521
1522rdpTransportLayer* freerdp_tcp_connect_layer(rdpContext* context, const char* hostname, int port,
1523 DWORD timeout)
1524{
1525 WINPR_ASSERT(context);
1526
1527 const rdpSettings* settings = context->settings;
1528 WINPR_ASSERT(settings);
1529
1530 rdpTransportLayer* layer = NULL;
1531 rdpTcpLayer* tcpLayer = NULL;
1532
1533 int sockfd = freerdp_tcp_connect(context, hostname, port, timeout);
1534 if (sockfd < 0)
1535 goto fail;
1536 if (!freerdp_tcp_set_keep_alive_mode(settings, sockfd))
1537 goto fail;
1538
1539 layer = transport_layer_new(freerdp_get_transport(context), sizeof(rdpTcpLayer));
1540 if (!layer)
1541 goto fail;
1542
1543 layer->Read = freerdp_tcp_layer_read;
1544 layer->Write = freerdp_tcp_layer_write;
1545 layer->Close = freerdp_tcp_layer_close;
1546 layer->Wait = freerdp_tcp_layer_wait;
1547 layer->GetEvent = freerdp_tcp_layer_get_event;
1548
1549 tcpLayer = (rdpTcpLayer*)layer->userContext;
1550 WINPR_ASSERT(tcpLayer);
1551
1552 tcpLayer->sockfd = -1;
1553 tcpLayer->hEvent = WSACreateEvent();
1554 if (!tcpLayer->hEvent)
1555 goto fail;
1556
1557 /* WSAEventSelect automatically sets the socket in non-blocking mode */
1558 if (WSAEventSelect((SOCKET)sockfd, tcpLayer->hEvent, FD_READ | FD_ACCEPT | FD_CLOSE))
1559 {
1560 WLog_ERR(TAG, "WSAEventSelect returned 0x%08X", WSAGetLastError());
1561 goto fail;
1562 }
1563
1564 tcpLayer->sockfd = sockfd;
1565
1566 return layer;
1567
1568fail:
1569 if (sockfd >= 0)
1570 closesocket((SOCKET)sockfd);
1571 transport_layer_free(layer);
1572 return NULL;
1573}
1574
1575BOOL freerdp_tcp_set_nodelay(wLog* log, DWORD level, int sockfd)
1576{
1577 WINPR_ASSERT(log);
1578
1579 int type = -1;
1580 socklen_t typelen = sizeof(type);
1581 char* ptype = (char*)&type;
1582 const int rc = getsockopt(sockfd, SOL_SOCKET, SO_TYPE, ptype, &typelen);
1583 if (rc < 0)
1584 {
1585 char buffer[128] = { 0 };
1586 WLog_Print(log, level, "can't get SOL_SOCKET|SO_TYPE (%s)",
1587 winpr_strerror(errno, buffer, sizeof(buffer)));
1588 return FALSE;
1589 }
1590 else if (type == SOCK_STREAM)
1591 {
1592 int option_value = -1;
1593 const socklen_t option_len = sizeof(option_value);
1594 const int sr =
1595 setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (void*)&option_value, option_len);
1596 if (sr < 0)
1597 {
1598 /* local unix sockets don't have the TCP_NODELAY implemented, so don't make this
1599 * error fatal */
1600 char buffer[128] = { 0 };
1601 WLog_Print(log, level, "can't set TCP_NODELAY (%s)",
1602 winpr_strerror(errno, buffer, sizeof(buffer)));
1603 return FALSE;
1604 }
1605 }
1606 else
1607 {
1608 WLog_Print(log, level, "Socket SOL_SOCKET|SO_TYPE %d unsupported", type);
1609 return FALSE;
1610 }
1611 return TRUE;
1612}
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