~ubuntu-branches/ubuntu/vivid/curl/vivid

« back to all changes in this revision

Viewing changes to lib/connect.c

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Schuldei
  • Date: 2009-04-02 23:35:45 UTC
  • mto: (1.2.1 upstream) (3.2.3 sid)
  • mto: This revision was merged to the branch mainline in revision 38.
  • Revision ID: james.westby@ubuntu.com-20090402233545-geixkwhe3izccjt7
Tags: upstream-7.19.4
ImportĀ upstreamĀ versionĀ 7.19.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
5
5
 *                            | (__| |_| |  _ <| |___
6
6
 *                             \___|\___/|_| \_\_____|
7
7
 *
8
 
 * Copyright (C) 1998 - 2008, Daniel Stenberg, <daniel@haxx.se>, et al.
 
8
 * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
9
9
 *
10
10
 * This software is licensed as described in the file COPYING, which
11
11
 * you should have received as part of this distribution. The terms
18
18
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19
19
 * KIND, either express or implied.
20
20
 *
21
 
 * $Id: connect.c,v 1.192 2008-05-21 21:08:31 danf Exp $
 
21
 * $Id: connect.c,v 1.213 2009-02-28 01:35:53 yangtse Exp $
22
22
 ***************************************************************************/
23
23
 
24
24
#include "setup.h"
25
25
 
26
 
#ifndef WIN32
27
 
/* headers for non-win32 */
28
26
#ifdef HAVE_SYS_TIME_H
29
27
#include <sys/time.h>
30
28
#endif
56
54
#include <arpa/inet.h>
57
55
#endif
58
56
#ifdef HAVE_STDLIB_H
59
 
#include <stdlib.h> /* required for free() prototype, without it, this crashes */
60
 
#endif              /* on macos 68K */
 
57
#include <stdlib.h>
 
58
#endif
61
59
 
62
 
#if (defined(HAVE_FIONBIO) && defined(NETWARE))
 
60
#if (defined(HAVE_IOCTL_FIONBIO) && defined(NETWARE))
63
61
#include <sys/filio.h>
64
62
#endif
65
63
#ifdef NETWARE
71
69
#include <inet.h>
72
70
#endif
73
71
 
74
 
#endif  /* !WIN32 */
75
 
 
76
72
#include <stdio.h>
77
73
#include <errno.h>
78
74
#include <string.h>
79
75
 
 
76
#define _MPRINTF_REPLACE /* use our functions only */
 
77
#include <curl/mprintf.h>
 
78
 
80
79
#include "urldata.h"
81
80
#include "sendf.h"
82
81
#include "if2ip.h"
99
98
#undef SO_NOSIGPIPE
100
99
#endif
101
100
 
 
101
struct Curl_sockaddr_ex {
 
102
  int family;
 
103
  int socktype;
 
104
  int protocol;
 
105
  unsigned int addrlen;
 
106
  union {
 
107
    struct sockaddr addr;
 
108
    struct Curl_sockaddr_storage buff;
 
109
  } _sa_ex_u;
 
110
};
 
111
#define sa_addr _sa_ex_u.addr
 
112
 
102
113
static bool verifyconnect(curl_socket_t sockfd, int *error);
103
114
 
104
115
static curl_socket_t
175
186
int Curl_nonblock(curl_socket_t sockfd,    /* operate on this */
176
187
                  int nonblock   /* TRUE or FALSE */)
177
188
{
178
 
#undef SETBLOCK
179
 
#define SETBLOCK 0
180
 
#ifdef HAVE_O_NONBLOCK
 
189
#if defined(USE_BLOCKING_SOCKETS)
 
190
 
 
191
  return 0; /* returns success */
 
192
 
 
193
#elif defined(HAVE_FCNTL_O_NONBLOCK)
 
194
 
181
195
  /* most recent unix versions */
182
196
  int flags;
183
 
 
184
197
  flags = fcntl(sockfd, F_GETFL, 0);
185
198
  if(FALSE != nonblock)
186
199
    return fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
187
200
  else
188
201
    return fcntl(sockfd, F_SETFL, flags & (~O_NONBLOCK));
189
 
#undef SETBLOCK
190
 
#define SETBLOCK 1
191
 
#endif
192
 
 
193
 
#if defined(HAVE_FIONBIO) && (SETBLOCK == 0)
 
202
 
 
203
#elif defined(HAVE_IOCTL_FIONBIO)
 
204
 
194
205
  /* older unix versions */
195
206
  int flags;
196
 
 
197
207
  flags = nonblock;
198
208
  return ioctl(sockfd, FIONBIO, &flags);
199
 
#undef SETBLOCK
200
 
#define SETBLOCK 2
201
 
#endif
202
 
 
203
 
#if defined(HAVE_IOCTLSOCKET) && (SETBLOCK == 0)
204
 
  /* Windows? */
 
209
 
 
210
#elif defined(HAVE_IOCTLSOCKET_FIONBIO)
 
211
 
 
212
  /* Windows */
205
213
  unsigned long flags;
206
214
  flags = nonblock;
207
 
 
208
215
  return ioctlsocket(sockfd, FIONBIO, &flags);
209
 
#undef SETBLOCK
210
 
#define SETBLOCK 3
211
 
#endif
212
 
 
213
 
#if defined(HAVE_IOCTLSOCKET_CASE) && (SETBLOCK == 0)
214
 
  /* presumably for Amiga */
 
216
 
 
217
#elif defined(HAVE_IOCTLSOCKET_CAMEL_FIONBIO)
 
218
 
 
219
  /* Amiga */
215
220
  return IoctlSocket(sockfd, FIONBIO, (long)nonblock);
216
 
#undef SETBLOCK
217
 
#define SETBLOCK 4
218
 
#endif
219
 
 
220
 
#if defined(HAVE_SO_NONBLOCK) && (SETBLOCK == 0)
 
221
 
 
222
#elif defined(HAVE_SETSOCKOPT_SO_NONBLOCK)
 
223
 
221
224
  /* BeOS */
222
225
  long b = nonblock ? 1 : 0;
223
226
  return setsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b));
