Annotation of embedaddon/curl/lib/connect.c, revision 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>