~ubuntu-branches/ubuntu/jaunty/cmake/jaunty-security

« back to all changes in this revision

Viewing changes to Source/CTest/Curl/connect.c

  • Committer: Bazaar Package Importer
  • Author(s): A. Maitland Bottoms
  • Date: 2006-06-18 16:34:11 UTC
  • mfrom: (1.4.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20060618163411-pi234s3v6jwlcmof
Tags: 2.4.2-1
* New upstream release (Closes: #338324)
* Put cmake .vim files into /usr/share/vim/addons/plugin/
  where they can be used. (Closes: #366663)
* Install cmake-mode.el so it can be used. (Closes: #366664)
* Ensure cmake FindKDE locates KDE libraries on Debian
  based distributions.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
 *                                  _   _ ____  _
 
3
 *  Project                     ___| | | |  _ \| |
 
4
 *                             / __| | | | |_) | |
 
5
 *                            | (__| |_| |  _ <| |___
 
6
 *                             \___|\___/|_| \_\_____|
 
7
 *
 
8
 * Copyright (C) 1998 - 2004, 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
 * $Id: connect.c,v 1.18 2004/10/13 14:01:04 andy Exp $
 
22
 ***************************************************************************/
 
23
 
 
24
#include "setup.h"
 
25
 
 
26
#ifndef WIN32
 
27
/* headers for non-win32 */
 
28
#include <sys/time.h>
 
29
#ifdef HAVE_SYS_TYPES_H
 
30
#include <sys/types.h>
 
31
#endif
 
32
#ifdef HAVE_SYS_SOCKET_H
 
33
#include <sys/socket.h>
 
34
#endif
 
35
#ifdef HAVE_NETINET_IN_H
 
36
#include <netinet/in.h> /* <netinet/tcp.h> may need it */
 
37
#endif
 
38
#ifdef HAVE_NETINET_TCP_H
 
39
#include <netinet/tcp.h> /* for TCP_NODELAY */
 
40
#endif
 
41
#ifdef HAVE_SYS_IOCTL_H
 
42
#include <sys/ioctl.h>
 
43
#endif
 
44
#ifdef HAVE_UNISTD_H
 
45
#include <unistd.h>
 
46
#endif
 
47
#ifdef HAVE_NETDB_H
 
48
#include <netdb.h>
 
49
#endif
 
50
#ifdef HAVE_FCNTL_H
 
51
#include <fcntl.h>
 
52
#endif
 
53
#ifdef HAVE_NETINET_IN_H
 
54
#include <netinet/in.h>
 
55
#endif
 
56
#ifdef HAVE_ARPA_INET_H
 
57
#include <arpa/inet.h>
 
58
#endif
 
59
#ifdef HAVE_STDLIB_H
 
60
#include <stdlib.h> /* required for free() prototype, without it, this crashes
 
61
                       on macos 68K */
 
62
#endif
 
63
#if (defined(HAVE_FIONBIO) && defined(__NOVELL_LIBC__))
 
64
#include <sys/filio.h>
 
65
#endif
 
66
#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
 
67
#undef in_addr_t
 
68
#define in_addr_t unsigned long
 
69
#endif
 
70
#ifdef  VMS
 
71
#include <in.h>
 
72
#include <inet.h>
 
73
#endif
 
74
 
 
75
#endif
 
76
#include <stdio.h>
 
77
#include <errno.h>
 
78
#include <string.h>
 
79
 
 
80
#ifndef TRUE
 
81
#define TRUE 1
 
82
#define FALSE 0
 
83
#endif
 
84
 
 
85
#ifdef WIN32
 
86
#include <windows.h>
 
87
#define EINPROGRESS WSAEINPROGRESS
 
88
#define EWOULDBLOCK WSAEWOULDBLOCK
 
89
#define EISCONN     WSAEISCONN
 
90
#define ENOTSOCK    WSAENOTSOCK
 
91
#define ECONNREFUSED WSAECONNREFUSED
 
92
#endif
 
93
 
 
94
#include "urldata.h"
 
95
#include "sendf.h"
 
96
#include "if2ip.h"
 
97
#include "strerror.h"
 
98
#include "connect.h"
 
99
#include "curl_memory.h"
 
100
 
 
101
/* The last #include file should be: */
 
102
#include "memdebug.h"
 
103
 
 
104
static bool verifyconnect(curl_socket_t sockfd, int *error);
 
105
 
 
106
static curl_socket_t
 
107
singleipconnect(struct connectdata *conn,
 
108
                Curl_addrinfo *ai, /* start connecting to this */
 
109
                long timeout_ms,
 
110
                bool *connected);
 
111
 
 
112
/*
 
113
 * Curl_ourerrno() returns the errno (or equivalent) on this platform to
 
114
 * hide platform specific for the function that calls this.
 
115
 */
 
116
int Curl_ourerrno(void)
 
117
{
 
118
#ifdef WIN32
 
119
  return (int)GetLastError();
 
120
#else
 
121
  return errno;
 
122
#endif
 
123
}
 
124
 
 
125
/*
 
126
 * Curl_nonblock() set the given socket to either blocking or non-blocking
 
127
 * mode based on the 'nonblock' boolean argument. This function is highly
 
128
 * portable.
 
129
 */
 
130
int Curl_nonblock(curl_socket_t sockfd,    /* operate on this */
 
131
                  int nonblock   /* TRUE or FALSE */)
 
132
{
 
133
#undef SETBLOCK
 
134
#ifdef HAVE_O_NONBLOCK
 
135
    {
 
136
    /* most recent unix versions */
 
137
    int flags;
 
138
 
 
139
    flags = fcntl(sockfd, F_GETFL, 0);
 
140
    if (TRUE == nonblock)
 
141
      return fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
 
142
    else
 
143
      return fcntl(sockfd, F_SETFL, flags & (~O_NONBLOCK));
 
144
    }
 
145
#define SETBLOCK 1
 
146
#endif
 
147
 
 
148
#ifdef HAVE_FIONBIO
 
149
    {
 
150
    /* older unix versions */
 
151
    int flags;
 
152
 
 
153
    flags = nonblock;
 
154
    return ioctl(sockfd, FIONBIO, &flags);
 
155
    }
 
156
#ifdef SETBLOCK
 
157
# undef SETBLOCK
 
158
#endif
 
159
#define SETBLOCK 2
 
160
#endif
 
161
 
 
162
#ifdef HAVE_IOCTLSOCKET
 
163
  /* Windows? */
 
164
  unsigned long flags;
 
165
  flags = nonblock;
 
166
  return ioctlsocket(sockfd, FIONBIO, &flags);
 
167
#define SETBLOCK 3
 
168
#endif
 
169
 
 
170
#ifdef HAVE_IOCTLSOCKET_CASE
 
171
  /* presumably for Amiga */
 
172
  return IoctlSocket(sockfd, FIONBIO, (long)nonblock);
 
173
#ifdef SETBLOCK
 
174
# undef SETBLOCK
 
175
#endif
 
176
#define SETBLOCK 4
 
177
#endif
 
178
 
 
179
#ifdef HAVE_SO_NONBLOCK
 
180
  /* BeOS */
 
181
  long b = nonblock ? 1 : 0;
 
182
  return setsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b));
 
183
#ifdef SETBLOCK
 
184
# undef SETBLOCK
 
185
#endif
 
186
#define SETBLOCK 5
 
187
#endif
 
188
 
 
189
#ifdef HAVE_DISABLED_NONBLOCKING
 
190
  (void)nonblock;
 
191
  (void)sockfd;
 
192
  return 0; /* returns success */
 
193
#ifdef SETBLOCK
 
194
# undef SETBLOCK
 
195
#endif
 
196
#define SETBLOCK 6
 
197
#endif
 
198
 
 
199
#ifndef SETBLOCK
 
200
#error "no non-blocking method was found/used/set"
 
201
#endif
 
202
}
 
203
 
 
204
/*
 
205
 * waitconnect() waits for a TCP connect on the given socket for the specified
 
206
 * number if milliseconds. It returns:
 
207
 * 0    fine connect
 
208
 * -1   select() error
 
209
 * 1    select() timeout
 
210
 * 2    select() returned with an error condition fd_set
 
211
 */
 
212
 
 
213
#define WAITCONN_CONNECTED     0
 
214
#define WAITCONN_SELECT_ERROR -1
 
215
#define WAITCONN_TIMEOUT       1
 
216
#define WAITCONN_FDSET_ERROR   2
 
217
 
 
218
static
 
219
int waitconnect(curl_socket_t sockfd, /* socket */
 
220
                long timeout_msec)
 
221
{
 
222
  fd_set fd;
 
223
  fd_set errfd;
 
224
  struct timeval interval;
 
225
  int rc;
 
226
#ifdef mpeix
 
227
  /* Call this function once now, and ignore the results. We do this to
 
228
     "clear" the error state on the socket so that we can later read it
 
229
     reliably. This is reported necessary on the MPE/iX operating system. */
 
230
  verifyconnect(sockfd, NULL);
 
231
#endif
 
232
 
 
233
  /* now select() until we get connect or timeout */
 
234
  FD_ZERO(&fd);
 
235
  FD_SET(sockfd, &fd);
 
236
 
 
237
  FD_ZERO(&errfd);
 
238
  FD_SET(sockfd, &errfd);
 
239
 
 
240
  interval.tv_sec = (int)(timeout_msec/1000);
 
241
  timeout_msec -= interval.tv_sec*1000;
 
242
 
 
243
  interval.tv_usec = timeout_msec*1000;
 
244
 
 
245
  rc = select(sockfd+1, NULL, &fd, &errfd, &interval);
 
246
  if(-1 == rc)
 
247
    /* error, no connect here, try next */
 
248
    return WAITCONN_SELECT_ERROR;
 
249
 
 
250
  else if(0 == rc)
 
251
    /* timeout, no connect today */
 
252
    return WAITCONN_TIMEOUT;
 
253
 
 
254
  if(FD_ISSET(sockfd, &errfd))
 
255
    /* error condition caught */
 
256
    return WAITCONN_FDSET_ERROR;
 
257
 
 
258
  /* we have a connect! */
 
259
  return WAITCONN_CONNECTED;
 
260
}
 
261
 
 
262
static CURLcode bindlocal(struct connectdata *conn,
 
263
                          curl_socket_t sockfd)
 
264
{
 
265
#ifdef HAVE_INET_NTOA
 
266
  bool bindworked = FALSE;
 
267
  struct SessionHandle *data = conn->data;
 
268
 
 
269
  /*************************************************************
 
270
   * Select device to bind socket to
 
271
   *************************************************************/
 
272
  if (strlen(data->set.device)<255) {
 
273
    struct Curl_dns_entry *h=NULL;
 
274
    char myhost[256] = "";
 
275
    in_addr_t in;
 
276
    int rc;
 
277
    bool was_iface = FALSE;
 
278
 
 
279
    /* First check if the given name is an IP address */
 
280
    in=inet_addr(data->set.device);
 
281
 
 
282
    if((in == CURL_INADDR_NONE) &&
 
283
       Curl_if2ip(data->set.device, myhost, sizeof(myhost))) {
 
284
      /*
 
285
       * We now have the numerical IPv4-style x.y.z.w in the 'myhost' buffer
 
286
       */
 
287
      rc = Curl_resolv(conn, myhost, 0, &h);
 
288
      if(rc == CURLRESOLV_PENDING)
 
289
        (void)Curl_wait_for_resolv(conn, &h);
 
290
 
 
291
      if(h)
 
292
        was_iface = TRUE;
 
293
    }
 
294
 
 
295
    if(!was_iface) {
 
296
      /*
 
297
       * This was not an interface, resolve the name as a host name
 
298
       * or IP number
 
299
       */
 
300
      rc = Curl_resolv(conn, data->set.device, 0, &h);
 
301
      if(rc == CURLRESOLV_PENDING)
 
302
        (void)Curl_wait_for_resolv(conn, &h);
 
303
 
 
304
      if(h)
 
305
        /* we know data->set.device is shorter than the myhost array */
 
306
        strcpy(myhost, data->set.device);
 
307
    }
 
308
 
 
309
    if(! *myhost) {
 
310
      /* need to fix this
 
311
         h=Curl_gethost(data,
 
312
         getmyhost(*myhost,sizeof(myhost)),
 
313
         hostent_buf,
 
314
         sizeof(hostent_buf));
 
315
      */
 
316
      failf(data, "Couldn't bind to '%s'", data->set.device);
 
317
      return CURLE_HTTP_PORT_FAILED;
 
318
    }
 
319
 
 
320
    infof(data, "We bind local end to %s\n", myhost);
 
321
 
 
322
#ifdef SO_BINDTODEVICE
 
323
    /* I am not sure any other OSs than Linux that provide this feature, and
 
324
     * at the least I cannot test. --Ben
 
325
     *
 
326
     * This feature allows one to tightly bind the local socket to a
 
327
     * particular interface.  This will force even requests to other local
 
328
     * interfaces to go out the external interface.
 
329
     *
 
330
     */
 
331
    if (was_iface) {
 
332
      /* Only bind to the interface when specified as interface, not just as a
 
333
       * hostname or ip address.
 
334
       */
 
335
      if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
 
336
                     data->set.device, strlen(data->set.device)+1) != 0) {
 
337
        /* printf("Failed to BINDTODEVICE, socket: %d  device: %s error: %s\n",
 
338
           sockfd, data->set.device, Curl_strerror(Curl_ourerrno())); */
 
339
        infof(data, "SO_BINDTODEVICE %s failed\n",
 
340
              data->set.device);
 
341
        /* This is typically "errno 1, error: Operation not permitted" if
 
342
           you're not running as root or another suitable privileged user */
 
343
      }
 
344
    }
 
345
#endif
 
346
 
 
347
    in=inet_addr(myhost);
 
348
    if (CURL_INADDR_NONE != in) {
 
349
 
 
350
      if ( h ) {
 
351
        Curl_addrinfo *addr = h->addr;
 
352
 
 
353
        Curl_resolv_unlock(data, h);
 
354
        /* we don't need it anymore after this function has returned */
 
355
 
 
356
        if( bind(sockfd, addr->ai_addr, (socklen_t)addr->ai_addrlen) >= 0) {
 
357
          /* we succeeded to bind */
 
358
#ifdef ENABLE_IPV6
 
359
          struct sockaddr_in6 add;
 
360
#else
 
361
          struct sockaddr_in add;
 
362
#endif
 
363
 
 
364
#ifdef __hpux
 
365
          int gsize = sizeof(add);
 
366
#else
 
367
          socklen_t gsize = sizeof(add);
 
368
#endif
 
369
          bindworked = TRUE;
 
370
 
 
371
          if(getsockname(sockfd, (struct sockaddr *) &add,
 
372
                         &gsize)<0) {
 
373
            failf(data, "getsockname() failed");
 
374
            return CURLE_HTTP_PORT_FAILED;
 
375
          }
 
376
        }
 
377
 
 
378
        if(!bindworked) {
 
379
          failf(data, "%s", Curl_strerror(conn, Curl_ourerrno()));
 
380
          return CURLE_HTTP_PORT_FAILED;
 
381
        }
 
382
 
 
383
      } /* end of if  h */
 
384
      else {
 
385
        failf(data,"could't find my own IP address (%s)", myhost);
 
386
        return CURLE_HTTP_PORT_FAILED;
 
387
      }
 
388
    } /* end of inet_addr */
 
389
 
 
390
    else {
 
391
      failf(data, "could't find my own IP address (%s)", myhost);
 
392
      return CURLE_HTTP_PORT_FAILED;
 
393
    }
 
394
 
 
395
    return CURLE_OK;
 
396
 
 
397
  } /* end of device selection support */
 
398
#endif /* end of HAVE_INET_NTOA */
 
399
 
 
400
  return CURLE_HTTP_PORT_FAILED;
 
401
}
 
