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