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
27 #ifdef HAVE_NETINET_IN_H
28 #include <netinet/in.h> /* <netinet/tcp.h> may need it */
29 #endif
30 #ifdef HAVE_SYS_UN_H
31 #include <sys/un.h> /* for sockaddr_un */
32 #endif
33 #ifdef HAVE_LINUX_TCP_H
34 #include <linux/tcp.h>
35 #elif defined(HAVE_NETINET_TCP_H)
36 #include <netinet/tcp.h>
37 #endif
38 #ifdef HAVE_NETINET_UDP_H
39 #include <netinet/udp.h>
40 #endif
41 #ifdef HAVE_SYS_IOCTL_H
42 #include <sys/ioctl.h>
43 #endif
44 #ifdef HAVE_NETDB_H
45 #include <netdb.h>
46 #endif
47 #ifdef HAVE_FCNTL_H
48 #include <fcntl.h>
49 #endif
50 #ifdef HAVE_ARPA_INET_H
51 #include <arpa/inet.h>
52 #endif
53
54 #ifdef __VMS
55 #include <in.h>
56 #include <inet.h>
57 #endif
58
59 #ifdef __DragonFly__
60 /* Required for __DragonFly_version */
61 #include <sys/param.h>
62 #endif
63
64 #include "urldata.h"
65 #include "bufq.h"
66 #include "sendf.h"
67 #include "if2ip.h"
68 #include "strerror.h"
69 #include "cfilters.h"
70 #include "cf-socket.h"
71 #include "connect.h"
72 #include "select.h"
73 #include "url.h" /* for Curl_safefree() */
74 #include "multiif.h"
75 #include "sockaddr.h" /* required for Curl_sockaddr_storage */
76 #include "inet_ntop.h"
77 #include "inet_pton.h"
78 #include "progress.h"
79 #include "warnless.h"
80 #include "conncache.h"
81 #include "multihandle.h"
82 #include "rand.h"
83 #include "share.h"
84 #include "strdup.h"
85 #include "version_win32.h"
86
87 /* The last 3 #include files should be in this order */
88 #include "curl_printf.h"
89 #include "curl_memory.h"
90 #include "memdebug.h"
91
92
93 #if defined(USE_IPV6) && defined(IPV6_V6ONLY) && defined(_WIN32)
94 /* It makes support for IPv4-mapped IPv6 addresses.
95 * Linux kernel, NetBSD, FreeBSD and Darwin: default is off;
96 * Windows Vista and later: default is on;
97 * DragonFly BSD: acts like off, and dummy setting;
98 * OpenBSD and earlier Windows: unsupported.
99 * Linux: controlled by /proc/sys/net/ipv6/bindv6only.
100 */
set_ipv6_v6only(curl_socket_t sockfd,int on)101 static void set_ipv6_v6only(curl_socket_t sockfd, int on)
102 {
103 (void)setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&on, sizeof(on));
104 }
105 #else
106 #define set_ipv6_v6only(x,y)
107 #endif
108
tcpnodelay(struct Curl_easy * data,curl_socket_t sockfd)109 static void tcpnodelay(struct Curl_easy *data, curl_socket_t sockfd)
110 {
111 #if defined(TCP_NODELAY)
112 curl_socklen_t onoff = (curl_socklen_t) 1;
113 int level = IPPROTO_TCP;
114 char buffer[STRERROR_LEN];
115
116 if(setsockopt(sockfd, level, TCP_NODELAY, (void *)&onoff,
117 sizeof(onoff)) < 0)
118 infof(data, "Could not set TCP_NODELAY: %s",
119 Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
120 #else
121 (void)data;
122 (void)sockfd;
123 #endif
124 }
125
126 #ifdef SO_NOSIGPIPE
127 /* The preferred method on macOS (10.2 and later) to prevent SIGPIPEs when
128 sending data to a dead peer (instead of relying on the 4th argument to send
129 being MSG_NOSIGNAL). Possibly also existing and in use on other BSD
130 systems? */
nosigpipe(struct Curl_easy * data,curl_socket_t sockfd)131 static void nosigpipe(struct Curl_easy *data,
132 curl_socket_t sockfd)
133 {
134 int onoff = 1;
135 (void)data;
136 if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff,
137 sizeof(onoff)) < 0) {
138 #if !defined(CURL_DISABLE_VERBOSE_STRINGS)
139 char buffer[STRERROR_LEN];
140 infof(data, "Could not set SO_NOSIGPIPE: %s",
141 Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
142 #endif
143 }
144 }
145 #else
146 #define nosigpipe(x,y) Curl_nop_stmt
147 #endif
148
149 #if defined(USE_WINSOCK) && \
150 defined(TCP_KEEPIDLE) && defined(TCP_KEEPINTVL) && defined(TCP_KEEPCNT)
151 /* Win 10, v 1709 (10.0.16299) and later can use SetSockOpt TCP_KEEP____
152 * so should use seconds */
153 #define CURL_WINSOCK_KEEP_SSO
154 #define KEEPALIVE_FACTOR(x)
155 #elif defined(USE_WINSOCK) || \
156 (defined(__sun) && !defined(TCP_KEEPIDLE)) || \
157 (defined(__DragonFly__) && __DragonFly_version < 500702) || \
158 (defined(_WIN32) && !defined(TCP_KEEPIDLE))
159 /* Solaris < 11.4, DragonFlyBSD < 500702 and Windows < 10.0.16299
160 * use millisecond units. */
161 #define KEEPALIVE_FACTOR(x) (x *= 1000)
162 #else
163 #define KEEPALIVE_FACTOR(x)
164 #endif
165
166 #if defined(USE_WINSOCK) && !defined(SIO_KEEPALIVE_VALS)
167 #define SIO_KEEPALIVE_VALS _WSAIOW(IOC_VENDOR,4)
168
169 struct tcp_keepalive {
170 u_long onoff;
171 u_long keepalivetime;
172 u_long keepaliveinterval;
173 };
174 #endif
175
176 static void
tcpkeepalive(struct Curl_easy * data,curl_socket_t sockfd)177 tcpkeepalive(struct Curl_easy *data,
178 curl_socket_t sockfd)
179 {
180 int optval = data->set.tcp_keepalive ? 1 : 0;
181
182 /* only set IDLE and INTVL if setting KEEPALIVE is successful */
183 if(setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE,
184 (void *)&optval, sizeof(optval)) < 0) {
185 infof(data, "Failed to set SO_KEEPALIVE on fd "
186 "%" FMT_SOCKET_T ": errno %d",
187 sockfd, SOCKERRNO);
188 }
189 else {
190 #if defined(SIO_KEEPALIVE_VALS) /* Windows */
191 /* Windows 10, version 1709 (10.0.16299) and later versions */
192 #if defined(CURL_WINSOCK_KEEP_SSO)
193 optval = curlx_sltosi(data->set.tcp_keepidle);
194 KEEPALIVE_FACTOR(optval);
195 if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE,
196 (const char *)&optval, sizeof(optval)) < 0) {
197 infof(data, "Failed to set TCP_KEEPIDLE on fd "
198 "%" FMT_SOCKET_T ": errno %d",
199 sockfd, SOCKERRNO);
200 }
201 optval = curlx_sltosi(data->set.tcp_keepintvl);
202 KEEPALIVE_FACTOR(optval);
203 if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL,
204 (const char *)&optval, sizeof(optval)) < 0) {
205 infof(data, "Failed to set TCP_KEEPINTVL on fd "
206 "%" FMT_SOCKET_T ": errno %d",
207 sockfd, SOCKERRNO);
208 }
209 optval = curlx_sltosi(data->set.tcp_keepcnt);
210 if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPCNT,
211 (const char *)&optval, sizeof(optval)) < 0) {
212 infof(data, "Failed to set TCP_KEEPCNT on fd "
213 "%" FMT_SOCKET_T ": errno %d",
214 sockfd, SOCKERRNO);
215 }
216 #else /* Windows < 10.0.16299 */
217 struct tcp_keepalive vals;
218 DWORD dummy;
219 vals.onoff = 1;
220 optval = curlx_sltosi(data->set.tcp_keepidle);
221 KEEPALIVE_FACTOR(optval);
222 vals.keepalivetime = (u_long)optval;
223 optval = curlx_sltosi(data->set.tcp_keepintvl);
224 KEEPALIVE_FACTOR(optval);
225 vals.keepaliveinterval = (u_long)optval;
226 if(WSAIoctl(sockfd, SIO_KEEPALIVE_VALS, (LPVOID) &vals, sizeof(vals),
227 NULL, 0, &dummy, NULL, NULL) != 0) {
228 infof(data, "Failed to set SIO_KEEPALIVE_VALS on fd "
229 "%" FMT_SOCKET_T ": errno %d", sockfd, SOCKERRNO);
230 }
231 #endif
232 #else /* !Windows */
233 #ifdef TCP_KEEPIDLE
234 optval = curlx_sltosi(data->set.tcp_keepidle);
235 KEEPALIVE_FACTOR(optval);
236 if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE,
237 (void *)&optval, sizeof(optval)) < 0) {
238 infof(data, "Failed to set TCP_KEEPIDLE on fd "
239 "%" FMT_SOCKET_T ": errno %d",
240 sockfd, SOCKERRNO);
241 }
242 #elif defined(TCP_KEEPALIVE)
243 /* macOS style */
244 optval = curlx_sltosi(data->set.tcp_keepidle);
245 KEEPALIVE_FACTOR(optval);
246 if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE,
247 (void *)&optval, sizeof(optval)) < 0) {
248 infof(data, "Failed to set TCP_KEEPALIVE on fd "
249 "%" FMT_SOCKET_T ": errno %d",
250 sockfd, SOCKERRNO);
251 }
252 #elif defined(TCP_KEEPALIVE_THRESHOLD)
253 /* Solaris <11.4 style */
254 optval = curlx_sltosi(data->set.tcp_keepidle);
255 KEEPALIVE_FACTOR(optval);
256 if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE_THRESHOLD,
257 (void *)&optval, sizeof(optval)) < 0) {
258 infof(data, "Failed to set TCP_KEEPALIVE_THRESHOLD on fd "
259 "%" FMT_SOCKET_T ": errno %d",
260 sockfd, SOCKERRNO);
261 }
262 #endif
263 #ifdef TCP_KEEPINTVL
264 optval = curlx_sltosi(data->set.tcp_keepintvl);
265 KEEPALIVE_FACTOR(optval);
266 if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL,
267 (void *)&optval, sizeof(optval)) < 0) {
268 infof(data, "Failed to set TCP_KEEPINTVL on fd "
269 "%" FMT_SOCKET_T ": errno %d",
270 sockfd, SOCKERRNO);
271 }
272 #elif defined(TCP_KEEPALIVE_ABORT_THRESHOLD)
273 /* Solaris <11.4 style */
274 /* TCP_KEEPALIVE_ABORT_THRESHOLD should equal to
275 * TCP_KEEPCNT * TCP_KEEPINTVL on other platforms.
276 * The default value of TCP_KEEPCNT is 9 on Linux,
277 * 8 on *BSD/macOS, 5 or 10 on Windows. We use the
278 * default config for Solaris <11.4 because there is
279 * no default value for TCP_KEEPCNT on Solaris 11.4.
280 *
281 * Note that the consequent probes will not be sent
282 * at equal intervals on Solaris, but will be sent
283 * using the exponential backoff algorithm. */
284 optval = curlx_sltosi(data->set.tcp_keepcnt) *
285 curlx_sltosi(data->set.tcp_keepintvl);
286 KEEPALIVE_FACTOR(optval);
287 if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE_ABORT_THRESHOLD,
288 (void *)&optval, sizeof(optval)) < 0) {
289 infof(data, "Failed to set TCP_KEEPALIVE_ABORT_THRESHOLD on fd "
290 "%" FMT_SOCKET_T ": errno %d", sockfd, SOCKERRNO);
291 }
292 #endif
293 #ifdef TCP_KEEPCNT
294 optval = curlx_sltosi(data->set.tcp_keepcnt);
295 if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPCNT,
296 (void *)&optval, sizeof(optval)) < 0) {
297 infof(data, "Failed to set TCP_KEEPCNT on fd "
298 "%" FMT_SOCKET_T ": errno %d", sockfd, SOCKERRNO);
299 }
300 #endif
301 #endif
302 }
303 }
304
305 /**
306 * Assign the address `ai` to the Curl_sockaddr_ex `dest` and
307 * set the transport used.
308 */
Curl_sock_assign_addr(struct Curl_sockaddr_ex * dest,const struct Curl_addrinfo * ai,int transport)309 void Curl_sock_assign_addr(struct Curl_sockaddr_ex *dest,
310 const struct Curl_addrinfo *ai,
311 int transport)
312 {
313 /*
314 * The Curl_sockaddr_ex structure is basically libcurl's external API
315 * curl_sockaddr structure with enough space available to directly hold
316 * any protocol-specific address structures. The variable declared here
317 * will be used to pass / receive data to/from the fopensocket callback
318 * if this has been set, before that, it is initialized from parameters.
319 */
320 dest->family = ai->ai_family;
321 switch(transport) {
322 case TRNSPRT_TCP:
323 dest->socktype = SOCK_STREAM;
324 dest->protocol = IPPROTO_TCP;
325 break;
326 case TRNSPRT_UNIX:
327 dest->socktype = SOCK_STREAM;
328 dest->protocol = IPPROTO_IP;
329 break;
330 default: /* UDP and QUIC */
331 dest->socktype = SOCK_DGRAM;
332 dest->protocol = IPPROTO_UDP;
333 break;
334 }
335 dest->addrlen = (unsigned int)ai->ai_addrlen;
336
337 if(dest->addrlen > sizeof(struct Curl_sockaddr_storage))
338 dest->addrlen = sizeof(struct Curl_sockaddr_storage);
339 memcpy(&dest->curl_sa_addr, ai->ai_addr, dest->addrlen);
340 }
341
socket_open(struct Curl_easy * data,struct Curl_sockaddr_ex * addr,curl_socket_t * sockfd)342 static CURLcode socket_open(struct Curl_easy *data,
343 struct Curl_sockaddr_ex *addr,
344 curl_socket_t *sockfd)
345 {
346 DEBUGASSERT(data);
347 DEBUGASSERT(data->conn);
348 if(data->set.fopensocket) {
349 /*
350 * If the opensocket callback is set, all the destination address
351 * information is passed to the callback. Depending on this information the
352 * callback may opt to abort the connection, this is indicated returning
353 * CURL_SOCKET_BAD; otherwise it will return a not-connected socket. When
354 * the callback returns a valid socket the destination address information
355 * might have been changed and this 'new' address will actually be used
356 * here to connect.
357 */
358 Curl_set_in_callback(data, TRUE);
359 *sockfd = data->set.fopensocket(data->set.opensocket_client,
360 CURLSOCKTYPE_IPCXN,
361 (struct curl_sockaddr *)addr);
362 Curl_set_in_callback(data, FALSE);
363 }
364 else {
365 /* opensocket callback not set, so simply create the socket now */
366 *sockfd = socket(addr->family, addr->socktype, addr->protocol);
367 }
368
369 if(*sockfd == CURL_SOCKET_BAD)
370 /* no socket, no connection */
371 return CURLE_COULDNT_CONNECT;
372
373 #if defined(USE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
374 if(data->conn->scope_id && (addr->family == AF_INET6)) {
375 struct sockaddr_in6 * const sa6 = (void *)&addr->curl_sa_addr;
376 sa6->sin6_scope_id = data->conn->scope_id;
377 }
378 #endif
379 return CURLE_OK;
380 }
381
382 /*
383 * Create a socket based on info from 'conn' and 'ai'.
384 *
385 * 'addr' should be a pointer to the correct struct to get data back, or NULL.
386 * 'sockfd' must be a pointer to a socket descriptor.
387 *
388 * If the open socket callback is set, used that!
389 *
390 */
Curl_socket_open(struct Curl_easy * data,const struct Curl_addrinfo * ai,struct Curl_sockaddr_ex * addr,int transport,curl_socket_t * sockfd)391 CURLcode Curl_socket_open(struct Curl_easy *data,
392 const struct Curl_addrinfo *ai,
393 struct Curl_sockaddr_ex *addr,
394 int transport,
395 curl_socket_t *sockfd)
396 {
397 struct Curl_sockaddr_ex dummy;
398
399 if(!addr)
400 /* if the caller does not want info back, use a local temp copy */
401 addr = &dummy;
402
403 Curl_sock_assign_addr(addr, ai, transport);
404 return socket_open(data, addr, sockfd);
405 }
406
socket_close(struct Curl_easy * data,struct connectdata * conn,int use_callback,curl_socket_t sock)407 static int socket_close(struct Curl_easy *data, struct connectdata *conn,
408 int use_callback, curl_socket_t sock)
409 {
410 if(CURL_SOCKET_BAD == sock)
411 return 0;
412
413 if(use_callback && conn && conn->fclosesocket) {
414 int rc;
415 Curl_multi_closed(data, sock);
416 Curl_set_in_callback(data, TRUE);
417 rc = conn->fclosesocket(conn->closesocket_client, sock);
418 Curl_set_in_callback(data, FALSE);
419 return rc;
420 }
421
422 if(conn)
423 /* tell the multi-socket code about this */
424 Curl_multi_closed(data, sock);
425
426 sclose(sock);
427
428 return 0;
429 }
430
431 /*
432 * Close a socket.
433 *
434 * 'conn' can be NULL, beware!
435 */
Curl_socket_close(struct Curl_easy * data,struct connectdata * conn,curl_socket_t sock)436 int Curl_socket_close(struct Curl_easy *data, struct connectdata *conn,
437 curl_socket_t sock)
438 {
439 return socket_close(data, conn, FALSE, sock);
440 }
441
442 #ifdef USE_WINSOCK
443 /* When you run a program that uses the Windows Sockets API, you may
444 experience slow performance when you copy data to a TCP server.
445
446 https://support.microsoft.com/kb/823764
447
448 Work-around: Make the Socket Send Buffer Size Larger Than the Program Send
449 Buffer Size
450
451 The problem described in this knowledge-base is applied only to pre-Vista
452 Windows. Following function trying to detect OS version and skips
453 SO_SNDBUF adjustment for Windows Vista and above.
454 */
455 #define DETECT_OS_NONE 0
456 #define DETECT_OS_PREVISTA 1
457 #define DETECT_OS_VISTA_OR_LATER 2
458
Curl_sndbuf_init(curl_socket_t sockfd)459 void Curl_sndbuf_init(curl_socket_t sockfd)
460 {
461 int val = CURL_MAX_WRITE_SIZE + 32;
462 int curval = 0;
463 int curlen = sizeof(curval);
464
465 static int detectOsState = DETECT_OS_NONE;
466
467 if(detectOsState == DETECT_OS_NONE) {
468 if(curlx_verify_windows_version(6, 0, 0, PLATFORM_WINNT,
469 VERSION_GREATER_THAN_EQUAL))
470 detectOsState = DETECT_OS_VISTA_OR_LATER;
471 else
472 detectOsState = DETECT_OS_PREVISTA;
473 }
474
475 if(detectOsState == DETECT_OS_VISTA_OR_LATER)
476 return;
477
478 if(getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *)&curval, &curlen) == 0)
479 if(curval > val)
480 return;
481
482 setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (const char *)&val, sizeof(val));
483 }
484 #endif /* USE_WINSOCK */
485
486 /*
487 * Curl_parse_interface()
488 *
489 * This is used to parse interface argument in the following formats.
490 * In all the examples, `host` can be an IP address or a hostname.
491 *
492 * <iface_or_host> - can be either an interface name or a host.
493 * if!<iface> - interface name.
494 * host!<host> - hostname.
495 * ifhost!<iface>!<host> - interface name and hostname.
496 *
497 * Parameters:
498 *
499 * input [in] - input string.
500 * len [in] - length of the input string.
501 * dev [in/out] - address where a pointer to newly allocated memory
502 * holding the interface-or-host will be stored upon
503 * completion.
504 * iface [in/out] - address where a pointer to newly allocated memory
505 * holding the interface will be stored upon completion.
506 * host [in/out] - address where a pointer to newly allocated memory
507 * holding the host will be stored upon completion.
508 *
509 * Returns CURLE_OK on success.
510 */
Curl_parse_interface(const char * input,char ** dev,char ** iface,char ** host)511 CURLcode Curl_parse_interface(const char *input,
512 char **dev, char **iface, char **host)
513 {
514 static const char if_prefix[] = "if!";
515 static const char host_prefix[] = "host!";
516 static const char if_host_prefix[] = "ifhost!";
517 size_t len;
518
519 DEBUGASSERT(dev);
520 DEBUGASSERT(iface);
521 DEBUGASSERT(host);
522
523 len = strlen(input);
524 if(len > 512)
525 return CURLE_BAD_FUNCTION_ARGUMENT;
526
527 if(!strncmp(if_prefix, input, strlen(if_prefix))) {
528 input += strlen(if_prefix);
529 if(!*input)
530 return CURLE_BAD_FUNCTION_ARGUMENT;
531 *iface = Curl_memdup0(input, len - strlen(if_prefix));
532 return *iface ? CURLE_OK : CURLE_OUT_OF_MEMORY;
533 }
534 else if(!strncmp(host_prefix, input, strlen(host_prefix))) {
535 input += strlen(host_prefix);
536 if(!*input)
537 return CURLE_BAD_FUNCTION_ARGUMENT;
538 *host = Curl_memdup0(input, len - strlen(host_prefix));
539 return *host ? CURLE_OK : CURLE_OUT_OF_MEMORY;
540 }
541 else if(!strncmp(if_host_prefix, input, strlen(if_host_prefix))) {
542 const char *host_part;
543 input += strlen(if_host_prefix);
544 len -= strlen(if_host_prefix);
545 host_part = memchr(input, '!', len);
546 if(!host_part || !*(host_part + 1))
547 return CURLE_BAD_FUNCTION_ARGUMENT;
548 *iface = Curl_memdup0(input, host_part - input);
549 if(!*iface)
550 return CURLE_OUT_OF_MEMORY;
551 ++host_part;
552 *host = Curl_memdup0(host_part, len - (host_part - input));
553 if(!*host) {
554 free(*iface);
555 *iface = NULL;
556 return CURLE_OUT_OF_MEMORY;
557 }
558 return CURLE_OK;
559 }
560
561 if(!*input)
562 return CURLE_BAD_FUNCTION_ARGUMENT;
563 *dev = Curl_memdup0(input, len);
564 return *dev ? CURLE_OK : CURLE_OUT_OF_MEMORY;
565 }
566
567 #ifndef CURL_DISABLE_BINDLOCAL
bindlocal(struct Curl_easy * data,struct connectdata * conn,curl_socket_t sockfd,int af,unsigned int scope)568 static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
569 curl_socket_t sockfd, int af, unsigned int scope)
570 {
571 struct Curl_sockaddr_storage sa;
572 struct sockaddr *sock = (struct sockaddr *)&sa; /* bind to this address */
573 curl_socklen_t sizeof_sa = 0; /* size of the data sock points to */
574 struct sockaddr_in *si4 = (struct sockaddr_in *)&sa;
575 #ifdef USE_IPV6
576 struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)&sa;
577 #endif
578
579 struct Curl_dns_entry *h = NULL;
580 unsigned short port = data->set.localport; /* use this port number, 0 for
581 "random" */
582 /* how many port numbers to try to bind to, increasing one at a time */
583 int portnum = data->set.localportrange;
584 const char *dev = data->set.str[STRING_DEVICE];
585 const char *iface_input = data->set.str[STRING_INTERFACE];
586 const char *host_input = data->set.str[STRING_BINDHOST];
587 const char *iface = iface_input ? iface_input : dev;
588 const char *host = host_input ? host_input : dev;
589 int error;
590 #ifdef IP_BIND_ADDRESS_NO_PORT
591 int on = 1;
592 #endif
593 #ifndef USE_IPV6
594 (void)scope;
595 #endif
596
597 /*************************************************************
598 * Select device to bind socket to
599 *************************************************************/
600 if(!iface && !host && !port)
601 /* no local kind of binding was requested */
602 return CURLE_OK;
603 else if(iface && (strlen(iface) >= 255) )
604 return CURLE_BAD_FUNCTION_ARGUMENT;
605
606 memset(&sa, 0, sizeof(struct Curl_sockaddr_storage));
607
608 if(iface || host) {
609 char myhost[256] = "";
610 int done = 0; /* -1 for error, 1 for address found */
611 if2ip_result_t if2ip_result = IF2IP_NOT_FOUND;
612
613 #ifdef SO_BINDTODEVICE
614 if(iface) {
615 /*
616 * This binds the local socket to a particular interface. This will
617 * force even requests to other local interfaces to go out the external
618 * interface. Only bind to the interface when specified as interface,
619 * not just as a hostname or ip address.
620 *
621 * The interface might be a VRF, eg: vrf-blue, which means it cannot be
622 * converted to an IP address and would fail Curl_if2ip. Simply try to
623 * use it straight away.
624 */
625 if(setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
626 iface, (curl_socklen_t)strlen(iface) + 1) == 0) {
627 /* This is often "errno 1, error: Operation not permitted" if you are
628 * not running as root or another suitable privileged user. If it
629 * succeeds it means the parameter was a valid interface and not an IP
630 * address. Return immediately.
631 */
632 if(!host_input) {
633 infof(data, "socket successfully bound to interface '%s'", iface);
634 return CURLE_OK;
635 }
636 }
637 }
638 #endif
639 if(!host_input) {
640 /* Discover IP from input device, then bind to it */
641 if2ip_result = Curl_if2ip(af,
642 #ifdef USE_IPV6
643 scope, conn->scope_id,
644 #endif
645 iface, myhost, sizeof(myhost));
646 }
647 switch(if2ip_result) {
648 case IF2IP_NOT_FOUND:
649 if(iface_input && !host_input) {
650 /* Do not fall back to treating it as a hostname */
651 char buffer[STRERROR_LEN];
652 data->state.os_errno = error = SOCKERRNO;
653 failf(data, "Couldn't bind to interface '%s' with errno %d: %s",
654 iface, error, Curl_strerror(error, buffer, sizeof(buffer)));
655 return CURLE_INTERFACE_FAILED;
656 }
657 break;
658 case IF2IP_AF_NOT_SUPPORTED:
659 /* Signal the caller to try another address family if available */
660 return CURLE_UNSUPPORTED_PROTOCOL;
661 case IF2IP_FOUND:
662 /*
663 * We now have the numerical IP address in the 'myhost' buffer
664 */
665 host = myhost;
666 infof(data, "Local Interface %s is ip %s using address family %i",
667 iface, host, af);
668 done = 1;
669 break;
670 }
671 if(!iface_input || host_input) {
672 /*
673 * This was not an interface, resolve the name as a hostname
674 * or IP number
675 *
676 * Temporarily force name resolution to use only the address type
677 * of the connection. The resolve functions should really be changed
678 * to take a type parameter instead.
679 */
680 unsigned char ipver = conn->ip_version;
681 int rc;
682
683 if(af == AF_INET)
684 conn->ip_version = CURL_IPRESOLVE_V4;
685 #ifdef USE_IPV6
686 else if(af == AF_INET6)
687 conn->ip_version = CURL_IPRESOLVE_V6;
688 #endif
689
690 rc = Curl_resolv(data, host, 80, FALSE, &h);
691 if(rc == CURLRESOLV_PENDING)
692 (void)Curl_resolver_wait_resolv(data, &h);
693 conn->ip_version = ipver;
694
695 if(h) {
696 int h_af = h->addr->ai_family;
697 /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */
698 Curl_printable_address(h->addr, myhost, sizeof(myhost));
699 infof(data, "Name '%s' family %i resolved to '%s' family %i",
700 host, af, myhost, h_af);
701 Curl_resolv_unlink(data, &h); /* this will NULL, potential free h */
702 if(af != h_af) {
703 /* bad IP version combo, signal the caller to try another address
704 family if available */
705 return CURLE_UNSUPPORTED_PROTOCOL;
706 }
707 done = 1;
708 }
709 else {
710 /*
711 * provided dev was no interface (or interfaces are not supported
712 * e.g. Solaris) no ip address and no domain we fail here
713 */
714 done = -1;
715 }
716 }
717
718 if(done > 0) {
719 #ifdef USE_IPV6
720 /* IPv6 address */
721 if(af == AF_INET6) {
722 #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
723 char *scope_ptr = strchr(myhost, '%');
724 if(scope_ptr)
725 *(scope_ptr++) = '\0';
726 #endif
727 if(Curl_inet_pton(AF_INET6, myhost, &si6->sin6_addr) > 0) {
728 si6->sin6_family = AF_INET6;
729 si6->sin6_port = htons(port);
730 #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
731 if(scope_ptr) {
732 /* The "myhost" string either comes from Curl_if2ip or from
733 Curl_printable_address. The latter returns only numeric scope
734 IDs and the former returns none at all. So the scope ID, if
735 present, is known to be numeric */
736 unsigned long scope_id = strtoul(scope_ptr, NULL, 10);
737 if(scope_id > UINT_MAX)
738 return CURLE_UNSUPPORTED_PROTOCOL;
739
740 si6->sin6_scope_id = (unsigned int)scope_id;
741 }
742 #endif
743 }
744 sizeof_sa = sizeof(struct sockaddr_in6);
745 }
746 else
747 #endif
748 /* IPv4 address */
749 if((af == AF_INET) &&
750 (Curl_inet_pton(AF_INET, myhost, &si4->sin_addr) > 0)) {
751 si4->sin_family = AF_INET;
752 si4->sin_port = htons(port);
753 sizeof_sa = sizeof(struct sockaddr_in);
754 }
755 }
756
757 if(done < 1) {
758 /* errorbuf is set false so failf will overwrite any message already in
759 the error buffer, so the user receives this error message instead of a
760 generic resolve error. */
761 char buffer[STRERROR_LEN];
762 data->state.errorbuf = FALSE;
763 data->state.os_errno = error = SOCKERRNO;
764 failf(data, "Couldn't bind to '%s' with errno %d: %s",
765 host, error, Curl_strerror(error, buffer, sizeof(buffer)));
766 return CURLE_INTERFACE_FAILED;
767 }
768 }
769 else {
770 /* no device was given, prepare sa to match af's needs */
771 #ifdef USE_IPV6
772 if(af == AF_INET6) {
773 si6->sin6_family = AF_INET6;
774 si6->sin6_port = htons(port);
775 sizeof_sa = sizeof(struct sockaddr_in6);
776 }
777 else
778 #endif
779 if(af == AF_INET) {
780 si4->sin_family = AF_INET;
781 si4->sin_port = htons(port);
782 sizeof_sa = sizeof(struct sockaddr_in);
783 }
784 }
785 #ifdef IP_BIND_ADDRESS_NO_PORT
786 (void)setsockopt(sockfd, SOL_IP, IP_BIND_ADDRESS_NO_PORT, &on, sizeof(on));
787 #endif
788 for(;;) {
789 if(bind(sockfd, sock, sizeof_sa) >= 0) {
790 /* we succeeded to bind */
791 infof(data, "Local port: %hu", port);
792 conn->bits.bound = TRUE;
793 return CURLE_OK;
794 }
795
796 if(--portnum > 0) {
797 port++; /* try next port */
798 if(port == 0)
799 break;
800 infof(data, "Bind to local port %d failed, trying next", port - 1);
801 /* We reuse/clobber the port variable here below */
802 if(sock->sa_family == AF_INET)
803 si4->sin_port = ntohs(port);
804 #ifdef USE_IPV6
805 else
806 si6->sin6_port = ntohs(port);
807 #endif
808 }
809 else
810 break;
811 }
812 {
813 char buffer[STRERROR_LEN];
814 data->state.os_errno = error = SOCKERRNO;
815 failf(data, "bind failed with errno %d: %s",
816 error, Curl_strerror(error, buffer, sizeof(buffer)));
817 }
818
819 return CURLE_INTERFACE_FAILED;
820 }
821 #endif
822
823 /*
824 * verifyconnect() returns TRUE if the connect really has happened.
825 */
verifyconnect(curl_socket_t sockfd,int * error)826 static bool verifyconnect(curl_socket_t sockfd, int *error)
827 {
828 bool rc = TRUE;
829 #ifdef SO_ERROR
830 int err = 0;
831 curl_socklen_t errSize = sizeof(err);
832
833 #ifdef _WIN32
834 /*
835 * In October 2003 we effectively nullified this function on Windows due to
836 * problems with it using all CPU in multi-threaded cases.
837 *
838 * In May 2004, we bring it back to offer more info back on connect failures.
839 * Gisle Vanem could reproduce the former problems with this function, but
840 * could avoid them by adding this SleepEx() call below:
841 *
842 * "I do not have Rational Quantify, but the hint from his post was
843 * ntdll::NtRemoveIoCompletion(). I would assume the SleepEx (or maybe
844 * just Sleep(0) would be enough?) would release whatever
845 * mutex/critical-section the ntdll call is waiting on.
846 *
847 * Someone got to verify this on Win-NT 4.0, 2000."
848 */
849
850 #ifdef _WIN32_WCE
851 Sleep(0);
852 #else
853 SleepEx(0, FALSE);
854 #endif
855
856 #endif
857
858 if(0 != getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&err, &errSize))
859 err = SOCKERRNO;
860 #ifdef _WIN32_WCE
861 /* Old Windows CE versions do not support SO_ERROR */
862 if(WSAENOPROTOOPT == err) {
863 SET_SOCKERRNO(0);
864 err = 0;
865 }
866 #endif
867 #if defined(EBADIOCTL) && defined(__minix)
868 /* Minix 3.1.x does not support getsockopt on UDP sockets */
869 if(EBADIOCTL == err) {
870 SET_SOCKERRNO(0);
871 err = 0;
872 }
873 #endif
874 if((0 == err) || (EISCONN == err))
875 /* we are connected, awesome! */
876 rc = TRUE;
877 else
878 /* This was not a successful connect */
879 rc = FALSE;
880 if(error)
881 *error = err;
882 #else
883 (void)sockfd;
884 if(error)
885 *error = SOCKERRNO;
886 #endif
887 return rc;
888 }
889
890 /**
891 * Determine the curl code for a socket connect() == -1 with errno.
892 */
socket_connect_result(struct Curl_easy * data,const char * ipaddress,int error)893 static CURLcode socket_connect_result(struct Curl_easy *data,
894 const char *ipaddress, int error)
895 {
896 switch(error) {
897 case EINPROGRESS:
898 case EWOULDBLOCK:
899 #if defined(EAGAIN)
900 #if (EAGAIN) != (EWOULDBLOCK)
901 /* On some platforms EAGAIN and EWOULDBLOCK are the
902 * same value, and on others they are different, hence
903 * the odd #if
904 */
905 case EAGAIN:
906 #endif
907 #endif
908 return CURLE_OK;
909
910 default:
911 /* unknown error, fallthrough and try another address! */
912 #ifdef CURL_DISABLE_VERBOSE_STRINGS
913 (void)ipaddress;
914 #else
915 {
916 char buffer[STRERROR_LEN];
917 infof(data, "Immediate connect fail for %s: %s",
918 ipaddress, Curl_strerror(error, buffer, sizeof(buffer)));
919 }
920 #endif
921 data->state.os_errno = error;
922 /* connect failed */
923 return CURLE_COULDNT_CONNECT;
924 }
925 }
926
927 /* We have a recv buffer to enhance reads with len < NW_SMALL_READS.
928 * This happens often on TLS connections where the TLS implementation
929 * tries to read the head of a TLS record, determine the length of the
930 * full record and then make a subsequent read for that.
931 * On large reads, we will not fill the buffer to avoid the double copy. */
932 #define NW_RECV_CHUNK_SIZE (64 * 1024)
933 #define NW_RECV_CHUNKS 1
934 #define NW_SMALL_READS (1024)
935
936 struct cf_socket_ctx {
937 int transport;
938 struct Curl_sockaddr_ex addr; /* address to connect to */
939 curl_socket_t sock; /* current attempt socket */
940 struct ip_quadruple ip; /* The IP quadruple 2x(addr+port) */
941 struct curltime started_at; /* when socket was created */
942 struct curltime connected_at; /* when socket connected/got first byte */
943 struct curltime first_byte_at; /* when first byte was recvd */
944 #ifdef USE_WINSOCK
945 struct curltime last_sndbuf_query_at; /* when SO_SNDBUF last queried */
946 ULONG sndbuf_size; /* the last set SO_SNDBUF size */
947 #endif
948 int error; /* errno of last failure or 0 */
949 #ifdef DEBUGBUILD
950 int wblock_percent; /* percent of writes doing EAGAIN */
951 int wpartial_percent; /* percent of bytes written in send */
952 int rblock_percent; /* percent of reads doing EAGAIN */
953 size_t recv_max; /* max enforced read size */
954 #endif
955 BIT(got_first_byte); /* if first byte was received */
956 BIT(listening); /* socket is listening */
957 BIT(accepted); /* socket was accepted, not connected */
958 BIT(sock_connected); /* socket is "connected", e.g. in UDP */
959 BIT(active);
960 };
961
cf_socket_ctx_init(struct cf_socket_ctx * ctx,const struct Curl_addrinfo * ai,int transport)962 static void cf_socket_ctx_init(struct cf_socket_ctx *ctx,
963 const struct Curl_addrinfo *ai,
964 int transport)
965 {
966 memset(ctx, 0, sizeof(*ctx));
967 ctx->sock = CURL_SOCKET_BAD;
968 ctx->transport = transport;
969 Curl_sock_assign_addr(&ctx->addr, ai, transport);
970 #ifdef DEBUGBUILD
971 {
972 char *p = getenv("CURL_DBG_SOCK_WBLOCK");
973 if(p) {
974 long l = strtol(p, NULL, 10);
975 if(l >= 0 && l <= 100)
976 ctx->wblock_percent = (int)l;
977 }
978 p = getenv("CURL_DBG_SOCK_WPARTIAL");
979 if(p) {
980 long l = strtol(p, NULL, 10);
981 if(l >= 0 && l <= 100)
982 ctx->wpartial_percent = (int)l;
983 }
984 p = getenv("CURL_DBG_SOCK_RBLOCK");
985 if(p) {
986 long l = strtol(p, NULL, 10);
987 if(l >= 0 && l <= 100)
988 ctx->rblock_percent = (int)l;
989 }
990 p = getenv("CURL_DBG_SOCK_RMAX");
991 if(p) {
992 long l = strtol(p, NULL, 10);
993 if(l >= 0)
994 ctx->recv_max = (size_t)l;
995 }
996 }
997 #endif
998 }
999
cf_socket_close(struct Curl_cfilter * cf,struct Curl_easy * data)1000 static void cf_socket_close(struct Curl_cfilter *cf, struct Curl_easy *data)
1001 {
1002 struct cf_socket_ctx *ctx = cf->ctx;
1003
1004 if(ctx && CURL_SOCKET_BAD != ctx->sock) {
1005 CURL_TRC_CF(data, cf, "cf_socket_close(%" FMT_SOCKET_T ")", ctx->sock);
1006 if(ctx->sock == cf->conn->sock[cf->sockindex])
1007 cf->conn->sock[cf->sockindex] = CURL_SOCKET_BAD;
1008 socket_close(data, cf->conn, !ctx->accepted, ctx->sock);
1009 ctx->sock = CURL_SOCKET_BAD;
1010 if(ctx->active && cf->sockindex == FIRSTSOCKET)
1011 cf->conn->remote_addr = NULL;
1012 ctx->active = FALSE;
1013 memset(&ctx->started_at, 0, sizeof(ctx->started_at));
1014 memset(&ctx->connected_at, 0, sizeof(ctx->connected_at));
1015 }
1016
1017 cf->connected = FALSE;
1018 }
1019
cf_socket_shutdown(struct Curl_cfilter * cf,struct Curl_easy * data,bool * done)1020 static CURLcode cf_socket_shutdown(struct Curl_cfilter *cf,
1021 struct Curl_easy *data,
1022 bool *done)
1023 {
1024 if(cf->connected) {
1025 struct cf_socket_ctx *ctx = cf->ctx;
1026
1027 CURL_TRC_CF(data, cf, "cf_socket_shutdown(%" FMT_SOCKET_T ")", ctx->sock);
1028 /* On TCP, and when the socket looks well and non-blocking mode
1029 * can be enabled, receive dangling bytes before close to avoid
1030 * entering RST states unnecessarily. */
1031 if(ctx->sock != CURL_SOCKET_BAD &&
1032 ctx->transport == TRNSPRT_TCP &&
1033 (curlx_nonblock(ctx->sock, TRUE) >= 0)) {
1034 unsigned char buf[1024];
1035 (void)sread(ctx->sock, buf, sizeof(buf));
1036 }
1037 }
1038 *done = TRUE;
1039 return CURLE_OK;
1040 }
1041
cf_socket_destroy(struct Curl_cfilter * cf,struct Curl_easy * data)1042 static void cf_socket_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
1043 {
1044 struct cf_socket_ctx *ctx = cf->ctx;
1045
1046 cf_socket_close(cf, data);
1047 CURL_TRC_CF(data, cf, "destroy");
1048 free(ctx);
1049 cf->ctx = NULL;
1050 }
1051
set_local_ip(struct Curl_cfilter * cf,struct Curl_easy * data)1052 static CURLcode set_local_ip(struct Curl_cfilter *cf,
1053 struct Curl_easy *data)
1054 {
1055 struct cf_socket_ctx *ctx = cf->ctx;
1056
1057 #ifdef HAVE_GETSOCKNAME
1058 if((ctx->sock != CURL_SOCKET_BAD) &&
1059 !(data->conn->handler->protocol & CURLPROTO_TFTP)) {
1060 /* TFTP does not connect, so it cannot get the IP like this */
1061
1062 char buffer[STRERROR_LEN];
1063 struct Curl_sockaddr_storage ssloc;
1064 curl_socklen_t slen = sizeof(struct Curl_sockaddr_storage);
1065
1066 memset(&ssloc, 0, sizeof(ssloc));
1067 if(getsockname(ctx->sock, (struct sockaddr*) &ssloc, &slen)) {
1068 int error = SOCKERRNO;
1069 failf(data, "getsockname() failed with errno %d: %s",
1070 error, Curl_strerror(error, buffer, sizeof(buffer)));
1071 return CURLE_FAILED_INIT;
1072 }
1073 if(!Curl_addr2string((struct sockaddr*)&ssloc, slen,
1074 ctx->ip.local_ip, &ctx->ip.local_port)) {
1075 failf(data, "ssloc inet_ntop() failed with errno %d: %s",
1076 errno, Curl_strerror(errno, buffer, sizeof(buffer)));
1077 return CURLE_FAILED_INIT;
1078 }
1079 }
1080 #else
1081 (void)data;
1082 ctx->ip.local_ip[0] = 0;
1083 ctx->ip.local_port = -1;
1084 #endif
1085 return CURLE_OK;
1086 }
1087
set_remote_ip(struct Curl_cfilter * cf,struct Curl_easy * data)1088 static CURLcode set_remote_ip(struct Curl_cfilter *cf,
1089 struct Curl_easy *data)
1090 {
1091 struct cf_socket_ctx *ctx = cf->ctx;
1092
1093 /* store remote address and port used in this connection attempt */
1094 if(!Curl_addr2string(&ctx->addr.curl_sa_addr,
1095 (curl_socklen_t)ctx->addr.addrlen,
1096 ctx->ip.remote_ip, &ctx->ip.remote_port)) {
1097 char buffer[STRERROR_LEN];
1098
1099 ctx->error = errno;
1100 /* malformed address or bug in inet_ntop, try next address */
1101 failf(data, "curl_sa_addr inet_ntop() failed with errno %d: %s",
1102 errno, Curl_strerror(errno, buffer, sizeof(buffer)));
1103 return CURLE_FAILED_INIT;
1104 }
1105 return CURLE_OK;
1106 }
1107
cf_socket_open(struct Curl_cfilter * cf,struct Curl_easy * data)1108 static CURLcode cf_socket_open(struct Curl_cfilter *cf,
1109 struct Curl_easy *data)
1110 {
1111 struct cf_socket_ctx *ctx = cf->ctx;
1112 int error = 0;
1113 bool isconnected = FALSE;
1114 CURLcode result = CURLE_COULDNT_CONNECT;
1115 bool is_tcp;
1116
1117 (void)data;
1118 DEBUGASSERT(ctx->sock == CURL_SOCKET_BAD);
1119 ctx->started_at = Curl_now();
1120 #ifdef SOCK_NONBLOCK
1121 /* Do not tuck SOCK_NONBLOCK into socktype when opensocket callback is set
1122 * because we would not know how socketype is about to be used in the
1123 * callback, SOCK_NONBLOCK might get factored out before calling socket().
1124 */
1125 if(!data->set.fopensocket)
1126 ctx->addr.socktype |= SOCK_NONBLOCK;
1127 #endif
1128 result = socket_open(data, &ctx->addr, &ctx->sock);
1129 #ifdef SOCK_NONBLOCK
1130 /* Restore the socktype after the socket is created. */
1131 if(!data->set.fopensocket)
1132 ctx->addr.socktype &= ~SOCK_NONBLOCK;
1133 #endif
1134 if(result)
1135 goto out;
1136
1137 result = set_remote_ip(cf, data);
1138 if(result)
1139 goto out;
1140
1141 #ifdef USE_IPV6
1142 if(ctx->addr.family == AF_INET6) {
1143 set_ipv6_v6only(ctx->sock, 0);
1144 infof(data, " Trying [%s]:%d...", ctx->ip.remote_ip, ctx->ip.remote_port);
1145 }
1146 else
1147 #endif
1148 infof(data, " Trying %s:%d...", ctx->ip.remote_ip, ctx->ip.remote_port);
1149
1150 #ifdef USE_IPV6
1151 is_tcp = (ctx->addr.family == AF_INET
1152 || ctx->addr.family == AF_INET6) &&
1153 ctx->addr.socktype == SOCK_STREAM;
1154 #else
1155 is_tcp = (ctx->addr.family == AF_INET) &&
1156 ctx->addr.socktype == SOCK_STREAM;
1157 #endif
1158 if(is_tcp && data->set.tcp_nodelay)
1159 tcpnodelay(data, ctx->sock);
1160
1161 nosigpipe(data, ctx->sock);
1162
1163 Curl_sndbuf_init(ctx->sock);
1164
1165 if(is_tcp && data->set.tcp_keepalive)
1166 tcpkeepalive(data, ctx->sock);
1167
1168 if(data->set.fsockopt) {
1169 /* activate callback for setting socket options */
1170 Curl_set_in_callback(data, TRUE);
1171 error = data->set.fsockopt(data->set.sockopt_client,
1172 ctx->sock,
1173 CURLSOCKTYPE_IPCXN);
1174 Curl_set_in_callback(data, FALSE);
1175
1176 if(error == CURL_SOCKOPT_ALREADY_CONNECTED)
1177 isconnected = TRUE;
1178 else if(error) {
1179 result = CURLE_ABORTED_BY_CALLBACK;
1180 goto out;
1181 }
1182 }
1183
1184 #ifndef CURL_DISABLE_BINDLOCAL
1185 /* possibly bind the local end to an IP, interface or port */
1186 if(ctx->addr.family == AF_INET
1187 #ifdef USE_IPV6
1188 || ctx->addr.family == AF_INET6
1189 #endif
1190 ) {
1191 result = bindlocal(data, cf->conn, ctx->sock, ctx->addr.family,
1192 Curl_ipv6_scope(&ctx->addr.curl_sa_addr));
1193 if(result) {
1194 if(result == CURLE_UNSUPPORTED_PROTOCOL) {
1195 /* The address family is not supported on this interface.
1196 We can continue trying addresses */
1197 result = CURLE_COULDNT_CONNECT;
1198 }
1199 goto out;
1200 }
1201 }
1202 #endif
1203
1204 #ifndef SOCK_NONBLOCK
1205 /* Set socket non-blocking, must be a non-blocking socket for
1206 * a non-blocking connect. */
1207 error = curlx_nonblock(ctx->sock, TRUE);
1208 if(error < 0) {
1209 result = CURLE_UNSUPPORTED_PROTOCOL;
1210 ctx->error = SOCKERRNO;
1211 goto out;
1212 }
1213 #else
1214 if(data->set.fopensocket) {
1215 /* Set socket non-blocking, must be a non-blocking socket for
1216 * a non-blocking connect. */
1217 error = curlx_nonblock(ctx->sock, TRUE);
1218 if(error < 0) {
1219 result = CURLE_UNSUPPORTED_PROTOCOL;
1220 ctx->error = SOCKERRNO;
1221 goto out;
1222 }
1223 }
1224 #endif
1225 ctx->sock_connected = (ctx->addr.socktype != SOCK_DGRAM);
1226 out:
1227 if(result) {
1228 if(ctx->sock != CURL_SOCKET_BAD) {
1229 socket_close(data, cf->conn, TRUE, ctx->sock);
1230 ctx->sock = CURL_SOCKET_BAD;
1231 }
1232 }
1233 else if(isconnected) {
1234 set_local_ip(cf, data);
1235 ctx->connected_at = Curl_now();
1236 cf->connected = TRUE;
1237 }
1238 CURL_TRC_CF(data, cf, "cf_socket_open() -> %d, fd=%" FMT_SOCKET_T,
1239 result, ctx->sock);
1240 return result;
1241 }
1242
do_connect(struct Curl_cfilter * cf,struct Curl_easy * data,bool is_tcp_fastopen)1243 static int do_connect(struct Curl_cfilter *cf, struct Curl_easy *data,
1244 bool is_tcp_fastopen)
1245 {
1246 struct cf_socket_ctx *ctx = cf->ctx;
1247 #ifdef TCP_FASTOPEN_CONNECT
1248 int optval = 1;
1249 #endif
1250 int rc = -1;
1251
1252 (void)data;
1253 if(is_tcp_fastopen) {
1254 #if defined(CONNECT_DATA_IDEMPOTENT) /* Darwin */
1255 # if defined(HAVE_BUILTIN_AVAILABLE)
1256 /* while connectx function is available since macOS 10.11 / iOS 9,
1257 it did not have the interface declared correctly until
1258 Xcode 9 / macOS SDK 10.13 */
1259 if(__builtin_available(macOS 10.11, iOS 9.0, tvOS 9.0, watchOS 2.0, *)) {
1260 sa_endpoints_t endpoints;
1261 endpoints.sae_srcif = 0;
1262 endpoints.sae_srcaddr = NULL;
1263 endpoints.sae_srcaddrlen = 0;
1264 endpoints.sae_dstaddr = &ctx->addr.curl_sa_addr;
1265 endpoints.sae_dstaddrlen = ctx->addr.addrlen;
1266
1267 rc = connectx(ctx->sock, &endpoints, SAE_ASSOCID_ANY,
1268 CONNECT_RESUME_ON_READ_WRITE | CONNECT_DATA_IDEMPOTENT,
1269 NULL, 0, NULL, NULL);
1270 }
1271 else {
1272 rc = connect(ctx->sock, &ctx->addr.curl_sa_addr, ctx->addr.addrlen);
1273 }
1274 # else
1275 rc = connect(ctx->sock, &ctx->addr.curl_sa_addr, ctx->addr.addrlen);
1276 # endif /* HAVE_BUILTIN_AVAILABLE */
1277 #elif defined(TCP_FASTOPEN_CONNECT) /* Linux >= 4.11 */
1278 if(setsockopt(ctx->sock, IPPROTO_TCP, TCP_FASTOPEN_CONNECT,
1279 (void *)&optval, sizeof(optval)) < 0)
1280 infof(data, "Failed to enable TCP Fast Open on fd %" FMT_SOCKET_T,
1281 ctx->sock);
1282
1283 rc = connect(ctx->sock, &ctx->addr.curl_sa_addr, ctx->addr.addrlen);
1284 #elif defined(MSG_FASTOPEN) /* old Linux */
1285 if(cf->conn->given->flags & PROTOPT_SSL)
1286 rc = connect(ctx->sock, &ctx->addr.curl_sa_addr, ctx->addr.addrlen);
1287 else
1288 rc = 0; /* Do nothing */
1289 #endif
1290 }
1291 else {
1292 rc = connect(ctx->sock, &ctx->addr.curl_sa_addr,
1293 (curl_socklen_t)ctx->addr.addrlen);
1294 }
1295 return rc;
1296 }
1297
cf_tcp_connect(struct Curl_cfilter * cf,struct Curl_easy * data,bool blocking,bool * done)1298 static CURLcode cf_tcp_connect(struct Curl_cfilter *cf,
1299 struct Curl_easy *data,
1300 bool blocking, bool *done)
1301 {
1302 struct cf_socket_ctx *ctx = cf->ctx;
1303 CURLcode result = CURLE_COULDNT_CONNECT;
1304 int rc = 0;
1305
1306 (void)data;
1307 if(cf->connected) {
1308 *done = TRUE;
1309 return CURLE_OK;
1310 }
1311
1312 /* TODO: need to support blocking connect? */
1313 if(blocking)
1314 return CURLE_UNSUPPORTED_PROTOCOL;
1315
1316 *done = FALSE; /* a negative world view is best */
1317 if(ctx->sock == CURL_SOCKET_BAD) {
1318 int error;
1319
1320 result = cf_socket_open(cf, data);
1321 if(result)
1322 goto out;
1323
1324 if(cf->connected) {
1325 *done = TRUE;
1326 return CURLE_OK;
1327 }
1328
1329 /* Connect TCP socket */
1330 rc = do_connect(cf, data, cf->conn->bits.tcp_fastopen);
1331 error = SOCKERRNO;
1332 set_local_ip(cf, data);
1333 CURL_TRC_CF(data, cf, "local address %s port %d...",
1334 ctx->ip.local_ip, ctx->ip.local_port);
1335 if(-1 == rc) {
1336 result = socket_connect_result(data, ctx->ip.remote_ip, error);
1337 goto out;
1338 }
1339 }
1340
1341 #ifdef mpeix
1342 /* Call this function once now, and ignore the results. We do this to
1343 "clear" the error state on the socket so that we can later read it
1344 reliably. This is reported necessary on the MPE/iX operating
1345 system. */
1346 (void)verifyconnect(ctx->sock, NULL);
1347 #endif
1348 /* check socket for connect */
1349 rc = SOCKET_WRITABLE(ctx->sock, 0);
1350
1351 if(rc == 0) { /* no connection yet */
1352 CURL_TRC_CF(data, cf, "not connected yet");
1353 return CURLE_OK;
1354 }
1355 else if(rc == CURL_CSELECT_OUT || cf->conn->bits.tcp_fastopen) {
1356 if(verifyconnect(ctx->sock, &ctx->error)) {
1357 /* we are connected with TCP, awesome! */
1358 ctx->connected_at = Curl_now();
1359 set_local_ip(cf, data);
1360 *done = TRUE;
1361 cf->connected = TRUE;
1362 CURL_TRC_CF(data, cf, "connected");
1363 return CURLE_OK;
1364 }
1365 }
1366 else if(rc & CURL_CSELECT_ERR) {
1367 (void)verifyconnect(ctx->sock, &ctx->error);
1368 result = CURLE_COULDNT_CONNECT;
1369 }
1370
1371 out:
1372 if(result) {
1373 if(ctx->error) {
1374 set_local_ip(cf, data);
1375 data->state.os_errno = ctx->error;
1376 SET_SOCKERRNO(ctx->error);
1377 #ifndef CURL_DISABLE_VERBOSE_STRINGS
1378 {
1379 char buffer[STRERROR_LEN];
1380 infof(data, "connect to %s port %u from %s port %d failed: %s",
1381 ctx->ip.remote_ip, ctx->ip.remote_port,
1382 ctx->ip.local_ip, ctx->ip.local_port,
1383 Curl_strerror(ctx->error, buffer, sizeof(buffer)));
1384 }
1385 #endif
1386 }
1387 if(ctx->sock != CURL_SOCKET_BAD) {
1388 socket_close(data, cf->conn, TRUE, ctx->sock);
1389 ctx->sock = CURL_SOCKET_BAD;
1390 }
1391 *done = FALSE;
1392 }
1393 return result;
1394 }
1395
cf_socket_get_host(struct Curl_cfilter * cf,struct Curl_easy * data,const char ** phost,const char ** pdisplay_host,int * pport)1396 static void cf_socket_get_host(struct Curl_cfilter *cf,
1397 struct Curl_easy *data,
1398 const char **phost,
1399 const char **pdisplay_host,
1400 int *pport)
1401 {
1402 struct cf_socket_ctx *ctx = cf->ctx;
1403 (void)data;
1404 *phost = cf->conn->host.name;
1405 *pdisplay_host = cf->conn->host.dispname;
1406 *pport = ctx->ip.remote_port;
1407 }
1408
cf_socket_adjust_pollset(struct Curl_cfilter * cf,struct Curl_easy * data,struct easy_pollset * ps)1409 static void cf_socket_adjust_pollset(struct Curl_cfilter *cf,
1410 struct Curl_easy *data,
1411 struct easy_pollset *ps)
1412 {
1413 struct cf_socket_ctx *ctx = cf->ctx;
1414
1415 if(ctx->sock != CURL_SOCKET_BAD) {
1416 /* A listening socket filter needs to be connected before the accept
1417 * for some weird FTP interaction. This should be rewritten, so that
1418 * FTP no longer does the socket checks and accept calls and delegates
1419 * all that to the filter. TODO. */
1420 if(ctx->listening) {
1421 Curl_pollset_set_in_only(data, ps, ctx->sock);
1422 CURL_TRC_CF(data, cf, "adjust_pollset, listening, POLLIN fd=%"
1423 FMT_SOCKET_T, ctx->sock);
1424 }
1425 else if(!cf->connected) {
1426 Curl_pollset_set_out_only(data, ps, ctx->sock);
1427 CURL_TRC_CF(data, cf, "adjust_pollset, !connected, POLLOUT fd=%"
1428 FMT_SOCKET_T, ctx->sock);
1429 }
1430 else if(!ctx->active) {
1431 Curl_pollset_add_in(data, ps, ctx->sock);
1432 CURL_TRC_CF(data, cf, "adjust_pollset, !active, POLLIN fd=%"
1433 FMT_SOCKET_T, ctx->sock);
1434 }
1435 }
1436 }
1437
cf_socket_data_pending(struct Curl_cfilter * cf,const struct Curl_easy * data)1438 static bool cf_socket_data_pending(struct Curl_cfilter *cf,
1439 const struct Curl_easy *data)
1440 {
1441 struct cf_socket_ctx *ctx = cf->ctx;
1442 int readable;
1443
1444 (void)data;
1445 readable = SOCKET_READABLE(ctx->sock, 0);
1446 return (readable > 0 && (readable & CURL_CSELECT_IN));
1447 }
1448
1449 #ifdef USE_WINSOCK
1450
1451 #ifndef SIO_IDEAL_SEND_BACKLOG_QUERY
1452 #define SIO_IDEAL_SEND_BACKLOG_QUERY 0x4004747B
1453 #endif
1454
win_update_sndbuf_size(struct cf_socket_ctx * ctx)1455 static void win_update_sndbuf_size(struct cf_socket_ctx *ctx)
1456 {
1457 ULONG ideal;
1458 DWORD ideallen;
1459 struct curltime n = Curl_now();
1460
1461 if(Curl_timediff(n, ctx->last_sndbuf_query_at) > 1000) {
1462 if(!WSAIoctl(ctx->sock, SIO_IDEAL_SEND_BACKLOG_QUERY, 0, 0,
1463 &ideal, sizeof(ideal), &ideallen, 0, 0) &&
1464 ideal != ctx->sndbuf_size &&
1465 !setsockopt(ctx->sock, SOL_SOCKET, SO_SNDBUF,
1466 (const char *)&ideal, sizeof(ideal))) {
1467 ctx->sndbuf_size = ideal;
1468 }
1469 ctx->last_sndbuf_query_at = n;
1470 }
1471 }
1472
1473 #endif /* USE_WINSOCK */
1474
cf_socket_send(struct Curl_cfilter * cf,struct Curl_easy * data,const void * buf,size_t len,bool eos,CURLcode * err)1475 static ssize_t cf_socket_send(struct Curl_cfilter *cf, struct Curl_easy *data,
1476 const void *buf, size_t len, bool eos,
1477 CURLcode *err)
1478 {
1479 struct cf_socket_ctx *ctx = cf->ctx;
1480 curl_socket_t fdsave;
1481 ssize_t nwritten;
1482 size_t orig_len = len;
1483
1484 (void)eos; /* unused */
1485 *err = CURLE_OK;
1486 fdsave = cf->conn->sock[cf->sockindex];
1487 cf->conn->sock[cf->sockindex] = ctx->sock;
1488
1489 #ifdef DEBUGBUILD
1490 /* simulate network blocking/partial writes */
1491 if(ctx->wblock_percent > 0) {
1492 unsigned char c = 0;
1493 Curl_rand_bytes(data, FALSE, &c, 1);
1494 if(c >= ((100-ctx->wblock_percent)*256/100)) {
1495 CURL_TRC_CF(data, cf, "send(len=%zu) SIMULATE EWOULDBLOCK", orig_len);
1496 *err = CURLE_AGAIN;
1497 nwritten = -1;
1498 cf->conn->sock[cf->sockindex] = fdsave;
1499 return nwritten;
1500 }
1501 }
1502 if(cf->cft != &Curl_cft_udp && ctx->wpartial_percent > 0 && len > 8) {
1503 len = len * ctx->wpartial_percent / 100;
1504 if(!len)
1505 len = 1;
1506 CURL_TRC_CF(data, cf, "send(len=%zu) SIMULATE partial write of %zu bytes",
1507 orig_len, len);
1508 }
1509 #endif
1510
1511 #if defined(MSG_FASTOPEN) && !defined(TCP_FASTOPEN_CONNECT) /* Linux */
1512 if(cf->conn->bits.tcp_fastopen) {
1513 nwritten = sendto(ctx->sock, buf, len, MSG_FASTOPEN,
1514 &cf->conn->remote_addr->curl_sa_addr,
1515 cf->conn->remote_addr->addrlen);
1516 cf->conn->bits.tcp_fastopen = FALSE;
1517 }
1518 else
1519 #endif
1520 nwritten = swrite(ctx->sock, buf, len);
1521
1522 if(-1 == nwritten) {
1523 int sockerr = SOCKERRNO;
1524
1525 if(
1526 #ifdef WSAEWOULDBLOCK
1527 /* This is how Windows does it */
1528 (WSAEWOULDBLOCK == sockerr)
1529 #else
1530 /* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned
1531 due to its inability to send off data without blocking. We therefore
1532 treat both error codes the same here */
1533 (EWOULDBLOCK == sockerr) || (EAGAIN == sockerr) || (EINTR == sockerr) ||
1534 (EINPROGRESS == sockerr)
1535 #endif
1536 ) {
1537 /* this is just a case of EWOULDBLOCK */
1538 *err = CURLE_AGAIN;
1539 }
1540 else {
1541 char buffer[STRERROR_LEN];
1542 failf(data, "Send failure: %s",
1543 Curl_strerror(sockerr, buffer, sizeof(buffer)));
1544 data->state.os_errno = sockerr;
1545 *err = CURLE_SEND_ERROR;
1546 }
1547 }
1548
1549 #if defined(USE_WINSOCK)
1550 if(!*err)
1551 win_update_sndbuf_size(ctx);
1552 #endif
1553
1554 CURL_TRC_CF(data, cf, "send(len=%zu) -> %d, err=%d",
1555 orig_len, (int)nwritten, *err);
1556 cf->conn->sock[cf->sockindex] = fdsave;
1557 return nwritten;
1558 }
1559
cf_socket_recv(struct Curl_cfilter * cf,struct Curl_easy * data,char * buf,size_t len,CURLcode * err)1560 static ssize_t cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
1561 char *buf, size_t len, CURLcode *err)
1562 {
1563 struct cf_socket_ctx *ctx = cf->ctx;
1564 ssize_t nread;
1565
1566 *err = CURLE_OK;
1567
1568 #ifdef DEBUGBUILD
1569 /* simulate network blocking/partial reads */
1570 if(cf->cft != &Curl_cft_udp && ctx->rblock_percent > 0) {
1571 unsigned char c = 0;
1572 Curl_rand(data, &c, 1);
1573 if(c >= ((100-ctx->rblock_percent)*256/100)) {
1574 CURL_TRC_CF(data, cf, "recv(len=%zu) SIMULATE EWOULDBLOCK", len);
1575 *err = CURLE_AGAIN;
1576 return -1;
1577 }
1578 }
1579 if(cf->cft != &Curl_cft_udp && ctx->recv_max && ctx->recv_max < len) {
1580 size_t orig_len = len;
1581 len = ctx->recv_max;
1582 CURL_TRC_CF(data, cf, "recv(len=%zu) SIMULATE max read of %zu bytes",
1583 orig_len, len);
1584 }
1585 #endif
1586
1587 *err = CURLE_OK;
1588 nread = sread(ctx->sock, buf, len);
1589
1590 if(-1 == nread) {
1591 int sockerr = SOCKERRNO;
1592
1593 if(
1594 #ifdef WSAEWOULDBLOCK
1595 /* This is how Windows does it */
1596 (WSAEWOULDBLOCK == sockerr)
1597 #else
1598 /* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned
1599 due to its inability to send off data without blocking. We therefore
1600 treat both error codes the same here */
1601 (EWOULDBLOCK == sockerr) || (EAGAIN == sockerr) || (EINTR == sockerr)
1602 #endif
1603 ) {
1604 /* this is just a case of EWOULDBLOCK */
1605 *err = CURLE_AGAIN;
1606 }
1607 else {
1608 char buffer[STRERROR_LEN];
1609
1610 failf(data, "Recv failure: %s",
1611 Curl_strerror(sockerr, buffer, sizeof(buffer)));
1612 data->state.os_errno = sockerr;
1613 *err = CURLE_RECV_ERROR;
1614 }
1615 }
1616
1617 CURL_TRC_CF(data, cf, "recv(len=%zu) -> %d, err=%d", len, (int)nread,
1618 *err);
1619 if(nread > 0 && !ctx->got_first_byte) {
1620 ctx->first_byte_at = Curl_now();
1621 ctx->got_first_byte = TRUE;
1622 }
1623 return nread;
1624 }
1625
cf_socket_update_data(struct Curl_cfilter * cf,struct Curl_easy * data)1626 static void cf_socket_update_data(struct Curl_cfilter *cf,
1627 struct Curl_easy *data)
1628 {
1629 /* Update the IP info held in the transfer, if we have that. */
1630 if(cf->connected && (cf->sockindex == FIRSTSOCKET)) {
1631 struct cf_socket_ctx *ctx = cf->ctx;
1632 data->info.primary = ctx->ip;
1633 /* not sure if this is redundant... */
1634 data->info.conn_remote_port = cf->conn->remote_port;
1635 }
1636 }
1637
cf_socket_active(struct Curl_cfilter * cf,struct Curl_easy * data)1638 static void cf_socket_active(struct Curl_cfilter *cf, struct Curl_easy *data)
1639 {
1640 struct cf_socket_ctx *ctx = cf->ctx;
1641
1642 /* use this socket from now on */
1643 cf->conn->sock[cf->sockindex] = ctx->sock;
1644 set_local_ip(cf, data);
1645 if(cf->sockindex == FIRSTSOCKET) {
1646 cf->conn->primary = ctx->ip;
1647 cf->conn->remote_addr = &ctx->addr;
1648 #ifdef USE_IPV6
1649 cf->conn->bits.ipv6 = (ctx->addr.family == AF_INET6);
1650 #endif
1651 }
1652 else {
1653 cf->conn->secondary = ctx->ip;
1654 }
1655 ctx->active = TRUE;
1656 }
1657
cf_socket_cntrl(struct Curl_cfilter * cf,struct Curl_easy * data,int event,int arg1,void * arg2)1658 static CURLcode cf_socket_cntrl(struct Curl_cfilter *cf,
1659 struct Curl_easy *data,
1660 int event, int arg1, void *arg2)
1661 {
1662 struct cf_socket_ctx *ctx = cf->ctx;
1663
1664 (void)arg1;
1665 (void)arg2;
1666 switch(event) {
1667 case CF_CTRL_CONN_INFO_UPDATE:
1668 cf_socket_active(cf, data);
1669 cf_socket_update_data(cf, data);
1670 break;
1671 case CF_CTRL_DATA_SETUP:
1672 cf_socket_update_data(cf, data);
1673 break;
1674 case CF_CTRL_FORGET_SOCKET:
1675 ctx->sock = CURL_SOCKET_BAD;
1676 break;
1677 }
1678 return CURLE_OK;
1679 }
1680
cf_socket_conn_is_alive(struct Curl_cfilter * cf,struct Curl_easy * data,bool * input_pending)1681 static bool cf_socket_conn_is_alive(struct Curl_cfilter *cf,
1682 struct Curl_easy *data,
1683 bool *input_pending)
1684 {
1685 struct cf_socket_ctx *ctx = cf->ctx;
1686 struct pollfd pfd[1];
1687 int r;
1688
1689 *input_pending = FALSE;
1690 (void)data;
1691 if(!ctx || ctx->sock == CURL_SOCKET_BAD)
1692 return FALSE;
1693
1694 /* Check with 0 timeout if there are any events pending on the socket */
1695 pfd[0].fd = ctx->sock;
1696 pfd[0].events = POLLRDNORM|POLLIN|POLLRDBAND|POLLPRI;
1697 pfd[0].revents = 0;
1698
1699 r = Curl_poll(pfd, 1, 0);
1700 if(r < 0) {
1701 CURL_TRC_CF(data, cf, "is_alive: poll error, assume dead");
1702 return FALSE;
1703 }
1704 else if(r == 0) {
1705 CURL_TRC_CF(data, cf, "is_alive: poll timeout, assume alive");
1706 return TRUE;
1707 }
1708 else if(pfd[0].revents & (POLLERR|POLLHUP|POLLPRI|POLLNVAL)) {
1709 CURL_TRC_CF(data, cf, "is_alive: err/hup/etc events, assume dead");
1710 return FALSE;
1711 }
1712
1713 CURL_TRC_CF(data, cf, "is_alive: valid events, looks alive");
1714 *input_pending = TRUE;
1715 return TRUE;
1716 }
1717
cf_socket_query(struct Curl_cfilter * cf,struct Curl_easy * data,int query,int * pres1,void * pres2)1718 static CURLcode cf_socket_query(struct Curl_cfilter *cf,
1719 struct Curl_easy *data,
1720 int query, int *pres1, void *pres2)
1721 {
1722 struct cf_socket_ctx *ctx = cf->ctx;
1723
1724 switch(query) {
1725 case CF_QUERY_SOCKET:
1726 DEBUGASSERT(pres2);
1727 *((curl_socket_t *)pres2) = ctx->sock;
1728 return CURLE_OK;
1729 case CF_QUERY_CONNECT_REPLY_MS:
1730 if(ctx->got_first_byte) {
1731 timediff_t ms = Curl_timediff(ctx->first_byte_at, ctx->started_at);
1732 *pres1 = (ms < INT_MAX) ? (int)ms : INT_MAX;
1733 }
1734 else
1735 *pres1 = -1;
1736 return CURLE_OK;
1737 case CF_QUERY_TIMER_CONNECT: {
1738 struct curltime *when = pres2;
1739 switch(ctx->transport) {
1740 case TRNSPRT_UDP:
1741 case TRNSPRT_QUIC:
1742 /* Since UDP connected sockets work different from TCP, we use the
1743 * time of the first byte from the peer as the "connect" time. */
1744 if(ctx->got_first_byte) {
1745 *when = ctx->first_byte_at;
1746 break;
1747 }
1748 FALLTHROUGH();
1749 default:
1750 *when = ctx->connected_at;
1751 break;
1752 }
1753 return CURLE_OK;
1754 }
1755 case CF_QUERY_IP_INFO:
1756 #ifdef USE_IPV6
1757 *pres1 = (ctx->addr.family == AF_INET6);
1758 #else
1759 *pres1 = FALSE;
1760 #endif
1761 *(struct ip_quadruple *)pres2 = ctx->ip;
1762 return CURLE_OK;
1763 default:
1764 break;
1765 }
1766 return cf->next ?
1767 cf->next->cft->query(cf->next, data, query, pres1, pres2) :
1768 CURLE_UNKNOWN_OPTION;
1769 }
1770
1771 struct Curl_cftype Curl_cft_tcp = {
1772 "TCP",
1773 CF_TYPE_IP_CONNECT,
1774 CURL_LOG_LVL_NONE,
1775 cf_socket_destroy,
1776 cf_tcp_connect,
1777 cf_socket_close,
1778 cf_socket_shutdown,
1779 cf_socket_get_host,
1780 cf_socket_adjust_pollset,
1781 cf_socket_data_pending,
1782 cf_socket_send,
1783 cf_socket_recv,
1784 cf_socket_cntrl,
1785 cf_socket_conn_is_alive,
1786 Curl_cf_def_conn_keep_alive,
1787 cf_socket_query,
1788 };
1789
Curl_cf_tcp_create(struct Curl_cfilter ** pcf,struct Curl_easy * data,struct connectdata * conn,const struct Curl_addrinfo * ai,int transport)1790 CURLcode Curl_cf_tcp_create(struct Curl_cfilter **pcf,
1791 struct Curl_easy *data,
1792 struct connectdata *conn,
1793 const struct Curl_addrinfo *ai,
1794 int transport)
1795 {
1796 struct cf_socket_ctx *ctx = NULL;
1797 struct Curl_cfilter *cf = NULL;
1798 CURLcode result;
1799
1800 (void)data;
1801 (void)conn;
1802 DEBUGASSERT(transport == TRNSPRT_TCP);
1803 ctx = calloc(1, sizeof(*ctx));
1804 if(!ctx) {
1805 result = CURLE_OUT_OF_MEMORY;
1806 goto out;
1807 }
1808 cf_socket_ctx_init(ctx, ai, transport);
1809
1810 result = Curl_cf_create(&cf, &Curl_cft_tcp, ctx);
1811
1812 out:
1813 *pcf = (!result) ? cf : NULL;
1814 if(result) {
1815 Curl_safefree(cf);
1816 Curl_safefree(ctx);
1817 }
1818
1819 return result;
1820 }
1821
cf_udp_setup_quic(struct Curl_cfilter * cf,struct Curl_easy * data)1822 static CURLcode cf_udp_setup_quic(struct Curl_cfilter *cf,
1823 struct Curl_easy *data)
1824 {
1825 struct cf_socket_ctx *ctx = cf->ctx;
1826 int rc;
1827 int one = 1;
1828
1829 (void)one;
1830
1831 /* QUIC needs a connected socket, nonblocking */
1832 DEBUGASSERT(ctx->sock != CURL_SOCKET_BAD);
1833
1834 rc = connect(ctx->sock, &ctx->addr.curl_sa_addr,
1835 (curl_socklen_t)ctx->addr.addrlen);
1836 if(-1 == rc) {
1837 return socket_connect_result(data, ctx->ip.remote_ip, SOCKERRNO);
1838 }
1839 ctx->sock_connected = TRUE;
1840 set_local_ip(cf, data);
1841 CURL_TRC_CF(data, cf, "%s socket %" FMT_SOCKET_T
1842 " connected: [%s:%d] -> [%s:%d]",
1843 (ctx->transport == TRNSPRT_QUIC) ? "QUIC" : "UDP",
1844 ctx->sock, ctx->ip.local_ip, ctx->ip.local_port,
1845 ctx->ip.remote_ip, ctx->ip.remote_port);
1846
1847 /* Currently, cf->ctx->sock is always non-blocking because the only
1848 * caller to cf_udp_setup_quic() is cf_udp_connect() that passes the
1849 * non-blocking socket created by cf_socket_open() to it. Thus, we
1850 * do not need to call curlx_nonblock() in cf_udp_setup_quic() anymore.
1851 */
1852 switch(ctx->addr.family) {
1853 #if defined(__linux__) && defined(IP_MTU_DISCOVER)
1854 case AF_INET: {
1855 int val = IP_PMTUDISC_DO;
1856 (void)setsockopt(ctx->sock, IPPROTO_IP, IP_MTU_DISCOVER, &val,
1857 sizeof(val));
1858 break;
1859 }
1860 #endif
1861 #if defined(__linux__) && defined(IPV6_MTU_DISCOVER)
1862 case AF_INET6: {
1863 int val = IPV6_PMTUDISC_DO;
1864 (void)setsockopt(ctx->sock, IPPROTO_IPV6, IPV6_MTU_DISCOVER, &val,
1865 sizeof(val));
1866 break;
1867 }
1868 #endif
1869 }
1870
1871 #if defined(__linux__) && defined(UDP_GRO) && \
1872 (defined(HAVE_SENDMMSG) || defined(HAVE_SENDMSG)) && \
1873 ((defined(USE_NGTCP2) && defined(USE_NGHTTP3)) || defined(USE_QUICHE))
1874 (void)setsockopt(ctx->sock, IPPROTO_UDP, UDP_GRO, &one,
1875 (socklen_t)sizeof(one));
1876 #endif
1877
1878 return CURLE_OK;
1879 }
1880
cf_udp_connect(struct Curl_cfilter * cf,struct Curl_easy * data,bool blocking,bool * done)1881 static CURLcode cf_udp_connect(struct Curl_cfilter *cf,
1882 struct Curl_easy *data,
1883 bool blocking, bool *done)
1884 {
1885 struct cf_socket_ctx *ctx = cf->ctx;
1886 CURLcode result = CURLE_COULDNT_CONNECT;
1887
1888 (void)blocking;
1889 if(cf->connected) {
1890 *done = TRUE;
1891 return CURLE_OK;
1892 }
1893 *done = FALSE;
1894 if(ctx->sock == CURL_SOCKET_BAD) {
1895 result = cf_socket_open(cf, data);
1896 if(result) {
1897 CURL_TRC_CF(data, cf, "cf_udp_connect(), open failed -> %d", result);
1898 goto out;
1899 }
1900
1901 if(ctx->transport == TRNSPRT_QUIC) {
1902 result = cf_udp_setup_quic(cf, data);
1903 if(result)
1904 goto out;
1905 CURL_TRC_CF(data, cf, "cf_udp_connect(), opened socket=%"
1906 FMT_SOCKET_T " (%s:%d)",
1907 ctx->sock, ctx->ip.local_ip, ctx->ip.local_port);
1908 }
1909 else {
1910 CURL_TRC_CF(data, cf, "cf_udp_connect(), opened socket=%"
1911 FMT_SOCKET_T " (unconnected)", ctx->sock);
1912 }
1913 *done = TRUE;
1914 cf->connected = TRUE;
1915 }
1916 out:
1917 return result;
1918 }
1919
1920 struct Curl_cftype Curl_cft_udp = {
1921 "UDP",
1922 CF_TYPE_IP_CONNECT,
1923 CURL_LOG_LVL_NONE,
1924 cf_socket_destroy,
1925 cf_udp_connect,
1926 cf_socket_close,
1927 cf_socket_shutdown,
1928 cf_socket_get_host,
1929 cf_socket_adjust_pollset,
1930 cf_socket_data_pending,
1931 cf_socket_send,
1932 cf_socket_recv,
1933 cf_socket_cntrl,
1934 cf_socket_conn_is_alive,
1935 Curl_cf_def_conn_keep_alive,
1936 cf_socket_query,
1937 };
1938
Curl_cf_udp_create(struct Curl_cfilter ** pcf,struct Curl_easy * data,struct connectdata * conn,const struct Curl_addrinfo * ai,int transport)1939 CURLcode Curl_cf_udp_create(struct Curl_cfilter **pcf,
1940 struct Curl_easy *data,
1941 struct connectdata *conn,
1942 const struct Curl_addrinfo *ai,
1943 int transport)
1944 {
1945 struct cf_socket_ctx *ctx = NULL;
1946 struct Curl_cfilter *cf = NULL;
1947 CURLcode result;
1948
1949 (void)data;
1950 (void)conn;
1951 DEBUGASSERT(transport == TRNSPRT_UDP || transport == TRNSPRT_QUIC);
1952 ctx = calloc(1, sizeof(*ctx));
1953 if(!ctx) {
1954 result = CURLE_OUT_OF_MEMORY;
1955 goto out;
1956 }
1957 cf_socket_ctx_init(ctx, ai, transport);
1958
1959 result = Curl_cf_create(&cf, &Curl_cft_udp, ctx);
1960
1961 out:
1962 *pcf = (!result) ? cf : NULL;
1963 if(result) {
1964 Curl_safefree(cf);
1965 Curl_safefree(ctx);
1966 }
1967
1968 return result;
1969 }
1970
1971 /* this is the TCP filter which can also handle this case */
1972 struct Curl_cftype Curl_cft_unix = {
1973 "UNIX",
1974 CF_TYPE_IP_CONNECT,
1975 CURL_LOG_LVL_NONE,
1976 cf_socket_destroy,
1977 cf_tcp_connect,
1978 cf_socket_close,
1979 cf_socket_shutdown,
1980 cf_socket_get_host,
1981 cf_socket_adjust_pollset,
1982 cf_socket_data_pending,
1983 cf_socket_send,
1984 cf_socket_recv,
1985 cf_socket_cntrl,
1986 cf_socket_conn_is_alive,
1987 Curl_cf_def_conn_keep_alive,
1988 cf_socket_query,
1989 };
1990
Curl_cf_unix_create(struct Curl_cfilter ** pcf,struct Curl_easy * data,struct connectdata * conn,const struct Curl_addrinfo * ai,int transport)1991 CURLcode Curl_cf_unix_create(struct Curl_cfilter **pcf,
1992 struct Curl_easy *data,
1993 struct connectdata *conn,
1994 const struct Curl_addrinfo *ai,
1995 int transport)
1996 {
1997 struct cf_socket_ctx *ctx = NULL;
1998 struct Curl_cfilter *cf = NULL;
1999 CURLcode result;
2000
2001 (void)data;
2002 (void)conn;
2003 DEBUGASSERT(transport == TRNSPRT_UNIX);
2004 ctx = calloc(1, sizeof(*ctx));
2005 if(!ctx) {
2006 result = CURLE_OUT_OF_MEMORY;
2007 goto out;
2008 }
2009 cf_socket_ctx_init(ctx, ai, transport);
2010
2011 result = Curl_cf_create(&cf, &Curl_cft_unix, ctx);
2012
2013 out:
2014 *pcf = (!result) ? cf : NULL;
2015 if(result) {
2016 Curl_safefree(cf);
2017 Curl_safefree(ctx);
2018 }
2019
2020 return result;
2021 }
2022
cf_tcp_accept_timeleft(struct Curl_cfilter * cf,struct Curl_easy * data)2023 static timediff_t cf_tcp_accept_timeleft(struct Curl_cfilter *cf,
2024 struct Curl_easy *data)
2025 {
2026 struct cf_socket_ctx *ctx = cf->ctx;
2027 timediff_t timeout_ms = DEFAULT_ACCEPT_TIMEOUT;
2028 timediff_t other;
2029 struct curltime now;
2030
2031 #ifndef CURL_DISABLE_FTP
2032 if(data->set.accepttimeout > 0)
2033 timeout_ms = data->set.accepttimeout;
2034 #endif
2035
2036 now = Curl_now();
2037 /* check if the generic timeout possibly is set shorter */
2038 other = Curl_timeleft(data, &now, FALSE);
2039 if(other && (other < timeout_ms))
2040 /* note that this also works fine for when other happens to be negative
2041 due to it already having elapsed */
2042 timeout_ms = other;
2043 else {
2044 /* subtract elapsed time */
2045 timeout_ms -= Curl_timediff(now, ctx->started_at);
2046 if(!timeout_ms)
2047 /* avoid returning 0 as that means no timeout! */
2048 timeout_ms = -1;
2049 }
2050 return timeout_ms;
2051 }
2052
cf_tcp_set_accepted_remote_ip(struct Curl_cfilter * cf,struct Curl_easy * data)2053 static void cf_tcp_set_accepted_remote_ip(struct Curl_cfilter *cf,
2054 struct Curl_easy *data)
2055 {
2056 struct cf_socket_ctx *ctx = cf->ctx;
2057 #ifdef HAVE_GETPEERNAME
2058 char buffer[STRERROR_LEN];
2059 struct Curl_sockaddr_storage ssrem;
2060 curl_socklen_t plen;
2061
2062 ctx->ip.remote_ip[0] = 0;
2063 ctx->ip.remote_port = 0;
2064 plen = sizeof(ssrem);
2065 memset(&ssrem, 0, plen);
2066 if(getpeername(ctx->sock, (struct sockaddr*) &ssrem, &plen)) {
2067 int error = SOCKERRNO;
2068 failf(data, "getpeername() failed with errno %d: %s",
2069 error, Curl_strerror(error, buffer, sizeof(buffer)));
2070 return;
2071 }
2072 if(!Curl_addr2string((struct sockaddr*)&ssrem, plen,
2073 ctx->ip.remote_ip, &ctx->ip.remote_port)) {
2074 failf(data, "ssrem inet_ntop() failed with errno %d: %s",
2075 errno, Curl_strerror(errno, buffer, sizeof(buffer)));
2076 return;
2077 }
2078 #else
2079 ctx->ip.remote_ip[0] = 0;
2080 ctx->ip.remote_port = 0;
2081 (void)data;
2082 #endif
2083 }
2084
cf_tcp_accept_connect(struct Curl_cfilter * cf,struct Curl_easy * data,bool blocking,bool * done)2085 static CURLcode cf_tcp_accept_connect(struct Curl_cfilter *cf,
2086 struct Curl_easy *data,
2087 bool blocking, bool *done)
2088 {
2089 struct cf_socket_ctx *ctx = cf->ctx;
2090 #ifdef USE_IPV6
2091 struct Curl_sockaddr_storage add;
2092 #else
2093 struct sockaddr_in add;
2094 #endif
2095 curl_socklen_t size = (curl_socklen_t) sizeof(add);
2096 curl_socket_t s_accepted = CURL_SOCKET_BAD;
2097 timediff_t timeout_ms;
2098 int socketstate = 0;
2099 bool incoming = FALSE;
2100
2101 /* we start accepted, if we ever close, we cannot go on */
2102 (void)data;
2103 (void)blocking;
2104 if(cf->connected) {
2105 *done = TRUE;
2106 return CURLE_OK;
2107 }
2108
2109 timeout_ms = cf_tcp_accept_timeleft(cf, data);
2110 if(timeout_ms < 0) {
2111 /* if a timeout was already reached, bail out */
2112 failf(data, "Accept timeout occurred while waiting server connect");
2113 return CURLE_FTP_ACCEPT_TIMEOUT;
2114 }
2115
2116 CURL_TRC_CF(data, cf, "Checking for incoming on fd=%" FMT_SOCKET_T
2117 " ip=%s:%d", ctx->sock, ctx->ip.local_ip, ctx->ip.local_port);
2118 socketstate = Curl_socket_check(ctx->sock, CURL_SOCKET_BAD,
2119 CURL_SOCKET_BAD, 0);
2120 CURL_TRC_CF(data, cf, "socket_check -> %x", socketstate);
2121 switch(socketstate) {
2122 case -1: /* error */
2123 /* let's die here */
2124 failf(data, "Error while waiting for server connect");
2125 return CURLE_FTP_ACCEPT_FAILED;
2126 default:
2127 if(socketstate & CURL_CSELECT_IN) {
2128 infof(data, "Ready to accept data connection from server");
2129 incoming = TRUE;
2130 }
2131 break;
2132 }
2133
2134 if(!incoming) {
2135 CURL_TRC_CF(data, cf, "nothing heard from the server yet");
2136 *done = FALSE;
2137 return CURLE_OK;
2138 }
2139
2140 if(0 == getsockname(ctx->sock, (struct sockaddr *) &add, &size)) {
2141 size = sizeof(add);
2142 s_accepted = accept(ctx->sock, (struct sockaddr *) &add, &size);
2143 }
2144
2145 if(CURL_SOCKET_BAD == s_accepted) {
2146 failf(data, "Error accept()ing server connect");
2147 return CURLE_FTP_PORT_FAILED;
2148 }
2149
2150 infof(data, "Connection accepted from server");
2151 (void)curlx_nonblock(s_accepted, TRUE); /* enable non-blocking */
2152 /* Replace any filter on SECONDARY with one listening on this socket */
2153 ctx->listening = FALSE;
2154 ctx->accepted = TRUE;
2155 socket_close(data, cf->conn, TRUE, ctx->sock);
2156 ctx->sock = s_accepted;
2157
2158 cf->conn->sock[cf->sockindex] = ctx->sock;
2159 cf_tcp_set_accepted_remote_ip(cf, data);
2160 set_local_ip(cf, data);
2161 ctx->active = TRUE;
2162 ctx->connected_at = Curl_now();
2163 cf->connected = TRUE;
2164 CURL_TRC_CF(data, cf, "accepted_set(sock=%" FMT_SOCKET_T
2165 ", remote=%s port=%d)",
2166 ctx->sock, ctx->ip.remote_ip, ctx->ip.remote_port);
2167
2168 if(data->set.fsockopt) {
2169 int error = 0;
2170
2171 /* activate callback for setting socket options */
2172 Curl_set_in_callback(data, true);
2173 error = data->set.fsockopt(data->set.sockopt_client,
2174 ctx->sock, CURLSOCKTYPE_ACCEPT);
2175 Curl_set_in_callback(data, false);
2176
2177 if(error)
2178 return CURLE_ABORTED_BY_CALLBACK;
2179 }
2180 return CURLE_OK;
2181 }
2182
2183 struct Curl_cftype Curl_cft_tcp_accept = {
2184 "TCP-ACCEPT",
2185 CF_TYPE_IP_CONNECT,
2186 CURL_LOG_LVL_NONE,
2187 cf_socket_destroy,
2188 cf_tcp_accept_connect,
2189 cf_socket_close,
2190 cf_socket_shutdown,
2191 cf_socket_get_host, /* TODO: not accurate */
2192 cf_socket_adjust_pollset,
2193 cf_socket_data_pending,
2194 cf_socket_send,
2195 cf_socket_recv,
2196 cf_socket_cntrl,
2197 cf_socket_conn_is_alive,
2198 Curl_cf_def_conn_keep_alive,
2199 cf_socket_query,
2200 };
2201
Curl_conn_tcp_listen_set(struct Curl_easy * data,struct connectdata * conn,int sockindex,curl_socket_t * s)2202 CURLcode Curl_conn_tcp_listen_set(struct Curl_easy *data,
2203 struct connectdata *conn,
2204 int sockindex, curl_socket_t *s)
2205 {
2206 CURLcode result;
2207 struct Curl_cfilter *cf = NULL;
2208 struct cf_socket_ctx *ctx = NULL;
2209
2210 /* replace any existing */
2211 Curl_conn_cf_discard_all(data, conn, sockindex);
2212 DEBUGASSERT(conn->sock[sockindex] == CURL_SOCKET_BAD);
2213
2214 ctx = calloc(1, sizeof(*ctx));
2215 if(!ctx) {
2216 result = CURLE_OUT_OF_MEMORY;
2217 goto out;
2218 }
2219 ctx->transport = conn->transport;
2220 ctx->sock = *s;
2221 ctx->listening = TRUE;
2222 ctx->accepted = FALSE;
2223 result = Curl_cf_create(&cf, &Curl_cft_tcp_accept, ctx);
2224 if(result)
2225 goto out;
2226 Curl_conn_cf_add(data, conn, sockindex, cf);
2227
2228 ctx->started_at = Curl_now();
2229 conn->sock[sockindex] = ctx->sock;
2230 set_local_ip(cf, data);
2231 CURL_TRC_CF(data, cf, "set filter for listen socket fd=%" FMT_SOCKET_T
2232 " ip=%s:%d", ctx->sock,
2233 ctx->ip.local_ip, ctx->ip.local_port);
2234
2235 out:
2236 if(result) {
2237 Curl_safefree(cf);
2238 Curl_safefree(ctx);
2239 }
2240 return result;
2241 }
2242
Curl_conn_is_tcp_listen(struct Curl_easy * data,int sockindex)2243 bool Curl_conn_is_tcp_listen(struct Curl_easy *data,
2244 int sockindex)
2245 {
2246 struct Curl_cfilter *cf = data->conn->cfilter[sockindex];
2247 while(cf) {
2248 if(cf->cft == &Curl_cft_tcp_accept)
2249 return TRUE;
2250 cf = cf->next;
2251 }
2252 return FALSE;
2253 }
2254
2255 /**
2256 * Return TRUE iff `cf` is a socket filter.
2257 */
cf_is_socket(struct Curl_cfilter * cf)2258 static bool cf_is_socket(struct Curl_cfilter *cf)
2259 {
2260 return cf && (cf->cft == &Curl_cft_tcp ||
2261 cf->cft == &Curl_cft_udp ||
2262 cf->cft == &Curl_cft_unix ||
2263 cf->cft == &Curl_cft_tcp_accept);
2264 }
2265
Curl_cf_socket_peek(struct Curl_cfilter * cf,struct Curl_easy * data,curl_socket_t * psock,const struct Curl_sockaddr_ex ** paddr,struct ip_quadruple * pip)2266 CURLcode Curl_cf_socket_peek(struct Curl_cfilter *cf,
2267 struct Curl_easy *data,
2268 curl_socket_t *psock,
2269 const struct Curl_sockaddr_ex **paddr,
2270 struct ip_quadruple *pip)
2271 {
2272 (void)data;
2273 if(cf_is_socket(cf) && cf->ctx) {
2274 struct cf_socket_ctx *ctx = cf->ctx;
2275
2276 if(psock)
2277 *psock = ctx->sock;
2278 if(paddr)
2279 *paddr = &ctx->addr;
2280 if(pip)
2281 *pip = ctx->ip;
2282 return CURLE_OK;
2283 }
2284 return CURLE_FAILED_INIT;
2285 }
2286