402
 
 
403
/*
 
404
 * verifyconnect() returns TRUE if the connect really has happened.
 
405
 */
 
406
static bool verifyconnect(curl_socket_t sockfd, int *error)
 
407
{
 
408
  bool rc;
 
409
#ifdef SO_ERROR
 
410
  int err = 0;
 
411
#ifdef __hpux
 
412
  int errSize = sizeof(err);
 
413
#else
 
414
  socklen_t errSize = sizeof(err);
 
415
#endif
 
416
 
 
417
 
 
418
#ifdef WIN32
 
419
  /*
 
420
   * In October 2003 we effectively nullified this function on Windows due to
 
421
   * problems with it using all CPU in multi-threaded cases.
 
422
   *
 
423
   * In May 2004, we bring it back to offer more info back on connect failures.
 
424
   * Gisle Vanem could reproduce the former problems with this function, but
 
425
   * could avoid them by adding this SleepEx() call below:
 
426
   *
 
427
   *    "I don't have Rational Quantify, but the hint from his post was
 
428
   *    ntdll::NtRemoveIoCompletion(). So I'd assume the SleepEx (or maybe
 
429
   *    just Sleep(0) would be enough?) would release whatever
 
430
   *    mutex/critical-section the ntdll call is waiting on.
 
431
   *
 
432
   *    Someone got to verify this on Win-NT 4.0, 2000."
 
433
   */
 
434
  SleepEx(0, FALSE);
 
435
#endif
 
436
 
 
437
  if( -1 == getsockopt(sockfd, SOL_SOCKET, SO_ERROR,
 
438
                       (void *)&err, &errSize))
 
439
    err = Curl_ourerrno();
 
440
 
 
441
  if ((0 == err) || (EISCONN == err))
 
442
    /* we are connected, awesome! */
 
443
    rc = TRUE;
 
444
  else
 
445
    /* This wasn't a successful connect */
 
446
    rc = FALSE;
 
447
  if (error)
 
448
    *error = err;
 
449
#else
 
450
  (void)sockfd;
 
451
  if (error)
 
452
    *error = Curl_ourerrno();
 
453
#endif
 
454
  return rc;
 
455
}
 
