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