Coverage Report

Created: 2025-10-10 06:31

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PROJ/curl/lib/socketpair.c
Line
Count
Source
1
/***************************************************************************
2
 *                                  _   _ ____  _
3
 *  Project                     ___| | | |  _ \| |
4
 *                             / __| | | | |_) | |
5
 *                            | (__| |_| |  _ <| |___
6
 *                             \___|\___/|_| \_\_____|
7
 *
8
 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
9
 *
10
 * This software is licensed as described in the file COPYING, which
11
 * you should have received as part of this distribution. The terms
12
 * are also available at https://curl.se/docs/copyright.html.
13
 *
14
 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15
 * copies of the Software, and permit persons to whom the Software is
16
 * furnished to do so, under the terms of the COPYING file.
17
 *
18
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19
 * KIND, either express or implied.
20
 *
21
 * SPDX-License-Identifier: curl
22
 *
23
 ***************************************************************************/
24
25
#include "curl_setup.h"
26
#include "socketpair.h"
27
#include "urldata.h"
28
#include "rand.h"
29
30
#ifdef USE_EVENTFD
31
32
#include <sys/eventfd.h>
33
34
int Curl_eventfd(curl_socket_t socks[2], bool nonblocking)
35
0
{
36
0
  int efd = eventfd(0, nonblocking ? EFD_CLOEXEC | EFD_NONBLOCK : EFD_CLOEXEC);
37
0
  if(efd == -1) {
38
0
    socks[0] = socks[1] = CURL_SOCKET_BAD;
39
0
    return -1;
40
0
  }
41
0
  socks[0] = socks[1] = efd;
42
0
  return 0;
43
0
}
44
45
#elif defined(HAVE_PIPE)
46
47
#ifdef HAVE_FCNTL
48
#include <fcntl.h>
49
#endif
50
51
int Curl_pipe(curl_socket_t socks[2], bool nonblocking)
52
{
53
#ifdef HAVE_PIPE2
54
  int flags = nonblocking ? O_NONBLOCK | O_CLOEXEC : O_CLOEXEC;
55
  if(pipe2(socks, flags))
56
    return -1;
57
#else
58
  if(pipe(socks))
59
    return -1;
60
#ifdef HAVE_FCNTL
61
  if(fcntl(socks[0], F_SETFD, FD_CLOEXEC) ||
62
     fcntl(socks[1], F_SETFD, FD_CLOEXEC)) {
63
    close(socks[0]);
64
    close(socks[1]);
65
    socks[0] = socks[1] = CURL_SOCKET_BAD;
66
    return -1;
67
  }
68
#endif
69
  if(nonblocking) {
70
    if(curlx_nonblock(socks[0], TRUE) < 0 ||
71
       curlx_nonblock(socks[1], TRUE) < 0) {
72
      close(socks[0]);
73
      close(socks[1]);
74
      socks[0] = socks[1] = CURL_SOCKET_BAD;
75
      return -1;
76
    }
77
  }
78
#endif
79
80
  return 0;
81
}
82
83
#endif /* USE_EVENTFD */
84
85
#ifndef CURL_DISABLE_SOCKETPAIR
86
#ifdef HAVE_SOCKETPAIR
87
#ifdef USE_SOCKETPAIR
88
int Curl_socketpair(int domain, int type, int protocol,
89
                    curl_socket_t socks[2], bool nonblocking)
90
{
91
#ifdef SOCK_NONBLOCK
92
  type = nonblocking ? type | SOCK_NONBLOCK : type;
93
#endif
94
  if(CURL_SOCKETPAIR(domain, type, protocol, socks))
95
    return -1;
96
#ifndef SOCK_NONBLOCK
97
  if(nonblocking) {
98
    if(curlx_nonblock(socks[0], TRUE) < 0 ||
99
       curlx_nonblock(socks[1], TRUE) < 0) {
100
      close(socks[0]);
101
      close(socks[1]);
102
      return -1;
103
    }
104
  }
105
#endif
106
  return 0;
107
}
108
#endif /* USE_SOCKETPAIR */
109
#else /* !HAVE_SOCKETPAIR */
110
#ifdef _WIN32
111
/*
112
 * This is a socketpair() implementation for Windows.
113
 */
114
#include <string.h>
115
#ifdef HAVE_IO_H
116
#include <io.h>
117
#endif
118
#else
119
#ifdef HAVE_NETDB_H
120
#include <netdb.h>
121
#endif
122
#ifdef HAVE_NETINET_IN_H
123
#include <netinet/in.h> /* IPPROTO_TCP */
124
#endif
125
#ifdef HAVE_ARPA_INET_H
126
#include <arpa/inet.h>
127
#endif
128
#ifndef INADDR_LOOPBACK
129
#define INADDR_LOOPBACK 0x7f000001
130
#endif /* !INADDR_LOOPBACK */
131
#endif /* !_WIN32 */
132
133
#include "curlx/nonblock.h" /* for curlx_nonblock */
134
#include "curlx/timeval.h"  /* needed before select.h */
135
#include "select.h"   /* for Curl_poll */
136
137
/* The last 2 #include files should be in this order */
138
#include "curl_memory.h"
139
#include "memdebug.h"
140
141
int Curl_socketpair(int domain, int type, int protocol,
142
                    curl_socket_t socks[2], bool nonblocking)