456
 
 
457
/* Used within the multi interface. Try next IP address, return TRUE if no
 
458
   more address exists */
 
459
static bool trynextip(struct connectdata *conn,
 
460
                      int sockindex,
 
461
                      bool *connected)
 
462
{
 
463
  curl_socket_t sockfd;
 
464
  Curl_addrinfo *ai;
 
465
 
 
466
  if(sockindex != FIRSTSOCKET)
 
467
    return TRUE; /* no next */
 
468
 
 
469
  /* try the next address */
 
470
  ai = conn->ip_addr->ai_next;
 
471
 
 
472
  while (ai) {
 
473
    sockfd = singleipconnect(conn, ai, 0L, connected);
 
474
    if(sockfd != CURL_SOCKET_BAD) {
 
475
      /* store the new socket descriptor */
 
476
      conn->sock[sockindex] = sockfd;
 
477
      conn->ip_addr = ai;
 
478
      return FALSE;
 
479
    }
 
480
    ai = ai->ai_next;
 
481
  }
 
482
  return TRUE;
 
483
}
 
484
 
 
485
/*
 
486
 * Curl_is_connected() is used from the multi interface to check if the
 
487
 * firstsocket has connected.
 
488
 */
 
489
 
 
490
CURLcode Curl_is_connected(struct connectdata *conn,
 
491
                           int sockindex,
 
492
                           bool *connected)
 