224
 
#undef SETBLOCK
225
 
#define SETBLOCK 5
226
 
#endif
227
 
 
228
 
#ifdef HAVE_DISABLED_NONBLOCKING
229
 
  return 0; /* returns success */
230
 
#undef SETBLOCK
231
 
#define SETBLOCK 6
232
 
#endif
233
 
 
234
 
#if(SETBLOCK == 0)
235
 
#error "no non-blocking method was found/used/set"
 
227
 
 
228
#else
 
229
#  error "no non-blocking method was found/used/set"
236
230
#endif
237
231
}
238
232
 
281
275
}
282
276
 
283
277
static CURLcode bindlocal(struct connectdata *conn,
284
 
                          curl_socket_t sockfd)
 
278
                          curl_socket_t sockfd, int af)
285
279
{
 
280
  struct SessionHandle *data = conn->data;
 
281
 
 
282
  struct Curl_sockaddr_storage sa;
 
283
  struct sockaddr *sock = (struct sockaddr *)&sa;  /* bind to this address */
 
284
  socklen_t sizeof_sa = 0; /* size of the data sock points to */
 
285
  struct sockaddr_in *si4 = (struct sockaddr_in *)&sa;
286
286
#ifdef ENABLE_IPV6
287
 
  char ipv6_addr[16];
 
287
  struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)&sa;
288
288
#endif
289
 
  struct SessionHandle *data = conn->data;
290
 
  struct sockaddr_in me;
291
 
  struct sockaddr *sock = NULL;  /* bind to this address */
292
 
  socklen_t socksize; /* size of the data sock points to */
 
289
 
 
290
  struct Curl_dns_entry *h=NULL;
293
291
  unsigned short port = data->set.localport; /* use this port number, 0 for
294
292
                                                "random" */
