FTP code turned into state machine. Not completely yet, but a good start.

The tag 'before_ftp_statemachine' was set just before this commit in case
of future need.
This commit is contained in:
Daniel Stenberg 2005-02-09 13:06:40 +00:00
parent 120f17ce04
commit 6a2e21ec8c
34 changed files with 2970 additions and 1755 deletions

View File

@ -245,7 +245,9 @@ typedef enum {
CURLE_COULDNT_RESOLVE_HOST, /* 6 */
CURLE_COULDNT_CONNECT, /* 7 */
CURLE_FTP_WEIRD_SERVER_REPLY, /* 8 */
CURLE_FTP_ACCESS_DENIED, /* 9 */
CURLE_FTP_ACCESS_DENIED, /* 9 a service was denied by the FTP server
due to lack of access - when login fails
this is not returned. */
CURLE_FTP_USER_PASSWORD_INCORRECT, /* 10 */
CURLE_FTP_WEIRD_PASS_REPLY, /* 11 */
CURLE_FTP_WEIRD_USER_REPLY, /* 12 */
@ -305,6 +307,8 @@ typedef enum {
CURLE_SEND_FAIL_REWIND, /* 65 - Sending the data requires a rewind
that failed */
CURLE_SSL_ENGINE_INITFAILED, /* 66 - failed to initialise ENGINE */
CURLE_LOGIN_DENIED, /* 67 - user, password or similar was not
accepted and we failed to login */
CURL_LAST /* never use! */
} CURLcode;

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@ -85,7 +85,7 @@
#define _MPRINTF_REPLACE /* use our functions only */
#include <curl/mprintf.h>
CURLcode Curl_dict(struct connectdata *conn)
CURLcode Curl_dict(struct connectdata *conn, bool *done)
{
char *word;
char *ppath;
@ -100,6 +100,8 @@ CURLcode Curl_dict(struct connectdata *conn)
char *path = conn->path;
curl_off_t *bytecount = &conn->bytecount;
*done = TRUE; /* unconditionally */
if(conn->bits.user_passwd) {
/* AUTH is missing */
}

View File

@ -2,18 +2,18 @@
#define __DICT_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
*
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
@ -24,7 +24,7 @@
* $Id$
***************************************************************************/
#ifndef CURL_DISABLE_DICT
CURLcode Curl_dict(struct connectdata *conn);
CURLcode Curl_dict(struct connectdata *conn, bool *done);
CURLcode Curl_dict_done(struct connectdata *conn);
#endif
#endif

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@ -266,7 +266,7 @@ static CURLcode file_upload(struct connectdata *conn)
* opposed to sockets) we instead perform the whole do-operation in this
* function.
*/
CURLcode Curl_file(struct connectdata *conn)
CURLcode Curl_file(struct connectdata *conn, bool *done)
{
/* This implementation ignores the host name in conformance with
RFC 1738. Only local files (reachable via the standard file system)
@ -286,6 +286,8 @@ CURLcode Curl_file(struct connectdata *conn)
int fd;
struct timeval now = Curl_tvnow();
*done = TRUE; /* unconditionally */
Curl_readwrite_init(conn);
Curl_initinfo(data);
Curl_pgrsStartNow(data);

View File

@ -2,18 +2,18 @@
#define __FILE_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
*
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
@ -24,7 +24,7 @@
* $Id$
***************************************************************************/
#ifndef CURL_DISABLE_FILE
CURLcode Curl_file(struct connectdata *);
CURLcode Curl_file(struct connectdata *, bool *done);
CURLcode Curl_file_done(struct connectdata *, CURLcode);
CURLcode Curl_file_connect(struct connectdata *);
#endif

4035
lib/ftp.c

File diff suppressed because it is too large Load Diff

View File

@ -1,18 +1,18 @@
#ifndef __FTP_H
#define __FTP_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
*
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
@ -24,14 +24,21 @@
***************************************************************************/
#ifndef CURL_DISABLE_FTP
CURLcode Curl_ftp(struct connectdata *conn);
CURLcode Curl_ftp(struct connectdata *conn, bool *done);
CURLcode Curl_ftp_done(struct connectdata *conn, CURLcode);
CURLcode Curl_ftp_connect(struct connectdata *conn);
CURLcode Curl_ftp_connect(struct connectdata *conn, bool *done);
CURLcode Curl_ftp_disconnect(struct connectdata *conn);
CURLcode Curl_ftpsendf(struct connectdata *, const char *fmt, ...);
CURLcode Curl_nbftpsendf(struct connectdata *, const char *fmt, ...);
CURLcode Curl_GetFTPResponse(ssize_t *nread, struct connectdata *conn,
int *ftpcode);
CURLcode Curl_ftp_nextconnect(struct connectdata *conn);
#endif
#endif
CURLcode Curl_ftp_multi_statemach(struct connectdata *conn, bool *done);
CURLcode Curl_ftp_fdset(struct connectdata *conn,
fd_set *read_fd_set,
fd_set *write_fd_set,
int *max_fdp);
CURLcode Curl_ftp_doing(struct connectdata *conn,
bool *dophase_done);
#endif /* CURL_DISABLE_FTP */
#endif /* __FTP_H */

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@ -99,7 +99,7 @@
#ifdef CURLRES_ARES
/*
* Curl_fdset() is called when someone from the outside world (using
* Curl_resolv_fdset() is called when someone from the outside world (using
* curl_multi_fdset()) wants to get our fd_set setup and we're talking with
* ares. The caller must make sure that this function is only called when we
* have a working ares channel.
@ -107,10 +107,10 @@
* Returns: CURLE_OK always!
*/
CURLcode Curl_fdset(struct connectdata *conn,
fd_set *read_fd_set,
fd_set *write_fd_set,
int *max_fdp)
CURLcode Curl_resolv_fdset(struct connectdata *conn,
fd_set *read_fd_set,
fd_set *write_fd_set,
int *max_fdp)
{
int max = ares_fds(conn->data->state.areschannel,

View File

@ -67,11 +67,6 @@
#include <process.h>
#endif
#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
#undef in_addr_t
#define in_addr_t unsigned long
#endif
#include "urldata.h"
#include "sendf.h"
#include "hostip.h"

View File

@ -67,11 +67,6 @@
#include <process.h>
#endif
#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
#undef in_addr_t
#define in_addr_t unsigned long
#endif
#include "urldata.h"
#include "sendf.h"
#include "hostip.h"

View File

@ -159,13 +159,13 @@ CURLcode Curl_is_resolved(struct connectdata *conn,
CURLcode Curl_wait_for_resolv(struct connectdata *conn,
struct Curl_dns_entry **dnsentry);
/* Curl_fdset() is a generic function that exists in multiple versions
/* Curl_resolv_fdset() is a generic function that exists in multiple versions
depending on what name resolve technology we've built to use. The function
is called from the curl_multi_fdset() function */
CURLcode Curl_fdset(struct connectdata *conn,
fd_set *read_fd_set,
fd_set *write_fd_set,
int *max_fdp);
CURLcode Curl_resolv_fdset(struct connectdata *conn,
fd_set *read_fd_set,
fd_set *write_fd_set,
int *max_fdp);
/* unlock a previously resolved dns entry */
void Curl_resolv_unlock(struct SessionHandle *data, struct Curl_dns_entry *dns);

View File

@ -67,11 +67,6 @@
#include <process.h>
#endif
#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
#undef in_addr_t
#define in_addr_t unsigned long
#endif
#include "urldata.h"
#include "sendf.h"
#include "hostip.h"

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@ -67,11 +67,6 @@
#include <process.h>
#endif
#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
#undef in_addr_t
#define in_addr_t unsigned long
#endif
#include "urldata.h"
#include "sendf.h"
#include "hostip.h"
@ -133,10 +128,10 @@ CURLcode Curl_is_resolved(struct connectdata *conn,
* It is present here to keep #ifdefs out from multi.c
*/
CURLcode Curl_fdset(struct connectdata *conn,
fd_set *read_fd_set,
fd_set *write_fd_set,
int *max_fdp)
CURLcode Curl_resolv_fdset(struct connectdata *conn,
fd_set *read_fd_set,
fd_set *write_fd_set,
int *max_fdp)
{
(void)conn;
(void)read_fd_set;

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@ -155,7 +155,7 @@ struct thread_data {
HANDLE thread_hnd;
unsigned thread_id;
DWORD thread_status;
curl_socket_t dummy_sock; /* dummy for Curl_fdset() */
curl_socket_t dummy_sock; /* dummy for Curl_resolv_fdset() */
FILE *stderr_file;
HANDLE mutex_waiting; /* marks that we are still waiting for a resolve */
HANDLE event_resolved; /* marks that the thread obtained the information */
@ -404,9 +404,9 @@ static bool init_resolve_thread (struct connectdata *conn,
destroy_thread_data(&conn->async);
return FALSE;
}
/* This socket is only to keep Curl_fdset() and select() happy; should never
* become signalled for read/write since it's unbound but Windows needs
* atleast 1 socket in select().
/* This socket is only to keep Curl_resolv_fdset() and select() happy;
* should never become signalled for read/write since it's unbound but
* Windows needs atleast 1 socket in select().
*/
td->dummy_sock = socket(AF_INET, SOCK_DGRAM, 0);
return TRUE;
@ -541,10 +541,10 @@ CURLcode Curl_is_resolved(struct connectdata *conn,
return CURLE_OK;
}
CURLcode Curl_fdset(struct connectdata *conn,
fd_set *read_fd_set,
fd_set *write_fd_set,
int *max_fdp)
CURLcode Curl_resolv_fdset(struct connectdata *conn,
fd_set *read_fd_set,
fd_set *write_fd_set,
int *max_fdp)
{
const struct thread_data *td =
(const struct thread_data *) conn->async.os_specific;

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@ -1222,7 +1222,7 @@ CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn,
* Curl_http_connect() performs HTTP stuff to do at connect-time, called from
* the generic Curl_connect().
*/
CURLcode Curl_http_connect(struct connectdata *conn)
CURLcode Curl_http_connect(struct connectdata *conn, bool *done)
{
struct SessionHandle *data;
CURLcode result;
@ -1261,6 +1261,8 @@ CURLcode Curl_http_connect(struct connectdata *conn)
data->state.first_host = strdup(conn->host.name);
}
*done = TRUE;
return CURLE_OK;
}
@ -1328,7 +1330,7 @@ CURLcode Curl_http_done(struct connectdata *conn,
* request is to be performed. This creates and sends a properly constructed
* HTTP request.
*/
CURLcode Curl_http(struct connectdata *conn)
CURLcode Curl_http(struct connectdata *conn, bool *done)
{
struct SessionHandle *data=conn->data;
char *buf = data->state.buffer; /* this is a short cut to the buffer */
@ -1342,6 +1344,11 @@ CURLcode Curl_http(struct connectdata *conn)
Curl_HttpReq httpreq = data->set.httpreq;
char *addcookies = NULL;
/* Always consider the DO phase done after this function call, even if there
may be parts of the request that is not yet sent, since we can deal with
the rest of the request in the PERFORM phase. */
*done = TRUE;
if(!conn->proto.http) {
/* Only allocate this struct if we don't already have it! */

View File

@ -8,7 +8,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@ -34,9 +34,9 @@ CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn,
char *hostname, int remote_port);
/* protocol-specific functions set up to be called by the main engine */
CURLcode Curl_http(struct connectdata *conn);
CURLcode Curl_http(struct connectdata *conn, bool *done);
CURLcode Curl_http_done(struct connectdata *, CURLcode);
CURLcode Curl_http_connect(struct connectdata *conn);
CURLcode Curl_http_connect(struct connectdata *conn, bool *done);
/* The following functions are defined in http_chunks.c */
void Curl_httpchunk_init(struct connectdata *conn);

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@ -224,7 +224,7 @@ static void (*ldap_free_urldesc)(LDAPURLDesc *) = _ldap_free_urldesc;
#endif
CURLcode Curl_ldap(struct connectdata *conn)
CURLcode Curl_ldap(struct connectdata *conn, bool *done)
{
CURLcode status = CURLE_OK;
int rc = 0;
@ -256,6 +256,7 @@ CURLcode Curl_ldap(struct connectdata *conn)
int num = 0;
struct SessionHandle *data=conn->data;
*done = TRUE; /* unconditionally */
infof(data, "LDAP local: %s\n", data->change.url);
if (!DynaOpen(&mod_name)) {

View File

@ -2,18 +2,18 @@
#define __LDAP_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
*
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
@ -24,6 +24,6 @@
* $Id$
***************************************************************************/
#ifndef CURL_DISABLE_LDAP
CURLcode Curl_ldap(struct connectdata *conn);
CURLcode Curl_ldap(struct connectdata *conn, bool *done);
#endif
#endif /* __LDAP_H */

View File

@ -45,6 +45,7 @@
#include "memory.h"
#include "easyif.h"
#include "multiif.h"
#include "sendf.h"
/* The last #include file should be: */
#include "memdebug.h"
@ -56,11 +57,14 @@ struct Curl_message {
};
typedef enum {
CURLM_STATE_INIT,
CURLM_STATE_INIT, /* start in this state */
CURLM_STATE_CONNECT, /* resolve/connect has been sent off */
CURLM_STATE_WAITRESOLVE, /* we're awaiting the resolve to finalize */
CURLM_STATE_WAITCONNECT, /* we're awaiting the connect to finalize */
CURLM_STATE_DO, /* send off the request (part 1) */
CURLM_STATE_WAITRESOLVE, /* awaiting the resolve to finalize */
CURLM_STATE_WAITCONNECT, /* awaiting the connect to finalize */
CURLM_STATE_PROTOCONNECT, /* completing the protocol-specific connect
phase */
CURLM_STATE_DO, /* start send off the request (part 1) */
CURLM_STATE_DOING, /* sending 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 */
@ -111,6 +115,33 @@ struct Curl_multi {
struct curl_hash *hostcache;
};
/* always use this function to change state, to make debugging easier */
static void multistate(struct Curl_one_easy *easy, CURLMstate state)
{
#ifdef CURLDEBUG
const char *statename[]={
"INIT",
"CONNECT",
"WAITRESOLVE",
"WAITCONNECT",
"PROTOCONNECT",
"DO",
"DOING",
"DO_MORE",
"PERFORM",
"DONE",
"COMPLETED",
};
CURLMstate oldstate = easy->state;
#endif
easy->state = state;
#ifdef CURLDEBUG
infof(easy->easy_handle,
"STATE: %s => %s handle %p: \n",
statename[oldstate], statename[easy->state], (char *)easy);
#endif
}
CURLM *curl_multi_init(void)
{
@ -158,7 +189,7 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle,
/* set the easy handle */
easy->easy_handle = easy_handle;
easy->state = CURLM_STATE_INIT;
multistate(easy, CURLM_STATE_INIT);
/* for multi interface connections, we share DNS cache automaticly */
easy->easy_handle->hostcache = multi->hostcache;
@ -258,7 +289,22 @@ CURLMcode curl_multi_fdset(CURLM *multi_handle,
break;
case CURLM_STATE_WAITRESOLVE:
/* waiting for a resolve to complete */
Curl_fdset(easy->easy_conn, read_fd_set, write_fd_set, &this_max_fd);
Curl_resolv_fdset(easy->easy_conn, read_fd_set, write_fd_set,
&this_max_fd);
if(this_max_fd > *max_fd)
*max_fd = this_max_fd;
break;
case CURLM_STATE_PROTOCONNECT:
Curl_protocol_fdset(easy->easy_conn, read_fd_set, write_fd_set,
&this_max_fd);
if(this_max_fd > *max_fd)
*max_fd = this_max_fd;
break;
case CURLM_STATE_DOING:
Curl_doing_fdset(easy->easy_conn, read_fd_set, write_fd_set,
&this_max_fd);
if(this_max_fd > *max_fd)
*max_fd = this_max_fd;
break;
@ -318,6 +364,8 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
struct Curl_message *msg = NULL;
bool connected;
bool async;
bool protocol_connect;
bool dophase_done;
*running_handles = 0; /* bump this once for every living handle */
@ -326,10 +374,6 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
easy=multi->easy.next;
while(easy) {
#if 0
fprintf(stderr, "HANDLE %p: State: %x\n",
(char *)easy, easy->state);
#endif
do {
if (CURLM_STATE_WAITCONNECT <= easy->state &&
easy->state <= CURLM_STATE_DO &&
@ -344,13 +388,13 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
easy->easy_handle->change.url_changed = FALSE;
easy->result = Curl_follow(easy->easy_handle, gotourl, FALSE);
if(CURLE_OK == easy->result)
easy->state = CURLM_STATE_CONNECT;
multistate(easy, CURLM_STATE_CONNECT);
else
free(gotourl);
}
else {
easy->result = CURLE_OUT_OF_MEMORY;
easy->state = CURLM_STATE_COMPLETED;
multistate(easy, CURLM_STATE_COMPLETED);
break;
}
}
@ -365,7 +409,7 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
if(CURLE_OK == easy->result) {
/* after init, go CONNECT */
easy->state = CURLM_STATE_CONNECT;
multistate(easy, CURLM_STATE_CONNECT);
result = CURLM_CALL_MULTI_PERFORM;
easy->easy_handle->state.used_interface = Curl_if_multi;
@ -376,16 +420,22 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
/* Connect. We get a connection identifier filled in. */
Curl_pgrsTime(easy->easy_handle, TIMER_STARTSINGLE);
easy->result = Curl_connect(easy->easy_handle, &easy->easy_conn,
&async);
&async, &protocol_connect);
if(CURLE_OK == easy->result) {
if(async)
/* We're now waiting for an asynchronous name lookup */
easy->state = CURLM_STATE_WAITRESOLVE;
multistate(easy, CURLM_STATE_WAITRESOLVE);
else {
/* after the connect has been sent off, go WAITCONNECT */
easy->state = CURLM_STATE_WAITCONNECT;
/* after the connect has been sent off, go WAITCONNECT unless the
protocol connect is already done and we can go directly to
DO! */
result = CURLM_CALL_MULTI_PERFORM;
if(protocol_connect)
multistate(easy, CURLM_STATE_DO);
else
multistate(easy, CURLM_STATE_WAITCONNECT);
}
}
break;
@ -401,14 +451,17 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
if(dns) {
/* Perform the next step in the connection phase, and then move on
to the WAITCONNECT state */
easy->result = Curl_async_resolved(easy->easy_conn);
easy->result = Curl_async_resolved(easy->easy_conn,
&protocol_connect);
if(CURLE_OK != easy->result)
/* if Curl_async_resolved() returns failure, the connection struct
is already freed and gone */
easy->easy_conn = NULL; /* no more connection */
easy->state = CURLM_STATE_WAITCONNECT;
else {
/* FIX: what if protocol_connect is TRUE here?! */
multistate(easy, CURLM_STATE_WAITCONNECT);
}
}
if(CURLE_OK != easy->result) {
@ -425,7 +478,8 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
easy->result = Curl_is_connected(easy->easy_conn, FIRSTSOCKET,
&connected);
if(connected)
easy->result = Curl_protocol_connect(easy->easy_conn);
easy->result = Curl_protocol_connect(easy->easy_conn,
&protocol_connect);
if(CURLE_OK != easy->result) {
/* failure detected */
@ -435,29 +489,64 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
}
if(connected) {
if(!protocol_connect) {
/* We have a TCP connection, but 'protocol_connect' may be false
and then we continue to 'STATE_PROTOCONNECT'. If protocol
connect is TRUE, we move on to STATE_DO. */
multistate(easy, CURLM_STATE_PROTOCONNECT);
fprintf(stderr, "WAITCONNECT => PROTOCONNECT\n");
}
else {
/* after the connect has completed, go DO */
multistate(easy, CURLM_STATE_DO);
result = CURLM_CALL_MULTI_PERFORM;
}
}
break;
case CURLM_STATE_PROTOCONNECT:
/* protocol-specific connect phase */
easy->result = Curl_protocol_connecting(easy->easy_conn,
&protocol_connect);
if(protocol_connect) {
/* after the connect has completed, go DO */
easy->state = CURLM_STATE_DO;
multistate(easy, CURLM_STATE_DO);
result = CURLM_CALL_MULTI_PERFORM;
}
else if(easy->result) {
/* failure detected */
Curl_posttransfer(easy->easy_handle);
Curl_done(&easy->easy_conn, easy->result);
Curl_disconnect(easy->easy_conn); /* close the connection */
easy->easy_conn = NULL; /* no more connection */
}
break;
case CURLM_STATE_DO:
/* Do the fetch or put request */
easy->result = Curl_do(&easy->easy_conn);
/* Perform the protocol's DO action */
easy->result = Curl_do(&easy->easy_conn, &dophase_done);
if(CURLE_OK == easy->result) {
/* after do, go PERFORM... or DO_MORE */
if(easy->easy_conn->bits.do_more) {
if(!dophase_done) {
/* DO was not completed in one function call, we must continue
DOING... */
multistate(easy, CURLM_STATE_DOING);
result = CURLM_OK;
}
/* after DO, go PERFORM... or DO_MORE */
else if(easy->easy_conn->bits.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;
multistate(easy, 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;
multistate(easy, CURLM_STATE_PERFORM);
result = CURLM_CALL_MULTI_PERFORM;
}
}
@ -471,10 +560,39 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
}
break;
case CURLM_STATE_DOING:
/* we continue DOING until the DO phase is complete */
easy->result = Curl_protocol_doing(easy->easy_conn, &dophase_done);
if(CURLE_OK == easy->result) {
if(dophase_done) {
/* after DO, go PERFORM... or DO_MORE */
if(easy->easy_conn->bits.do_more) {
/* we're supposed to do more, but we need to sit down, relax
and wait a little while first */
multistate(easy, 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) {
multistate(easy, CURLM_STATE_PERFORM);
result = CURLM_CALL_MULTI_PERFORM;
}
}
} /* dophase_done */
}
else {
/* failure detected */
Curl_posttransfer(easy->easy_handle);
Curl_done(&easy->easy_conn, easy->result);
Curl_disconnect(easy->easy_conn); /* close the connection */
easy->easy_conn = NULL; /* no more connection */
}
break;
case CURLM_STATE_DO_MORE:
/*
* First, check if we really are ready to do more.
*/
/* Ready to do more? */
easy->result = Curl_is_connected(easy->easy_conn, SECONDARYSOCKET,
&connected);
if(connected) {
@ -487,7 +605,7 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
easy->result = Curl_readwrite_init(easy->easy_conn);
if(CURLE_OK == easy->result) {
easy->state = CURLM_STATE_PERFORM;
multistate(easy, CURLM_STATE_PERFORM);
result = CURLM_CALL_MULTI_PERFORM;
}
}
@ -532,7 +650,7 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
if(easy->result == CURLE_OK)
easy->result = Curl_follow(easy->easy_handle, newurl, retry);
if(CURLE_OK == easy->result) {
easy->state = CURLM_STATE_CONNECT;
multistate(easy, CURLM_STATE_CONNECT);
result = CURLM_CALL_MULTI_PERFORM;
}
else
@ -542,7 +660,7 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
}
else {
/* after the transfer is done, go DONE */
easy->state = CURLM_STATE_DONE;
multistate(easy, CURLM_STATE_DONE);
result = CURLM_CALL_MULTI_PERFORM;
}
}
@ -553,7 +671,7 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
/* after we have DONE what we're supposed to do, go COMPLETED, and
it doesn't matter what the Curl_done() returned! */
easy->state = CURLM_STATE_COMPLETED;
multistate(easy, CURLM_STATE_COMPLETED);
break;
case CURLM_STATE_COMPLETED:
@ -571,7 +689,7 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
/*
* If an error was returned, and we aren't in completed state now,
* then we go to completed and consider this transfer aborted. */
easy->state = CURLM_STATE_COMPLETED;
multistate(easy, CURLM_STATE_COMPLETED);
}
else
/* this one still lives! */
@ -600,7 +718,6 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
multi->num_msgs++; /* increase message counter */
}
easy = easy->next; /* operate on next handle */
}

View File

@ -27,5 +27,4 @@
* Prototypes for library-wide functions provided by multi.c
*/
void Curl_multi_rmeasy(void *multi, CURL *data);
#endif /* __MULTIIF_H */

View File

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@ -1065,7 +1065,7 @@ CURLcode Curl_telnet_done(struct connectdata *conn, CURLcode status)
return CURLE_OK;
}
CURLcode Curl_telnet(struct connectdata *conn)
CURLcode Curl_telnet(struct connectdata *conn, bool *done)
{
CURLcode code;
struct SessionHandle *data = conn->data;
@ -1093,6 +1093,8 @@ CURLcode Curl_telnet(struct connectdata *conn)
char *buf = data->state.buffer;
struct TELNET *tn;
*done = TRUE; /* uncontionally */
code = init_telnet(conn);
if(code)
return code;

View File

@ -2,18 +2,18 @@
#define __TELNET_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
*
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
@ -24,7 +24,7 @@
* $Id$
***************************************************************************/
#ifndef CURL_DISABLE_TELNET
CURLcode Curl_telnet(struct connectdata *conn);
CURLcode Curl_telnet(struct connectdata *conn, bool *done);
CURLcode Curl_telnet_done(struct connectdata *conn, CURLcode);
#endif
#endif

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@ -2027,9 +2027,11 @@ Curl_connect_host(struct SessionHandle *data,
do {
bool async;
bool protocol_done=TRUE; /* will be TRUE always since this is only used
within the easy interface */
Curl_pgrsTime(data, TIMER_STARTSINGLE);
data->change.url_changed = FALSE;
res = Curl_connect(data, conn, &async);
res = Curl_connect(data, conn, &async, &protocol_done);
if((CURLE_OK == res) && async) {
/* Now, if async is TRUE here, we need to wait for the name
@ -2037,8 +2039,9 @@ Curl_connect_host(struct SessionHandle *data,
res = Curl_wait_for_resolv(*conn, NULL);
if(CURLE_OK == res)
/* Resolved, continue with the connection */
res = Curl_async_resolved(*conn);
res = Curl_async_resolved(*conn, &protocol_done);
else
/* if we can't resolve, we kill this "connection" now */
(void)Curl_disconnect(*conn);
}
if(res)
@ -2126,8 +2129,8 @@ CURLcode Curl_perform(struct SessionHandle *data)
}
if(res == CURLE_OK) {
res = Curl_do(&conn);
bool do_done;
res = Curl_do(&conn, &do_done);
/* for non 3rd party transfer only */
if(res == CURLE_OK && !data->set.source_url) {

158
lib/url.c
View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@ -1989,41 +1989,117 @@ static void verboseconnect(struct connectdata *conn)
conn->ip_addr_str, conn->port);
}
CURLcode Curl_protocol_fdset(struct connectdata *conn,
fd_set *read_fd_set,
fd_set *write_fd_set,
int *max_fdp)
{
CURLcode res = CURLE_OK;
if(conn->curl_proto_fdset)
res = conn->curl_proto_fdset(conn, read_fd_set, write_fd_set, max_fdp);
return res;
}
CURLcode Curl_doing_fdset(struct connectdata *conn,
fd_set *read_fd_set,
fd_set *write_fd_set,
int *max_fdp)
{
CURLcode res = CURLE_OK;
if(conn && conn->curl_doing_fdset)
res = conn->curl_doing_fdset(conn, read_fd_set, write_fd_set, max_fdp);
return res;
}
/*
* We are doing protocol-specific connecting and this is being called over and
* over from the multi interface until the connection phase is done on
* protocol layer.
*/
CURLcode Curl_protocol_connecting(struct connectdata *conn, bool *done)
{
CURLcode result=CURLE_OK;
if(conn && conn->curl_connecting) {
*done = FALSE;
result = conn->curl_connecting(conn, done);
}
else
*done = TRUE;
return result;
}
/*
* We are DOING this is being called over and over from the multi interface
* until the DOING phase is done on protocol layer.
*/
CURLcode Curl_protocol_doing(struct connectdata *conn, bool *done)
{
CURLcode result=CURLE_OK;
if(conn && conn->curl_doing) {
*done = FALSE;
result = conn->curl_doing(conn, done);
}
else
*done = TRUE;
return result;
}
/*
* 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.
*/
CURLcode Curl_protocol_connect(struct connectdata *conn)
CURLcode Curl_protocol_connect(struct connectdata *conn, bool *protocol_done)
{
struct SessionHandle *data = conn->data;
CURLcode result=CURLE_OK;
if(conn->bits.tcpconnect)
*protocol_done = FALSE;
if(conn->bits.tcpconnect && conn->bits.protoconnstart) {
/* We already are connected, get back. This may happen when the connect
worked fine in the first call, like when we connect to a local server
or proxy. */
or proxy. Note that we don't know if the protocol is actually done.
Unless this protocol doesn't have any protocol-connect callback, as
then we know we're done. */
if(!conn->curl_connecting)
*protocol_done = TRUE;
return CURLE_OK;
}
Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */
if(!conn->bits.tcpconnect) {
if(data->set.verbose)
verboseconnect(conn);
Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */
if(conn->curl_connect) {
/* is there a protocol-specific connect() procedure? */
if(data->set.verbose)
verboseconnect(conn);
}
/* 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();
if(!conn->bits.protoconnstart) {
if(conn->curl_connect) {
/* is there a protocol-specific connect() procedure? */
/* Call the protocol-specific connect function */
result = conn->curl_connect(conn);
/* 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, protocol_done);
}
else
*protocol_done = TRUE;
/* it has started, possibly even completed but that knowledge isn't stored
in this bit! */
conn->bits.protoconnstart = TRUE;
}
return result; /* pass back status */
@ -2733,6 +2809,10 @@ static CURLcode CreateConnection(struct SessionHandle *data,
conn->curl_do_more = Curl_ftp_nextconnect;
conn->curl_done = Curl_ftp_done;
conn->curl_connect = Curl_ftp_connect;
conn->curl_connecting = Curl_ftp_multi_statemach;
conn->curl_doing = Curl_ftp_doing;
conn->curl_proto_fdset = Curl_ftp_fdset;
conn->curl_doing_fdset = Curl_ftp_fdset;
conn->curl_disconnect = Curl_ftp_disconnect;
}
@ -3385,17 +3465,21 @@ static CURLcode CreateConnection(struct SessionHandle *data,
*/
static CURLcode SetupConnection(struct connectdata *conn,
struct Curl_dns_entry *hostaddr)
struct Curl_dns_entry *hostaddr,
bool *protocol_done)
{
struct SessionHandle *data = conn->data;
CURLcode result=CURLE_OK;
Curl_pgrsTime(data, TIMER_NAMELOOKUP);
if(conn->protocol & PROT_FILE)
if(conn->protocol & PROT_FILE) {
/* There's nothing in this function to setup if we're only doing
a file:// transfer */
*protocol_done = TRUE;
return result;
}
*protocol_done = FALSE; /* default to not done */
/*************************************************************
* Send user-agent to HTTP proxies even if the target protocol
@ -3416,13 +3500,13 @@ static CURLcode SetupConnection(struct connectdata *conn,
conn->headerbytecount = 0;
if(CURL_SOCKET_BAD == conn->sock[FIRSTSOCKET]) {
bool connected;
bool connected = FALSE;
/* Connect only if not already connected! */
result = ConnectPlease(conn, hostaddr, &connected);
if(connected) {
result = Curl_protocol_connect(conn);
result = Curl_protocol_connect(conn, protocol_done);
if(CURLE_OK == result)
conn->bits.tcpconnect = TRUE;
}
@ -3436,6 +3520,7 @@ static CURLcode SetupConnection(struct connectdata *conn,
else {
Curl_pgrsTime(data, TIMER_CONNECT); /* we're connected already */
conn->bits.tcpconnect = TRUE;
*protocol_done = TRUE;
if(data->set.verbose)
verboseconnect(conn);
}
@ -3460,7 +3545,8 @@ static CURLcode SetupConnection(struct connectdata *conn,
CURLcode Curl_connect(struct SessionHandle *data,
struct connectdata **in_connect,
bool *asyncp)
bool *asyncp,
bool *protocol_done)
{
CURLcode code;
struct Curl_dns_entry *dns;
@ -3476,7 +3562,7 @@ CURLcode Curl_connect(struct SessionHandle *data,
/* 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);
code = SetupConnection(*in_connect, dns, protocol_done);
/* else
response will be received and treated async wise */
}
@ -3494,12 +3580,16 @@ CURLcode Curl_connect(struct SessionHandle *data,
}
/* 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)
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);
CURLcode code = SetupConnection(conn, conn->async.dns, protocol_done);
if(code)
/* We're not allowed to return failure with memory left allocated
@ -3573,7 +3663,7 @@ CURLcode Curl_done(struct connectdata **connp,
return result;
}
CURLcode Curl_do(struct connectdata **connp)
CURLcode Curl_do(struct connectdata **connp, bool *done)
{
CURLcode result=CURLE_OK;
struct connectdata *conn = *connp;
@ -3583,7 +3673,7 @@ CURLcode Curl_do(struct connectdata **connp)
if(conn->curl_do) {
/* generic protocol-specific function pointer set in curl_connect() */
result = conn->curl_do(conn);
result = conn->curl_do(conn, done);
/* This was formerly done in transfer.c, but we better do it here */
@ -3603,8 +3693,10 @@ CURLcode Curl_do(struct connectdata **connp)
if(CURLE_OK == result) {
bool async;
bool protocol_done = TRUE;
/* Now, redo the connect and get a new connection */
result = Curl_connect(data, connp, &async);
result = Curl_connect(data, connp, &async, &protocol_done);
if(CURLE_OK == result) {
/* We have connected or sent away a name resolve query fine */
@ -3617,13 +3709,13 @@ CURLcode Curl_do(struct connectdata **connp)
return result;
/* Resolved, continue with the connection */
result = Curl_async_resolved(conn);
result = Curl_async_resolved(conn, &protocol_done);
if(result)
return result;
}
/* ... finally back to actually retry the DO phase */
result = conn->curl_do(conn);
result = conn->curl_do(conn, done);
}
}
}

View File

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@ -31,17 +31,28 @@ CURLcode Curl_open(struct SessionHandle **curl);
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 **,
bool *async);
CURLcode Curl_async_resolved(struct connectdata *conn);
CURLcode Curl_do(struct connectdata **);
bool *async, bool *protocol_connect);
CURLcode Curl_async_resolved(struct connectdata *conn,
bool *protocol_connect);
CURLcode Curl_do(struct connectdata **, bool *done);
CURLcode Curl_do_more(struct connectdata *);
CURLcode Curl_done(struct connectdata **, CURLcode);
CURLcode Curl_disconnect(struct connectdata *);
CURLcode Curl_protocol_connect(struct connectdata *conn);
CURLcode Curl_protocol_connect(struct connectdata *conn, bool *done);
CURLcode Curl_protocol_connecting(struct connectdata *conn, bool *done);
CURLcode Curl_protocol_doing(struct connectdata *conn, bool *done);
bool Curl_ssl_config_matches(struct ssl_config_data* data,
struct ssl_config_data* needle);
bool Curl_clone_ssl_config(struct ssl_config_data* source,
struct ssl_config_data* dest);
void Curl_free_ssl_config(struct ssl_config_data* sslc);
void Curl_safefree(void *ptr);
CURLcode Curl_protocol_fdset(struct connectdata *conn,
fd_set *read_fd_set,
fd_set *write_fd_set,
int *max_fdp);
CURLcode Curl_doing_fdset(struct connectdata *conn,
fd_set *read_fd_set,
fd_set *write_fd_set,
int *max_fdp);
#endif

View File

@ -243,6 +243,42 @@ struct HTTP {
/****************************************************************************
* FTP unique setup
***************************************************************************/
typedef enum {
FTP_STOP, /* do nothing state, stops the state machine */
FTP_WAIT220, /* waiting for the inintial 220 response immediately after
a connect */
FTP_AUTH,
FTP_USER,
FTP_PASS,
FTP_ACCT,
FTP_PBSZ,
FTP_PROT,
FTP_PWD,
FTP_QUOTE, /* waiting for a response to a command sent in a quote list */
FTP_RETR_PREQUOTE,
FTP_STOR_PREQUOTE,
FTP_POSTQUOTE,
FTP_CWD, /* change dir */
FTP_MKD, /* if the dir didn't exist */
FTP_MDTM, /* to figure out the datestamp */
FTP_TYPE, /* to set type when doing a head-like request */
FTP_LIST_TYPE, /* set type when about to do a dir list */
FTP_RETR_TYPE, /* set type when about to RETR a file */
FTP_STOR_TYPE, /* set type when about to STOR a file */
FTP_SIZE, /* get the remote file's size for head-like request */
FTP_RETR_SIZE, /* get the remote file's size for RETR */
FTP_STOR_SIZE, /* get the size for (resumed) STOR */
FTP_REST, /* when used to check if the server supports it in head-like */
FTP_RETR_REST, /* when asking for "resume" in for RETR */
FTP_PORT, /* generic state for PORT, LPRT and EPRT, check count1 */
FTP_PASV, /* generic state for PASV and EPSV, check count1 */
FTP_LIST, /* generic state for LIST, NLST or a custom list command */
FTP_RETR,
FTP_STOR, /* generic state for STOR and APPE */
FTP_QUIT,
FTP_LAST /* never used */
} ftpstate;
struct FTP {
curl_off_t *bytecountp;
char *user; /* user name string */
@ -271,6 +307,18 @@ struct FTP {
bool cwddone; /* if it has been determined that the proper CWD combo
already has been done */
char *prevpath; /* conn->path from the previous transfer */
size_t nread_resp; /* number of bytes currently read of a server response */
int count1; /* general purpose counter for the state machine */
int count2; /* general purpose counter for the state machine */
int count3; /* general purpose counter for the state machine */
char *sendthis; /* allocated pointer to a buffer that is to be sent to the
ftp server */
size_t sendleft; /* number of bytes left to send from the sendthis buffer */
size_t sendsize; /* total size of the sendthis buffer */
struct timeval response; /* set to Curl_tvnow() when a command has been sent
off, used to time-out response reading */
ftpstate state; /* always use ftp.c:state() to change state! */
curl_off_t downloadsize;
};
/****************************************************************************
@ -309,9 +357,12 @@ struct ConnectBits {
bool forbidchunk; /* used only to explicitly forbid chunk-upload for
specific upload buffers. See readmoredata() in
http.c for details. */
bool tcpconnect; /* the tcp stream (or simimlar) is connected, this
is set the first time on the first connect function
call */
bool tcpconnect; /* the TCP layer (or simimlar) is connected, this is set
the first time on the first connect function call */
bool protoconnstart;/* the protocol layer has STARTED its operation after
the TCP layer connect */
bool retry; /* this connection is about to get closed and then
re-attempted at another connection. */
bool no_body; /* CURLOPT_NO_BODY (or similar) was set */
@ -510,7 +561,7 @@ struct connectdata {
/* These two functions MUST be set by the curl_connect() function to be
be protocol dependent */
CURLcode (*curl_do)(struct connectdata *);
CURLcode (*curl_do)(struct connectdata *, bool *done);
CURLcode (*curl_done)(struct connectdata *, CURLcode);
/* If the curl_do() function is better made in two halves, this
@ -521,8 +572,29 @@ struct connectdata {
/* 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.
* The 'done' pointer points to a bool that should be set to TRUE if the
* function completes before return. If it doesn't complete, the caller
* should call the curl_connecting() function until it is.
*/
CURLcode (*curl_connect)(struct connectdata *);
CURLcode (*curl_connect)(struct connectdata *, bool *done);
/* See above. Currently only used for FTP. */
CURLcode (*curl_connecting)(struct connectdata *, bool *done);
CURLcode (*curl_doing)(struct connectdata *, bool *done);
/* Called from the multi interface during the PROTOCONNECT phase, and it
should then return a proper fd set */
CURLcode (*curl_proto_fdset)(struct connectdata *conn,
fd_set *read_fd_set,
fd_set *write_fd_set,
int *max_fdp);
/* Called from the multi interface during the DOING phase, and it should
then return a proper fd set */
CURLcode (*curl_doing_fdset)(struct connectdata *conn,
fd_set *read_fd_set,
fd_set *write_fd_set,
int *max_fdp);
/* This function *MAY* be set to a protocol-dependent function that is run
* by the curl_disconnect(), as a step in the disconnection.

View File

@ -21,7 +21,6 @@
* $Id$
***************************************************************************/
/* This is now designed to have its own local setup.h */
#include "setup.h"
#include <stdio.h>
@ -3726,7 +3725,8 @@ operate(struct Configurable *config, int argc, char *argv[])
}
}
} /* if CURLE_OK */
else if(CURLE_FTP_USER_PASSWORD_INCORRECT == res) {
else if((CURLE_FTP_USER_PASSWORD_INCORRECT == res) ||
(CURLE_LOGIN_DENIED == res)) {
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
if(response/100 == 5)

View File

@ -21,7 +21,7 @@ REPLY USER 314 bluah you fewl!
# Verify data after the test has been "shot"
<verify>
<errorcode>
12
67
</errorcode>
<protocol>
USER anonymous

View File

@ -21,7 +21,7 @@ REPLY PASS 314 bluah you f00l!
# Verify data after the test has been "shot"
<verify>
<errorcode>
11
67
</errorcode>
<protocol>
USER anonymous

View File

@ -15,7 +15,7 @@ ftp
FTP download with strict timeout and slow CWD
</name>
<command>
ftp://%HOSTIP:%FTPPORT/path/to/file/126 -m 3
ftp://%HOSTIP:%FTPPORT/path/to/file/190 -m 3
</command>
<file name="log/ftpserver.cmd">
DELAY CWD 15
@ -24,6 +24,7 @@ DELAY CWD 15
# Verify data after the test has been "shot"
<verify>
# 28 is CURLE_OPERATION_TIMEOUTED
<errorcode>
28
</errorcode>

View File

@ -21,7 +21,7 @@ REPLY PASS 530 temporarily not available
# Verify data after the test has been "shot"
<verify>
<errorcode>
10
67
</errorcode>
<protocol>
USER anonymous

View File

@ -20,8 +20,9 @@ REPLY PASS 530 temporarily not available
# Verify data after the test has been "shot"
<verify>
# 67 is CURLE_LOGIN_DENIED
<errorcode>
10
67
</errorcode>
<protocol>
USER anonymous

View File

@ -9,7 +9,6 @@ int test(char *URL)
curl_easy_setopt(curl, CURLOPT_NOBODY, 1);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
curl_easy_cleanup(curl);
return (int)res;
}