FreeRDP
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Modules Pages
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 1;
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 char* freerdp_tcp_get_ip_address(int sockfd, BOOL* pIPv6)
708{
709 struct sockaddr_storage saddr = { 0 };
710 socklen_t length = sizeof(struct sockaddr_storage);
711
712 if (getsockname(sockfd, (struct sockaddr*)&saddr, &length) != 0)
713 {
714 return NULL;
715 }
716
717 return freerdp_tcp_address_to_string(&saddr, pIPv6);
718}
719
720char* freerdp_tcp_get_peer_address(SOCKET sockfd)
721{
722 struct sockaddr_storage saddr = { 0 };
723 socklen_t length = sizeof(struct sockaddr_storage);
724
725 if (getpeername((int)sockfd, (struct sockaddr*)&saddr, &length) != 0)
726 {
727 return NULL;
728 }
729
730 return freerdp_tcp_address_to_string(&saddr, NULL);
731}
732
733static int freerdp_uds_connect(const char* path)
734{
735#ifndef _WIN32
736 int status = 0;
737 int sockfd = 0;
738 struct sockaddr_un addr = { 0 };
739 sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
740
741 if (sockfd == -1)
742 {
743 WLog_ERR(TAG, "socket");
744 return -1;
745 }
746
747 addr.sun_family = AF_UNIX;
748 strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
749 status = connect(sockfd, (struct sockaddr*)&addr, sizeof(addr));
750
751 if (status < 0)
752 {
753 WLog_ERR(TAG, "connect");
754 close(sockfd);
755 return -1;
756 }
757
758 return sockfd;
759#else /* ifndef _WIN32 */
760 return -1;
761#endif
762}
763
764struct addrinfo* freerdp_tcp_resolve_host(const char* hostname, int port, int ai_flags)
765{
766 char* service = NULL;
767 char port_str[16];
768 int status = 0;
769 struct addrinfo hints = { 0 };
770 struct addrinfo* result = NULL;
771 hints.ai_family = AF_UNSPEC;
772 hints.ai_socktype = SOCK_STREAM;
773 hints.ai_flags = ai_flags;
774
775 if (port >= 0)
776 {
777 (void)sprintf_s(port_str, sizeof(port_str) - 1, "%d", port);
778 service = port_str;
779 }
780
781 status = getaddrinfo(hostname, service, &hints, &result);
782
783 if (status)
784 return NULL;
785
786 return result;
787}
788
789static BOOL freerdp_tcp_is_hostname_resolvable(rdpContext* context, const char* hostname)
790{
791 struct addrinfo* result = freerdp_tcp_resolve_host(hostname, -1, 0);
792
793 if (!result)
794 {
795 freerdp_set_last_error_if_not(context, FREERDP_ERROR_DNS_NAME_NOT_FOUND);
796
797 return FALSE;
798 }
799
800 freerdp_set_last_error_log(context, 0);
801 freeaddrinfo(result);
802 return TRUE;
803}
804
805static BOOL freerdp_tcp_connect_timeout(rdpContext* context, int sockfd, struct sockaddr* addr,
806 socklen_t addrlen, UINT32 timeout)
807{
808 BOOL rc = FALSE;
809 HANDLE handles[2] = { 0 };
810 DWORD count = 0;
811 u_long arg = 0;
812 DWORD tout = (timeout > 0) ? timeout : INFINITE;
813
814 handles[count] = CreateEvent(NULL, TRUE, FALSE, NULL);
815
816 if (!handles[count])
817 return FALSE;
818
819 const int wsastatus = WSAEventSelect((SOCKET)sockfd, handles[count++],
820 FD_READ | FD_WRITE | FD_CONNECT | FD_CLOSE);
821
822 if (wsastatus < 0)
823 {
824 WLog_ERR(TAG, "WSAEventSelect failed with %d", WSAGetLastError());
825 goto fail;
826 }
827
828 handles[count++] = utils_get_abort_event(context->rdp);
829 const int constatus = _connect((SOCKET)sockfd, addr, WINPR_ASSERTING_INT_CAST(int, addrlen));
830
831 if (constatus < 0)
832 {
833 const int estatus = WSAGetLastError();
834
835 switch (estatus)
836 {
837 case WSAEINPROGRESS:
838 case WSAEWOULDBLOCK:
839 break;
840
841 default:
842 goto fail;
843 }
844 }
845
846 const DWORD wstatus = WaitForMultipleObjects(count, handles, FALSE, tout);
847
848 if (WAIT_OBJECT_0 != wstatus)
849 goto fail;
850
851 const SSIZE_T res = recv(sockfd, NULL, 0, 0);
852
853 if (res == SOCKET_ERROR)
854 {
855 if (WSAGetLastError() == WSAECONNRESET)
856 goto fail;
857 }
858
859 const int status = WSAEventSelect((SOCKET)sockfd, handles[0], 0);
860
861 if (status < 0)
862 {
863 WLog_ERR(TAG, "WSAEventSelect failed with %d", WSAGetLastError());
864 goto fail;
865 }
866
867 if (_ioctlsocket((SOCKET)sockfd, FIONBIO, &arg) != 0)
868 goto fail;
869
870 rc = TRUE;
871fail:
872 (void)CloseHandle(handles[0]);
873 return rc;
874}
875
876typedef struct
877{
878 SOCKET s;
879 struct addrinfo* addr;
880 struct addrinfo* result;
881} t_peer;
882
883static void peer_free(t_peer* peer)
884{
885 if (peer->s != INVALID_SOCKET)
886 closesocket(peer->s);
887
888 freeaddrinfo(peer->addr);
889 memset(peer, 0, sizeof(t_peer));
890 peer->s = INVALID_SOCKET;
891}
892
893static int freerdp_tcp_connect_multi(rdpContext* context, char** hostnames, const UINT32* ports,
894 UINT32 count, UINT16 port, WINPR_ATTR_UNUSED UINT32 timeout)
895{
896 UINT32 sindex = count;
897 SOCKET sockfd = INVALID_SOCKET;
898 struct addrinfo* addr = NULL;
899 struct addrinfo* result = NULL;
900
901 HANDLE* events = (HANDLE*)calloc(count + 1, sizeof(HANDLE));
902 t_peer* peers = (t_peer*)calloc(count, sizeof(t_peer));
903
904 if (!peers || !events || (count < 1))
905 {
906 free(peers);
907 free((void*)events);
908 return -1;
909 }
910
911 for (UINT32 index = 0; index < count; index++)
912 {
913 int curPort = port;
914
915 if (ports)
916 curPort = WINPR_ASSERTING_INT_CAST(int, ports[index]);
917
918 result = freerdp_tcp_resolve_host(hostnames[index], curPort, 0);
919
920 if (!result)
921 continue;
922
923 addr = result;
924
925 if ((addr->ai_family == AF_INET6) && (addr->ai_next != 0))
926 {
927 while ((addr = addr->ai_next))
928 {
929 if (addr->ai_family == AF_INET)
930 break;
931 }
932
933 if (!addr)
934 addr = result;
935 }
936
937 peers[index].s = _socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
938
939 if (peers[index].s == INVALID_SOCKET)
940 {
941 freeaddrinfo(result);
942 continue;
943 }
944
945 peers[index].addr = addr;
946 peers[index].result = result;
947 }
948
949 for (UINT32 index = 0; index < count; index++)
950 {
951 sockfd = peers[index].s;
952 addr = peers[index].addr;
953
954 if ((sockfd == INVALID_SOCKET) || (!addr))
955 continue;
956
957 /* blocking tcp connect */
958 const int rc =
959 _connect(sockfd, addr->ai_addr, WINPR_ASSERTING_INT_CAST(int, addr->ai_addrlen));
960
961 if (rc >= 0)
962 {
963 /* connection success */
964 sindex = index;
965 break;
966 }
967 }
968
969 if (sindex < count)
970 {
971 sockfd = peers[sindex].s;
972 peers[sindex].s = INVALID_SOCKET;
973 }
974 else
975 freerdp_set_last_error_log(context, FREERDP_ERROR_CONNECT_CANCELLED);
976
977 for (UINT32 index = 0; index < count; index++)
978 peer_free(&peers[index]);
979
980 free(peers);
981 free((void*)events);
982 return (int)sockfd;
983}
984
985BOOL freerdp_tcp_set_keep_alive_mode(const rdpSettings* settings, int sockfd)
986{
987 const BOOL keepalive = (freerdp_settings_get_bool(settings, FreeRDP_TcpKeepAlive));
988 UINT32 optval = 0;
989 socklen_t optlen = 0;
990 optval = keepalive ? 1 : 0;
991 optlen = sizeof(optval);
992
993 if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (void*)&optval, optlen) < 0)
994 {
995 WLog_WARN(TAG, "setsockopt() SOL_SOCKET, SO_KEEPALIVE");
996 }
997
998#ifndef _WIN32
999#ifdef TCP_KEEPIDLE
1000 optval = keepalive ? freerdp_settings_get_uint32(settings, FreeRDP_TcpKeepAliveDelay) : 0;
1001 optlen = sizeof(optval);
1002
1003 if (setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE, (void*)&optval, optlen) < 0)
1004 {
1005 WLog_WARN(TAG, "setsockopt() IPPROTO_TCP, TCP_KEEPIDLE");
1006 }
1007
1008#endif
1009#ifndef SOL_TCP
1010 /* "tcp" from /etc/protocols as getprotobyname(3C) */
1011#define SOL_TCP 6
1012#endif
1013#ifdef TCP_KEEPCNT
1014 optval = keepalive ? freerdp_settings_get_uint32(settings, FreeRDP_TcpKeepAliveRetries) : 0;
1015 optlen = sizeof(optval);
1016
1017 if (setsockopt(sockfd, SOL_TCP, TCP_KEEPCNT, (void*)&optval, optlen) < 0)
1018 {
1019 WLog_WARN(TAG, "setsockopt() SOL_TCP, TCP_KEEPCNT");
1020 }
1021
1022#endif
1023#ifdef TCP_KEEPINTVL
1024 optval = keepalive ? freerdp_settings_get_uint32(settings, FreeRDP_TcpKeepAliveInterval) : 0;
1025 optlen = sizeof(optval);
1026
1027 if (setsockopt(sockfd, SOL_TCP, TCP_KEEPINTVL, (void*)&optval, optlen) < 0)
1028 {
1029 WLog_WARN(TAG, "setsockopt() SOL_TCP, TCP_KEEPINTVL");
1030 }
1031
1032#endif
1033#endif
1034#if defined(__MACOSX__) || defined(__IOS__)
1035 optval = 1;
1036 optlen = sizeof(optval);
1037
1038 if (setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void*)&optval, optlen) < 0)
1039 {
1040 WLog_WARN(TAG, "setsockopt() SOL_SOCKET, SO_NOSIGPIPE");
1041 }
1042
1043#endif
1044#ifdef TCP_USER_TIMEOUT
1045 optval = freerdp_settings_get_uint32(settings, FreeRDP_TcpAckTimeout);
1046 optlen = sizeof(optval);
1047
1048 if (setsockopt(sockfd, SOL_TCP, TCP_USER_TIMEOUT, (void*)&optval, optlen) < 0)
1049 {
1050 WLog_WARN(TAG, "setsockopt() SOL_TCP, TCP_USER_TIMEOUT");
1051 }
1052
1053#endif
1054 return TRUE;
1055}
1056
1057int freerdp_tcp_connect(rdpContext* context, const char* hostname, int port, DWORD timeout)
1058{
1059 rdpTransport* transport = NULL;
1060 if (!context || !context->rdp)
1061 return -1;
1062 transport = context->rdp->transport;
1063 if (!transport)
1064 return -1;
1065 return transport_tcp_connect(context->rdp->transport, hostname, port, timeout);
1066}
1067
1068static int get_next_addrinfo(rdpContext* context, struct addrinfo* input, struct addrinfo** result,
1069 UINT32 errorCode)
1070{
1071 WINPR_ASSERT(context);
1072 WINPR_ASSERT(result);
1073
1074 struct addrinfo* addr = input;
1075 if (!addr)
1076 goto fail;
1077
1078 if (freerdp_settings_get_bool(context->settings, FreeRDP_PreferIPv6OverIPv4))
1079 {
1080 while (addr && (addr->ai_family != AF_INET6))
1081 addr = addr->ai_next;
1082 if (!addr)
1083 addr = input;
1084 }
1085
1086 /* We want to force IPvX, abort if not detected */
1087 const UINT32 IPvX = freerdp_settings_get_uint32(context->settings, FreeRDP_ForceIPvX);
1088 switch (IPvX)
1089 {
1090 case 4:
1091 case 6:
1092 {
1093 const int family = (IPvX == 4) ? AF_INET : AF_INET6;
1094 while (addr && (addr->ai_family != family))
1095 addr = addr->ai_next;
1096 }
1097 break;
1098 default:
1099 break;
1100 }
1101
1102 if (!addr)
1103 goto fail;
1104
1105 *result = addr;
1106 return 0;
1107
1108fail:
1109 freerdp_set_last_error_if_not(context, errorCode);
1110 freeaddrinfo(input);
1111 return -1;
1112}
1113
1114int freerdp_tcp_default_connect(rdpContext* context, rdpSettings* settings, const char* hostname,
1115 int port, DWORD timeout)
1116{
1117 int sockfd = 0;
1118 UINT32 optval = 0;
1119 socklen_t optlen = 0;
1120 BOOL ipcSocket = FALSE;
1121 BOOL useExternalDefinedSocket = FALSE;
1122
1123 if (!hostname)
1124 {
1125 freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
1126
1127 return -1;
1128 }
1129
1130 if (hostname[0] == '/')
1131 ipcSocket = TRUE;
1132
1133 if (hostname[0] == '|')
1134 useExternalDefinedSocket = TRUE;
1135
1136 const char* vsock = utils_is_vsock(hostname);
1137 if (ipcSocket)
1138 {
1139 sockfd = freerdp_uds_connect(hostname);
1140
1141 if (sockfd < 0)
1142 {
1143 freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
1144 return -1;
1145 }
1146 }
1147 else if (useExternalDefinedSocket)
1148 sockfd = port;
1149 else if (vsock)
1150 {
1151#if defined(HAVE_AF_VSOCK_H)
1152 hostname = vsock;
1153 sockfd = socket(AF_VSOCK, SOCK_STREAM, 0);
1154 if (sockfd < 0)
1155 {
1156 char buffer[256] = { 0 };
1157 WLog_WARN(TAG, "socket(AF_VSOCK, SOCK_STREAM, 0) failed with %s [%d]",
1158 winpr_strerror(errno, buffer, sizeof(buffer)));
1159 freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
1160 return -1;
1161 }
1162
1163 struct sockaddr_vm addr = { 0 };
1164
1165 addr.svm_family = AF_VSOCK;
1166 addr.svm_port = WINPR_ASSERTING_INT_CAST(typeof(addr.svm_port), port);
1167
1168 errno = 0;
1169 char* ptr = NULL;
1170 unsigned long val = strtoul(hostname, &ptr, 10);
1171 if (errno || (val > UINT32_MAX))
1172 {
1173 char ebuffer[256] = { 0 };
1174 WLog_ERR(TAG, "could not extract port from '%s', value=%ul, error=%s", hostname, val,
1175 winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
1176 return -1;
1177 }
1178 addr.svm_cid = WINPR_ASSERTING_INT_CAST(typeof(addr.svm_cid), val);
1179 if (addr.svm_cid == 2)
1180 {
1181 addr.svm_flags = VMADDR_FLAG_TO_HOST;
1182 }
1183 if ((connect(sockfd, (struct sockaddr*)&addr, sizeof(struct sockaddr_vm))) == -1)
1184 {
1185 WLog_ERR(TAG, "failed to connect to %s", hostname);
1186 return -1;
1187 }
1188#else
1189 WLog_ERR(TAG, "Compiled without AF_VSOCK, '%s' not supported", hostname);
1190 return -1;
1191#endif
1192 }
1193 else
1194 {
1195 sockfd = -1;
1196
1197 if (!settings->GatewayEnabled)
1198 {
1199 if (!freerdp_tcp_is_hostname_resolvable(context, hostname) ||
1200 settings->RemoteAssistanceMode)
1201 {
1202 if (settings->TargetNetAddressCount > 0)
1203 {
1204 WINPR_ASSERT(port <= UINT16_MAX);
1205 sockfd = freerdp_tcp_connect_multi(
1206 context, settings->TargetNetAddresses, settings->TargetNetPorts,
1207 settings->TargetNetAddressCount, (UINT16)port, timeout);
1208 }
1209 }
1210 }
1211
1212 if (sockfd <= 0)
1213 {
1214 char* peerAddress = NULL;
1215 struct addrinfo* addr = NULL;
1216 struct addrinfo* result = NULL;
1217
1218 result = freerdp_tcp_resolve_host(hostname, port, 0);
1219
1220 if (!result)
1221 {
1222 freerdp_set_last_error_if_not(context, FREERDP_ERROR_DNS_NAME_NOT_FOUND);
1223
1224 return -1;
1225 }
1226 freerdp_set_last_error_log(context, 0);
1227
1228 /* By default we take the first returned entry.
1229 *
1230 * If PreferIPv6OverIPv4 = TRUE we force to IPv6 if there
1231 * is such an address available, but fall back to first if not found
1232 */
1233 const int rc =
1234 get_next_addrinfo(context, result, &addr, FREERDP_ERROR_DNS_NAME_NOT_FOUND);
1235 if (rc < 0)
1236 return rc;
1237
1238 do
1239 {
1240 sockfd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
1241 if (sockfd < 0)
1242 {
1243 const int lrc = get_next_addrinfo(context, addr->ai_next, &addr,
1244 FREERDP_ERROR_CONNECT_FAILED);
1245 if (lrc < 0)
1246 return lrc;
1247 }
1248 } while (sockfd < 0);
1249
1250 if ((peerAddress = freerdp_tcp_address_to_string(
1251 (const struct sockaddr_storage*)addr->ai_addr, NULL)) != NULL)
1252 {
1253 WLog_DBG(TAG, "connecting to peer %s", peerAddress);
1254 free(peerAddress);
1255 }
1256
1257 if (!freerdp_tcp_connect_timeout(context, sockfd, addr->ai_addr, addr->ai_addrlen,
1258 timeout))
1259 {
1260 freeaddrinfo(result);
1261 close(sockfd);
1262
1263 freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
1264
1265 WLog_ERR(TAG, "failed to connect to %s", hostname);
1266 return -1;
1267 }
1268
1269 freeaddrinfo(result);
1270 }
1271 }
1272
1273 if (!vsock)
1274 {
1275 free(settings->ClientAddress);
1276 settings->ClientAddress = freerdp_tcp_get_ip_address(sockfd, &settings->IPv6Enabled);
1277
1278 if (!settings->ClientAddress)
1279 {
1280 if (!useExternalDefinedSocket)
1281 close(sockfd);
1282
1283 freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
1284
1285 WLog_ERR(TAG, "Couldn't get socket ip address");
1286 return -1;
1287 }
1288 }
1289
1290 optval = 1;
1291 optlen = sizeof(optval);
1292
1293 if (!ipcSocket && !useExternalDefinedSocket)
1294 {
1295 if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (void*)&optval, optlen) < 0)
1296 WLog_ERR(TAG, "unable to set TCP_NODELAY");
1297 }
1298
1299 /* receive buffer must be a least 32 K */
1300 if (getsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (void*)&optval, &optlen) == 0)
1301 {
1302 if (optval < (1024 * 32))
1303 {
1304 optval = 1024 * 32;
1305 optlen = sizeof(optval);
1306
1307 if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (void*)&optval, optlen) < 0)
1308 {
1309 close(sockfd);
1310
1311 freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
1312
1313 WLog_ERR(TAG, "unable to set receive buffer len");
1314 return -1;
1315 }
1316 }
1317 }
1318
1319 if (!ipcSocket && !useExternalDefinedSocket)
1320 {
1321 if (!freerdp_tcp_set_keep_alive_mode(settings, sockfd))
1322 {
1323 close(sockfd);
1324
1325 freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
1326
1327 WLog_ERR(TAG, "Couldn't set keep alive mode.");
1328 return -1;
1329 }
1330 }
1331
1332 if (WaitForSingleObject(utils_get_abort_event(context->rdp), 0) == WAIT_OBJECT_0)
1333 {
1334 close(sockfd);
1335 return -1;
1336 }
1337
1338 return sockfd;
1339}
1340
1341struct rdp_tcp_layer
1342{
1343 int sockfd;
1344 HANDLE hEvent;
1345};
1346typedef struct rdp_tcp_layer rdpTcpLayer;
1347
1348static int freerdp_tcp_layer_read(void* userContext, void* data, int bytes)
1349{
1350 if (!userContext)
1351 return -1;
1352 if (!data || !bytes)
1353 return 0;
1354
1355 rdpTcpLayer* tcpLayer = (rdpTcpLayer*)userContext;
1356
1357 int error = 0;
1358 int status = 0;
1359
1360 (void)WSAResetEvent(tcpLayer->hEvent);
1361 status = _recv((SOCKET)tcpLayer->sockfd, data, bytes, 0);
1362
1363 if (status > 0)
1364 return status;
1365
1366 if (status == 0)
1367 return -1; /* socket closed */
1368
1369 error = WSAGetLastError();
1370
1371 if ((error == WSAEWOULDBLOCK) || (error == WSAEINTR) || (error == WSAEINPROGRESS) ||
1372 (error == WSAEALREADY))
1373 {
1374 status = 0;
1375 }
1376 else
1377 {
1378 status = -1;
1379 }
1380
1381 return status;
1382}
1383
1384static int freerdp_tcp_layer_write(void* userContext, const void* data, int bytes)
1385{
1386 if (!userContext)
1387 return -1;
1388 if (!data || !bytes)
1389 return 0;
1390
1391 rdpTcpLayer* tcpLayer = (rdpTcpLayer*)userContext;
1392
1393 int error = 0;
1394 int status = 0;
1395
1396 status = _send((SOCKET)tcpLayer->sockfd, data, bytes, 0);
1397
1398 if (status <= 0)
1399 {
1400 error = WSAGetLastError();
1401
1402 if ((error == WSAEWOULDBLOCK) || (error == WSAEINTR) || (error == WSAEINPROGRESS) ||
1403 (error == WSAEALREADY))
1404 {
1405 status = 0;
1406 }
1407 else
1408 {
1409 status = -1;
1410 }
1411 }
1412
1413 return status;
1414}
1415
1416static BOOL freerdp_tcp_layer_close(void* userContext)
1417{
1418 if (!userContext)
1419 return FALSE;
1420
1421 rdpTcpLayer* tcpLayer = (rdpTcpLayer*)userContext;
1422
1423 if (tcpLayer->sockfd >= 0)
1424 closesocket((SOCKET)tcpLayer->sockfd);
1425 if (tcpLayer->hEvent)
1426 (void)CloseHandle(tcpLayer->hEvent);
1427
1428 return TRUE;
1429}
1430
1431static BOOL freerdp_tcp_layer_wait(void* userContext, BOOL waitWrite, DWORD timeout)
1432{
1433 if (!userContext)
1434 return FALSE;
1435
1436 rdpTcpLayer* tcpLayer = (rdpTcpLayer*)userContext;
1437
1438 int status = -1;
1439 int sockfd = tcpLayer->sockfd;
1440#ifdef WINPR_HAVE_POLL_H
1441 struct pollfd pollset = { 0 };
1442 pollset.fd = sockfd;
1443 pollset.events = waitWrite ? POLLOUT : POLLIN;
1444
1445 do
1446 {
1447 status = poll(&pollset, 1, (int)timeout);
1448 } while ((status < 0) && (errno == EINTR));
1449
1450#else
1451 fd_set rset = { 0 };
1452 struct timeval tv = { 0 };
1453 FD_ZERO(&rset);
1454 FD_SET(sockfd, &rset);
1455
1456 if (timeout)
1457 {
1458 tv.tv_sec = timeout / 1000;
1459 tv.tv_usec = (timeout % 1000) * 1000;
1460 }
1461
1462 do
1463 {
1464 if (waitWrite)
1465 status = select(sockfd + 1, NULL, &rset, NULL, timeout ? &tv : NULL);
1466 else
1467 status = select(sockfd + 1, &rset, NULL, NULL, timeout ? &tv : NULL);
1468 } while ((status < 0) && (errno == EINTR));
1469
1470#endif
1471
1472 return status != 0;
1473}
1474
1475static HANDLE freerdp_tcp_layer_get_event(void* userContext)
1476{
1477 if (!userContext)
1478 return NULL;
1479
1480 rdpTcpLayer* tcpLayer = (rdpTcpLayer*)userContext;
1481
1482 return tcpLayer->hEvent;
1483}
1484
1485rdpTransportLayer* freerdp_tcp_connect_layer(rdpContext* context, const char* hostname, int port,
1486 DWORD timeout)
1487{
1488 WINPR_ASSERT(context);
1489
1490 const rdpSettings* settings = context->settings;
1491 WINPR_ASSERT(settings);
1492
1493 rdpTransportLayer* layer = NULL;
1494 rdpTcpLayer* tcpLayer = NULL;
1495
1496 int sockfd = freerdp_tcp_connect(context, hostname, port, timeout);
1497 if (sockfd < 0)
1498 goto fail;
1499 if (!freerdp_tcp_set_keep_alive_mode(settings, sockfd))
1500 goto fail;
1501
1502 layer = transport_layer_new(freerdp_get_transport(context), sizeof(rdpTcpLayer));
1503 if (!layer)
1504 goto fail;
1505
1506 layer->Read = freerdp_tcp_layer_read;
1507 layer->Write = freerdp_tcp_layer_write;
1508 layer->Close = freerdp_tcp_layer_close;
1509 layer->Wait = freerdp_tcp_layer_wait;
1510 layer->GetEvent = freerdp_tcp_layer_get_event;
1511
1512 tcpLayer = (rdpTcpLayer*)layer->userContext;
1513 WINPR_ASSERT(tcpLayer);
1514
1515 tcpLayer->sockfd = -1;
1516 tcpLayer->hEvent = WSACreateEvent();
1517 if (!tcpLayer->hEvent)
1518 goto fail;
1519
1520 /* WSAEventSelect automatically sets the socket in non-blocking mode */
1521 if (WSAEventSelect((SOCKET)sockfd, tcpLayer->hEvent, FD_READ | FD_ACCEPT | FD_CLOSE))
1522 {
1523 WLog_ERR(TAG, "WSAEventSelect returned 0x%08X", WSAGetLastError());
1524 goto fail;
1525 }
1526
1527 tcpLayer->sockfd = sockfd;
1528
1529 return layer;
1530
1531fail:
1532 if (sockfd >= 0)
1533 closesocket((SOCKET)sockfd);
1534 transport_layer_free(layer);
1535 return NULL;
1536}
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_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