295
293
  /* how many port numbers to try to bind to, increasing one at a time */
296
294
  int portnum = data->set.localportrange;
297
295
  const char *dev = data->set.str[STRING_DEVICE];
 
296
  int error;
 
297
  char myhost[256] = "";
 
298
  int done = 0; /* -1 for error, 1 for address found */
298
299
 
299
300
  /*************************************************************
300
301
   * Select device to bind socket to
301
302
   *************************************************************/
 
303
  if ( !dev && !port )
 
304
    /* no local kind of binding was requested */
 
305
    return CURLE_OK;
 
306
 
 
307
  memset(&sa, 0, sizeof(struct Curl_sockaddr_storage));
 
308
 
302
309
  if(dev && (strlen(dev)<255) ) {
303
 
    struct Curl_dns_entry *h=NULL;
304
 
    char myhost[256] = "";
305
 
    in_addr_t in;
306
 
    int rc;
307
 
    bool was_iface = FALSE;
308
 
    int in6 = -1;
309
 
 
310
 
    /* First check if the given name is an IP address */
311
 
    in=inet_addr((char *) dev);
312
 
 
313
 
    if((in == CURL_INADDR_NONE) &&
314
 
       Curl_if2ip(dev, myhost, sizeof(myhost))) {
315
 
      /*
316
 
       * We now have the numerical IPv4-style x.y.z.w in the 'myhost' buffer
317
 
       */
318
 
      rc = Curl_resolv(conn, myhost, 0, &h);
319
 
      if(rc == CURLRESOLV_PENDING)
320
 
        (void)Curl_wait_for_resolv(conn, &h);
321
 
 
322
 
      if(h) {
323
 
        was_iface = TRUE;
324
 
        Curl_resolv_unlock(data, h);
325
 
      }
326
 
    }
327
 
 
328
 
    if(!was_iface) {
329
 
      /*
330
 
       * This was not an interface, resolve the name as a host name
331
 
       * or IP number
332
 
       */
333
 
      rc = Curl_resolv(conn, dev, 0, &h);
334
 
      if(rc == CURLRESOLV_PENDING)
335
 
        (void)Curl_wait_for_resolv(conn, &h);
336
 
 
337
 
      if(h) {
338
 
        if(in == CURL_INADDR_NONE)
339
 
          /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */
340
 
          Curl_inet_ntop(h->addr->ai_addr->sa_family,
341
 
                         &((struct sockaddr_in*)h->addr->ai_addr)->sin_addr,
342
 
                         myhost, sizeof myhost);
343
 
        else
344
 
          /* we know data->set.device is shorter than the myhost array */
345
 
          strcpy(myhost, dev);
346
 
        Curl_resolv_unlock(data, h);
347
 
      }
348
 
    }
349
 
 
350
 
    if(! *myhost) {
351
 
      /* need to fix this
352
 
         h=Curl_gethost(data,
353
 
         getmyhost(*myhost,sizeof(myhost)),
354
 
         hostent_buf,
355
 
         sizeof(hostent_buf));
356
 
      */
357
 
      failf(data, "Couldn't bind to '%s'", dev);
358
 
      return CURLE_INTERFACE_FAILED;
359
 
    }
360
 
 
361
 
    infof(data, "Bind local address to %s\n", myhost);
 
310
 
 
311
    /* interface */
 
312
    if(Curl_if2ip(af, dev, myhost, sizeof(myhost))) {
 
313
      /*
 
314
       * We now have the numerical IP address in the 'myhost' buffer
 
315
       */
 
316
      infof(data, "Local Interface %s is ip %s using address family %i\n",
 
317
            dev, myhost, af);
 
318
      done = 1;
362
319
 
363
320
#ifdef SO_BINDTODEVICE
364
 
    /* I am not sure any other OSs than Linux that provide this feature, and
365
 
     * at the least I cannot test. --Ben
366
 
     *
367
 
     * This feature allows one to tightly bind the local socket to a
368
 
     * particular interface.  This will force even requests to other local
369
 
     * interfaces to go out the external interface.
370
 
     *
371
 
     */
372
 
    if(was_iface) {
373
 
      /* Only bind to the interface when specified as interface, not just as a
 
321
      /* I am not sure any other OSs than Linux that provide this feature, and
 
322
       * at the least I cannot test. --Ben
 
323
       *
 
324
       * This feature allows one to tightly bind the local socket to a
 
325
       * particular interface.  This will force even requests to other local
 
326
       * interfaces to go out the external interface.
 
327
       *
 
328
       *
 
329
       * Only bind to the interface when specified as interface, not just as a
374
330
       * hostname or ip address.
375
331
       */
376
332
      if(setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
377
 
                     dev, strlen(dev)+1) != 0) {
378
 
        /* printf("Failed to BINDTODEVICE, socket: %d  device: %s error: %s\n",
379
 
           sockfd, dev, Curl_strerror(SOCKERRNO)); */
380
 
        infof(data, "SO_BINDTODEVICE %s failed\n", dev);
 
333
                    dev, strlen(dev)+1) != 0) {
 
334
        error = SOCKERRNO;
 
335
        infof(data, "SO_BINDTODEVICE %s failed with errno %d: %s;"
 
336
              " will do regular bind\n",
 
337
              dev, error, Curl_strerror(conn, error));
381
338
        /* This is typically "errno 1, error: Operation not permitted" if
382
339
           you're not running as root or another suitable privileged user */
383
340
      }
384
 
    }
