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