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