Coverage Report

Created: 2025-07-01 06:46

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