Coverage Report

Created: 2026-07-16 07:14

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