File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / curl / lib / connect.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 3 10:01:15 2020 UTC (4 years, 1 month ago) by misho
Branches: curl, MAIN
CVS tags: v7_70_0p4, HEAD
curl

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>