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