385
 
#endif
386
 
 
387
 
    in=inet_addr(myhost);
388
 
 
389
 
#ifdef ENABLE_IPV6
390
 
    in6 = Curl_inet_pton (AF_INET6, myhost, (void *)&ipv6_addr);
391
 
#endif
392
 
    if(CURL_INADDR_NONE == in && -1 == in6) {
393
 
      failf(data,"couldn't find my own IP address (%s)", myhost);
 
341
#endif
 
342
    }
 
343
    else {
 
344
      /*
 
345
       * This was not an interface, resolve the name as a host name
 
346
       * or IP number
 
347
       *
 
348
       * Temporarily force name resolution to use only the address type
 
349
       * of the connection. The resolve functions should really be changed
 
350
       * to take a type parameter instead.
 
351
       */
 
352
      long ipver = data->set.ip_version;
 
353
      int rc;
 
354
 
 
355
      if (af == AF_INET)
 
356
        data->set.ip_version = CURL_IPRESOLVE_V4;
 
357
#ifdef ENABLE_IPV6
 
358
      else if (af == AF_INET6)
 
359
        data->set.ip_version = CURL_IPRESOLVE_V6;
 
360
#endif
 
361
 
 
362
      rc = Curl_resolv(conn, dev, 0, &h);
 
363
      if(rc == CURLRESOLV_PENDING)
 
364
        (void)Curl_wait_for_resolv(conn, &h);
 
365
      data->set.ip_version = ipver;
 
366
 
 
367
      if(h) {
 
368
        /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */
 
369
        Curl_printable_address(h->addr, myhost, sizeof(myhost));
 
370
        infof(data, "Name '%s' family %i resolved to '%s' family %i\n",
 
371
              dev, af, myhost, h->addr->ai_family);
 
372
        Curl_resolv_unlock(data, h);
 
373
        done = 1;
 
374
      }
 
375
      else {
 
376
        /*
 
377
         * provided dev was no interface (or interfaces are not supported
 
378
         * e.g. solaris) no ip address and no domain we fail here
 
379
         */
 
380
        done = -1;
 
381
      }
 
382
    }
 
