quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

socketpair.c (7108B)


      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 {
     36   int efd = eventfd(0, nonblocking ? EFD_CLOEXEC | EFD_NONBLOCK : EFD_CLOEXEC);
     37   if(efd == -1) {
     38     socks[0] = socks[1] = CURL_SOCKET_BAD;
     39     return -1;
     40   }
     41   socks[0] = socks[1] = efd;
     42   return 0;
     43 }
     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 {
     90 #ifdef SOCK_NONBLOCK
     91   type = nonblocking ? type | SOCK_NONBLOCK : type;
     92 #endif
     93   if(socketpair(domain, type, protocol, socks))
     94     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   return 0;
    106 }
    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 */