493
{
 
494
  int rc;
 
495
  struct SessionHandle *data = conn->data;
 
496
  CURLcode code = CURLE_OK;
 
497
  curl_socket_t sockfd = conn->sock[sockindex];
 
498
  long allow = DEFAULT_CONNECT_TIMEOUT;
 
499
  long has_passed;
 
500
 
 
501
  curlassert(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET);
 
502
 
 
503
  *connected = FALSE; /* a very negative world view is best */
 
504
 
 
505
  /* Evaluate in milliseconds how much time that has passed */
 
506
  has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.start);
 
507
 
 
508
  /* subtract the most strict timeout of the ones */
 
509
  if(data->set.timeout && data->set.connecttimeout) {
 
510
    if (data->set.timeout < data->set.connecttimeout)
 
511
      allow = data->set.timeout*1000;
 
512
    else
 
513
      allow = data->set.connecttimeout*1000;
 
514
  }
 
515
  else if(data->set.timeout) {
 
516
    allow = data->set.timeout*1000;
 
517
  }
 
518
  else if(data->set.connecttimeout) {
 
519
    allow = data->set.connecttimeout*1000;
 
520
  }
 
521
 
 
522
  if(has_passed > allow ) {
 
523
    /* time-out, bail out, go home */
 
524
    failf(data, "Connection time-out after %ld ms", has_passed);
 
525
    return CURLE_OPERATION_TIMEOUTED;
 
526
  }
 
