~ubuntu-branches/ubuntu/natty/curl/natty-proposed

« back to all changes in this revision

Viewing changes to lib/hostthre.c

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Schuldei
  • Date: 2009-05-24 21:12:19 UTC
  • mfrom: (1.1.12 upstream)
  • mto: (3.3.1 squeeze)
  • mto: This revision was merged to the branch mainline in revision 39.
  • Revision ID: james.westby@ubuntu.com-20090524211219-7jgcwuhl04ixuqsm
Tags: upstream-7.19.5
ImportĀ upstreamĀ versionĀ 7.19.5

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: hostthre.c,v 1.51 2008-02-10 04:20:10 yangtse Exp $
 
21
 * $Id: hostthre.c,v 1.59 2009-04-21 11:46:16 yangtse Exp $
22
22
 ***************************************************************************/
23
23
 
24
24
#include "setup.h"
26
26
#include <string.h>
27
27
#include <errno.h>
28
28
 
29
 
#ifdef NEED_MALLOC_H
30
 
#include <malloc.h>
31
 
#endif
32
29
#ifdef HAVE_SYS_SOCKET_H
33
30
#include <sys/socket.h>
34
31
#endif
53
50
#include <stdlib.h>
54
51
#endif
55
52
 
56
 
#ifdef HAVE_SETJMP_H
57
 
#include <setjmp.h>
58
 
#endif
59
 
 
60
53
#ifdef HAVE_PROCESS_H
61
54
#include <process.h>
62
55
#endif
74
67
#include "strerror.h"
75
68
#include "url.h"
76
69
#include "multiif.h"
 
70
#include "inet_pton.h"
77
71
 
78
72
#define _MPRINTF_REPLACE /* use our functions only */
79
73
#include <curl/mprintf.h>
80
74
 
81
75
#include "inet_ntop.h"
82
76
 
83
 
#include "memory.h"
 
77
#include "curl_memory.h"
84
78
/* The last #include file should be: */
85
79
#include "memdebug.h"
86
80
 
96
90
/* This function is used to init a threaded resolve */
97
91
static bool init_resolve_thread(struct connectdata *conn,
98
92
                                const char *hostname, int port,
99
 
                                const Curl_addrinfo *hints);
 
93
                                const struct addrinfo *hints);
100
94
 
101
95
#ifdef CURLRES_IPV4
102
96
  #define THREAD_FUNC  gethostbyname_thread
106
100
  #define THREAD_NAME "getaddrinfo_thread"
107
101
#endif
108
102
 
109
 
#if defined(DEBUG_THREADING_GETHOSTBYNAME) || \
110
 
    defined(DEBUG_THREADING_GETADDRINFO)
111
 
/* If this is defined, provide tracing */
112
 
#define TRACE(args)  \
113
 
 do { trace_it("%u: ", __LINE__); trace_it args; } while(0)
114
 
 
115
 
static void trace_it (const char *fmt, ...)
116
 
{
117
 
  static int do_trace = -1;
118
 
  va_list args;
119
 
 
120
 
  if(do_trace == -1) {
121
 
    const char *env = getenv("CURL_TRACE");
122
 
    do_trace = (env && atoi(env) > 0);
123
 
  }
124
 
  if(!do_trace)
125
 
    return;
126
 
  va_start (args, fmt);
127
 
  vfprintf (stderr, fmt, args);
128
 
  fflush (stderr);
129
 
  va_end (args);
130
 
}
131
 
#else
132
 
#define TRACE(x)
133
 
#endif
134
 
 
135
 
#ifdef DEBUG_THREADING_GETADDRINFO
136
 
static void dump_addrinfo (struct connectdata *conn, const struct addrinfo *ai)
137
 
{
138
 
  TRACE(("dump_addrinfo:\n"));
139
 
  for ( ; ai; ai = ai->ai_next) {
140
 
    char  buf [INET6_ADDRSTRLEN];
141
 
 
142
 
    trace_it("    fam %2d, CNAME %s, ",
143
 
             ai->ai_family, ai->ai_canonname ? ai->ai_canonname : "<none>");
144
 
    if(Curl_printable_address(ai, buf, sizeof(buf)))
145
 
      trace_it("%s\n", buf);
146
 
    else
147
 
      trace_it("failed; %s\n", Curl_strerror(conn, SOCKERRNO));
148
 
  }
149
 
}
150
 
#endif
151
 
 
152
103
struct thread_data {
153
104
  HANDLE thread_hnd;
154
105
  unsigned thread_id;
312
263
    else {
313
264
      rc = Curl_addrinfo4_callback(conn, SOCKERRNO, NULL);
314
265
    }
315
 
