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