527
  if(conn->bits.tcpconnect) {
 
528
    /* we are connected already! */
 
529
    *connected = TRUE;
 
530
    return CURLE_OK;
 
531
  }
 
532
 
 
533
  /* check for connect without timeout as we want to return immediately */
 
534
  rc = waitconnect(sockfd, 0);
 
535
 
 
536
  if(WAITCONN_CONNECTED == rc) {
 
537
    if (verifyconnect(sockfd, NULL)) {
 
538
      /* we are connected, awesome! */
 
539
      *connected = TRUE;
 
540
      return CURLE_OK;
 
541
    }
 
542
    /* nope, not connected for real */
 
543
    infof(data, "Connection failed\n");
 
544
    if(trynextip(conn, sockindex, connected)) {
 
545
      code = CURLE_COULDNT_CONNECT;
 
546
    }
 
547
  }
 
548
  else if(WAITCONN_TIMEOUT != rc) {
 
549
    /* nope, not connected  */
 
550
    infof(data, "Connection failed\n");
 
551
    if(trynextip(conn, sockindex, connected)) {
 
552
      int error = Curl_ourerrno();
 
553
      failf(data, "Failed connect to %s:%d; %s",
 
554
            conn->host.name, conn->port, Curl_strerror(conn,error));
 
555
      code = CURLE_COULDNT_CONNECT;
 
556
    }
 
557
  }
 
