Annotation of embedaddon/curl/lib/connect.c, revision 1.1.1.1

1.1       misho       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>