Skip to content
Snippets Groups Projects
url.c 128 KiB
Newer Older
  • Learn to ignore specific revisions
  •     }
        else {
          Curl_pgrsTime(data, TIMER_CONNECT); /* we're connected already */
          conn->bits.tcpconnect = TRUE;
          *protocol_done = TRUE;
          if(data->set.verbose)
            verboseconnect(conn);
        }
        /* Stop the loop now */
        break;
    
    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,
    
    {
      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 this is a re-used connection 'dns'
             will be NULL here. Continue connecting from here */
    
          code = SetupConnection(*in_connect, dns, protocol_done);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
           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 */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      }
      else {
        if ((*in_connect)->is_in_pipeline)
          data->state.is_in_pipeline = TRUE;
    
    /* Call this function after Curl_connect() has returned async=TRUE and
    
       then a successful name resolve has been received.
    
       Note: this function disconnects and frees the conn data in case of
       resolve failure */
    CURLcode Curl_async_resolved(struct connectdata *conn,
                                 bool *protocol_done)
    
    #if defined(USE_ARES) || defined(USE_THREADING_GETHOSTBYNAME) || \
        defined(USE_THREADING_GETADDRINFO)
    
      CURLcode code = SetupConnection(conn, conn->async.dns, protocol_done);
    
    
      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;
    
      (void)protocol_done;
    
    CURLcode Curl_done(struct connectdata **connp,
    
                       CURLcode status) /* an error if this is called after an
                                           error was detected */
    
    {
      CURLcode result;
    
      struct SessionHandle *data = conn->data;
    
      if(conn->bits.done)
        return CURLE_OK; /* Curl_done() has already been called */
    
      conn->bits.done = TRUE; /* called just now! */
    
    
      if(Curl_removeHandleFromPipeline(data, conn->recv_pipe) &&
         conn->readchannel_inuse)
    
      if(Curl_removeHandleFromPipeline(data, conn->send_pipe) &&
         conn->writechannel_inuse)
    
      /* cleanups done even if the connection is re-used */
    
      if(data->reqdata.rangestringalloc) {
        free(data->reqdata.range);
        data->reqdata.rangestringalloc = FALSE;
      }
    
      /* Cleanup possible redirect junk */
      if(data->reqdata.newurl) {
        free(data->reqdata.newurl);
        data->reqdata.newurl = NULL;
    
      if(conn->dns_entry) {
        Curl_resolv_unlock(data, conn->dns_entry); /* done with this */
        conn->dns_entry = NULL;
      }
    
    
      /* this calls the protocol-specific function pointer previously set */
      if(conn->curl_done)
    
        result = conn->curl_done(conn, status);
    
      else
        result = CURLE_OK;
    
    
      Curl_pgrsDone(conn); /* done with the operation */
    
      /* for ares-using, make sure all possible outstanding requests are properly
         cancelled before we proceed */
      ares_cancel(data->state.areschannel);
    
    
      /* 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 = Curl_disconnect(conn); /* close the connection */
    
        *connp = NULL; /* to make the caller of this function better detect that
                          this was actually killed here */
    
    
        /* 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;
      }
    
        ConnectionDone(conn); /* the connection is no longer in use */
    
    
        /* remember the most recently used connection */
        data->state.lastconnect = conn->connectindex;
    
    
        infof(data, "Connection #%ld to host %s left intact\n",
    
              conn->bits.httpproxy?conn->proxy.dispname:conn->host.dispname);
    
    CURLcode Curl_do(struct connectdata **connp, bool *done)
    
      CURLcode result=CURLE_OK;
    
      struct connectdata *conn = *connp;
    
      struct SessionHandle *data = conn->data;
    
      conn->bits.done = FALSE; /* Curl_done() is not called yet */
    
      conn->bits.do_more = FALSE; /* by default there's no curl_do_more() to use */
    
        /* generic protocol-specific function pointer set in curl_connect() */
    
        /* 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 connection */
    
          result = Curl_done(&conn, result); /* we are so done with this */
    
          /* conn may no longer be a good pointer */
    
          /*
           * According to bug report #1330310. We need to check for
           * CURLE_SEND_ERROR here as well. I figure this could happen when the
           * request failed on a FTP connection and thus Curl_done() itself tried
           * to use the connection (again). Slight Lack of feedback in the report,
           * but I don't think this extra check can do much harm.
           */
          if((CURLE_OK == result) || (CURLE_SEND_ERROR == result)) {
    
            /* Now, redo the connect and get a new connection */
    
            result = Curl_connect(data, connp, &async, &protocol_done);
    
            if(CURLE_OK == result) {
              /* We have connected or sent away a name resolve query fine */
    
    
              conn = *connp; /* setup conn to again point to something nice */
    
              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, &protocol_done);
    
              /* ... 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;
    }