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