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#if !defined(HAVE_SOCKETPAIR) && !defined(CURL_DISABLE_SOCKETPAIR) 31#ifdef _WIN32 32/* 33 * This is a socketpair() implementation for Windows. 34 */ 35#include <string.h> 36#include <io.h> 37#else 38#ifdef HAVE_NETDB_H 39#include <netdb.h> 40#endif 41#ifdef HAVE_NETINET_IN_H 42#include <netinet/in.h> /* IPPROTO_TCP */ 43#endif 44#ifdef HAVE_ARPA_INET_H 45#include <arpa/inet.h> 46#endif 47#ifndef INADDR_LOOPBACK 48#define INADDR_LOOPBACK 0x7f000001 49#endif /* !INADDR_LOOPBACK */ 50#endif /* !_WIN32 */ 51 52#include "nonblock.h" /* for curlx_nonblock */ 53#include "timeval.h" /* needed before select.h */ 54#include "select.h" /* for Curl_poll */ 55 56/* The last 3 #include files should be in this order */ 57#include "curl_printf.h" 58#include "curl_memory.h" 59#include "memdebug.h" 60 61int Curl_socketpair(int domain, int type, int protocol, 62 curl_socket_t socks[2]) 63{ 64 union { 65 struct sockaddr_in inaddr; 66 struct sockaddr addr; 67 } a; 68 curl_socket_t listener; 69 curl_socklen_t addrlen = sizeof(a.inaddr); 70 int reuse = 1; 71 struct pollfd pfd[1]; 72 (void)domain; 73 (void)type; 74 (void)protocol; 75 76 listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 77 if(listener == CURL_SOCKET_BAD) 78 return -1; 79 80 memset(&a, 0, sizeof(a)); 81 a.inaddr.sin_family = AF_INET; 82 a.inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 83 a.inaddr.sin_port = 0; 84 85 socks[0] = socks[1] = CURL_SOCKET_BAD; 86 87#if defined(_WIN32) || defined(__CYGWIN__) 88 /* don't set SO_REUSEADDR on Windows */ 89 (void)reuse; 90#ifdef SO_EXCLUSIVEADDRUSE 91 { 92 int exclusive = 1; 93 if(setsockopt(listener, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, 94 (char *)&exclusive, (curl_socklen_t)sizeof(exclusive)) == -1) 95 goto error; 96 } 97#endif 98#else 99 if(setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, 100 (char *)&reuse, (curl_socklen_t)sizeof(reuse)) == -1) 101 goto error; 102#endif 103 if(bind(listener, &a.addr, sizeof(a.inaddr)) == -1) 104 goto error; 105 if(getsockname(listener, &a.addr, &addrlen) == -1 || 106 addrlen < (int)sizeof(a.inaddr)) 107 goto error; 108 if(listen(listener, 1) == -1) 109 goto error; 110 socks[0] = socket(AF_INET, SOCK_STREAM, 0); 111 if(socks[0] == CURL_SOCKET_BAD) 112 goto error; 113 if(connect(socks[0], &a.addr, sizeof(a.inaddr)) == -1) 114 goto error; 115 116 /* use non-blocking accept to make sure we don't block forever */ 117 if(curlx_nonblock(listener, TRUE) < 0) 118 goto error; 119 pfd[0].fd = listener; 120 pfd[0].events = POLLIN; 121 pfd[0].revents = 0; 122 (void)Curl_poll(pfd, 1, 1000); /* one second */ 123 socks[1] = accept(listener, NULL, NULL); 124 if(socks[1] == CURL_SOCKET_BAD) 125 goto error; 126 else { 127 struct curltime start = Curl_now(); 128 char rnd[9]; 129 char check[sizeof(rnd)]; 130 char *p = &check[0]; 131 size_t s = sizeof(check); 132 133 if(Curl_rand(NULL, (unsigned char *)rnd, sizeof(rnd))) 134 goto error; 135 136 /* write data to the socket */ 137 swrite(socks[0], rnd, sizeof(rnd)); 138 /* verify that we read the correct data */ 139 do { 140 ssize_t nread; 141 142 pfd[0].fd = socks[1]; 143 pfd[0].events = POLLIN; 144 pfd[0].revents = 0; 145 (void)Curl_poll(pfd, 1, 1000); /* one second */ 146 147 nread = sread(socks[1], p, s); 148 if(nread == -1) { 149 int sockerr = SOCKERRNO; 150 /* Don't block forever */ 151 if(Curl_timediff(Curl_now(), start) > (60 * 1000)) 152 goto error; 153 if( 154#ifdef WSAEWOULDBLOCK 155 /* This is how Windows does it */ 156 (WSAEWOULDBLOCK == sockerr) 157#else 158 /* errno may be EWOULDBLOCK or on some systems EAGAIN when it 159 returned due to its inability to send off data without 160 blocking. We therefore treat both error codes the same here */ 161 (EWOULDBLOCK == sockerr) || (EAGAIN == sockerr) || 162 (EINTR == sockerr) || (EINPROGRESS == sockerr) 163#endif 164 ) { 165 continue; 166 } 167 goto error; 168 } 169 s -= nread; 170 if(s) { 171 p += nread; 172 continue; 173 } 174 if(memcmp(rnd, check, sizeof(check))) 175 goto error; 176 break; 177 } while(1); 178 } 179 180 sclose(listener); 181 return 0; 182 183error: 184 sclose(listener); 185 sclose(socks[0]); 186 sclose(socks[1]); 187 return -1; 188} 189 190#endif /* ! HAVE_SOCKETPAIR */ 191