558
  /*
 
559
   * If the connection failed here, we should attempt to connect to the "next
 
560
   * address" for the given host.
 
561
   */
 
562
 
 
563
  return code;
 
564
}
 
565
 
 
566
static void tcpnodelay(struct connectdata *conn,
 
567
                       curl_socket_t sockfd)
 
568
{
 
569
#ifdef TCP_NODELAY
 
570
  struct SessionHandle *data= conn->data;
 
571
  socklen_t onoff = (socklen_t) data->set.tcp_nodelay;
 
572
  if(setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (void *)&onoff,
 
573
                sizeof(onoff)) < 0)
 
574
    infof(data, "Could not set TCP_NODELAY: %s\n",
 
575
          Curl_strerror(conn, Curl_ourerrno()));
 
576
  else
 
577
    infof(data,"TCP_NODELAY set\n");
 
578
#else
 
579
  (void)conn;
 
580
  (void)sockfd;
 
581
#endif
 
582
}
 
583
 
 
584
/* singleipconnect() connects to the given IP only, and it may return without
 
585
   having connected if used from the multi interface. */
 
586
static curl_socket_t
 
587
singleipconnect(struct connectdata *conn,
 
588
                Curl_addrinfo *ai,
 
589
                long timeout_ms,
 
590
                bool *connected)
 
