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