Skip to content
Snippets Groups Projects
url.c 103 KiB
Newer Older
  • Learn to ignore specific revisions
  •   if((data->set.timeout || data->set.connecttimeout) && !data->set.no_signal) {
    
    #ifdef HAVE_SIGACTION
        if(keep_copysig) {
          /* we got a struct as it looked before, now put that one back nice
             and clean */
          sigaction(SIGALRM, &keep_sigact, NULL); /* put it back */
        }
    
    #else
    #ifdef HAVE_SIGNAL
        /* restore the previous SIGALRM handler */
        signal(SIGALRM, keep_sigact);
    #endif
    
    #endif
        /* switch back the alarm() to either zero or to what it was before minus
           the time we spent until now! */
        if(prev_alarm) {
          /* there was an alarm() set before us, now put it back */
          long elapsed_ms = Curl_tvdiff(Curl_tvnow(), conn->created);
          long alarm_set;
    
          /* the alarm period is counted in even number of seconds */
          alarm_set = prev_alarm - elapsed_ms/1000;
    
          if(alarm_set<=0) {
            /* if it turned negative, we should fire off a SIGALRM here, but we
               won't, and zero would be to switch it off so we never set it to
               less than 1! */
            alarm(1);
            result = CURLE_OPERATION_TIMEOUTED;
            failf(data, "Previous alarm fired off!");
          }
          else
            alarm(alarm_set);
        }
        else
          alarm(0); /* just shut it off */
      }
    #endif
    
    
      return result;
    }
    
    /* SetupConnection() should be called after the name resolve initiated in
     * CreateConnection() is all done.
     */
     
    static CURLcode SetupConnection(struct connectdata *conn,
                                    struct Curl_dns_entry *hostaddr)
    {
      struct SessionHandle *data = conn->data;
      CURLcode result=CURLE_OK;
    
      Curl_pgrsTime(data, TIMER_NAMELOOKUP);
    
      if(conn->protocol & PROT_FILE)
        /* There's nothing in this function to setup if we're only doing
           a file:// transfer */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      /*************************************************************
       * Proxy authentication
       *************************************************************/
    
    #if 0 /* This code is not needed anymore (moved to http.c) */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        char *authorization;
    
        snprintf(data->state.buffer, BUFSIZE, "%s:%s",
    
        if(Curl_base64_encode(data->state.buffer, strlen(data->state.buffer),
    
          Curl_safefree(conn->allocptr.proxyuserpwd);
    
          conn->allocptr.proxyuserpwd =
    
            aprintf("Proxy-authorization: Basic %s\015\012", authorization);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          free(authorization);
        }
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      }
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
      /*************************************************************
       * Send user-agent to HTTP proxies even if the target protocol
       * isn't HTTP.
       *************************************************************/
    
      if((conn->protocol&PROT_HTTP) ||
         (data->change.proxy && *data->change.proxy)) {
    
            aprintf("User-Agent: %s\015\012", data->set.useragent);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      if(data->set.encoding) {
    
        Curl_safefree(conn->allocptr.accept_encoding);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        conn->allocptr.accept_encoding =
          aprintf("Accept-Encoding: %s\015\012", data->set.encoding);
      }
    
    
      conn->bytecount = 0;
      conn->headerbytecount = 0;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      if(-1 == conn->firstsocket) {
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        /* Connect only if not already connected! */
    
        result = ConnectPlease(conn, hostaddr, &connected);
    
    
          result = Curl_protocol_connect(conn, hostaddr);
    
          if(CURLE_OK == result)
            conn->bits.tcpconnect = TRUE;
        }
        else
          conn->bits.tcpconnect = FALSE;
    
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        if(CURLE_OK != result)
          return result;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      }
    
      else {
        Curl_pgrsTime(data, TIMER_CONNECT); /* we're connected already */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      }
    
    
      conn->now = Curl_tvnow(); /* time this *after* the connect is done, we
                                   set this here perhaps a second time */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    
    #ifdef __EMX__
      /* 20000330 mgs
       * the check is quite a hack...
       * we're calling _fsetmode to fix the problem with fwrite converting newline
       * characters (you get mangled text files, and corrupted binary files when
       * you download to stdout and redirect it to a file). */
    
    
      if ((data->set.out)->_handle == NULL) {
    
        _fsetmode(stdout, "b");
      }
    #endif
    
    
    CURLcode Curl_connect(struct SessionHandle *data,
    
                          struct connectdata **in_connect,
                          bool *asyncp)
    
    {
      CURLcode code;
    
      *asyncp = FALSE; /* assume synchronous resolves by default */
      
    
      /* call the stuff that needs to be called */
    
      code = CreateConnection(data, in_connect, &dns, asyncp);
    
      if(CURLE_OK == code) {
        /* no error */
        if(dns || !*asyncp)
          /* If an address is available it means that we already have the name
             resolved, OR it isn't async.
             If so => continue connecting from here */
          code = SetupConnection(*in_connect, dns);
        /* else
             response will be received and treated async wise */
      }
      
    
      if(CURLE_OK != code) {
        /* We're not allowed to return failure with memory left allocated
           in the connectdata struct, free those here */
    
        if(*in_connect) {
          Curl_disconnect(*in_connect); /* close the connection */
          *in_connect = NULL;           /* return a NULL */
    
    /* Call this function after Curl_connect() has returned async=TRUE and
       then a successful name resolve has been received */
    CURLcode Curl_async_resolved(struct connectdata *conn)
    {
    #ifdef USE_ARES
      CURLcode code = SetupConnection(conn, conn->async.dns);
    
      if(code)
        /* We're not allowed to return failure with memory left allocated
           in the connectdata struct, free those here */
        Curl_disconnect(conn); /* close the connection */
    
      return code;
    #else
      (void)conn;
      return CURLE_OK;
    #endif
    }
    
    
    
    CURLcode Curl_done(struct connectdata *conn)
    
      struct SessionHandle *data=conn->data;
    
      CURLcode result;
    
    
      /* cleanups done even if the connection is re-used */
    
      if(conn->bits.rangestringalloc) {
        free(conn->range);
        conn->bits.rangestringalloc = FALSE;
      }
    
    
      /* Cleanup possible redirect junk */
      if(conn->newurl) {
        free(conn->newurl);
        conn->newurl = NULL;
      }
    
        Curl_resolv_unlock(conn->data, conn->connect_addr); /* done with this */
    
    #if defined(CURLDEBUG) && defined(AGGRESIVE_TEST)
    
      /* scan for DNS cache entries still marked as in use */
      Curl_hash_apply(data->hostcache,
                      NULL, Curl_scan_cache_used);
    #endif
    
    
      /* this calls the protocol-specific function pointer previously set */
      if(conn->curl_done)
        result = conn->curl_done(conn);
      else
        result = CURLE_OK;
    
    
      Curl_pgrsDone(conn); /* done with the operation */
    
      /* if data->set.reuse_forbid is TRUE, it means the libcurl client has
    
         forced us to close this no matter what we think.
    
         if conn->bits.close is TRUE, it means that the connection should be
         closed in spite of all our efforts to be nice, due to protocol
         restrictions in our or the server's end */
    
      if(data->set.reuse_forbid || conn->bits.close) {
        CURLcode res2;
        res2 = Curl_disconnect(conn); /* close the connection */
    
        /* If we had an error already, make sure we return that one. But
           if we got a new error, return that. */
        if(!result && res2)
          result = res2;
      }
    
        infof(data, "Connection #%d left intact\n", conn->connectindex);
    
    CURLcode Curl_do(struct connectdata **connp)
    
      CURLcode result=CURLE_OK;
    
      struct connectdata *conn = *connp;
      struct SessionHandle *data=conn->data;
    
      conn->bits.do_more = FALSE; /* by default there's no curl_do_more() to use */
    
        /* generic protocol-specific function pointer set in curl_connect() */
        result = conn->curl_do(conn);
    
    
        /* This was formerly done in transfer.c, but we better do it here */
    
        if((CURLE_SEND_ERROR == result) && conn->bits.reuse) {
    
          /* This was a re-use of a connection and we got a write error in the
           * DO-phase. Then we DISCONNECT this connection and have another attempt
           * to CONNECT and then DO again! The retry cannot possibly find another
           * connection to re-use, since we only keep one possible connection for
           * each.  */
    
          infof(data, "Re-used connection seems dead, get a new one\n");
    
          conn->bits.close = TRUE; /* enforce close of this connetion */
          result = Curl_done(conn);   /* we are so done with this */
          if(CURLE_OK == result) {
    
            /* Now, redo the connect and get a new connection */
    
            result = Curl_connect(data, connp, &async);
            if(CURLE_OK == result) {
              /* We have connected or sent away a name resolve query fine */
    
              if(async) {
                /* Now, if async is TRUE here, we need to wait for the name
                   to resolve */
                result = Curl_wait_for_resolv(conn, NULL);
                if(result)
                  return result;
                
                /* Resolved, continue with the connection */
                result = Curl_async_resolved(conn);              
                if(result)
                  return result;
              }
              
    
              /* ... finally back to actually retry the DO phase */
    
    CURLcode Curl_do_more(struct connectdata *conn)
    {
      CURLcode result=CURLE_OK;
    
      if(conn->curl_do_more)
        result = conn->curl_do_more(conn);
    
      return result;
    }
    
    
    static bool safe_strequal(char* str1, char* str2)
    {
      if(str1 && str2)
        /* both pointers point to something then compare them */
        return strequal(str1, str2);
      else
        /* if both pointers are NULL then treat them as equal */
        return (!str1 && !str2);
    }
    
    
    bool
    Curl_ssl_config_matches(struct ssl_config_data* data,
                            struct ssl_config_data* needle)
    
    {
      if((data->version == needle->version) &&
         (data->verifypeer == needle->verifypeer) &&
         (data->verifyhost == needle->verifyhost) &&
         safe_strequal(data->CApath, needle->CApath) &&
         safe_strequal(data->CAfile, needle->CAfile) &&
         safe_strequal(data->random_file, needle->random_file) &&
         safe_strequal(data->egdsocket, needle->egdsocket) &&
         safe_strequal(data->cipher_list, needle->cipher_list))
    
        return TRUE;
    
      return FALSE;
    
    bool
    Curl_clone_ssl_config(struct ssl_config_data *source,
                          struct ssl_config_data *dest)
    
      dest->verifyhost = source->verifyhost;
      dest->verifypeer = source->verifypeer;
      dest->version = source->version;
    
      if(source->CAfile) {
        dest->CAfile = strdup(source->CAfile);
        if(!dest->CAfile)
    
          return FALSE;
    
      if(source->CApath) {
        dest->CApath = strdup(source->CApath);
        if(!dest->CApath)
    
          return FALSE;
    
      if(source->cipher_list) {
        dest->cipher_list = strdup(source->cipher_list);
        if(!dest->cipher_list)
    
          return FALSE;
    
      if(source->egdsocket) {
        dest->egdsocket = strdup(source->egdsocket);
        if(!dest->egdsocket)
    
          return FALSE;
    
      if(source->random_file) {
        dest->random_file = strdup(source->random_file);
        if(!dest->random_file)
    
          return FALSE;
    
    void Curl_free_ssl_config(struct ssl_config_data* sslc)
    
    {
      if(sslc->CAfile)
        free(sslc->CAfile);
    
      if(sslc->CApath)
        free(sslc->CApath);
    
      if(sslc->cipher_list)
        free(sslc->cipher_list);
    
      if(sslc->egdsocket)
        free(sslc->egdsocket);
    
      if(sslc->random_file)
        free(sslc->random_file);
    }