383
 
 
384
    if(done > 0) {
 
385
#ifdef ENABLE_IPV6
 
386
      /* ipv6 address */
 
387
      if((af == AF_INET6) &&
 
388
         (Curl_inet_pton(AF_INET6, myhost, &si6->sin6_addr) > 0)) {
 
389
        si6->sin6_family = AF_INET6;
 
390
        si6->sin6_port = htons(port);
 
391
        sizeof_sa = sizeof(struct sockaddr_in6);
 
392
      }
 
393
      else
 
394
#endif
 
395
      /* ipv4 address */
 
396
      if((af == AF_INET) &&
 
397
         (Curl_inet_pton(AF_INET, myhost, &si4->sin_addr) > 0)) {
 
398
        si4->sin_family = AF_INET;
 
399
        si4->sin_port = htons(port);
 
400
        sizeof_sa = sizeof(struct sockaddr_in);
 
401
      }
 
402
    }
 
403
 
 
404
    if(done < 1) {
 
405
      failf(data, "Couldn't bind to '%s'", dev);
394
406
      return CURLE_INTERFACE_FAILED;
395
 
    } /* end of inet_addr */
396
 
 
397
 
    if( h ) {
398
 
      Curl_addrinfo *addr = h->addr;
399
 
      sock = addr->ai_addr;
400
 
      socksize = addr->ai_addrlen;
 
407
    }
 
408
  }
 
409
  else {
 
410
    /* no device was given, prepare sa to match af's needs */
 
411
#ifdef ENABLE_IPV6
 
412
    if ( af == AF_INET6 ) {
 
413
      si6->sin6_family = AF_INET6;
 
414
      si6->sin6_port = htons(port);
 
415
      sizeof_sa = sizeof(struct sockaddr_in6);
401
416
    }
402
417
    else
403
 
      return CURLE_INTERFACE_FAILED;
404
 
 
405
 
  }
406
 
  else if(port) {
407
 
    /* if a local port number is requested but no local IP, extract the
408
 
       address from the socket */
409
 
    memset(&me, 0, sizeof(struct sockaddr));
410
 
    me.sin_family = AF_INET;
411
 
    me.sin_addr.s_addr = INADDR_ANY;
412
 
 
413
 
    sock = (struct sockaddr *)&me;
414
 
    socksize = sizeof(struct sockaddr);
415
 
 
416
 
  }
417
 
  else
418
 
    /* no local kind of binding was requested */
419
 
    return CURLE_OK;
 
418
#endif
 
419
    if ( af == AF_INET ) {
 
420
      si4->sin_family = AF_INET;
 
421
      si4->sin_port = htons(port);
 
422
      sizeof_sa = sizeof(struct sockaddr_in);
 
423
    }
 
424
  }
420
425
 
421
426
  do {
422
 
 
423
 
    /* Set port number to bind to, 0 makes the system pick one */
424
 
    if(sock->sa_family == AF_INET)
425
 
      ((struct sockaddr_in *)sock)->sin_port = htons(port);
426
 
#ifdef ENABLE_IPV6
427
 
    else
428
 
      ((struct sockaddr_in6 *)sock)->sin6_port = htons(port);
429
 
#endif
430
 
 
431
 
    if( bind(sockfd, sock, socksize) >= 0) {
432
 
      /* we succeeded to bind */
 
427
    if( bind(sockfd, sock, sizeof_sa) >= 0) {
 
428
    /* we succeeded to bind */
433
429
      struct Curl_sockaddr_storage add;
434
 
      socklen_t size;
435
 
 
436
 
      size = sizeof(add);
 
430
      socklen_t size = sizeof(add);
 
431
      memset(&add, 0, sizeof(struct Curl_sockaddr_storage));
437
432
      if(getsockname(sockfd, (struct sockaddr *) &add, &size) < 0) {
438
 
        failf(data, "getsockname() failed");
 
433
        data->state.os_errno = error = SOCKERRNO;
 
434
        failf(data, "getsockname() failed with errno %d: %s",
 
435
              error, Curl_strerror(conn, error));
439
436
        return CURLE_INTERFACE_FAILED;
440
437
      }
441
 
      /* We re-use/clobber the port variable here below */
442
 
      if(((struct sockaddr *)&add)->sa_family == AF_INET)
443
 
        port = ntohs(((struct sockaddr_in *)&add)->sin_port);
444
 
#ifdef ENABLE_IPV6
445
 
      else
446
 
        port = ntohs(((struct sockaddr_in6 *)&add)->sin6_port);
447
 
#endif
448
438
      infof(data, "Local port: %d\n", port);
449
439
      conn->bits.bound = TRUE;
450
440
      return CURLE_OK;
451
441
    }
 
442
 
452
443
    if(--portnum > 0) {
453
444
      infof(data, "Bind to local port %d failed, trying next\n", port);
454
445
      port++; /* try next port */
 
446
      /* We re-use/clobber the port variable here below */
 
447
      if(sock->sa_family == AF_INET)
 
448
        si4->sin_port = ntohs(port);
 
449
#ifdef ENABLE_IPV6
 
450
      else
 
451
        si6->sin6_port = ntohs(port);
 
452
#endif
455
453
    }
456
454
    else
457
455
      break;
458
456
  } while(1);
459
457
 
460
 
  data->state.os_errno = SOCKERRNO;
461
 
  failf(data, "bind failure: %s",
462
 
        Curl_strerror(conn, data->state.os_errno));
 
458
  data->state.os_errno = error = SOCKERRNO;
 
459
  failf(data, "bind failed with errno %d: %s",
 
460
        error, Curl_strerror(conn, error));
 
461
 
463
462
  return CURLE_INTERFACE_FAILED;
464
 
 
465
463
}
466
464
 