591
{
 
592
  char addr_buf[128];
 
593
  int rc;
 
594
  int error;
 
595
  bool conected;
 
596
  struct SessionHandle *data = conn->data;
 
597
  curl_socket_t sockfd = socket(ai->ai_family, ai->ai_socktype,
 
598
                                ai->ai_protocol);
 
599
  if (sockfd == CURL_SOCKET_BAD)
 
600
    return CURL_SOCKET_BAD;
 
601
 
 
602
  *connected = FALSE; /* default is not connected */
 
603
 
 
604
  Curl_printable_address(ai, addr_buf, sizeof(addr_buf));
 
605
  infof(data, "  Trying %s... ", addr_buf);
 
606
 
 
607
  if(data->set.tcp_nodelay)
 
608
    tcpnodelay(conn, sockfd);
 
609
 
 
610
  if(conn->data->set.device) {
 
611
    /* user selected to bind the outgoing socket to a specified "device"
 
612
       before doing connect */
 
613
    CURLcode res = bindlocal(conn, sockfd);
 
614
    if(res)
 
615
      return res;
 
616
  }
 
617
 
 
618
  /* set socket non-blocking */
 
619
  Curl_nonblock(sockfd, TRUE);
 
620
 
 
621
  rc = connect(sockfd, ai->ai_addr, ai->ai_addrlen);
 
622
 
 
623
  if(-1 == rc) {
 
624
    error = Curl_ourerrno();
 
625
 
 
626
    switch (error) {
 
627
    case EINPROGRESS:
 
628
    case EWOULDBLOCK:
 
629
#if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
 
630
      /* On some platforms EAGAIN and EWOULDBLOCK are the
 
631
       * same value, and on others they are different, hence
 
632
       * the odd #if
 
633
       */
 
634
    case EAGAIN:
 
635
#endif
 
636
      rc = waitconnect(sockfd, timeout_ms);
 
637
      break;
 
638
    default:
 
639
      /* unknown error, fallthrough and try another address! */
 
640
      failf(data, "Failed to connect to %s: %s",
 
641
            addr_buf, Curl_strerror(conn,error));
 
642
      break;
 
643
    }
 
644
  }
 
645
 
 
646
  /* The 'WAITCONN_TIMEOUT == rc' comes from the waitconnect(), and not from
 
647
     connect(). We can be sure of this since connect() cannot return 1. */
 
648
  if((WAITCONN_TIMEOUT == rc) &&
 
649
     (data->state.used_interface == Curl_if_multi)) {
 
650
    /* Timeout when running the multi interface */
 
651
    return sockfd;
 
652
  }
 
653
 
 
654
  conected = verifyconnect(sockfd, &error);
 
655
 
 
656
  if(!rc && conected) {
 
657
    /* we are connected, awesome! */
 
658
    *connected = TRUE; /* this is a true connect */
 
659
    infof(data, "connected\n");
 
660
    return sockfd;
 
661
  }
 
662
  else if(WAITCONN_TIMEOUT == rc)
 
663
    infof(data, "Timeout\n");
 
664
  else
 
665
    infof(data, "%s\n", Curl_strerror(conn, error));
 
666
 
 
667
  /* connect failed or timed out */
 
668
  sclose(sockfd);
 
669
 
 
670
  return CURL_SOCKET_BAD;
 
671
}
 
672
 
 
673
/*
 
674
 * TCP connect to the given host with timeout, proxy or remote doesn't matter.
 
675
 * There might be more than one IP address to try out. Fill in the passed
 
676
 * pointer with the connected socket.
 
677
 */
 
678
 
 
679
CURLcode Curl_connecthost(struct connectdata *conn,  /* context */
 
680
                          struct Curl_dns_entry *remotehost, /* use this one */
 
681
                          curl_socket_t *sockconn,   /* the connected socket */
 
682
                          Curl_addrinfo **addr,      /* the one we used */
 
683
                          bool *connected)           /* really connected? */
 
