diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/connect.c | 91 | ||||
| -rw-r--r-- | lib/connect.h | 9 | ||||
| -rw-r--r-- | lib/ftp.c | 282 | ||||
| -rw-r--r-- | lib/ftp.h | 10 | ||||
| -rw-r--r-- | lib/multi.c | 111 | ||||
| -rw-r--r-- | lib/url.c | 85 | ||||
| -rw-r--r-- | lib/url.h | 4 | ||||
| -rw-r--r-- | lib/urldata.h | 11 | 
8 files changed, 433 insertions, 170 deletions
diff --git a/lib/connect.c b/lib/connect.c index ba00b73e9..545062c66 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -338,6 +338,70 @@ int socketerror(int sockfd)  }  /* + * Curl_is_connected() is used from the multi interface to check if the + * firstsocket has connected. + */ + +CURLcode Curl_is_connected(struct connectdata *conn, +                           int sockfd, +                           bool *connected) +{ +  int rc; +  struct SessionHandle *data = conn->data; + +  *connected = FALSE; /* a very negative world view is best */ + +  if(data->set.timeout || data->set.connecttimeout) { +    /* there is a timeout set */ + +    /* Evaluate in milliseconds how much time that has passed */ +    long has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.start); + +    /* subtract the most strict timeout of the ones */ +    if(data->set.timeout && data->set.connecttimeout) { +      if (data->set.timeout < data->set.connecttimeout) +        has_passed -= data->set.timeout*1000; +      else  +        has_passed -= data->set.connecttimeout*1000; +    } +    else if(data->set.timeout) +      has_passed -= data->set.timeout*1000; +    else +      has_passed -= data->set.connecttimeout*1000; + +    if(has_passed > 0 ) { +      /* time-out, bail out, go home */ +      failf(data, "Connection time-out"); +      return CURLE_OPERATION_TIMEOUTED; +    } +  } + +  /* check for connect without timeout as we want to return immediately */ +  rc = waitconnect(sockfd, 0); + +  if(0 == rc) { +    int err = socketerror(sockfd); +    if ((0 == err) || (EISCONN == err)) { +      /* we are connected, awesome! */ +      *connected = TRUE; +      return CURLE_OK; +    } +    /* nope, not connected for real */ +  } + +  /* +   * If the connection phase is "done" here, we should attempt to connect +   * to the "next address" in the Curl_hostaddr structure that we resolved +   * before. But we don't have that struct around anymore and we can't just +   * keep a pointer since the cache might in fact have gotten pruned by the +   * time we want to read this... Alas, we don't do this yet. +   */ + +  return CURLE_OK; +} + + +/*   * TCP connect to the given host with timeout, proxy or remote doesn't matter.   * There might be more than one IP address to try out. Fill in the passed   * pointer with the connected socket. @@ -347,7 +411,8 @@ CURLcode Curl_connecthost(struct connectdata *conn,  /* context */                            Curl_addrinfo *remotehost, /* use one in here */                            int port,                  /* connect to this */                            int *sockconn,             /* the connected socket */ -                          Curl_ipconnect **addr)     /* the one we used */ +                          Curl_ipconnect **addr,     /* the one we used */ +                          bool *connected)           /* really connected? */  {    struct SessionHandle *data = conn->data;    int rc; @@ -437,8 +502,11 @@ CURLcode Curl_connecthost(struct connectdata *conn,  /* context */          case EAGAIN:  #endif          case EINTR: -            /* asynchronous connect, wait for connect or timeout */ +          if(data->state.used_interface == Curl_if_multi) +            /* don't hang when doing multi */ +            timeout_ms = 0; +            rc = waitconnect(sockfd, timeout_ms);            break;          case ECONNREFUSED: /* no one listening */ @@ -448,6 +516,7 @@ CURLcode Curl_connecthost(struct connectdata *conn,  /* context */            break;          }        } +        if(0 == rc) {          /* we might be connected, if the socket says it is OK! Ask it! */          int err; @@ -455,11 +524,17 @@ CURLcode Curl_connecthost(struct connectdata *conn,  /* context */          err = socketerror(sockfd);          if ((0 == err) || (EISCONN == err)) {            /* we are connected, awesome! */ +          *connected = TRUE; /* this is truly a connect */            break;  	}          failf(data, "socket error: %d", err);          /* we are _not_ connected, it was a false alert, continue please */        } +      else if(data->state.used_interface == Curl_if_multi) { +        /* When running the multi interface, we bail out here */ +        rc = 0; +        break; +      }        /* connect failed or timed out */        sclose(sockfd); @@ -542,8 +617,11 @@ CURLcode Curl_connecthost(struct connectdata *conn,  /* context */           */        case EAGAIN:  #endif -          /* asynchronous connect, wait for connect or timeout */ +        if(data->state.used_interface == Curl_if_multi) +          /* don't hang when doing multi */ +          timeout_ms = 0; +          rc = waitconnect(sockfd, timeout_ms);          break;        default: @@ -558,6 +636,7 @@ CURLcode Curl_connecthost(struct connectdata *conn,  /* context */        int err = socketerror(sockfd);        if ((0 == err) || (EISCONN == err)) {          /* we are connected, awesome! */ +        *connected = TRUE; /* this is a true connect */          break;        }        /* nope, not connected for real */ @@ -565,6 +644,12 @@ CURLcode Curl_connecthost(struct connectdata *conn,  /* context */      }      if(0 != rc) { +      if(data->state.used_interface == Curl_if_multi) { +        /* When running the multi interface, we bail out here */ +        rc = 0; +        break; +      } +        /* get a new timeout for next attempt */        after = Curl_tvnow();        timeout_ms -= Curl_tvdiff(after, before); diff --git a/lib/connect.h b/lib/connect.h index f44252346..5a6b8e63c 100644 --- a/lib/connect.h +++ b/lib/connect.h @@ -26,10 +26,15 @@  int Curl_nonblock(int socket,    /* operate on this */                    int nonblock   /* TRUE or FALSE */); +CURLcode Curl_is_connected(struct connectdata *conn, +                           int sockfd, +                           bool *connected); +  CURLcode Curl_connecthost(struct connectdata *conn,                            Curl_addrinfo *host, /* connect to this */                            int port,       /* connect to this port number */                            int *sockconn,  /* not set if error is returned */ -                          Curl_ipconnect **addr /* the one we used */ -                          ); /*  index we used */ +                          Curl_ipconnect **addr, /* the one we used */ +                          bool *connected /* truly connected? */ +                          );  #endif @@ -387,8 +387,10 @@ int Curl_GetFTPResponse(char *buf,    return nread; /* total amount of bytes read */  } -/* ftp_connect() should do everything that is to be considered a part -   of the connection phase. */ +/* + * Curl_ftp_connect() should do everything that is to be considered a part of + * the connection phase. + */  CURLcode Curl_ftp_connect(struct connectdata *conn)  {    /* this is FTP and no proxy */ @@ -1321,7 +1323,8 @@ CURLcode ftp_use_port(struct connectdata *conn)   */  static -CURLcode ftp_use_pasv(struct connectdata *conn) +CURLcode ftp_use_pasv(struct connectdata *conn, +                      bool *connected)  {    struct SessionHandle *data = conn->data;    ssize_t nread; @@ -1473,7 +1476,14 @@ CURLcode ftp_use_pasv(struct connectdata *conn)                              addr,                              connectport,                              &conn->secondarysocket, -                            &conninfo); +                            &conninfo, +                            connected); + +  /* +   * When this is used from the multi interface, this might've returned with +   * the 'connected' set to FALSE and thus we are now awaiting a non-blocking +   * connect to connect and we should not be "hanging" here waiting. +   */    if((CURLE_OK == result) &&              data->set.verbose) @@ -1494,127 +1504,24 @@ CURLcode ftp_use_pasv(struct connectdata *conn)    return CURLE_OK;  } -/*********************************************************************** - * - * ftp_perform() +/* + * Curl_ftp_nextconnect()   * - * This is the actual DO function for FTP. Get a file/directory according to - * the options previously setup. + * This function shall be called when the second FTP connection has been + * established and is confirmed connected.   */ -static -CURLcode ftp_perform(struct connectdata *conn) +CURLcode Curl_ftp_nextconnect(struct connectdata *conn)  { -  /* this is FTP and no proxy */ -  ssize_t nread; -  CURLcode result=CURLE_OK;    struct SessionHandle *data=conn->data;    char *buf = data->state.buffer; /* this is our buffer */ +  CURLcode result; +  ssize_t nread; +  int ftpcode; /* for ftp status */    /* the ftp struct is already inited in ftp_connect() */    struct FTP *ftp = conn->proto.ftp; -    long *bytecountp = ftp->bytecountp; -  int ftpcode; /* for ftp status */ - -  /* Send any QUOTE strings? */ -  if(data->set.quote) { -    if ((result = ftp_sendquote(conn, data->set.quote)) != CURLE_OK) -      return result; -  } -     -  /* This is a re-used connection. Since we change directory to where the -     transfer is taking place, we must now get back to the original dir -     where we ended up after login: */ -  if (conn->bits.reuse) { -    if ((result = ftp_cwd(conn, ftp->entrypath)) != CURLE_OK) -      return result; -  } - -  /* change directory first! */ -  if(ftp->dir && ftp->dir[0]) { -    if ((result = ftp_cwd(conn, ftp->dir)) != CURLE_OK) -        return result; -  } - -  /* Requested time of file? */ -  if(data->set.get_filetime && ftp->file) { -    result = ftp_getfiletime(conn, ftp->file); -    if(result) -      return result; -  } - -  /* If we have selected NOBODY and HEADER, it means that we only want file -     information. Which in FTP can't be much more than the file size and -     date. */ -  if(data->set.no_body && data->set.include_header && ftp->file) { -    /* The SIZE command is _not_ RFC 959 specified, and therefor many servers -       may not support it! It is however the only way we have to get a file's -       size! */ -    ssize_t filesize; - -    ftp->no_transfer = TRUE; /* this means no actual transfer is made */ -     -    /* Some servers return different sizes for different modes, and thus we -       must set the proper type before we check the size */ -    result = ftp_transfertype(conn, data->set.ftp_ascii); -    if(result) -      return result; - -    /* failing to get size is not a serious error */ -    result = ftp_getsize(conn, ftp->file, &filesize); - -    if(CURLE_OK == result) { -      sprintf(buf, "Content-Length: %d\r\n", filesize); -      result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0); -      if(result) -        return result; -    } - -    /* If we asked for a time of the file and we actually got one as -       well, we "emulate" a HTTP-style header in our output. */ - -#ifdef HAVE_STRFTIME -    if(data->set.get_filetime && data->info.filetime) { -      struct tm *tm; -#ifdef HAVE_LOCALTIME_R -      struct tm buffer; -      tm = (struct tm *)localtime_r(&data->info.filetime, &buffer); -#else -      tm = localtime((unsigned long *)&data->info.filetime); -#endif -      /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */ -      strftime(buf, BUFSIZE-1, "Last-Modified: %a, %d %b %Y %H:%M:%S %Z\r\n", -               tm); -      result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0); -      if(result) -        return result; -    } -#endif - -    return CURLE_OK; -  } - -  if(data->set.no_body) -    /* doesn't really transfer any data */ -    ftp->no_transfer = TRUE; -  /* Get us a second connection up and connected */ -  else if(data->set.ftp_use_port) { -    /* We have chosen to use the PORT command */ -    result = ftp_use_port(conn); -    if(CURLE_OK == result) -      /* we have the data connection ready */ -      infof(data, "Connected the data stream with PORT!\n"); -  } -  else { -    /* We have chosen (this is default) to use the PASV command */ -    result = ftp_use_pasv(conn); -    if(CURLE_OK == result) -      infof(data, "Connected the data stream with PASV!\n"); -  } -   -  if(result) -    return result;    if(data->set.upload) { @@ -1993,6 +1900,128 @@ CURLcode ftp_perform(struct connectdata *conn)  /***********************************************************************   * + * ftp_perform() + * + * This is the actual DO function for FTP. Get a file/directory according to + * the options previously setup. + */ + +static +CURLcode ftp_perform(struct connectdata *conn, +                     bool *connected)  /* for the TCP connect status after +                                          PASV / PORT */ +{ +  /* this is FTP and no proxy */ +  CURLcode result=CURLE_OK; +  struct SessionHandle *data=conn->data; +  char *buf = data->state.buffer; /* this is our buffer */ + +  /* the ftp struct is already inited in ftp_connect() */ +  struct FTP *ftp = conn->proto.ftp; + +  /* Send any QUOTE strings? */ +  if(data->set.quote) { +    if ((result = ftp_sendquote(conn, data->set.quote)) != CURLE_OK) +      return result; +  } +     +  /* This is a re-used connection. Since we change directory to where the +     transfer is taking place, we must now get back to the original dir +     where we ended up after login: */ +  if (conn->bits.reuse) { +    if ((result = ftp_cwd(conn, ftp->entrypath)) != CURLE_OK) +      return result; +  } + +  /* change directory first! */ +  if(ftp->dir && ftp->dir[0]) { +    if ((result = ftp_cwd(conn, ftp->dir)) != CURLE_OK) +        return result; +  } + +  /* Requested time of file? */ +  if(data->set.get_filetime && ftp->file) { +    result = ftp_getfiletime(conn, ftp->file); +    if(result) +      return result; +  } + +  /* If we have selected NOBODY and HEADER, it means that we only want file +     information. Which in FTP can't be much more than the file size and +     date. */ +  if(data->set.no_body && data->set.include_header && ftp->file) { +    /* The SIZE command is _not_ RFC 959 specified, and therefor many servers +       may not support it! It is however the only way we have to get a file's +       size! */ +    ssize_t filesize; + +    ftp->no_transfer = TRUE; /* this means no actual transfer is made */ +     +    /* Some servers return different sizes for different modes, and thus we +       must set the proper type before we check the size */ +    result = ftp_transfertype(conn, data->set.ftp_ascii); +    if(result) +      return result; + +    /* failing to get size is not a serious error */ +    result = ftp_getsize(conn, ftp->file, &filesize); + +    if(CURLE_OK == result) { +      sprintf(buf, "Content-Length: %d\r\n", filesize); +      result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0); +      if(result) +        return result; +    } + +    /* If we asked for a time of the file and we actually got one as +       well, we "emulate" a HTTP-style header in our output. */ + +#ifdef HAVE_STRFTIME +    if(data->set.get_filetime && data->info.filetime) { +      struct tm *tm; +#ifdef HAVE_LOCALTIME_R +      struct tm buffer; +      tm = (struct tm *)localtime_r(&data->info.filetime, &buffer); +#else +      tm = localtime((unsigned long *)&data->info.filetime); +#endif +      /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */ +      strftime(buf, BUFSIZE-1, "Last-Modified: %a, %d %b %Y %H:%M:%S %Z\r\n", +               tm); +      result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0); +      if(result) +        return result; +    } +#endif + +    return CURLE_OK; +  } + +  if(data->set.no_body) +    /* doesn't really transfer any data */ +    ftp->no_transfer = TRUE; +  /* Get us a second connection up and connected */ +  else if(data->set.ftp_use_port) { +    /* We have chosen to use the PORT command */ +    result = ftp_use_port(conn); +    if(CURLE_OK == result) { +      /* we have the data connection ready */ +      infof(data, "Ordered connect of the data stream with PORT!\n"); +      *connected = TRUE; /* mark us "still connected" */ +    } +  } +  else { +    /* We have chosen (this is default) to use the PASV command */ +    result = ftp_use_pasv(conn, connected); +    if(connected) +      infof(data, "Connected the data stream with PASV!\n"); +  } +   +  return result; +} + +/*********************************************************************** + *   * Curl_ftp()   *   * This function is registered as 'curl_do' function. It decodes the path @@ -2003,6 +2032,7 @@ CURLcode ftp_perform(struct connectdata *conn)  CURLcode Curl_ftp(struct connectdata *conn)  {    CURLcode retcode; +  bool connected;    struct SessionHandle *data = conn->data;    struct FTP *ftp; @@ -2049,15 +2079,15 @@ CURLcode Curl_ftp(struct connectdata *conn)    else      ftp->dir = NULL; -  retcode = ftp_perform(conn); - -  /* clean up here, success or error doesn't matter */ -  if(ftp->file) -    free(ftp->file); -  if(ftp->dir) -    free(ftp->dir); +  retcode = ftp_perform(conn, &connected); -  ftp->file = ftp->dir = NULL; /* zero */ +  if(CURLE_OK == retcode) { +    if(connected) +      retcode = Curl_ftp_nextconnect(conn); +    else +      /* since we didn't connect now, we want do_more to get called */ +      conn->do_more = TRUE; +  }    return retcode;  } @@ -2128,6 +2158,12 @@ CURLcode Curl_ftp_disconnect(struct connectdata *conn)        free(ftp->entrypath);      if(ftp->cache)        free(ftp->cache); +    if(ftp->file) +      free(ftp->file); +    if(ftp->dir) +      free(ftp->dir); + +    ftp->file = ftp->dir = NULL; /* zero */    }    return CURLE_OK;  } @@ -1,6 +1,5 @@  #ifndef __FTP_H  #define __FTP_H -  /*****************************************************************************   *                                  _   _ ____  _        *  Project                     ___| | | |  _ \| |     @@ -24,22 +23,15 @@   * $Id$   *****************************************************************************/ -/* MN 06/07/02 */  #ifndef CURL_DISABLE_FTP -  CURLcode Curl_ftp(struct connectdata *conn);  CURLcode Curl_ftp_done(struct connectdata *conn);  CURLcode Curl_ftp_connect(struct connectdata *conn);  CURLcode Curl_ftp_disconnect(struct connectdata *conn); -  CURLcode Curl_ftpsendf(struct connectdata *, const char *fmt, ...); - -/* The kerberos stuff needs this: */  int Curl_GetFTPResponse(char *buf, struct connectdata *conn,                          int *ftpcode); - -/* MN 06/07/02 */ +CURLcode Curl_ftp_nextconnect(struct connectdata *conn);  #endif -  #endif diff --git a/lib/multi.c b/lib/multi.c index 2e6a408b4..0830aa4ae 100644 --- a/lib/multi.c +++ b/lib/multi.c @@ -29,6 +29,7 @@  #include "urldata.h"  #include "transfer.h"  #include "url.h" +#include "connect.h"  /* The last #include file should be: */  #ifdef MALLOCDEBUG @@ -43,11 +44,13 @@ struct Curl_message {  typedef enum {    CURLM_STATE_INIT, -  CURLM_STATE_CONNECT, -  CURLM_STATE_DO, -  CURLM_STATE_PERFORM, -  CURLM_STATE_DONE, -  CURLM_STATE_COMPLETED, +  CURLM_STATE_CONNECT,     /* connect has been sent off */ +  CURLM_STATE_WAITCONNECT, /* we're awaiting the connect to finalize */ +  CURLM_STATE_DO,          /* send off the request (part 1) */ +  CURLM_STATE_DO_MORE,     /* send off the request (part 2) */ +  CURLM_STATE_PERFORM,     /* transfer data */ +  CURLM_STATE_DONE,        /* post data transfer operation */ +  CURLM_STATE_COMPLETED,   /* operation complete */    CURLM_STATE_LAST /* not a true state, never use this */  } CURLMstate; @@ -224,6 +227,32 @@ CURLMcode curl_multi_fdset(CURLM *multi_handle,      switch(easy->state) {      default:        break; +    case CURLM_STATE_WAITCONNECT: +    case CURLM_STATE_DO_MORE: +      { +        /* when we're waiting for a connect, we wait for the socket to +           become writable */ +        struct connectdata *conn = easy->easy_conn; +        int sockfd; + +        if(CURLM_STATE_WAITCONNECT == easy->state) { +          sockfd = conn->firstsocket; +          FD_SET(sockfd, write_fd_set); +        } +        else { +          /* When in DO_MORE state, we could be either waiting for us +             to connect to a remote site, or we could wait for that site +             to connect to us. It makes a difference in the way: if we +             connect to the site we wait for the socket to become writable, if  +             the site connects to us we wait for it to become readable */ +          sockfd = conn->secondarysocket; +          FD_SET(sockfd, write_fd_set); +        } + +        if(sockfd > *max_fd) +          *max_fd = sockfd; +      } +      break;      case CURLM_STATE_PERFORM:        /* This should have a set of file descriptors for us to set.  */        /* after the transfer is done, go DONE */ @@ -251,6 +280,7 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)    bool done;    CURLMcode result=CURLM_OK;    struct Curl_message *msg = NULL; +  bool connected;    *running_handles = 0; /* bump this once for every living handle */ @@ -259,6 +289,12 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)    easy=multi->easy.next;    while(easy) { + +#ifdef MALLOCDEBUG +    fprintf(stderr, "HANDLE %p: State: %x\n", +            (char *)easy, easy->state); +#endif +      switch(easy->state) {      case CURLM_STATE_INIT:        /* init this transfer. */ @@ -287,23 +323,80 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)        /* Connect. We get a connection identifier filled in. */        easy->result = Curl_connect(easy->easy_handle, &easy->easy_conn); -      /* after connect, go DO */ +      /* after the connect has been sent off, go WAITCONNECT */        if(CURLE_OK == easy->result) { -        easy->state = CURLM_STATE_DO; +        easy->state = CURLM_STATE_WAITCONNECT;          result = CURLM_CALL_MULTI_PERFORM;         }        break; + +    case CURLM_STATE_WAITCONNECT: +      { +        bool connected; +        easy->result = Curl_is_connected(easy->easy_conn, +                                         easy->easy_conn->firstsocket, +                                         &connected); +        if(connected) +          easy->result = Curl_protocol_connect(easy->easy_conn, NULL); + +        if(CURLE_OK != easy->result) +          /* failure detected */ +          break; + +        if(connected) { +          /* after the connect has completed, go DO */ +          easy->state = CURLM_STATE_DO; +          result = CURLM_CALL_MULTI_PERFORM;  +        } +      } +      break; +      case CURLM_STATE_DO:        /* Do the fetch or put request */        easy->result = Curl_do(&easy->easy_conn); -      /* after do, go PERFORM */        if(CURLE_OK == easy->result) { -        if(CURLE_OK == Curl_readwrite_init(easy->easy_conn)) { + +        /* after do, go PERFORM... or DO_MORE */ +        if(easy->easy_conn->do_more) { +          /* we're supposed to do more, but we need to sit down, relax +             and wait a little while first */ +          easy->state = CURLM_STATE_DO_MORE; +          result = CURLM_OK; +        } +        else { +          /* we're done with the DO, now PERFORM */ +          easy->result = Curl_readwrite_init(easy->easy_conn); +          if(CURLE_OK == easy->result) { +            easy->state = CURLM_STATE_PERFORM; +            result = CURLM_CALL_MULTI_PERFORM;  +          } +        } +      } +      break; + +    case CURLM_STATE_DO_MORE: +      /* +       * First, check if we really are ready to do more. +       */ +      easy->result = Curl_is_connected(easy->easy_conn, +                                       easy->easy_conn->secondarysocket, +                                       &connected); +      if(connected) { +        /* +         * When we are connected, DO MORE and then go PERFORM +         */ +        easy->result = Curl_do_more(easy->easy_conn); + +        if(CURLE_OK == easy->result) +          easy->result = Curl_readwrite_init(easy->easy_conn); + +        if(CURLE_OK == easy->result) {            easy->state = CURLM_STATE_PERFORM;            result = CURLM_CALL_MULTI_PERFORM;           }        }        break; +      case CURLM_STATE_PERFORM:        /* read/write data if it is ready to do so */        easy->result = Curl_readwrite(easy->easy_conn, &done); @@ -1307,7 +1307,8 @@ ConnectionStore(struct SessionHandle *data,  }  static CURLcode ConnectPlease(struct connectdata *conn, -                              Curl_addrinfo *hostaddr) +                              Curl_addrinfo *hostaddr, +                              bool *connected)  {    CURLcode result;    Curl_ipconnect *addr; @@ -1319,7 +1320,8 @@ static CURLcode ConnectPlease(struct connectdata *conn,                             hostaddr,                             conn->port,                             &conn->firstsocket, -                           &addr); +                           &addr, +                           connected);    if(CURLE_OK == result) {      /* All is cool, then we store the current information from the hostaddr         struct to the serv_addr, as it might be needed later. The address @@ -1374,7 +1376,7 @@ static void verboseconnect(struct connectdata *conn,      struct in_addr in;      (void) memcpy(&in.s_addr, &conn->serv_addr.sin_addr, sizeof (in.s_addr));      infof(data, "Connected to %s (%s) port %d\n", -          hostaddr?hostaddr->h_name:"[re-used]", +          hostaddr?hostaddr->h_name:"",  #if defined(HAVE_INET_NTOA_R)            inet_ntoa_r(in, ntoa_buf, sizeof(ntoa_buf)),  #else @@ -1385,6 +1387,42 @@ static void verboseconnect(struct connectdata *conn,  #endif  } +/* + * We have discovered that the TCP connection has been successful, we can now + * proceed with some action. + * + * If we're using the multi interface, this host address pointer is most + * likely NULL at this point as we can't keep the resolved info around. This + * may call for some reworking, like a reference counter in the struct or + * something. The hostaddr is not used for very much though, we have the + * 'serv_addr' field in the connectdata struct for most of it. + */ +CURLcode Curl_protocol_connect(struct connectdata *conn, +                               Curl_addrinfo *hostaddr) +{ +  struct SessionHandle *data = conn->data; +  CURLcode result; +   +  Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */ + +  if(data->set.verbose) +    verboseconnect(conn, hostaddr); + +  if(conn->curl_connect) { +    /* is there a protocol-specific connect() procedure? */ + +    /* set start time here for timeout purposes in the +     * connect procedure, it is later set again for the +     * progress meter purpose */ +    conn->now = Curl_tvnow(); + +    /* Call the protocol-specific connect function */ +    result = conn->curl_connect(conn); +  } + +  return result; /* pass back status */ +} +  static CURLcode CreateConnection(struct SessionHandle *data,                                   struct connectdata **in_connect)  { @@ -1780,6 +1818,7 @@ static CURLcode CreateConnection(struct SessionHandle *data,      conn->remote_port = PORT_HTTP;      conn->protocol |= PROT_HTTP;      conn->curl_do = Curl_http; +    conn->curl_do_more = NULL;      conn->curl_done = Curl_http_done;      conn->curl_connect = Curl_http_connect;  #else @@ -1797,6 +1836,7 @@ static CURLcode CreateConnection(struct SessionHandle *data,      conn->protocol |= PROT_HTTP|PROT_HTTPS|PROT_SSL;      conn->curl_do = Curl_http; +    conn->curl_do_more = NULL;      conn->curl_done = Curl_http_done;      conn->curl_connect = Curl_http_connect; @@ -1819,6 +1859,7 @@ static CURLcode CreateConnection(struct SessionHandle *data,        }      conn->protocol |= PROT_GOPHER;      conn->curl_do = Curl_http; +    conn->curl_do_more = NULL;      conn->curl_done = Curl_http_done;  #else      failf(data, LIBCURL_NAME @@ -1867,6 +1908,7 @@ static CURLcode CreateConnection(struct SessionHandle *data,      }      else {        conn->curl_do = Curl_ftp; +      conn->curl_do_more = Curl_ftp_nextconnect;        conn->curl_done = Curl_ftp_done;        conn->curl_connect = Curl_ftp_connect;        conn->curl_disconnect = Curl_ftp_disconnect; @@ -2441,29 +2483,16 @@ static CURLcode CreateConnection(struct SessionHandle *data,    conn->headerbytecount = 0;    if(-1 == conn->firstsocket) { +    bool connected; +      /* Connect only if not already connected! */ -    result = ConnectPlease(conn, hostaddr); -    Curl_pgrsTime(data, TIMER_CONNECT); /* connect done, good or bad */ +    result = ConnectPlease(conn, hostaddr, &connected); + +    if(connected) +      result = Curl_protocol_connect(conn, hostaddr);      if(CURLE_OK != result)        return result; - -    if(data->set.verbose) -      verboseconnect(conn, hostaddr); - -    if(conn->curl_connect) { -      /* is there a protocol-specific connect() procedure? */ - -      /* set start time here for timeout purposes in the -       * connect procedure, it is later set again for the -       * progress meter purpose */ -      conn->now = Curl_tvnow(); - -      /* Call the protocol-specific connect function */ -      result = conn->curl_connect(conn); -      if(result != CURLE_OK) -        return result; /* pass back errors */ -    }    }    else {      Curl_pgrsTime(data, TIMER_CONNECT); /* we're connected already */ @@ -2558,6 +2587,8 @@ CURLcode Curl_do(struct connectdata **connp)    struct connectdata *conn = *connp;    struct SessionHandle *data=conn->data; +  conn->do_more = FALSE; /* by default there's no curl_do_more() to use */ +    if(conn->curl_do) {      /* generic protocol-specific function pointer set in curl_connect() */      result = conn->curl_do(conn); @@ -2587,6 +2618,16 @@ CURLcode Curl_do(struct connectdata **connp)    return result;  } +CURLcode Curl_do_more(struct connectdata *conn) +{ +  CURLcode result=CURLE_OK; + +  if(conn->curl_do_more) +    result = conn->curl_do_more(conn); + +  return result; +} +  /*   * local variables:   * eval: (load-file "../curl-mode.el") @@ -32,7 +32,9 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...);  CURLcode Curl_close(struct SessionHandle *data); /* opposite of curl_open() */  CURLcode Curl_connect(struct SessionHandle *, struct connectdata **);  CURLcode Curl_do(struct connectdata **); +CURLcode Curl_do_more(struct connectdata *);  CURLcode Curl_done(struct connectdata *);  CURLcode Curl_disconnect(struct connectdata *); - +CURLcode Curl_protocol_connect(struct connectdata *conn, +                               Curl_addrinfo *hostaddr);  #endif diff --git a/lib/urldata.h b/lib/urldata.h index 9c7b18b1b..44a4a7200 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -328,6 +328,12 @@ struct connectdata {    CURLcode (*curl_do)(struct connectdata *connect);    CURLcode (*curl_done)(struct connectdata *connect); +  /* If the curl_do() function is better made in two halves, this +   * curl_do_more() function will be called afterwards, if set. For example +   * for doing the FTP stuff after the PASV/PORT command. +   */ +  CURLcode (*curl_do_more)(struct connectdata *connect); +    /* This function *MAY* be set to a protocol-dependent function that is run     * after the connect() and everything is done, as a step in the connection.     */  @@ -414,7 +420,10 @@ struct connectdata {        buffer, so the next read should read from where this pointer points to,        and the 'upload_present' contains the number of bytes available at this        position */ -  char *upload_fromhere;                                    +  char *upload_fromhere; + +  bool do_more; /* this is set TRUE if the ->curl_do_more() function is +                   supposed to be called, after ->curl_do() */  };  /*  | 