467
465
/*
531
529
  return rc;
532
530
}
533
531
 
534
 
CURLcode Curl_store_ip_addr(struct connectdata *conn)
535
 
{
536
 
  char addrbuf[256];
537
 
  Curl_printable_address(conn->ip_addr, addrbuf, sizeof(addrbuf));
538
 
 
539
 
  /* save the string */
540
 
  Curl_safefree(conn->ip_addr_str);
541
 
  conn->ip_addr_str = strdup(addrbuf);
542
 
  if(!conn->ip_addr_str)
543
 
    return CURLE_OUT_OF_MEMORY; /* FAIL */
544
 
 
545
 
#ifdef PF_INET6
546
 
  if(conn->ip_addr->ai_family == PF_INET6)
547
 
    conn->bits.ipv6 = TRUE;
548
 
#endif
549
 
 
550
 
  return CURLE_OK;
551
 
}
552
 
 
553
532
/* Used within the multi interface. Try next IP address, return TRUE if no
554
 
   more address exists */
 
533
   more address exists or error */
555
534
static bool trynextip(struct connectdata *conn,
556
535
                      int sockindex,
557
536
                      bool *connected)
576
555
      /* store the new socket descriptor */
577
556
      conn->sock[sockindex] = sockfd;
578
557
      conn->ip_addr = ai;
579
 
 
580
 
      Curl_store_ip_addr(conn);
581
 
      return FALSE;
 
558
      break;
582
559
    }
583
560
    ai = ai->ai_next;
584
561
  }
735
712
                long timeout_ms,
736
713
                bool *connected)