684
{
 
685
  struct SessionHandle *data = conn->data;
 
686
  curl_socket_t sockfd = CURL_SOCKET_BAD;
 
687
  int aliasindex;
 
688
  int num_addr;
 
689
  Curl_addrinfo *ai;
 
690
  Curl_addrinfo *curr_addr;
 
691
 
 
692
  struct timeval after;
 
693
  struct timeval before = Curl_tvnow();
 
694
 
 
695
  /*************************************************************
 
696
   * Figure out what maximum time we have left
 
697
   *************************************************************/
 
698
  long timeout_ms= DEFAULT_CONNECT_TIMEOUT;
 
699
  long timeout_per_addr;
 
700
 
 
701
  *connected = FALSE; /* default to not connected */
 
702
 
 
703
  if(data->set.timeout || data->set.connecttimeout) {
 
704
    long has_passed;
 
705
 
 
706
    /* Evaluate in milliseconds how much time that has passed */
 
707
    has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.start);
 
708
 
 
709
#ifndef min
 
710
#define min(a, b)   ((a) < (b) ? (a) : (b))
 
711
#endif
 
712
 
 
713
    /* get the most strict timeout of the ones converted to milliseconds */
 
714
    if(data->set.timeout && data->set.connecttimeout) {
 
715
      if (data->set.timeout < data->set.connecttimeout)
 
716
        timeout_ms = data->set.timeout*1000;
 
717
      else
 
718
        timeout_ms = data->set.connecttimeout*1000;
 
719
    }
 
720
    else if(data->set.timeout)
 
721
      timeout_ms = data->set.timeout*1000;
 
722
    else
 
723
      timeout_ms = data->set.connecttimeout*1000;
 
724
 
 
725
    /* subtract the passed time */
 
726
    timeout_ms -= has_passed;
 
727
 
 
728
    if(timeout_ms < 0) {
 
729
      /* a precaution, no need to continue if time already is up */
 
730
      failf(data, "Connection time-out");
 
731
      return CURLE_OPERATION_TIMEOUTED;
 
732
    }
 
733
  }
 
734
 
 
735
  /* Max time for each address */
 
736
  num_addr = Curl_num_addresses(remotehost->addr);
 
737
  timeout_per_addr = timeout_ms / num_addr;
 
738
 
 
739
  ai = remotehost->addr;
 
740
 
 
741
  /* Below is the loop that attempts to connect to all IP-addresses we
 
742
   * know for the given host. One by one until one IP succeeds.
 
743
   */
 
744
 
 
745
  if(data->state.used_interface == Curl_if_multi)
 
746
    /* don't hang when doing multi */
 
747
    timeout_per_addr = timeout_ms = 0;
 
748
 
 
749
  /*
 
750
   * Connecting with a Curl_addrinfo chain
 
751
   */
 
752
  for (curr_addr = ai, aliasindex=0; curr_addr;
 
753
       curr_addr = curr_addr->ai_next, aliasindex++) {
 
754
 
 
755
    /* start connecting to the IP curr_addr points to */
 
756
    sockfd = singleipconnect(conn, curr_addr, timeout_per_addr, connected);
 
757
 
 
758
    if(sockfd != CURL_SOCKET_BAD)
 
759
      break;
 
760
 
 
761
    /* get a new timeout for next attempt */
 
762
    after = Curl_tvnow();
 
763
    timeout_ms -= Curl_tvdiff(after, before);
 
764
    if(timeout_ms < 0) {
 
765
      failf(data, "connect() timed out!");
 
766
      return CURLE_OPERATION_TIMEOUTED;
 
767
    }
 
768
    before = after;
 
769
  }  /* end of connect-to-each-address loop */
 
770
 
 
771
  if (sockfd == CURL_SOCKET_BAD) {
 
772
    /* no good connect was made */
 
773
    *sockconn = CURL_SOCKET_BAD;
 
774
    return CURLE_COULDNT_CONNECT;
 
775
  }
 
776
 
 
777
  /* leave the socket in non-blocking mode */
 
778
 
 
779
  /* store the address we use */
 
780
  if(addr)
 
781
    *addr = curr_addr;
 
782
 
 
783
  /* allow NULL-pointers to get passed in */
 
784
  if(sockconn)
 
785
    *sockconn = sockfd;    /* the socket descriptor we've connected */
 
786
 
 
787
  return CURLE_OK;
 
788
}