    TRACE(("Winsock-error %d, addr %s\n", conn->async.status,
316
 
           he ? inet_ntoa(*(struct in_addr*)he->h_addr) : "unknown"));
317
266
    release_thread_sync(&tsd);
318
267
  }
319
268
 
337
286
{
338
287
  struct connectdata *conn = (struct connectdata*) arg;
339
288
  struct thread_data *td   = (struct thread_data*) conn->async.os_specific;
340
 
  struct addrinfo    *res;
 
289
  Curl_addrinfo      *res;
341
290
  char   service [NI_MAXSERV];
342
291
  int    rc;
343
292
  struct addrinfo hints = td->hints;
362
311
     need */
363
312
  SetEvent(td->event_thread_started);
364
313
 
365
 
  rc = getaddrinfo(tsd.hostname, service, &hints, &res);
 
314
  rc = Curl_getaddrinfo_ex(tsd.hostname, service, &hints, &res);
366
315
 
367
316
  /* is parent thread waiting for us and are we able to access conn members? */
368
317
  if(acquire_thread_sync(&tsd)) {
371
320
    SetEvent(td->event_resolved);
372
321
 
373
322
    if(rc == 0) {
374
 
#ifdef DEBUG_THREADING_GETADDRINFO
375
 
      dump_addrinfo (conn, res);
376
 
#endif
377
323
      rc = Curl_addrinfo6_callback(conn, CURL_ASYNC_SUCCESS, res);
378
324
    }
379
325
    else {
380
326
      rc = Curl_addrinfo6_callback(conn, SOCKERRNO, NULL);
381
 
      TRACE(("Winsock-error %d, no address\n", conn->async.status));
382
327
    }
383
328
    release_thread_sync(&tsd);
384
329
  }
449
394
 */
450
395
static bool init_resolve_thread (struct connectdata *conn,
451
396
                                 const char *hostname, int port,
452
 
                                 const Curl_addrinfo *hints)
 
397
                                 const struct addrinfo *hints)
453
398
{
454
399
  struct thread_data *td = calloc(sizeof(*td), 1);
455
400
  HANDLE thread_and_event[2] = {0};
536
481
#endif
537
482
 
538
483
  if(!td->thread_hnd) {
539
 
#ifdef _WIN32_WCE
540
 
     TRACE(("CreateThread() failed; %s\n", Curl_strerror(conn, ERRNO)));
541
 
#else
 
484
#ifndef _WIN32_WCE
542
485
     SET_ERRNO(errno);
543
 
     TRACE(("_beginthreadex() failed; %s\n", Curl_strerror(conn, ERRNO)));
544
486
#endif
545
487
     Curl_destroy_thread_data(&conn->async);
546
488
     return FALSE;
580
522
  struct thread_data   *td = (struct thread_data*) conn->async.os_specific;
581
523
  struct SessionHandle *data = conn->data;
582
524
  long   timeout;
583
 
  DWORD  status, ticks;
 
525
  DWORD  status;
584
526
  CURLcode rc;
585
527
 
586
528
  DEBUGASSERT(conn && td);
591
533
    conn->data->set.connecttimeout ? conn->data->set.connecttimeout :
592
534
    conn->data->set.timeout ? conn->data->set.timeout :
593
535
    CURL_TIMEOUT_RESOLVE * 1000; /* default name resolve timeout */
594
 
  ticks = GetTickCount();
595
536
 
596
537
  /* wait for the thread to resolve the name */
597
538
  status = WaitForSingleObject(td->event_resolved, timeout);
614
555
      TerminateThread(td->thread_hnd, 0);
615
556
      conn->async.done = TRUE;
616
557
      td->thread_status = (DWORD)-1;
617
 
      TRACE(("%s() thread stuck?!, ", THREAD_NAME));
618
558
    }
619
559
    else {
620
560
      /* Thread finished before timeout; propagate Winsock error to this
623
563
       */
624
564
      SET_SOCKERRNO(conn->async.status);
625
565
      GetExitCodeThread(td->thread_hnd, &td->thread_status);
626
 
      TRACE(("%s() status %lu, thread retval %lu, ",
627
 
             THREAD_NAME, status, td->thread_status));
628
566
    }
629
567
  }
630
568
  else {
631
569
    conn->async.done = TRUE;
632
570
    td->thread_status = (DWORD)-1;
633
 
    TRACE(("%s() timeout, ", THREAD_NAME));
634
571
  }
635
572
 
636
 
  TRACE(("elapsed %lu ms\n", GetTickCount()-ticks));
637
 
 
638
573
  if(entry)
639
574
    *entry = conn->async.dns;
640
575
 
690
625
    /* we're done */
691
626
    Curl_destroy_thread_data(&conn->async);