737
714
{
 
715
  struct Curl_sockaddr_ex addr;
738
716
  char addr_buf[128];
739
717
  int rc;
740
718
  int error;
742
720
  struct SessionHandle *data = conn->data;
743
721
  curl_socket_t sockfd;
744
722
  CURLcode res;
745
 
  /*
746
 
   * Curl_sockaddr_storage, which is basically sockaddr_storage has a space
747
 
   * for a largest possible struct sockaddr only. We should add some space for
748
 
   * the other fields we are using. Hence the addr_storage size math.
749
 
   */
750
 
  char addr_storage[sizeof(struct curl_sockaddr)-
751
 
                    sizeof(struct sockaddr)+
752
 
                    sizeof(struct Curl_sockaddr_storage)];
753
 
  struct curl_sockaddr *addr=(struct curl_sockaddr*)&addr_storage;
754
723
  const void *iptoprint;
755
 
 
756
 
  addr->family=ai->ai_family;
757
 
  addr->socktype=conn->socktype;
758
 
  addr->protocol=ai->ai_protocol;
759
 
  addr->addrlen =
760
 
    (ai->ai_addrlen < (socklen_t)sizeof(struct Curl_sockaddr_storage)) ?
761
 
     (unsigned int)ai->ai_addrlen : sizeof(struct Curl_sockaddr_storage);
762
 
  memcpy(&addr->addr, ai->ai_addr, addr->addrlen);
763
 
 
764
 
  /* If set, use opensocket callback to get the socket */
 
724
  struct sockaddr_in * const sa4 = (void *)&addr.sa_addr;
 
725
#ifdef ENABLE_IPV6
 
726
  struct sockaddr_in6 * const sa6 = (void *)&addr.sa_addr;
 
727
#endif
 
728
 
 
729
  /*
 
730
   * The Curl_sockaddr_ex structure is basically libcurl's external API
 
731
   * curl_sockaddr structure with enough space available to directly hold
 
732
   * any protocol-specific address structures. The variable declared here
 
733
   * will be used to pass / receive data to/from the fopensocket callback
 
734
   * if this has been set, before that, it is initialized from parameters.
 
735
   */
 
736
 
 
737
  addr.family = ai->ai_family;
 
738
  addr.socktype = conn->socktype;
 
739
  addr.protocol = ai->ai_protocol;
 
740
  addr.addrlen = ai->ai_addrlen;
 
741
 
 
742
  if(addr.addrlen > sizeof(struct Curl_sockaddr_storage))
 
743
     addr.addrlen = sizeof(struct Curl_sockaddr_storage);
 
744
  memcpy(&addr.sa_addr, ai->ai_addr, addr.addrlen);
 
745
 
 
746
  *connected = FALSE; /* default is not connected */
 
747
 
765
748
  if(data->set.fopensocket)
 
749
   /*
 
750
    * If the opensocket callback is set, all the destination address information
 
751
    * is passed to the callback. Depending on this information the callback may
 
752
    * opt to abort the connection, this is indicated returning CURL_SOCKET_BAD;
 
753
    * otherwise it will return a not-connected socket. When the callback returns
 
754
    * a valid socket the destination address information might have been changed
 
755
    * and this 'new' address will actually be used here to connect.
 
756
    */
766
757
    sockfd = data->set.fopensocket(data->set.opensocket_client,
767
 
                                   CURLSOCKTYPE_IPCXN, addr);
 
758
                                   CURLSOCKTYPE_IPCXN,
 
759
                                   (struct curl_sockaddr *)&addr);
768
760
  else
769
 
    sockfd = socket(addr->family, addr->socktype, addr->protocol);
 
761
    /* opensocket callback not set, so simply create the socket now */
 
762
    sockfd = socket(addr.family, addr.socktype, addr.protocol);
 
763
 
770
764
  if(sockfd == CURL_SOCKET_BAD)
 
765
    /* no socket, no connection */
771
766
    return CURL_SOCKET_BAD;
772
767
 
773
 
  *connected = FALSE; /* default is not connected */
 
768
#if defined(ENABLE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
 
769
  if (conn->scope && (addr.family == AF_INET6))
 
770
    sa6->sin6_scope_id = conn->scope;
 
771
#endif
774
772
 
775
773
  /* FIXME: do we have Curl_printable_address-like with struct sockaddr* as
776
774
     argument? */
777
775
#if defined(HAVE_SYS_UN_H) && defined(AF_UNIX)
778
 
  if(addr->family==AF_UNIX)
 
776
  if(addr.family == AF_UNIX) {
779
777
    infof(data, "  Trying %s... ",
780
 
          ((const struct sockaddr_un*)(&addr->addr))->sun_path);
 
778
          ((const struct sockaddr_un*)(&addr.sa_addr))->sun_path);
 
