1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel (at) 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.haxx.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 ***************************************************************************/ 22 23 #include "curl_setup.h" 24 25 #ifdef HAVE_NETINET_IN_H 26 #include <netinet/in.h> /* <netinet/tcp.h> may need it */ 27 #endif 28 #ifdef HAVE_SYS_UN_H 29 #include <sys/un.h> /* for sockaddr_un */ 30 #endif 31 #ifdef HAVE_LINUX_TCP_H 32 #include <linux/tcp.h> 33 #elif defined(HAVE_NETINET_TCP_H) 34 #include <netinet/tcp.h> 35 #endif 36 #ifdef HAVE_SYS_IOCTL_H 37 #include <sys/ioctl.h> 38 #endif 39 #ifdef HAVE_NETDB_H 40 #include <netdb.h> 41 #endif 42 #ifdef HAVE_FCNTL_H 43 #include <fcntl.h> 44 #endif 45 #ifdef HAVE_ARPA_INET_H 46 #include <arpa/inet.h> 47 #endif 48 49 #if (defined(HAVE_IOCTL_FIONBIO) && defined(NETWARE)) 50 #include <sys/filio.h> 51 #endif 52 #ifdef NETWARE 53 #undef in_addr_t 54 #define in_addr_t unsigned long 55 #endif 56 #ifdef __VMS 57 #include <in.h> 58 #include <inet.h> 59 #endif 60 61 #include "urldata.h" 62 #include "sendf.h" 63 #include "if2ip.h" 64 #include "strerror.h" 65 #include "connect.h" 66 #include "select.h" 67 #include "url.h" /* for Curl_safefree() */ 68 #include "multiif.h" 69 #include "sockaddr.h" /* required for Curl_sockaddr_storage */ 70 #include "inet_ntop.h" 71 #include "inet_pton.h" 72 #include "vtls/vtls.h" /* for Curl_ssl_check_cxn() */ 73 #include "progress.h" 74 #include "warnless.h" 75 #include "conncache.h" 76 #include "multihandle.h" 77 #include "system_win32.h" 78 79 /* The last 3 #include files should be in this order */ 80 #include "curl_printf.h" 81 #include "curl_memory.h" 82 #include "memdebug.h" 83 84 #ifdef __SYMBIAN32__ 85 /* This isn't actually supported under Symbian OS */ 86 #undef SO_NOSIGPIPE 87 #endif 88 89 static bool verifyconnect(curl_socket_t sockfd, int *error); 90 91 #if defined(__DragonFly__) || defined(HAVE_WINSOCK_H) 92 /* DragonFlyBSD and Windows use millisecond units */ 93 #define KEEPALIVE_FACTOR(x) (x *= 1000) 94 #else 95 #define KEEPALIVE_FACTOR(x) 96 #endif 97 98 #if defined(HAVE_WINSOCK2_H) && !defined(SIO_KEEPALIVE_VALS) 99 #define SIO_KEEPALIVE_VALS _WSAIOW(IOC_VENDOR,4) 100 101 struct tcp_keepalive { 102 u_long onoff; 103 u_long keepalivetime; 104 u_long keepaliveinterval; 105 }; 106 #endif 107 108 static void 109 tcpkeepalive(struct Curl_easy *data, 110 curl_socket_t sockfd) 111 { 112 int optval = data->set.tcp_keepalive?1:0; 113 114 /* only set IDLE and INTVL if setting KEEPALIVE is successful */ 115 if(setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, 116 (void *)&optval, sizeof(optval)) < 0) { 117 infof(data, "Failed to set SO_KEEPALIVE on fd %d\n", sockfd); 118 } 119 else { 120 #if defined(SIO_KEEPALIVE_VALS) 121 struct tcp_keepalive vals; 122 DWORD dummy; 123 vals.onoff = 1; 124 optval = curlx_sltosi(data->set.tcp_keepidle); 125 KEEPALIVE_FACTOR(optval); 126 vals.keepalivetime = optval; 127 optval = curlx_sltosi(data->set.tcp_keepintvl); 128 KEEPALIVE_FACTOR(optval); 129 vals.keepaliveinterval = optval; 130 if(WSAIoctl(sockfd, SIO_KEEPALIVE_VALS, (LPVOID) &vals, sizeof(vals), 131 NULL, 0, &dummy, NULL, NULL) != 0) { 132 infof(data, "Failed to set SIO_KEEPALIVE_VALS on fd %d: %d\n", 133 (int)sockfd, WSAGetLastError()); 134 } 135 #else 136 #ifdef TCP_KEEPIDLE 137 optval = curlx_sltosi(data->set.tcp_keepidle); 138 KEEPALIVE_FACTOR(optval); 139 if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE, 140 (void *)&optval, sizeof(optval)) < 0) { 141 infof(data, "Failed to set TCP_KEEPIDLE on fd %d\n", sockfd); 142 } 143 #endif 144 #ifdef TCP_KEEPINTVL 145 optval = curlx_sltosi(data->set.tcp_keepintvl); 146 KEEPALIVE_FACTOR(optval); 147 if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL, 148 (void *)&optval, sizeof(optval)) < 0) { 149 infof(data, "Failed to set TCP_KEEPINTVL on fd %d\n", sockfd); 150 } 151 #endif 152 #ifdef TCP_KEEPALIVE 153 /* Mac OS X style */ 154 optval = curlx_sltosi(data->set.tcp_keepidle); 155 KEEPALIVE_FACTOR(optval); 156 if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE, 157 (void *)&optval, sizeof(optval)) < 0) { 158 infof(data, "Failed to set TCP_KEEPALIVE on fd %d\n", sockfd); 159 } 160 #endif 161 #endif 162 } 163 } 164 165 static CURLcode 166 singleipconnect(struct connectdata *conn, 167 const Curl_addrinfo *ai, /* start connecting to this */ 168 curl_socket_t *sock); 169 170 /* 171 * Curl_timeleft() returns the amount of milliseconds left allowed for the 172 * transfer/connection. If the value is negative, the timeout time has already 173 * elapsed. 174 * 175 * The start time is stored in progress.t_startsingle - as set with 176 * Curl_pgrsTime(..., TIMER_STARTSINGLE); 177 * 178 * If 'nowp' is non-NULL, it points to the current time. 179 * 'duringconnect' is FALSE if not during a connect, as then of course the 180 * connect timeout is not taken into account! 181 * 182 * @unittest: 1303 183 */ 184 timediff_t Curl_timeleft(struct Curl_easy *data, 185 struct curltime *nowp, 186 bool duringconnect) 187 { 188 int timeout_set = 0; 189 timediff_t timeout_ms = duringconnect?DEFAULT_CONNECT_TIMEOUT:0; 190 struct curltime now; 191 192 /* if a timeout is set, use the most restrictive one */ 193 194 if(data->set.timeout > 0) 195 timeout_set |= 1; 196 if(duringconnect && (data->set.connecttimeout > 0)) 197 timeout_set |= 2; 198 199 switch(timeout_set) { 200 case 1: 201 timeout_ms = data->set.timeout; 202 break; 203 case 2: 204 timeout_ms = data->set.connecttimeout; 205 break; 206 case 3: 207 if(data->set.timeout < data->set.connecttimeout) 208 timeout_ms = data->set.timeout; 209 else 210 timeout_ms = data->set.connecttimeout; 211 break; 212 default: 213 /* use the default */ 214 if(!duringconnect) 215 /* if we're not during connect, there's no default timeout so if we're 216 at zero we better just return zero and not make it a negative number 217 by the math below */ 218 return 0; 219 break; 220 } 221 222 if(!nowp) { 223 now = Curl_now(); 224 nowp = &now; 225 } 226 227 /* subtract elapsed time */ 228 if(duringconnect) 229 /* since this most recent connect started */ 230 timeout_ms -= Curl_timediff(*nowp, data->progress.t_startsingle); 231 else 232 /* since the entire operation started */ 233 timeout_ms -= Curl_timediff(*nowp, data->progress.t_startop); 234 if(!timeout_ms) 235 /* avoid returning 0 as that means no timeout! */ 236 return -1; 237 238 return timeout_ms; 239 } 240 241 static CURLcode bindlocal(struct connectdata *conn, 242 curl_socket_t sockfd, int af, unsigned int scope) 243 { 244 struct Curl_easy *data = conn->data; 245 246 struct Curl_sockaddr_storage sa; 247 struct sockaddr *sock = (struct sockaddr *)&sa; /* bind to this address */ 248 curl_socklen_t sizeof_sa = 0; /* size of the data sock points to */ 249 struct sockaddr_in *si4 = (struct sockaddr_in *)&sa; 250 #ifdef ENABLE_IPV6 251 struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)&sa; 252 #endif 253 254 struct Curl_dns_entry *h = NULL; 255 unsigned short port = data->set.localport; /* use this port number, 0 for 256 "random" */ 257 /* how many port numbers to try to bind to, increasing one at a time */ 258 int portnum = data->set.localportrange; 259 const char *dev = data->set.str[STRING_DEVICE]; 260 int error; 261 262 /************************************************************* 263 * Select device to bind socket to 264 *************************************************************/ 265 if(!dev && !port) 266 /* no local kind of binding was requested */ 267 return CURLE_OK; 268 269 memset(&sa, 0, sizeof(struct Curl_sockaddr_storage)); 270 271 if(dev && (strlen(dev)<255) ) { 272 char myhost[256] = ""; 273 int done = 0; /* -1 for error, 1 for address found */ 274 bool is_interface = FALSE; 275 bool is_host = FALSE; 276 static const char *if_prefix = "if!"; 277 static const char *host_prefix = "host!"; 278 279 if(strncmp(if_prefix, dev, strlen(if_prefix)) == 0) { 280 dev += strlen(if_prefix); 281 is_interface = TRUE; 282 } 283 else if(strncmp(host_prefix, dev, strlen(host_prefix)) == 0) { 284 dev += strlen(host_prefix); 285 is_host = TRUE; 286 } 287 288 /* interface */ 289 if(!is_host) { 290 #ifdef SO_BINDTODEVICE 291 /* I am not sure any other OSs than Linux that provide this feature, 292 * and at the least I cannot test. --Ben 293 * 294 * This feature allows one to tightly bind the local socket to a 295 * particular interface. This will force even requests to other 296 * local interfaces to go out the external interface. 297 * 298 * 299 * Only bind to the interface when specified as interface, not just 300 * as a hostname or ip address. 301 * 302 * interface might be a VRF, eg: vrf-blue, which means it cannot be 303 * converted to an IP address and would fail Curl_if2ip. Simply try 304 * to use it straight away. 305 */ 306 if(setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, 307 dev, (curl_socklen_t)strlen(dev) + 1) == 0) { 308 /* This is typically "errno 1, error: Operation not permitted" if 309 * you're not running as root or another suitable privileged 310 * user. 311 * If it succeeds it means the parameter was a valid interface and 312 * not an IP address. Return immediately. 313 */ 314 return CURLE_OK; 315 } 316 #endif 317 318 switch(Curl_if2ip(af, scope, conn->scope_id, dev, 319 myhost, sizeof(myhost))) { 320 case IF2IP_NOT_FOUND: 321 if(is_interface) { 322 /* Do not fall back to treating it as a host name */ 323 failf(data, "Couldn't bind to interface '%s'", dev); 324 return CURLE_INTERFACE_FAILED; 325 } 326 break; 327 case IF2IP_AF_NOT_SUPPORTED: 328 /* Signal the caller to try another address family if available */ 329 return CURLE_UNSUPPORTED_PROTOCOL; 330 case IF2IP_FOUND: 331 is_interface = TRUE; 332 /* 333 * We now have the numerical IP address in the 'myhost' buffer 334 */ 335 infof(data, "Local Interface %s is ip %s using address family %i\n", 336 dev, myhost, af); 337 done = 1; 338 break; 339 } 340 } 341 if(!is_interface) { 342 /* 343 * This was not an interface, resolve the name as a host name 344 * or IP number 345 * 346 * Temporarily force name resolution to use only the address type 347 * of the connection. The resolve functions should really be changed 348 * to take a type parameter instead. 349 */ 350 long ipver = conn->ip_version; 351 int rc; 352 353 if(af == AF_INET) 354 conn->ip_version = CURL_IPRESOLVE_V4; 355 #ifdef ENABLE_IPV6 356 else if(af == AF_INET6) 357 conn->ip_version = CURL_IPRESOLVE_V6; 358 #endif 359 360 rc = Curl_resolv(conn, dev, 0, &h); 361 if(rc == CURLRESOLV_PENDING) 362 (void)Curl_resolver_wait_resolv(conn, &h); 363 conn->ip_version = ipver; 364 365 if(h) { 366 /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */ 367 Curl_printable_address(h->addr, myhost, sizeof(myhost)); 368 infof(data, "Name '%s' family %i resolved to '%s' family %i\n", 369 dev, af, myhost, h->addr->ai_family); 370 Curl_resolv_unlock(data, h); 371 done = 1; 372 } 373 else { 374 /* 375 * provided dev was no interface (or interfaces are not supported 376 * e.g. solaris) no ip address and no domain we fail here 377 */ 378 done = -1; 379 } 380 } 381 382 if(done > 0) { 383 #ifdef ENABLE_IPV6 384 /* IPv6 address */ 385 if(af == AF_INET6) { 386 #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 387 char *scope_ptr = strchr(myhost, '%'); 388 if(scope_ptr) 389 *(scope_ptr++) = 0; 390 #endif 391 if(Curl_inet_pton(AF_INET6, myhost, &si6->sin6_addr) > 0) { 392 si6->sin6_family = AF_INET6; 393 si6->sin6_port = htons(port); 394 #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 395 if(scope_ptr) 396 /* The "myhost" string either comes from Curl_if2ip or from 397 Curl_printable_address. The latter returns only numeric scope 398 IDs and the former returns none at all. So the scope ID, if 399 present, is known to be numeric */ 400 si6->sin6_scope_id = atoi(scope_ptr); 401 #endif 402 } 403 sizeof_sa = sizeof(struct sockaddr_in6); 404 } 405 else 406 #endif 407 /* IPv4 address */ 408 if((af == AF_INET) && 409 (Curl_inet_pton(AF_INET, myhost, &si4->sin_addr) > 0)) { 410 si4->sin_family = AF_INET; 411 si4->sin_port = htons(port); 412 sizeof_sa = sizeof(struct sockaddr_in); 413 } 414 } 415 416 if(done < 1) { 417 /* errorbuf is set false so failf will overwrite any message already in 418 the error buffer, so the user receives this error message instead of a 419 generic resolve error. */ 420 data->state.errorbuf = FALSE; 421 failf(data, "Couldn't bind to '%s'", dev); 422 return CURLE_INTERFACE_FAILED; 423 } 424 } 425 else { 426 /* no device was given, prepare sa to match af's needs */ 427 #ifdef ENABLE_IPV6 428 if(af == AF_INET6) { 429 si6->sin6_family = AF_INET6; 430 si6->sin6_port = htons(port); 431 sizeof_sa = sizeof(struct sockaddr_in6); 432 } 433 else 434 #endif 435 if(af == AF_INET) { 436 si4->sin_family = AF_INET; 437 si4->sin_port = htons(port); 438 sizeof_sa = sizeof(struct sockaddr_in); 439 } 440 } 441 442 for(;;) { 443 if(bind(sockfd, sock, sizeof_sa) >= 0) { 444 /* we succeeded to bind */ 445 struct Curl_sockaddr_storage add; 446 curl_socklen_t size = sizeof(add); 447 memset(&add, 0, sizeof(struct Curl_sockaddr_storage)); 448 if(getsockname(sockfd, (struct sockaddr *) &add, &size) < 0) { 449 data->state.os_errno = error = SOCKERRNO; 450 failf(data, "getsockname() failed with errno %d: %s", 451 error, Curl_strerror(conn, error)); 452 return CURLE_INTERFACE_FAILED; 453 } 454 infof(data, "Local port: %hu\n", port); 455 conn->bits.bound = TRUE; 456 return CURLE_OK; 457 } 458 459 if(--portnum > 0) { 460 infof(data, "Bind to local port %hu failed, trying next\n", port); 461 port++; /* try next port */ 462 /* We re-use/clobber the port variable here below */ 463 if(sock->sa_family == AF_INET) 464 si4->sin_port = ntohs(port); 465 #ifdef ENABLE_IPV6 466 else 467 si6->sin6_port = ntohs(port); 468 #endif 469 } 470 else 471 break; 472 } 473 474 data->state.os_errno = error = SOCKERRNO; 475 failf(data, "bind failed with errno %d: %s", 476 error, Curl_strerror(conn, error)); 477 478 return CURLE_INTERFACE_FAILED; 479 } 480 481 /* 482 * verifyconnect() returns TRUE if the connect really has happened. 483 */ 484 static bool verifyconnect(curl_socket_t sockfd, int *error) 485 { 486 bool rc = TRUE; 487 #ifdef SO_ERROR 488 int err = 0; 489 curl_socklen_t errSize = sizeof(err); 490 491 #ifdef WIN32 492 /* 493 * In October 2003 we effectively nullified this function on Windows due to 494 * problems with it using all CPU in multi-threaded cases. 495 * 496 * In May 2004, we bring it back to offer more info back on connect failures. 497 * Gisle Vanem could reproduce the former problems with this function, but 498 * could avoid them by adding this SleepEx() call below: 499 * 500 * "I don't have Rational Quantify, but the hint from his post was 501 * ntdll::NtRemoveIoCompletion(). So I'd assume the SleepEx (or maybe 502 * just Sleep(0) would be enough?) would release whatever 503 * mutex/critical-section the ntdll call is waiting on. 504 * 505 * Someone got to verify this on Win-NT 4.0, 2000." 506 */ 507 508 #ifdef _WIN32_WCE 509 Sleep(0); 510 #else 511 SleepEx(0, FALSE); 512 #endif 513 514 #endif 515 516 if(0 != getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&err, &errSize)) 517 err = SOCKERRNO; 518 #ifdef _WIN32_WCE 519 /* Old WinCE versions don't support SO_ERROR */ 520 if(WSAENOPROTOOPT == err) { 521 SET_SOCKERRNO(0); 522 err = 0; 523 } 524 #endif 525 #ifdef __minix 526 /* Minix 3.1.x doesn't support getsockopt on UDP sockets */ 527 if(EBADIOCTL == err) { 528 SET_SOCKERRNO(0); 529 err = 0; 530 } 531 #endif 532 if((0 == err) || (EISCONN == err)) 533 /* we are connected, awesome! */ 534 rc = TRUE; 535 else 536 /* This wasn't a successful connect */ 537 rc = FALSE; 538 if(error) 539 *error = err; 540 #else 541 (void)sockfd; 542 if(error) 543 *error = SOCKERRNO; 544 #endif 545 return rc; 546 } 547 548 /* Used within the multi interface. Try next IP address, return TRUE if no 549 more address exists or error */ 550 static CURLcode trynextip(struct connectdata *conn, 551 int sockindex, 552 int tempindex) 553 { 554 const int other = tempindex ^ 1; 555 CURLcode result = CURLE_COULDNT_CONNECT; 556 557 /* First clean up after the failed socket. 558 Don't close it yet to ensure that the next IP's socket gets a different 559 file descriptor, which can prevent bugs when the curl_multi_socket_action 560 interface is used with certain select() replacements such as kqueue. */ 561 curl_socket_t fd_to_close = conn->tempsock[tempindex]; 562 conn->tempsock[tempindex] = CURL_SOCKET_BAD; 563 564 if(sockindex == FIRSTSOCKET) { 565 Curl_addrinfo *ai = NULL; 566 int family = AF_UNSPEC; 567 568 if(conn->tempaddr[tempindex]) { 569 /* find next address in the same protocol family */ 570 family = conn->tempaddr[tempindex]->ai_family; 571 ai = conn->tempaddr[tempindex]->ai_next; 572 } 573 #ifdef ENABLE_IPV6 574 else if(conn->tempaddr[0]) { 575 /* happy eyeballs - try the other protocol family */ 576 int firstfamily = conn->tempaddr[0]->ai_family; 577 family = (firstfamily == AF_INET) ? AF_INET6 : AF_INET; 578 ai = conn->tempaddr[0]->ai_next; 579 } 580 #endif 581 582 while(ai) { 583 if(conn->tempaddr[other]) { 584 /* we can safely skip addresses of the other protocol family */ 585 while(ai && ai->ai_family != family) 586 ai = ai->ai_next; 587 } 588 589 if(ai) { 590 result = singleipconnect(conn, ai, &conn->tempsock[tempindex]); 591 if(result == CURLE_COULDNT_CONNECT) { 592 ai = ai->ai_next; 593 continue; 594 } 595 596 conn->tempaddr[tempindex] = ai; 597 } 598 break; 599 } 600 } 601 602 if(fd_to_close != CURL_SOCKET_BAD) 603 Curl_closesocket(conn, fd_to_close); 604 605 return result; 606 } 607 608 /* Copies connection info into the session handle to make it available 609 when the session handle is no longer associated with a connection. */ 610 void Curl_persistconninfo(struct connectdata *conn) 611 { 612 memcpy(conn->data->info.conn_primary_ip, conn->primary_ip, MAX_IPADR_LEN); 613 memcpy(conn->data->info.conn_local_ip, conn->local_ip, MAX_IPADR_LEN); 614 conn->data->info.conn_scheme = conn->handler->scheme; 615 conn->data->info.conn_protocol = conn->handler->protocol; 616 conn->data->info.conn_primary_port = conn->primary_port; 617 conn->data->info.conn_local_port = conn->local_port; 618 } 619 620 /* retrieves ip address and port from a sockaddr structure. 621 note it calls Curl_inet_ntop which sets errno on fail, not SOCKERRNO. */ 622 static bool getaddressinfo(struct sockaddr *sa, char *addr, 623 long *port) 624 { 625 unsigned short us_port; 626 struct sockaddr_in *si = NULL; 627 #ifdef ENABLE_IPV6 628 struct sockaddr_in6 *si6 = NULL; 629 #endif 630 #if defined(HAVE_SYS_UN_H) && defined(AF_UNIX) 631 struct sockaddr_un *su = NULL; 632 #endif 633 634 switch(sa->sa_family) { 635 case AF_INET: 636 si = (struct sockaddr_in *)(void *) sa; 637 if(Curl_inet_ntop(sa->sa_family, &si->sin_addr, 638 addr, MAX_IPADR_LEN)) { 639 us_port = ntohs(si->sin_port); 640 *port = us_port; 641 return TRUE; 642 } 643 break; 644 #ifdef ENABLE_IPV6 645 case AF_INET6: 646 si6 = (struct sockaddr_in6 *)(void *) sa; 647 if(Curl_inet_ntop(sa->sa_family, &si6->sin6_addr, 648 addr, MAX_IPADR_LEN)) { 649 us_port = ntohs(si6->sin6_port); 650 *port = us_port; 651 return TRUE; 652 } 653 break; 654 #endif 655 #if defined(HAVE_SYS_UN_H) && defined(AF_UNIX) 656 case AF_UNIX: 657 su = (struct sockaddr_un*)sa; 658 snprintf(addr, MAX_IPADR_LEN, "%s", su->sun_path); 659 *port = 0; 660 return TRUE; 661 #endif 662 default: 663 break; 664 } 665 666 addr[0] = '\0'; 667 *port = 0; 668 errno = EAFNOSUPPORT; 669 return FALSE; 670 } 671 672 /* retrieves the start/end point information of a socket of an established 673 connection */ 674 void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd) 675 { 676 curl_socklen_t len; 677 struct Curl_sockaddr_storage ssrem; 678 struct Curl_sockaddr_storage ssloc; 679 struct Curl_easy *data = conn->data; 680 681 if(conn->socktype == SOCK_DGRAM) 682 /* there's no connection! */ 683 return; 684 685 if(!conn->bits.reuse && !conn->bits.tcp_fastopen) { 686 len = sizeof(struct Curl_sockaddr_storage); 687 if(getpeername(sockfd, (struct sockaddr*) &ssrem, &len)) { 688 int error = SOCKERRNO; 689 failf(data, "getpeername() failed with errno %d: %s", 690 error, Curl_strerror(conn, error)); 691 return; 692 } 693 694 len = sizeof(struct Curl_sockaddr_storage); 695 memset(&ssloc, 0, sizeof(ssloc)); 696 if(getsockname(sockfd, (struct sockaddr*) &ssloc, &len)) { 697 int error = SOCKERRNO; 698 failf(data, "getsockname() failed with errno %d: %s", 699 error, Curl_strerror(conn, error)); 700 return; 701 } 702 703 if(!getaddressinfo((struct sockaddr*)&ssrem, 704 conn->primary_ip, &conn->primary_port)) { 705 failf(data, "ssrem inet_ntop() failed with errno %d: %s", 706 errno, Curl_strerror(conn, errno)); 707 return; 708 } 709 memcpy(conn->ip_addr_str, conn->primary_ip, MAX_IPADR_LEN); 710 711 if(!getaddressinfo((struct sockaddr*)&ssloc, 712 conn->local_ip, &conn->local_port)) { 713 failf(data, "ssloc inet_ntop() failed with errno %d: %s", 714 errno, Curl_strerror(conn, errno)); 715 return; 716 } 717 718 } 719 720 /* persist connection info in session handle */ 721 Curl_persistconninfo(conn); 722 } 723 724 /* 725 * Curl_is_connected() checks if the socket has connected. 726 */ 727 728 CURLcode Curl_is_connected(struct connectdata *conn, 729 int sockindex, 730 bool *connected) 731 { 732 struct Curl_easy *data = conn->data; 733 CURLcode result = CURLE_OK; 734 timediff_t allow; 735 int error = 0; 736 struct curltime now; 737 int rc; 738 int i; 739 740 DEBUGASSERT(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET); 741 742 *connected = FALSE; /* a very negative world view is best */ 743 744 if(conn->bits.tcpconnect[sockindex]) { 745 /* we are connected already! */ 746 *connected = TRUE; 747 return CURLE_OK; 748 } 749 750 now = Curl_now(); 751 752 /* figure out how long time we have left to connect */ 753 allow = Curl_timeleft(data, &now, TRUE); 754 755 if(allow < 0) { 756 /* time-out, bail out, go home */ 757 failf(data, "Connection time-out"); 758 return CURLE_OPERATION_TIMEDOUT; 759 } 760 761 for(i = 0; i<2; i++) { 762 const int other = i ^ 1; 763 if(conn->tempsock[i] == CURL_SOCKET_BAD) 764 continue; 765 766 #ifdef mpeix 767 /* Call this function once now, and ignore the results. We do this to 768 "clear" the error state on the socket so that we can later read it 769 reliably. This is reported necessary on the MPE/iX operating system. */ 770 (void)verifyconnect(conn->tempsock[i], NULL); 771 #endif 772 773 /* check socket for connect */ 774 rc = SOCKET_WRITABLE(conn->tempsock[i], 0); 775 776 if(rc == 0) { /* no connection yet */ 777 error = 0; 778 if(Curl_timediff(now, conn->connecttime) >= conn->timeoutms_per_addr) { 779 infof(data, "After %ldms connect time, move on!\n", 780 conn->timeoutms_per_addr); 781 error = ETIMEDOUT; 782 } 783 784 /* should we try another protocol family? */ 785 if(i == 0 && conn->tempaddr[1] == NULL && 786 Curl_timediff(now, conn->connecttime) >= HAPPY_EYEBALLS_TIMEOUT) { 787 trynextip(conn, sockindex, 1); 788 } 789 } 790 else if(rc == CURL_CSELECT_OUT || conn->bits.tcp_fastopen) { 791 if(verifyconnect(conn->tempsock[i], &error)) { 792 /* we are connected with TCP, awesome! */ 793 794 /* use this socket from now on */ 795 conn->sock[sockindex] = conn->tempsock[i]; 796 conn->ip_addr = conn->tempaddr[i]; 797 conn->tempsock[i] = CURL_SOCKET_BAD; 798 #ifdef ENABLE_IPV6 799 conn->bits.ipv6 = (conn->ip_addr->ai_family == AF_INET6)?TRUE:FALSE; 800 #endif 801 802 /* close the other socket, if open */ 803 if(conn->tempsock[other] != CURL_SOCKET_BAD) { 804 Curl_closesocket(conn, conn->tempsock[other]); 805 conn->tempsock[other] = CURL_SOCKET_BAD; 806 } 807 808 /* see if we need to do any proxy magic first once we connected */ 809 result = Curl_connected_proxy(conn, sockindex); 810 if(result) 811 return result; 812 813 conn->bits.tcpconnect[sockindex] = TRUE; 814 815 *connected = TRUE; 816 if(sockindex == FIRSTSOCKET) 817 Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */ 818 Curl_updateconninfo(conn, conn->sock[sockindex]); 819 Curl_verboseconnect(conn); 820 821 return CURLE_OK; 822 } 823 infof(data, "Connection failed\n"); 824 } 825 else if(rc & CURL_CSELECT_ERR) 826 (void)verifyconnect(conn->tempsock[i], &error); 827 828 /* 829 * The connection failed here, we should attempt to connect to the "next 830 * address" for the given host. But first remember the latest error. 831 */ 832 if(error) { 833 data->state.os_errno = error; 834 SET_SOCKERRNO(error); 835 if(conn->tempaddr[i]) { 836 CURLcode status; 837 char ipaddress[MAX_IPADR_LEN]; 838 Curl_printable_address(conn->tempaddr[i], ipaddress, MAX_IPADR_LEN); 839 infof(data, "connect to %s port %ld failed: %s\n", 840 ipaddress, conn->port, Curl_strerror(conn, error)); 841 842 conn->timeoutms_per_addr = conn->tempaddr[i]->ai_next == NULL ? 843 allow : allow / 2; 844 845 status = trynextip(conn, sockindex, i); 846 if(status != CURLE_COULDNT_CONNECT 847 || conn->tempsock[other] == CURL_SOCKET_BAD) 848 /* the last attempt failed and no other sockets remain open */ 849 result = status; 850 } 851 } 852 } 853 854 if(result) { 855 /* no more addresses to try */ 856 857 const char *hostname; 858 859 /* if the first address family runs out of addresses to try before 860 the happy eyeball timeout, go ahead and try the next family now */ 861 if(conn->tempaddr[1] == NULL) { 862 result = trynextip(conn, sockindex, 1); 863 if(!result) 864 return result; 865 } 866 867 if(conn->bits.socksproxy) 868 hostname = conn->socks_proxy.host.name; 869 else if(conn->bits.httpproxy) 870 hostname = conn->http_proxy.host.name; 871 else if(conn->bits.conn_to_host) 872 hostname = conn->conn_to_host.name; 873 else 874 hostname = conn->host.name; 875 876 failf(data, "Failed to connect to %s port %ld: %s", 877 hostname, conn->port, Curl_strerror(conn, error)); 878 } 879 880 return result; 881 } 882 883 void Curl_tcpnodelay(struct connectdata *conn, curl_socket_t sockfd) 884 { 885 #if defined(TCP_NODELAY) 886 #if !defined(CURL_DISABLE_VERBOSE_STRINGS) 887 struct Curl_easy *data = conn->data; 888 #endif 889 curl_socklen_t onoff = (curl_socklen_t) 1; 890 int level = IPPROTO_TCP; 891 892 #if defined(CURL_DISABLE_VERBOSE_STRINGS) 893 (void) conn; 894 #endif 895 896 if(setsockopt(sockfd, level, TCP_NODELAY, (void *)&onoff, 897 sizeof(onoff)) < 0) 898 infof(data, "Could not set TCP_NODELAY: %s\n", 899 Curl_strerror(conn, SOCKERRNO)); 900 else 901 infof(data, "TCP_NODELAY set\n"); 902 #else 903 (void)conn; 904 (void)sockfd; 905 #endif 906 } 907 908 #ifdef SO_NOSIGPIPE 909 /* The preferred method on Mac OS X (10.2 and later) to prevent SIGPIPEs when 910 sending data to a dead peer (instead of relying on the 4th argument to send 911 being MSG_NOSIGNAL). Possibly also existing and in use on other BSD 912 systems? */ 913 static void nosigpipe(struct connectdata *conn, 914 curl_socket_t sockfd) 915 { 916 struct Curl_easy *data = conn->data; 917 int onoff = 1; 918 if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff, 919 sizeof(onoff)) < 0) 920 infof(data, "Could not set SO_NOSIGPIPE: %s\n", 921 Curl_strerror(conn, SOCKERRNO)); 922 } 923 #else 924 #define nosigpipe(x,y) Curl_nop_stmt 925 #endif 926 927 #ifdef USE_WINSOCK 928 /* When you run a program that uses the Windows Sockets API, you may 929 experience slow performance when you copy data to a TCP server. 930 931 https://support.microsoft.com/kb/823764 932 933 Work-around: Make the Socket Send Buffer Size Larger Than the Program Send 934 Buffer Size 935 936 The problem described in this knowledge-base is applied only to pre-Vista 937 Windows. Following function trying to detect OS version and skips 938 SO_SNDBUF adjustment for Windows Vista and above. 939 */ 940 #define DETECT_OS_NONE 0 941 #define DETECT_OS_PREVISTA 1 942 #define DETECT_OS_VISTA_OR_LATER 2 943 944 void Curl_sndbufset(curl_socket_t sockfd) 945 { 946 int val = CURL_MAX_WRITE_SIZE + 32; 947 int curval = 0; 948 int curlen = sizeof(curval); 949 950 static int detectOsState = DETECT_OS_NONE; 951 952 if(detectOsState == DETECT_OS_NONE) { 953 if(Curl_verify_windows_version(6, 0, PLATFORM_WINNT, 954 VERSION_GREATER_THAN_EQUAL)) 955 detectOsState = DETECT_OS_VISTA_OR_LATER; 956 else 957 detectOsState = DETECT_OS_PREVISTA; 958 } 959 960 if(detectOsState == DETECT_OS_VISTA_OR_LATER) 961 return; 962 963 if(getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *)&curval, &curlen) == 0) 964 if(curval > val) 965 return; 966 967 setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (const char *)&val, sizeof(val)); 968 } 969 #endif 970 971 /* 972 * singleipconnect() 973 * 974 * Note that even on connect fail it returns CURLE_OK, but with 'sock' set to 975 * CURL_SOCKET_BAD. Other errors will however return proper errors. 976 * 977 * singleipconnect() connects to the given IP only, and it may return without 978 * having connected. 979 */ 980 static CURLcode singleipconnect(struct connectdata *conn, 981 const Curl_addrinfo *ai, 982 curl_socket_t *sockp) 983 { 984 struct Curl_sockaddr_ex addr; 985 int rc = -1; 986 int error = 0; 987 bool isconnected = FALSE; 988 struct Curl_easy *data = conn->data; 989 curl_socket_t sockfd; 990 CURLcode result; 991 char ipaddress[MAX_IPADR_LEN]; 992 long port; 993 bool is_tcp; 994 #ifdef TCP_FASTOPEN_CONNECT 995 int optval = 1; 996 #endif 997 998 *sockp = CURL_SOCKET_BAD; 999 1000 result = Curl_socket(conn, ai, &addr, &sockfd); 1001 if(result) 1002 /* Failed to create the socket, but still return OK since we signal the 1003 lack of socket as well. This allows the parent function to keep looping 1004 over alternative addresses/socket families etc. */ 1005 return CURLE_OK; 1006 1007 /* store remote address and port used in this connection attempt */ 1008 if(!getaddressinfo((struct sockaddr*)&addr.sa_addr, 1009 ipaddress, &port)) { 1010 /* malformed address or bug in inet_ntop, try next address */ 1011 failf(data, "sa_addr inet_ntop() failed with errno %d: %s", 1012 errno, Curl_strerror(conn, errno)); 1013 Curl_closesocket(conn, sockfd); 1014 return CURLE_OK; 1015 } 1016 infof(data, " Trying %s...\n", ipaddress); 1017 1018 #ifdef ENABLE_IPV6 1019 is_tcp = (addr.family == AF_INET || addr.family == AF_INET6) && 1020 addr.socktype == SOCK_STREAM; 1021 #else 1022 is_tcp = (addr.family == AF_INET) && addr.socktype == SOCK_STREAM; 1023 #endif 1024 if(is_tcp && data->set.tcp_nodelay) 1025 Curl_tcpnodelay(conn, sockfd); 1026 1027 nosigpipe(conn, sockfd); 1028 1029 Curl_sndbufset(sockfd); 1030 1031 if(is_tcp && data->set.tcp_keepalive) 1032 tcpkeepalive(data, sockfd); 1033 1034 if(data->set.fsockopt) { 1035 /* activate callback for setting socket options */ 1036 error = data->set.fsockopt(data->set.sockopt_client, 1037 sockfd, 1038 CURLSOCKTYPE_IPCXN); 1039 1040 if(error == CURL_SOCKOPT_ALREADY_CONNECTED) 1041 isconnected = TRUE; 1042 else if(error) { 1043 Curl_closesocket(conn, sockfd); /* close the socket and bail out */ 1044 return CURLE_ABORTED_BY_CALLBACK; 1045 } 1046 } 1047 1048 /* possibly bind the local end to an IP, interface or port */ 1049 if(addr.family == AF_INET 1050 #ifdef ENABLE_IPV6 1051 || addr.family == AF_INET6 1052 #endif 1053 ) { 1054 result = bindlocal(conn, sockfd, addr.family, 1055 Curl_ipv6_scope((struct sockaddr*)&addr.sa_addr)); 1056 if(result) { 1057 Curl_closesocket(conn, sockfd); /* close socket and bail out */ 1058 if(result == CURLE_UNSUPPORTED_PROTOCOL) { 1059 /* The address family is not supported on this interface. 1060 We can continue trying addresses */ 1061 return CURLE_COULDNT_CONNECT; 1062 } 1063 return result; 1064 } 1065 } 1066 1067 /* set socket non-blocking */ 1068 (void)curlx_nonblock(sockfd, TRUE); 1069 1070 conn->connecttime = Curl_now(); 1071 if(conn->num_addr > 1) 1072 Curl_expire(data, conn->timeoutms_per_addr, EXPIRE_DNS_PER_NAME); 1073 1074 /* Connect TCP sockets, bind UDP */ 1075 if(!isconnected && (conn->socktype == SOCK_STREAM)) { 1076 if(conn->bits.tcp_fastopen) { 1077 #if defined(CONNECT_DATA_IDEMPOTENT) /* Darwin */ 1078 # if defined(HAVE_BUILTIN_AVAILABLE) 1079 /* while connectx function is available since macOS 10.11 / iOS 9, 1080 it did not have the interface declared correctly until 1081 Xcode 9 / macOS SDK 10.13 */ 1082 if(__builtin_available(macOS 10.11, iOS 9.0, tvOS 9.0, watchOS 2.0, *)) { 1083 sa_endpoints_t endpoints; 1084 endpoints.sae_srcif = 0; 1085 endpoints.sae_srcaddr = NULL; 1086 endpoints.sae_srcaddrlen = 0; 1087 endpoints.sae_dstaddr = &addr.sa_addr; 1088 endpoints.sae_dstaddrlen = addr.addrlen; 1089 1090 rc = connectx(sockfd, &endpoints, SAE_ASSOCID_ANY, 1091 CONNECT_RESUME_ON_READ_WRITE | CONNECT_DATA_IDEMPOTENT, 1092 NULL, 0, NULL, NULL); 1093 } 1094 else { 1095 rc = connect(sockfd, &addr.sa_addr, addr.addrlen); 1096 } 1097 # else 1098 rc = connect(sockfd, &addr.sa_addr, addr.addrlen); 1099 # endif /* HAVE_BUILTIN_AVAILABLE */ 1100 #elif defined(TCP_FASTOPEN_CONNECT) /* Linux >= 4.11 */ 1101 if(setsockopt(sockfd, IPPROTO_TCP, TCP_FASTOPEN_CONNECT, 1102 (void *)&optval, sizeof(optval)) < 0) 1103 infof(data, "Failed to enable TCP Fast Open on fd %d\n", sockfd); 1104 else 1105 infof(data, "TCP_FASTOPEN_CONNECT set\n"); 1106 1107 rc = connect(sockfd, &addr.sa_addr, addr.addrlen); 1108 #elif defined(MSG_FASTOPEN) /* old Linux */ 1109 if(conn->given->flags & PROTOPT_SSL) 1110 rc = connect(sockfd, &addr.sa_addr, addr.addrlen); 1111 else 1112 rc = 0; /* Do nothing */ 1113 #endif 1114 } 1115 else { 1116 rc = connect(sockfd, &addr.sa_addr, addr.addrlen); 1117 } 1118 1119 if(-1 == rc) 1120 error = SOCKERRNO; 1121 } 1122 else { 1123 *sockp = sockfd; 1124 return CURLE_OK; 1125 } 1126 1127 if(-1 == rc) { 1128 switch(error) { 1129 case EINPROGRESS: 1130 case EWOULDBLOCK: 1131 #if defined(EAGAIN) 1132 #if (EAGAIN) != (EWOULDBLOCK) 1133 /* On some platforms EAGAIN and EWOULDBLOCK are the 1134 * same value, and on others they are different, hence 1135 * the odd #if 1136 */ 1137 case EAGAIN: 1138 #endif 1139 #endif 1140 result = CURLE_OK; 1141 break; 1142 1143 default: 1144 /* unknown error, fallthrough and try another address! */ 1145 infof(data, "Immediate connect fail for %s: %s\n", 1146 ipaddress, Curl_strerror(conn, error)); 1147 data->state.os_errno = error; 1148 1149 /* connect failed */ 1150 Curl_closesocket(conn, sockfd); 1151 result = CURLE_COULDNT_CONNECT; 1152 } 1153 } 1154 1155 if(!result) 1156 *sockp = sockfd; 1157 1158 return result; 1159 } 1160 1161 /* 1162 * TCP connect to the given host with timeout, proxy or remote doesn't matter. 1163 * There might be more than one IP address to try out. Fill in the passed 1164 * pointer with the connected socket. 1165 */ 1166 1167 CURLcode Curl_connecthost(struct connectdata *conn, /* context */ 1168 const struct Curl_dns_entry *remotehost) 1169 { 1170 struct Curl_easy *data = conn->data; 1171 struct curltime before = Curl_now(); 1172 CURLcode result = CURLE_COULDNT_CONNECT; 1173 1174 timediff_t timeout_ms = Curl_timeleft(data, &before, TRUE); 1175 1176 if(timeout_ms < 0) { 1177 /* a precaution, no need to continue if time already is up */ 1178 failf(data, "Connection time-out"); 1179 return CURLE_OPERATION_TIMEDOUT; 1180 } 1181 1182 conn->num_addr = Curl_num_addresses(remotehost->addr); 1183 conn->tempaddr[0] = remotehost->addr; 1184 conn->tempaddr[1] = NULL; 1185 conn->tempsock[0] = CURL_SOCKET_BAD; 1186 conn->tempsock[1] = CURL_SOCKET_BAD; 1187 1188 /* Max time for the next connection attempt */ 1189 conn->timeoutms_per_addr = 1190 conn->tempaddr[0]->ai_next == NULL ? timeout_ms : timeout_ms / 2; 1191 1192 /* start connecting to first IP */ 1193 while(conn->tempaddr[0]) { 1194 result = singleipconnect(conn, conn->tempaddr[0], &(conn->tempsock[0])); 1195 if(!result) 1196 break; 1197 conn->tempaddr[0] = conn->tempaddr[0]->ai_next; 1198 } 1199 1200 if(conn->tempsock[0] == CURL_SOCKET_BAD) { 1201 if(!result) 1202 result = CURLE_COULDNT_CONNECT; 1203 return result; 1204 } 1205 1206 data->info.numconnects++; /* to track the number of connections made */ 1207 Curl_expire(conn->data, HAPPY_EYEBALLS_TIMEOUT, EXPIRE_HAPPY_EYEBALLS); 1208 1209 return CURLE_OK; 1210 } 1211 1212 struct connfind { 1213 struct connectdata *tofind; 1214 bool found; 1215 }; 1216 1217 static int conn_is_conn(struct connectdata *conn, void *param) 1218 { 1219 struct connfind *f = (struct connfind *)param; 1220 if(conn == f->tofind) { 1221 f->found = TRUE; 1222 return 1; 1223 } 1224 return 0; 1225 } 1226 1227 /* 1228 * Used to extract socket and connectdata struct for the most recent 1229 * transfer on the given Curl_easy. 1230 * 1231 * The returned socket will be CURL_SOCKET_BAD in case of failure! 1232 */ 1233 curl_socket_t Curl_getconnectinfo(struct Curl_easy *data, 1234 struct connectdata **connp) 1235 { 1236 curl_socket_t sockfd; 1237 1238 DEBUGASSERT(data); 1239 1240 /* this works for an easy handle: 1241 * - that has been used for curl_easy_perform() 1242 * - that is associated with a multi handle, and whose connection 1243 * was detached with CURLOPT_CONNECT_ONLY 1244 */ 1245 if(data->state.lastconnect && (data->multi_easy || data->multi)) { 1246 struct connectdata *c = data->state.lastconnect; 1247 struct connfind find; 1248 find.tofind = data->state.lastconnect; 1249 find.found = FALSE; 1250 1251 Curl_conncache_foreach(data, data->multi_easy? 1252 &data->multi_easy->conn_cache: 1253 &data->multi->conn_cache, &find, conn_is_conn); 1254 1255 if(!find.found) { 1256 data->state.lastconnect = NULL; 1257 return CURL_SOCKET_BAD; 1258 } 1259 1260 if(connp) 1261 /* only store this if the caller cares for it */ 1262 *connp = c; 1263 sockfd = c->sock[FIRSTSOCKET]; 1264 } 1265 else 1266 return CURL_SOCKET_BAD; 1267 1268 return sockfd; 1269 } 1270 1271 /* 1272 * Check if a connection seems to be alive. 1273 */ 1274 bool Curl_connalive(struct connectdata *conn) 1275 { 1276 /* First determine if ssl */ 1277 if(conn->ssl[FIRSTSOCKET].use) { 1278 /* use the SSL context */ 1279 if(!Curl_ssl_check_cxn(conn)) 1280 return false; /* FIN received */ 1281 } 1282 /* Minix 3.1 doesn't support any flags on recv; just assume socket is OK */ 1283 #ifdef MSG_PEEK 1284 else if(conn->sock[FIRSTSOCKET] == CURL_SOCKET_BAD) 1285 return false; 1286 else { 1287 /* use the socket */ 1288 char buf; 1289 if(recv((RECV_TYPE_ARG1)conn->sock[FIRSTSOCKET], (RECV_TYPE_ARG2)&buf, 1290 (RECV_TYPE_ARG3)1, (RECV_TYPE_ARG4)MSG_PEEK) == 0) { 1291 return false; /* FIN received */ 1292 } 1293 } 1294 #endif 1295 return true; 1296 } 1297 1298 /* 1299 * Close a socket. 1300 * 1301 * 'conn' can be NULL, beware! 1302 */ 1303 int Curl_closesocket(struct connectdata *conn, 1304 curl_socket_t sock) 1305 { 1306 if(conn && conn->fclosesocket) { 1307 if((sock == conn->sock[SECONDARYSOCKET]) && 1308 conn->sock_accepted[SECONDARYSOCKET]) 1309 /* if this socket matches the second socket, and that was created with 1310 accept, then we MUST NOT call the callback but clear the accepted 1311 status */ 1312 conn->sock_accepted[SECONDARYSOCKET] = FALSE; 1313 else { 1314 Curl_multi_closed(conn, sock); 1315 return conn->fclosesocket(conn->closesocket_client, sock); 1316 } 1317 } 1318 1319 if(conn) 1320 /* tell the multi-socket code about this */ 1321 Curl_multi_closed(conn, sock); 1322 1323 sclose(sock); 1324 1325 return 0; 1326 } 1327 1328 /* 1329 * Create a socket based on info from 'conn' and 'ai'. 1330 * 1331 * 'addr' should be a pointer to the correct struct to get data back, or NULL. 1332 * 'sockfd' must be a pointer to a socket descriptor. 1333 * 1334 * If the open socket callback is set, used that! 1335 * 1336 */ 1337 CURLcode Curl_socket(struct connectdata *conn, 1338 const Curl_addrinfo *ai, 1339 struct Curl_sockaddr_ex *addr, 1340 curl_socket_t *sockfd) 1341 { 1342 struct Curl_easy *data = conn->data; 1343 struct Curl_sockaddr_ex dummy; 1344 1345 if(!addr) 1346 /* if the caller doesn't want info back, use a local temp copy */ 1347 addr = &dummy; 1348 1349 /* 1350 * The Curl_sockaddr_ex structure is basically libcurl's external API 1351 * curl_sockaddr structure with enough space available to directly hold 1352 * any protocol-specific address structures. The variable declared here 1353 * will be used to pass / receive data to/from the fopensocket callback 1354 * if this has been set, before that, it is initialized from parameters. 1355 */ 1356 1357 addr->family = ai->ai_family; 1358 addr->socktype = conn->socktype; 1359 addr->protocol = conn->socktype == SOCK_DGRAM?IPPROTO_UDP:ai->ai_protocol; 1360 addr->addrlen = ai->ai_addrlen; 1361 1362 if(addr->addrlen > sizeof(struct Curl_sockaddr_storage)) 1363 addr->addrlen = sizeof(struct Curl_sockaddr_storage); 1364 memcpy(&addr->sa_addr, ai->ai_addr, addr->addrlen); 1365 1366 if(data->set.fopensocket) 1367 /* 1368 * If the opensocket callback is set, all the destination address 1369 * information is passed to the callback. Depending on this information the 1370 * callback may opt to abort the connection, this is indicated returning 1371 * CURL_SOCKET_BAD; otherwise it will return a not-connected socket. When 1372 * the callback returns a valid socket the destination address information 1373 * might have been changed and this 'new' address will actually be used 1374 * here to connect. 1375 */ 1376 *sockfd = data->set.fopensocket(data->set.opensocket_client, 1377 CURLSOCKTYPE_IPCXN, 1378 (struct curl_sockaddr *)addr); 1379 else 1380 /* opensocket callback not set, so simply create the socket now */ 1381 *sockfd = socket(addr->family, addr->socktype, addr->protocol); 1382 1383 if(*sockfd == CURL_SOCKET_BAD) 1384 /* no socket, no connection */ 1385 return CURLE_COULDNT_CONNECT; 1386 1387 #if defined(ENABLE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID) 1388 if(conn->scope_id && (addr->family == AF_INET6)) { 1389 struct sockaddr_in6 * const sa6 = (void *)&addr->sa_addr; 1390 sa6->sin6_scope_id = conn->scope_id; 1391 } 1392 #endif 1393 1394 return CURLE_OK; 1395 1396 } 1397 1398 /* 1399 * Curl_conncontrol() marks streams or connection for closure. 1400 */ 1401 void Curl_conncontrol(struct connectdata *conn, 1402 int ctrl /* see defines in header */ 1403 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) 1404 , const char *reason 1405 #endif 1406 ) 1407 { 1408 /* close if a connection, or a stream that isn't multiplexed */ 1409 bool closeit = (ctrl == CONNCTRL_CONNECTION) || 1410 ((ctrl == CONNCTRL_STREAM) && !(conn->handler->flags & PROTOPT_STREAM)); 1411 if((ctrl == CONNCTRL_STREAM) && 1412 (conn->handler->flags & PROTOPT_STREAM)) 1413 DEBUGF(infof(conn->data, "Kill stream: %s\n", reason)); 1414 else if(closeit != conn->bits.close) { 1415 DEBUGF(infof(conn->data, "Marked for [%s]: %s\n", 1416 closeit?"closure":"keep alive", reason)); 1417 conn->bits.close = closeit; /* the only place in the source code that 1418 should assign this bit */ 1419 } 1420 } 1421 1422 /* Data received can be cached at various levels, so check them all here. */ 1423 bool Curl_conn_data_pending(struct connectdata *conn, int sockindex) 1424 { 1425 int readable; 1426 1427 if(Curl_ssl_data_pending(conn, sockindex) || 1428 Curl_recv_has_postponed_data(conn, sockindex)) 1429 return true; 1430 1431 readable = SOCKET_READABLE(conn->sock[sockindex], 0); 1432 return (readable > 0 && (readable & CURL_CSELECT_IN)); 1433 } 1434