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