Coverage Report

Created: 2025-06-09 07:07

/src/gdal/curl/lib/socketpair.c
Line
Count
Source (jump to first uncovered line)
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
1.47k
{
36
1.47k
  int efd = eventfd(0, nonblocking ? EFD_CLOEXEC | EFD_NONBLOCK : EFD_CLOEXEC);
37
1.47k
  if(efd == -1) {
38
0
    socks[0] = socks[1] = CURL_SOCKET_BAD;
39
0
    return -1;
40
0
  }
41
1.47k
  socks[0] = socks[1] = efd;
42
1.47k
  return 0;
43
1.47k
}
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
int Curl_socketpair(int domain, int type, int protocol,
88
                    curl_socket_t socks[2], bool nonblocking)
89
0
{
90
0
#ifdef SOCK_NONBLOCK
91
0
  type = nonblocking ? type | SOCK_NONBLOCK : type;
92
0
#endif
93
0
  if(socketpair(domain, type, protocol, socks))
94
0
    return -1;
95
#ifndef SOCK_NONBLOCK
96
  if(nonblocking) {
97
    if(curlx_nonblock(socks[0], TRUE) < 0 ||
98
       curlx_nonblock(socks[1], TRUE) < 0) {
99
      close(socks[0]);
100
      close(socks[1]);
101
      return -1;
102
    }
103
  }
104
#endif
105
0
  return 0;
106
0
}
107
#else /* !HAVE_SOCKETPAIR */
108
#ifdef _WIN32
109
/*
110
 * This is a socketpair() implementation for Windows.
111
 */
112
#include <string.h>
113
#ifdef HAVE_IO_H
114
#include <io.h>
115
#endif
116
#else
117
#ifdef HAVE_NETDB_H
118
#include <netdb.h>
119
#endif
120
#ifdef HAVE_NETINET_IN_H
121
#include <netinet/in.h> /* IPPROTO_TCP */
122
#endif
123
#ifdef HAVE_ARPA_INET_H
124
#include <arpa/inet.h>
125
#endif
126
#ifndef INADDR_LOOPBACK
127
#define INADDR_LOOPBACK 0x7f000001
128
#endif /* !INADDR_LOOPBACK */
129
#endif /* !_WIN32 */
130
131
#include "curlx/nonblock.h" /* for curlx_nonblock */
132
#include "curlx/timeval.h"  /* needed before select.h */
133
#include "select.h"   /* for Curl_poll */
134
135
/* The last 3 #include files should be in this order */
136
#include "curl_printf.h"
137
#include "curl_memory.h"
138
#include "memdebug.h"
139
140
int Curl_socketpair(int domain, int type, int protocol,
141
                    curl_socket_t socks[2], bool nonblocking)
142
{
143
  union {
144
    struct sockaddr_in inaddr;
145
    struct sockaddr addr;
146
  } a;
147
  curl_socket_t listener;
148
  curl_socklen_t addrlen = sizeof(a.inaddr);
149
  int reuse = 1;
150
  struct pollfd pfd[1];
151
  (void)domain;
152
  (void)type;
153
  (void)protocol;
154
155
  listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
156
  if(listener == CURL_SOCKET_BAD)
157
    return -1;
158
159
  memset(&a, 0, sizeof(a));
160
  a.inaddr.sin_family = AF_INET;
161
  a.inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
162
  a.inaddr.sin_port = 0;
163
164
  socks[0] = socks[1] = CURL_SOCKET_BAD;
165
166
#if defined(_WIN32) || defined(__CYGWIN__)
167
  /* do not set SO_REUSEADDR on Windows */
168
  (void)reuse;
169
#ifdef SO_EXCLUSIVEADDRUSE
170
  {
171
    int exclusive = 1;
172
    if(setsockopt(listener, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
173
                  (char *)&exclusive, (curl_socklen_t)sizeof(exclusive)) == -1)
174
      goto error;
175
  }
176
#endif
177
#else
178
  if(setsockopt(listener, SOL_SOCKET, SO_REUSEADDR,
179
                (char *)&reuse, (curl_socklen_t)sizeof(reuse)) == -1)
180
    goto error;
181
#endif
182
  if(bind(listener, &a.addr, sizeof(a.inaddr)) == -1)
183
    goto error;
184
  if(getsockname(listener, &a.addr, &addrlen) == -1 ||
185
     addrlen < (int)sizeof(a.inaddr))
186
    goto error;
187
  if(listen(listener, 1) == -1)
188
    goto error;
189
  socks[0] = socket(AF_INET, SOCK_STREAM, 0);
190
  if(socks[0] == CURL_SOCKET_BAD)
191
    goto error;
192
  if(connect(socks[0], &a.addr, sizeof(a.inaddr)) == -1)
193
    goto error;
194
195
  /* use non-blocking accept to make sure we do not block forever */
196
  if(curlx_nonblock(listener, TRUE) < 0)
197
    goto error;
198
  pfd[0].fd = listener;
199
  pfd[0].events = POLLIN;
200
  pfd[0].revents = 0;
201
  (void)Curl_poll(pfd, 1, 1000); /* one second */
202
  socks[1] = accept(listener, NULL, NULL);
203
  if(socks[1] == CURL_SOCKET_BAD)
204
    goto error;
205
  else {
206
    struct curltime start = curlx_now();
207
    char rnd[9];
208
    char check[sizeof(rnd)];
209
    char *p = &check[0];
210
    size_t s = sizeof(check);
211
212
    if(Curl_rand(NULL, (unsigned char *)rnd, sizeof(rnd)))
213
      goto error;
214
215
    /* write data to the socket */
216
    swrite(socks[0], rnd, sizeof(rnd));
217
    /* verify that we read the correct data */
218
    do {
219
      ssize_t nread;
220
221
      pfd[0].fd = socks[1];
222
      pfd[0].events = POLLIN;
223
      pfd[0].revents = 0;
224
      (void)Curl_poll(pfd, 1, 1000); /* one second */
225
226
      nread = sread(socks[1], p, s);
227
      if(nread == -1) {
228
        int sockerr = SOCKERRNO;
229
        /* Do not block forever */
230
        if(curlx_timediff(curlx_now(), start) > (60 * 1000))
231
          goto error;
232
        if(
233
#ifdef USE_WINSOCK
234
          /* This is how Windows does it */
235
          (SOCKEWOULDBLOCK == sockerr)
236
#else
237
          /* errno may be EWOULDBLOCK or on some systems EAGAIN when it
238
             returned due to its inability to send off data without
239
             blocking. We therefore treat both error codes the same here */
240
          (SOCKEWOULDBLOCK == sockerr) || (EAGAIN == sockerr) ||
241
          (SOCKEINTR == sockerr) || (SOCKEINPROGRESS == sockerr)
242
#endif
243
          ) {
244
          continue;
245
        }
246
        goto error;
247
      }
248
      s -= nread;
249
      if(s) {
250
        p += nread;
251
        continue;
252
      }
253
      if(memcmp(rnd, check, sizeof(check)))
254
        goto error;
255
      break;
256
    } while(1);
257
  }
258
259
  if(nonblocking)
260
    if(curlx_nonblock(socks[0], TRUE) < 0 ||
261
       curlx_nonblock(socks[1], TRUE) < 0)
262
      goto error;
263
  sclose(listener);
264
  return 0;
265
266
error:
267
  sclose(listener);
268
  sclose(socks[0]);
269
  sclose(socks[1]);
270
  return -1;
271
}
272
#endif
273
#endif /* !CURL_DISABLE_SOCKETPAIR */