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