779
    snprintf(data->info.ip, MAX_IPADR_LEN, "%s",
 
780
             ((const struct sockaddr_un*)(&addr.sa_addr))->sun_path);
 
781
    strcpy(conn->ip_addr_str, data->info.ip);
 
782
  }
781
783
  else
782
784
#endif
783
785
  {
784
786
#ifdef ENABLE_IPV6
785
 
    if(addr->family==AF_INET6)
786
 
      iptoprint= &((const struct sockaddr_in6*)(&addr->addr))->sin6_addr;
 
787
    if(addr.family == AF_INET6) {
 
788
      iptoprint = &sa6->sin6_addr;
 
789
      conn->bits.ipv6 = TRUE;
 
790
    }
787
791
    else
788
792
#endif
789
 
      iptoprint = &((const struct sockaddr_in*)(&addr->addr))->sin_addr;
 
793
    {
 
794
      iptoprint = &sa4->sin_addr;
 
795
    }
790
796
 
791
 
    if(Curl_inet_ntop(addr->family, iptoprint, addr_buf,
792
 
                      sizeof(addr_buf)) != NULL)
 
797
    if(Curl_inet_ntop(addr.family, iptoprint, addr_buf,
 
798
                      sizeof(addr_buf)) != NULL) {
793
799
      infof(data, "  Trying %s... ", addr_buf);
 
800
      snprintf(data->info.ip, MAX_IPADR_LEN, "%s", addr_buf);
 
801
      strcpy(conn->ip_addr_str, data->info.ip);
 
802
    }
794
803
  }
795
804
 
796
805
  if(data->set.tcp_nodelay)
810
819
  }
811
820
 
812
821
  /* possibly bind the local end to an IP, interface or port */
813
 
  res = bindlocal(conn, sockfd);
 
822
  res = bindlocal(conn, sockfd, addr.family);
814
823
  if(res) {
815
824
    sclose(sockfd); /* close socket and bail out */
816
825
    return CURL_SOCKET_BAD;
821
830
 
822
831
  /* Connect TCP sockets, bind UDP */
823
832
  if(conn->socktype == SOCK_STREAM)
824
 
    rc = connect(sockfd, &addr->addr, addr->addrlen);
 
833
    rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
825
834
  else
826
835
    rc = 0;
827
836
 
831
840
    switch (error) {
832
841
    case EINPROGRESS:
833
842
    case EWOULDBLOCK:
834
 
#if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
 
843
#if defined(EAGAIN)
 
844
#if (EAGAIN) != (EWOULDBLOCK)
835
845
      /* On some platforms EAGAIN and EWOULDBLOCK are the
836
846
       * same value, and on others they are different, hence
837
847
       * the odd #if
838
848
       */
839
849
    case EAGAIN:
840
850
#endif
 
851
#endif
841
852
      rc = waitconnect(sockfd, timeout_ms);
842
853
      break;
843
854
    default:
906
917
  long timeout_ms;
907
918
  long timeout_per_addr;
908
919
 
 
920
  DEBUGASSERT(sockconn);
909
921
  *connected = FALSE; /* default to not connected */
910
922
 
911
923
  /* get the timeout left */
954
966
    before = after;
955
967
  }  /* end of connect-to-each-address loop */
956
968
 
 
969
  *sockconn = sockfd;    /* the socket descriptor we've connected */
 
970
 
957
971
  if(sockfd == CURL_SOCKET_BAD) {
958
972
    /* no good connect was made */
959
 
    *sockconn = CURL_SOCKET_BAD;
960
973
    failf(data, "couldn't connect to host");
961
974
    return CURLE_COULDNT_CONNECT;
962
975
  }
967
980
  if(addr)
968
981
    *addr = curr_addr;
969
982
 
970
 
  /* allow NULL-pointers to get passed in */
971
 
  if(sockconn)
972
 
    *sockconn = sockfd;    /* the socket descriptor we've connected */
973
 
 
974
983
  data->info.numconnects++; /* to track the number of connections made */
975
984
 
976
985
  return CURLE_OK;