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