692
627
    if(!conn->async.dns) {
693
 
      TRACE(("Curl_is_resolved(): CURLE_COULDNT_RESOLVE_HOST\n"));
694
628
      failf(data, "Could not resolve host: %s; %s",
695
629
            conn->host.name, Curl_strerror(conn, conn->async.status));
696
630
      return CURLE_COULDNT_RESOLVE_HOST;
697
631
    }
698
632
    *entry = conn->async.dns;
699
 
    TRACE(("resolved okay, dns %p\n", *entry));
700
633
  }
701
634
  return CURLE_OK;
702
635
}
730
663
{
731
664
  struct hostent *h = NULL;
732
665
  struct SessionHandle *data = conn->data;
733
 
  in_addr_t in;
 
666
  struct in_addr in;
734
667
 
735
668
  *waitp = 0; /* don't wait, we act synchronously */
736
669
 
737
 
  in = inet_addr(hostname);
738
 
  if(in != CURL_INADDR_NONE)
 
670
  if(Curl_inet_pton(AF_INET, hostname, &in) > 0)
739
671
    /* This is a dotted IP address 123.123.123.123-style */
740
 
    return Curl_ip2addr(in, hostname, port);
 
672
    return Curl_ip2addr(AF_INET, &in, hostname, port);
741
673
 
742
674
  /* fire up a new resolver thread! */
743
675
  if(init_resolve_thread(conn, hostname, port, NULL)) {
768
700
                                int port,
769
701
                                int *waitp)
770
702
{
771
 
  struct addrinfo hints, *res;
 
703
  struct addrinfo hints;
 
704
  Curl_addrinfo *res;
772
705
  int error;
773
706
  char sbuf[NI_MAXSERV];
774
 
  curl_socket_t s;
775
707
  int pf;
776
708
  struct SessionHandle *data = conn->data;
777
709
 
778
710
  *waitp = FALSE; /* default to synch response */
779
711
 
780
 
  /* see if we have an IPv6 stack */
781
 
  s = socket(PF_INET6, SOCK_DGRAM, 0);
782
 
  if(s == CURL_SOCKET_BAD) {
783
 
    /* Some non-IPv6 stacks have been found to make very slow name resolves
784
 
     * when PF_UNSPEC is used, so thus we switch to a mere PF_INET lookup if
785
 
     * the stack seems to be a non-ipv6 one. */
786
 
 
 
712
  /*
 
713
   * Check if a limited name resolve has been requested.
 
714
   */
 
715
  switch(data->set.ip_version) {
 
716
  case CURL_IPRESOLVE_V4:
787
717
    pf = PF_INET;
 
718
    break;
 
719
  case CURL_IPRESOLVE_V6:
 
720
    pf = PF_INET6;
 
721
    break;
 
722
  default:
 
723
    pf = PF_UNSPEC;
 
724
    break;
788
725
  }
789
 
  else {
790
 
    /* This seems to be an IPv6-capable stack, use PF_UNSPEC for the widest
791
 
     * possible checks. And close the socket again.
792
 
     */
793
 
    sclose(s);
794
 
 
795
 
    /*
796
 
     * Check if a more limited name resolve has been requested.
797
 
     */
798
 
    switch(data->set.ip_version) {
799
 
    case CURL_IPRESOLVE_V4:
 
726
 
 
727
  if (pf != PF_INET) {
 
728
    /* see if we have an IPv6 stack */
 
729
    curl_socket_t s = socket(PF_INET6, SOCK_DGRAM, 0);
 
730
    if(s == CURL_SOCKET_BAD) {
 
731
      /* Some non-IPv6 stacks have been found to make very slow name resolves
 
732
       * when PF_UNSPEC is used, so thus we switch to a mere PF_INET lookup if
 
733
       * the stack seems to be a non-ipv6 one. */
 
734
 
800
735
      pf = PF_INET;
801
 
      break;
802
 
    case CURL_IPRESOLVE_V6:
803
 
      pf = PF_INET6;
804
 
      break;
805
 
    default:
806
 
      pf = PF_UNSPEC;
807
 
      break;
 
736
    }
 
737
    else {
 
738
      /* This seems to be an IPv6-capable stack, use PF_UNSPEC for the widest
 
739
       * possible checks. And close the socket again.
 
740
       */
 
741
      sclose(s);
808
742
    }
809
743
  }
810
744
 
826
760
  infof(data, "init_resolve_thread() failed for %s; %s\n",
827
761
        hostname, Curl_strerror(conn, ERRNO));
828
762
 
829
 
  error = getaddrinfo(hostname, sbuf, &hints, &res);
 
763
  error = Curl_getaddrinfo_ex(hostname, sbuf, &hints, &res);
830
764
  if(error) {
831
765
    infof(data, "getaddrinfo() failed for %s:%d; %s\n",
832
766
          hostname, port, Curl_strerror(conn, SOCKERRNO));