143
{
144
  union {
145
    struct sockaddr_in inaddr;
146
    struct sockaddr addr;
147
  } a;
148
  curl_socket_t listener;
149
  curl_socklen_t addrlen = sizeof(a.inaddr);
150
  int reuse = 1;
151
  struct pollfd pfd[1];
152
  (void)domain;
153
  (void)type;
154
  (void)protocol;
155
156
  listener = CURL_SOCKET(AF_INET, SOCK_STREAM, IPPROTO_TCP);
157
  if(listener == CURL_SOCKET_BAD)
158
    return -1;
159
160
  memset(&a, 0, sizeof(a));
161
  a.inaddr.sin_family = AF_INET;
162
  a.inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
163
  a.inaddr.sin_port = 0;
164
165
  socks[0] = socks[1] = CURL_SOCKET_BAD;
166
167
#if defined(_WIN32) || defined(__CYGWIN__)
168
  /* do not set SO_REUSEADDR on Windows */
169
  (void)reuse;
170
#ifdef SO_EXCLUSIVEADDRUSE
171
  {
172
    int exclusive = 1;
173
    if(setsockopt(listener, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
174
                  (char *)&exclusive, (curl_socklen_t)sizeof(exclusive)) == -1)
175
      goto error;
176
  }
177
#endif
178
#else
179
  if(setsockopt(listener, SOL_SOCKET, SO_REUSEADDR,
180
                (char *)&reuse, (curl_socklen_t)sizeof(reuse)) == -1)
181
    goto error;
182
#endif
183
  if(bind(listener, &a.addr, sizeof(a.inaddr)) == -1)
184
    goto error;
185
  if(getsockname(listener, &a.addr, &addrlen) == -1 ||
186
     addrlen < (int)sizeof(a.inaddr))
187
    goto error;
188
  if(listen(listener, 1) == -1)
189
    goto error;
190
  socks[0] = CURL_SOCKET(AF_INET, SOCK_STREAM, 0);
191
  if(socks[0] == CURL_SOCKET_BAD)
192
    goto error;
193
  if(connect(socks[0], &a.addr, sizeof(a.inaddr)) == -1)
194
    goto error;
195
196
  /* use non-blocking accept to make sure we do not block forever */
197
  if(curlx_nonblock(listener, TRUE) < 0)
198
    goto error;
199
  pfd[0].fd = listener;
200
  pfd[0].events = POLLIN;
201
  pfd[0].revents = 0;
202
  (void)Curl_poll(pfd, 1, 1000); /* one second */
203
  socks[1] = CURL_ACCEPT(listener, NULL, NULL);
204
  if(socks[1] == CURL_SOCKET_BAD)
205
    goto error;
206
  else {
207
    struct curltime start = curlx_now();
208
    char rnd[9];
209
    char check[sizeof(rnd)];
210
    char *p = &check[0];
211
    size_t s = sizeof(check);
212
213
    if(Curl_rand(NULL, (unsigned char *)rnd, sizeof(rnd)))
214
      goto error;
215
216
    /* write data to the socket */
217
    swrite(socks[0], rnd, sizeof(rnd));
218
    /* verify that we read the correct data */
219
    do {
220
      ssize_t nread;
221
222
      pfd[0].fd = socks[1];
223
      pfd[0].events = POLLIN;
224
      pfd[0].revents = 0;
225
      (void)Curl_poll(pfd, 1, 1000); /* one second */
226
227
      nread = sread(socks[1], p, s);
228
      if(nread == -1) {
229
        int sockerr = SOCKERRNO;
230
        /* Do not block forever */
231
        if(curlx_timediff(curlx_now(), start) > (60 * 1000))
232
          goto error;
233
        if(
234
#ifdef USE_WINSOCK
235
          /* This is how Windows does it */
236
          (SOCKEWOULDBLOCK == sockerr)
237
#else
238
          /* errno may be EWOULDBLOCK or on some systems EAGAIN when it
239
             returned due to its inability to send off data without
240
             blocking. We therefore treat both error codes the same here */
241
          (SOCKEWOULDBLOCK == sockerr) || (EAGAIN == sockerr) ||
242
          (SOCKEINTR == sockerr) || (SOCKEINPROGRESS == sockerr)
243
#endif
244
          ) {
245
          continue;
246
        }
247
        goto error;
248
      }
249
      s -= nread;
250
      if(s) {
251
        p += nread;
252
        continue;
253
      }
254
      if(memcmp(rnd, check, sizeof(check)))
255
        goto error;
256
      break;
257
    } while(1);
258
  }
259
260
  if(nonblocking)
261
    if(curlx_nonblock(socks[0], TRUE) < 0 ||
262
       curlx_nonblock(socks[1], TRUE) < 0)
263
      goto error;
264
  sclose(listener);
265
  return 0;
266
267
error:
268
  sclose(listener);
269
  sclose(socks[0]);
270
  sclose(socks[1]);
271
  return -1;
272
}
273
#endif
274
#endif /* !CURL_DISABLE_SOCKETPAIR */