From 07b6e7363d910ad4828376d568a2f19fd8d64661 Mon Sep 17 00:00:00 2001 From: Patrick Monnerat Date: Fri, 12 Oct 2007 13:36:37 +0000 Subject: Added per-protocol callback static tables, replacing callback ptr storage in the connectdata structure by a single handler table ptr. --- CHANGES | 4 + lib/curl_ldap.h | 7 +- lib/dict.c | 29 +++- lib/dict.h | 3 +- lib/file.c | 29 +++- lib/file.h | 3 +- lib/ftp.c | 191 ++++++++++++++++++++++++-- lib/ftp.h | 25 ++-- lib/http.c | 59 +++++++- lib/http.h | 11 +- lib/ldap.c | 47 ++++++- lib/ssh.c | 82 ++++++++++-- lib/ssh.h | 14 +- lib/telnet.c | 31 ++++- lib/telnet.h | 3 +- lib/tftp.c | 72 +++++++++- lib/tftp.h | 4 +- lib/url.c | 409 +++++++++++++++++--------------------------------------- lib/urldata.h | 98 ++++++++------ 19 files changed, 712 insertions(+), 409 deletions(-) diff --git a/CHANGES b/CHANGES index 1fe68b576..56f7c79f9 100644 --- a/CHANGES +++ b/CHANGES @@ -6,6 +6,10 @@ Changelog +Patrick M (12 October 2007) +- Added per-protocol callback static tables, replacing callback ptr storage + in the connectdata structure by a single handler table ptr. + Dan F (11 October 2007) - Fixed the -l option of runtests.pl diff --git a/lib/curl_ldap.h b/lib/curl_ldap.h index 071cbcb43..7813ae70b 100644 --- a/lib/curl_ldap.h +++ b/lib/curl_ldap.h @@ -24,6 +24,11 @@ * $Id$ ***************************************************************************/ #ifndef CURL_DISABLE_LDAP -CURLcode Curl_ldap(struct connectdata *conn, bool *done); +extern const struct Curl_handler Curl_handler_ldap; + +#ifdef HAVE_LDAP_SSL +extern const struct Curl_handler Curl_handler_ldaps; +#endif + #endif #endif /* __CURL_LDAP_H */ diff --git a/lib/dict.c b/lib/dict.c index 43bc72ebf..8266e2bb6 100644 --- a/lib/dict.c +++ b/lib/dict.c @@ -82,6 +82,33 @@ /* The last #include file should be: */ #include "memdebug.h" + +/* + * Forward declarations. + */ + +static CURLcode Curl_dict(struct connectdata *conn, bool *done); + +/* + * DICT protocol handler. + */ + +const struct Curl_handler Curl_handler_dict = { + "DICT", /* scheme */ + NULL, /* setup_connection */ + Curl_dict, /* do_it */ + NULL, /* done */ + NULL, /* do_more */ + NULL, /* connect_it */ + NULL, /* connecting */ + NULL, /* doing */ + NULL, /* proto_getsock */ + NULL, /* doing_getsock */ + NULL, /* disconnect */ + PORT_DICT, /* defport */ + PROT_DICT /* protocol */ +}; + static char *unescape_word(struct SessionHandle *data, const char *inp) { char *newp; @@ -115,7 +142,7 @@ static char *unescape_word(struct SessionHandle *data, const char *inp) return dictp; } -CURLcode Curl_dict(struct connectdata *conn, bool *done) +static CURLcode Curl_dict(struct connectdata *conn, bool *done) { char *word; char *eword; diff --git a/lib/dict.h b/lib/dict.h index d3da1936f..eb4fb9d3b 100644 --- a/lib/dict.h +++ b/lib/dict.h @@ -24,7 +24,6 @@ * $Id$ ***************************************************************************/ #ifndef CURL_DISABLE_DICT -CURLcode Curl_dict(struct connectdata *conn, bool *done); -CURLcode Curl_dict_done(struct connectdata *conn); +extern const struct Curl_handler Curl_handler_dict; #endif #endif diff --git a/lib/file.c b/lib/file.c index 88d6bf26a..dcee427ee 100644 --- a/lib/file.c +++ b/lib/file.c @@ -89,6 +89,33 @@ /* The last #include file should be: */ #include "memdebug.h" + +/* + * Forward declarations. + */ + +static CURLcode Curl_file(struct connectdata *, bool *done); + +/* + * FILE scheme handler. + */ + +const struct Curl_handler Curl_handler_file = { + "FILE", /* scheme */ + NULL, /* setup_connection */ + Curl_file, /* do_it */ + Curl_file_done, /* done */ + NULL, /* do_more */ + NULL, /* connect_it */ + NULL, /* connecting */ + NULL, /* doing */ + NULL, /* proto_getsock */ + NULL, /* doing_getsock */ + NULL, /* disconnect */ + 0, /* defport */ + PROT_FILE /* protocol */ +}; + /* * Curl_file_connect() gets called from Curl_protocol_connect() to allow us to * do protocol-specific actions at connect-time. We emulate a @@ -316,7 +343,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, bool *done) +static 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) diff --git a/lib/file.h b/lib/file.h index 20a1c4c06..227c0d181 100644 --- a/lib/file.h +++ b/lib/file.h @@ -24,7 +24,8 @@ * $Id$ ***************************************************************************/ #ifndef CURL_DISABLE_FILE -CURLcode Curl_file(struct connectdata *, bool *done); +extern const struct Curl_handler Curl_handler_file; + CURLcode Curl_file_done(struct connectdata *, CURLcode, bool premature); CURLcode Curl_file_connect(struct connectdata *); #endif diff --git a/lib/ftp.c b/lib/ftp.c index 1cb5d14da..19b1f4efc 100644 --- a/lib/ftp.c +++ b/lib/ftp.c @@ -133,6 +133,20 @@ static CURLcode ftp_nb_type(struct connectdata *conn, bool ascii, ftpstate newstate); static int ftp_need_type(struct connectdata *conn, bool ascii); +static CURLcode Curl_ftp(struct connectdata *conn, bool *done); +static CURLcode Curl_ftp_done(struct connectdata *conn, + CURLcode, bool premature); +static CURLcode Curl_ftp_connect(struct connectdata *conn, bool *done); +static CURLcode Curl_ftp_disconnect(struct connectdata *conn); +static CURLcode Curl_ftp_nextconnect(struct connectdata *conn); +static CURLcode Curl_ftp_multi_statemach(struct connectdata *conn, bool *done); +static int Curl_ftp_getsock(struct connectdata *conn, + curl_socket_t *socks, + int numsocks); +static CURLcode Curl_ftp_doing(struct connectdata *conn, + bool *dophase_done); +static CURLcode Curl_ftp_setup_connection(struct connectdata * conn); +static CURLcode Curl_ftps_setup_connection(struct connectdata * conn); /* easy-to-use macro: */ #define FTPSENDF(x,y,z) if ((result = Curl_ftpsendf(x,y,z)) != CURLE_OK) \ @@ -141,6 +155,95 @@ static int ftp_need_type(struct connectdata *conn, return result +/* + * FTP protocol handler. + */ + +const struct Curl_handler Curl_handler_ftp = { + "FTP", /* scheme */ + Curl_ftp_setup_connection, /* setup_connection */ + Curl_ftp, /* do_it */ + Curl_ftp_done, /* done */ + Curl_ftp_nextconnect, /* do_more */ + Curl_ftp_connect, /* connect_it */ + Curl_ftp_multi_statemach, /* connecting */ + Curl_ftp_doing, /* doing */ + Curl_ftp_getsock, /* proto_getsock */ + Curl_ftp_getsock, /* doing_getsock */ + Curl_ftp_disconnect, /* disconnect */ + PORT_FTP, /* defport */ + PROT_FTP /* protocol */ +}; + + +#ifdef USE_SSL +/* + * FTPS protocol handler. + */ + +const struct Curl_handler Curl_handler_ftps = { + "FTPS", /* scheme */ + Curl_ftps_setup_connection, /* setup_connection */ + Curl_ftp, /* do_it */ + Curl_ftp_done, /* done */ + Curl_ftp_nextconnect, /* do_more */ + Curl_ftp_connect, /* connect_it */ + Curl_ftp_multi_statemach, /* connecting */ + Curl_ftp_doing, /* doing */ + Curl_ftp_getsock, /* proto_getsock */ + Curl_ftp_getsock, /* doing_getsock */ + Curl_ftp_disconnect, /* disconnect */ + PORT_FTPS, /* defport */ + PROT_FTP | PROT_FTPS | PROT_SSL /* protocol */ +}; +#endif + +#ifndef CURL_DISABLE_HTTP +/* + * HTTP-proxyed FTP protocol handler. + */ + +const struct Curl_handler Curl_handler_ftp_proxy = { + "FTP", /* scheme */ + NULL, /* setup_connection */ + Curl_http, /* do_it */ + Curl_http_done, /* done */ + NULL, /* do_more */ + NULL, /* connect_it */ + NULL, /* connecting */ + NULL, /* doing */ + NULL, /* proto_getsock */ + NULL, /* doing_getsock */ + NULL, /* disconnect */ + PORT_FTP, /* defport */ + PROT_HTTP /* protocol */ +}; + + +# ifdef USE_SSL +/* + * HTTP-proxyed FTPS protocol handler. + */ + +const struct Curl_handler Curl_handler_ftps_proxy = { + "FTPS", /* scheme */ + NULL, /* setup_connection */ + Curl_http, /* do_it */ + Curl_http_done, /* done */ + NULL, /* do_more */ + NULL, /* connect_it */ + NULL, /* connecting */ + NULL, /* doing */ + NULL, /* proto_getsock */ + NULL, /* doing_getsock */ + NULL, /* disconnect */ + PORT_FTPS, /* defport */ + PROT_HTTP /* protocol */ +}; +# endif +#endif + + /* * NOTE: back in the old days, we added code in the FTP code that made NOBODY * requests on files respond with headers passed to the client/stdout that @@ -706,9 +809,9 @@ static CURLcode ftp_state_pwd(struct connectdata *conn) } /* For the FTP "protocol connect" and "doing" phases only */ -int Curl_ftp_getsock(struct connectdata *conn, - curl_socket_t *socks, - int numsocks) +static int Curl_ftp_getsock(struct connectdata *conn, + curl_socket_t *socks, + int numsocks) { struct ftp_conn *ftpc = &conn->proto.ftpc; @@ -2819,8 +2922,8 @@ static long ftp_state_timeout(struct connectdata *conn) /* called repeatedly until done from multi.c */ -CURLcode Curl_ftp_multi_statemach(struct connectdata *conn, - bool *done) +static CURLcode Curl_ftp_multi_statemach(struct connectdata *conn, + bool *done) { curl_socket_t sock = conn->sock[FIRSTSOCKET]; int rc; @@ -2928,8 +3031,8 @@ static CURLcode ftp_init(struct connectdata *conn) * phase is done when this function returns, or FALSE is not. When called as * a part of the easy interface, it will always be TRUE. */ -CURLcode Curl_ftp_connect(struct connectdata *conn, - bool *done) /* see description above */ +static CURLcode Curl_ftp_connect(struct connectdata *conn, + bool *done) /* see description above */ { CURLcode result; #ifndef CURL_DISABLE_HTTP @@ -3017,8 +3120,8 @@ CURLcode Curl_ftp_connect(struct connectdata *conn, * * Input argument is already checked for validity. */ -CURLcode Curl_ftp_done(struct connectdata *conn, CURLcode status, - bool premature) +static CURLcode Curl_ftp_done(struct connectdata *conn, CURLcode status, + bool premature) { struct SessionHandle *data = conn->data; struct FTP *ftp = data->reqdata.proto.ftp; @@ -3368,7 +3471,7 @@ static CURLcode ftp_range(struct connectdata *conn) * connected. */ -CURLcode Curl_ftp_nextconnect(struct connectdata *conn) +static CURLcode Curl_ftp_nextconnect(struct connectdata *conn) { struct SessionHandle *data=conn->data; CURLcode result = CURLE_OK; @@ -3485,7 +3588,7 @@ CURLcode ftp_perform(struct connectdata *conn, * * The input argument is already checked for validity. */ -CURLcode Curl_ftp(struct connectdata *conn, bool *done) +static CURLcode Curl_ftp(struct connectdata *conn, bool *done) { CURLcode retcode = CURLE_OK; @@ -3682,7 +3785,7 @@ static CURLcode ftp_quit(struct connectdata *conn) * Disconnect from an FTP server. Cleanup protocol-specific per-connection * resources. BLOCKING. */ -CURLcode Curl_ftp_disconnect(struct connectdata *conn) +static CURLcode Curl_ftp_disconnect(struct connectdata *conn) { struct ftp_conn *ftpc= &conn->proto.ftpc; @@ -3933,8 +4036,8 @@ static CURLcode ftp_dophase_done(struct connectdata *conn, } /* called from multi.c while DOing */ -CURLcode Curl_ftp_doing(struct connectdata *conn, - bool *dophase_done) +static CURLcode Curl_ftp_doing(struct connectdata *conn, + bool *dophase_done) { CURLcode result; result = Curl_ftp_multi_statemach(conn, dophase_done); @@ -3996,4 +4099,64 @@ CURLcode ftp_regular_transfer(struct connectdata *conn, return result; } +static CURLcode Curl_ftp_setup_connection(struct connectdata * conn) +{ + struct SessionHandle *data = conn->data; + char * type; + char command; + + if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) { + /* Unless we have asked to tunnel ftp operations through the proxy, we + switch and use HTTP operations only */ +#ifndef CURL_DISABLE_HTTP + if (conn->handler == &Curl_handler_ftp) + conn->handler = &Curl_handler_ftp_proxy; + else + conn->handler = &Curl_handler_ftps_proxy; +#else + failf(data, "FTP over http proxy requires HTTP support built-in!"); + return CURLE_UNSUPPORTED_PROTOCOL; +#endif + } + + data->reqdata.path++; /* don't include the initial slash */ + + /* FTP URLs support an extension like ";type=" that + * we'll try to get now! */ + type = strstr(data->reqdata.path, ";type="); + + if (!type) + type = strstr(conn->host.rawalloc, ";type="); + + if (type) { + *type = 0; /* it was in the middle of the hostname */ + command = (char) toupper((int) type[6]); + + switch (command) { + case 'A': /* ASCII mode */ + data->set.prefer_ascii = TRUE; + break; + + case 'D': /* directory mode */ + data->set.ftp_list_only = TRUE; + break; + + case 'I': /* binary mode */ + default: + /* switch off ASCII */ + data->set.prefer_ascii = FALSE; + break; + } + } + + return CURLE_OK; +} + +static CURLcode Curl_ftps_setup_connection(struct connectdata * conn) +{ + struct SessionHandle *data = conn->data; + + conn->ssl[SECONDARYSOCKET].use = data->set.ftp_ssl != CURLUSESSL_CONTROL; + return Curl_ftp_setup_connection(conn); +} #endif /* CURL_DISABLE_FTP */ diff --git a/lib/ftp.h b/lib/ftp.h index b64e70506..13652acda 100644 --- a/lib/ftp.h +++ b/lib/ftp.h @@ -24,20 +24,23 @@ ***************************************************************************/ #ifndef CURL_DISABLE_FTP -CURLcode Curl_ftp(struct connectdata *conn, bool *done); -CURLcode Curl_ftp_done(struct connectdata *conn, CURLcode, bool premature); -CURLcode Curl_ftp_connect(struct connectdata *conn, bool *done); -CURLcode Curl_ftp_disconnect(struct connectdata *conn); +extern const struct Curl_handler Curl_handler_ftp; + +#ifdef USE_SSL +extern const struct Curl_handler Curl_handler_ftps; +#endif + +#ifndef CURL_DISABLE_HTTP +extern const struct Curl_handler Curl_handler_ftp_proxy; + +# ifdef USE_SSL +extern const struct Curl_handler Curl_handler_ftps_proxy; +# endif +#endif + 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); -CURLcode Curl_ftp_multi_statemach(struct connectdata *conn, bool *done); -int Curl_ftp_getsock(struct connectdata *conn, - curl_socket_t *socks, - int numsocks); -CURLcode Curl_ftp_doing(struct connectdata *conn, - bool *dophase_done); #endif /* CURL_DISABLE_FTP */ #endif /* __FTP_H */ diff --git a/lib/http.c b/lib/http.c index babd406d8..173106c6e 100644 --- a/lib/http.c +++ b/lib/http.c @@ -104,6 +104,57 @@ /* The last #include file should be: */ #include "memdebug.h" + +/* + * Forward declarations. + */ + +static CURLcode Curl_https_connecting(struct connectdata *conn, bool *done); +static int Curl_https_getsock(struct connectdata *conn, + curl_socket_t *socks, + int numsocks); + +/* + * HTTP handler interface. + */ +const struct Curl_handler Curl_handler_http = { + "HTTP", /* scheme */ + NULL, /* setup_connection */ + Curl_http, /* do_it */ + Curl_http_done, /* done */ + NULL, /* do_more */ + Curl_http_connect, /* connect_it */ + NULL, /* connecting */ + NULL, /* doing */ + NULL, /* proto_getsock */ + NULL, /* doing_getsock */ + NULL, /* disconnect */ + PORT_HTTP, /* defport */ + PROT_HTTP, /* protocol */ +}; + +#ifdef USE_SSL +/* + * HTTPS handler interface. + */ +const struct Curl_handler Curl_handler_https = { + "HTTPS", /* scheme */ + NULL, /* setup_connection */ + Curl_http, /* do_it */ + Curl_http_done, /* done */ + NULL, /* do_more */ + Curl_http_connect, /* connect_it */ + Curl_https_connecting, /* connecting */ + NULL, /* doing */ + Curl_https_getsock, /* proto_getsock */ + NULL, /* doing_getsock */ + NULL, /* disconnect */ + PORT_HTTPS, /* defport */ + PROT_HTTP | PROT_HTTPS | PROT_SSL /* protocol */ +}; +#endif + + /* * checkheaders() checks the linked list of custom HTTP headers for a * particular header (prefix). @@ -1619,7 +1670,7 @@ CURLcode Curl_http_connect(struct connectdata *conn, bool *done) return CURLE_OK; } -CURLcode Curl_https_connecting(struct connectdata *conn, bool *done) +static CURLcode Curl_https_connecting(struct connectdata *conn, bool *done) { CURLcode result; DEBUGASSERT((conn) && (conn->protocol & PROT_HTTPS)); @@ -1635,9 +1686,9 @@ CURLcode Curl_https_connecting(struct connectdata *conn, bool *done) #ifdef USE_SSLEAY /* This function is OpenSSL-specific. It should be made to query the generic SSL layer instead. */ -int Curl_https_getsock(struct connectdata *conn, - curl_socket_t *socks, - int numsocks) +static int Curl_https_getsock(struct connectdata *conn, + curl_socket_t *socks, + int numsocks) { if (conn->protocol & PROT_HTTPS) { struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET]; diff --git a/lib/http.h b/lib/http.h index 0b8f8b63e..f41ebb6e8 100644 --- a/lib/http.h +++ b/lib/http.h @@ -24,6 +24,13 @@ * $Id$ ***************************************************************************/ #ifndef CURL_DISABLE_HTTP + +extern const struct Curl_handler Curl_handler_http; + +#ifdef USE_SSL +extern const struct Curl_handler Curl_handler_https; +#endif + bool Curl_compareheader(const char *headerline, /* line to check */ const char *header, /* header keyword _with_ colon */ const char *content); /* content string to find */ @@ -37,10 +44,6 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, CURLcode Curl_http(struct connectdata *conn, bool *done); CURLcode Curl_http_done(struct connectdata *, CURLcode, bool premature); CURLcode Curl_http_connect(struct connectdata *conn, bool *done); -CURLcode Curl_https_connecting(struct connectdata *conn, bool *done); -int Curl_https_getsock(struct connectdata *conn, - curl_socket_t *socks, - int numsocks); /* The following functions are defined in http_chunks.c */ void Curl_httpchunk_init(struct connectdata *conn); diff --git a/lib/ldap.c b/lib/ldap.c index 365c112fe..e9467e009 100644 --- a/lib/ldap.c +++ b/lib/ldap.c @@ -118,7 +118,52 @@ static void _ldap_free_urldesc (LDAPURLDesc *ludp); #endif -CURLcode Curl_ldap(struct connectdata *conn, bool *done) +static CURLcode Curl_ldap(struct connectdata *conn, bool *done); + +/* + * LDAP protocol handler. + */ + +const struct Curl_handler Curl_handler_ldap = { + "LDAP", /* scheme */ + NULL, /* setup_connection */ + Curl_ldap, /* do_it */ + NULL, /* done */ + NULL, /* do_more */ + NULL, /* connect_it */ + NULL, /* connecting */ + NULL, /* doing */ + NULL, /* proto_getsock */ + NULL, /* doing_getsock */ + NULL, /* disconnect */ + PORT_LDAP, /* defport */ + PROT_LDAP /* protocol */ +}; + +#ifdef HAVE_LDAP_SSL +/* + * LDAPS protocol handler. + */ + +const struct Curl_handler Curl_handler_ldaps = { + "LDAPS", /* scheme */ + NULL, /* setup_connection */ + Curl_ldap, /* do_it */ + NULL, /* done */ + NULL, /* do_more */ + NULL, /* connect_it */ + NULL, /* connecting */ + NULL, /* doing */ + NULL, /* proto_getsock */ + NULL, /* doing_getsock */ + NULL, /* disconnect */ + PORT_LDAPS, /* defport */ + PROT_LDAP | PROT_SSL /* protocol */ +}; +#endif + + +static CURLcode Curl_ldap(struct connectdata *conn, bool *done) { CURLcode status = CURLE_OK; int rc = 0; diff --git a/lib/ssh.c b/lib/ssh.c index 9dce09630..9d5e71e1c 100644 --- a/lib/ssh.c +++ b/lib/ssh.c @@ -134,6 +134,63 @@ static LIBSSH2_FREE_FUNC(libssh2_free); static int get_pathname(const char **cpp, char **path); +static CURLcode Curl_ssh_connect(struct connectdata *conn, bool *done); +static CURLcode Curl_ssh_multi_statemach(struct connectdata *conn, bool *done); + +static CURLcode Curl_scp_do(struct connectdata *conn, bool *done); +static CURLcode Curl_scp_done(struct connectdata *conn, + CURLcode, bool premature); +static CURLcode Curl_scp_doing(struct connectdata *conn, + bool *dophase_done); + +static CURLcode Curl_sftp_do(struct connectdata *conn, bool *done); +static CURLcode Curl_sftp_done(struct connectdata *conn, + CURLcode, bool premature); +static CURLcode Curl_sftp_doing(struct connectdata *conn, + bool *dophase_done); + +/* + * SCP protocol handler. + */ + +const struct Curl_handler Curl_handler_scp = { + "SCP", /* scheme */ + NULL, /* setup_connection */ + Curl_scp_do, /* do_it */ + Curl_scp_done, /* done */ + NULL, /* do_more */ + Curl_ssh_connect, /* connect_it */ + Curl_ssh_multi_statemach, /* connecting */ + Curl_scp_doing, /* doing */ + NULL, /* proto_getsock */ + NULL, /* doing_getsock */ + NULL, /* disconnect */ + PORT_SSH, /* defport */ + PROT_SCP /* protocol */ +}; + + +/* + * SFTP protocol handler. + */ + +const struct Curl_handler Curl_handler_sftp = { + "SFTP", /* scheme */ + NULL, /* setup_connection */ + Curl_sftp_do, /* do_it */ + Curl_sftp_done, /* done */ + NULL, /* do_more */ + Curl_ssh_connect, /* connect_it */ + Curl_ssh_multi_statemach, /* connecting */ + Curl_sftp_doing, /* doing */ + NULL, /* proto_getsock */ + NULL, /* doing_getsock */ + NULL, /* disconnect */ + PORT_SSH, /* defport */ + PROT_SFTP /* protocol */ +}; + + static void kbd_callback(const char *name, int name_len, const char *instruction, int instruction_len, int num_prompts, @@ -1719,8 +1776,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn) } /* called repeatedly until done from multi.c */ -CURLcode Curl_ssh_multi_statemach(struct connectdata *conn, - bool *done) +static CURLcode Curl_ssh_multi_statemach(struct connectdata *conn, bool *done) { struct ssh_conn *sshc = &conn->proto.sshc; CURLcode result = CURLE_OK; @@ -1783,7 +1839,7 @@ static CURLcode ssh_init(struct connectdata *conn) * Curl_ssh_connect() gets called from Curl_protocol_connect() to allow us to * do protocol-specific actions at connect-time. */ -CURLcode Curl_ssh_connect(struct connectdata *conn, bool *done) +static CURLcode Curl_ssh_connect(struct connectdata *conn, bool *done) { struct SSHPROTO *ssh; curl_socket_t sock; @@ -1878,8 +1934,8 @@ CURLcode scp_perform(struct connectdata *conn, } /* called from multi.c while DOing */ -CURLcode Curl_scp_doing(struct connectdata *conn, - bool *dophase_done) +static CURLcode Curl_scp_doing(struct connectdata *conn, + bool *dophase_done) { CURLcode result; result = Curl_ssh_multi_statemach(conn, dophase_done); @@ -1891,7 +1947,7 @@ CURLcode Curl_scp_doing(struct connectdata *conn, } -CURLcode Curl_scp_do(struct connectdata *conn, bool *done) +static CURLcode Curl_scp_do(struct connectdata *conn, bool *done) { CURLcode res; bool connected = 0; @@ -1931,8 +1987,8 @@ CURLcode Curl_scp_do(struct connectdata *conn, bool *done) return res; } -CURLcode Curl_scp_done(struct connectdata *conn, CURLcode status, - bool premature) +static CURLcode Curl_scp_done(struct connectdata *conn, CURLcode status, + bool premature) { CURLcode result = CURLE_OK; bool done = FALSE; @@ -2048,8 +2104,8 @@ CURLcode sftp_perform(struct connectdata *conn, } /* called from multi.c while DOing */ -CURLcode Curl_sftp_doing(struct connectdata *conn, - bool *dophase_done) +static CURLcode Curl_sftp_doing(struct connectdata *conn, + bool *dophase_done) { CURLcode result; result = Curl_ssh_multi_statemach(conn, dophase_done); @@ -2060,7 +2116,7 @@ CURLcode Curl_sftp_doing(struct connectdata *conn, return result; } -CURLcode Curl_sftp_do(struct connectdata *conn, bool *done) +static CURLcode Curl_sftp_do(struct connectdata *conn, bool *done) { CURLcode res; bool connected = 0; @@ -2100,8 +2156,8 @@ CURLcode Curl_sftp_do(struct connectdata *conn, bool *done) return res; } -CURLcode Curl_sftp_done(struct connectdata *conn, CURLcode status, - bool premature) +static CURLcode Curl_sftp_done(struct connectdata *conn, CURLcode status, + bool premature) { CURLcode result = CURLE_OK; bool done = FALSE; diff --git a/lib/ssh.h b/lib/ssh.h index 71b48db04..8ac2a41ee 100644 --- a/lib/ssh.h +++ b/lib/ssh.h @@ -25,28 +25,18 @@ ***************************************************************************/ #ifdef USE_LIBSSH2 - -CURLcode Curl_ssh_connect(struct connectdata *conn, bool *done); -CURLcode Curl_ssh_multi_statemach(struct connectdata *conn, bool *done); - -CURLcode Curl_scp_do(struct connectdata *conn, bool *done); -CURLcode Curl_scp_done(struct connectdata *conn, CURLcode, bool premature); +extern const struct Curl_handler Curl_handler_scp; +extern const struct Curl_handler Curl_handler_sftp; ssize_t Curl_scp_send(struct connectdata *conn, int sockindex, void *mem, size_t len); ssize_t Curl_scp_recv(struct connectdata *conn, int sockindex, char *mem, size_t len); -CURLcode Curl_sftp_do(struct connectdata *conn, bool *done); -CURLcode Curl_sftp_done(struct connectdata *conn, CURLcode, bool premature); ssize_t Curl_sftp_send(struct connectdata *conn, int sockindex, void *mem, size_t len); ssize_t Curl_sftp_recv(struct connectdata *conn, int sockindex, char *mem, size_t len); -CURLcode Curl_sftp_doing(struct connectdata *conn, - bool *dophase_done); -CURLcode Curl_scp_doing(struct connectdata *conn, - bool *dophase_done); #endif /* USE_LIBSSH2 */ diff --git a/lib/telnet.c b/lib/telnet.c index 93a598252..b7c470125 100644 --- a/lib/telnet.c +++ b/lib/telnet.c @@ -125,6 +125,10 @@ static void printsub(struct SessionHandle *data, size_t length); static void suboption(struct connectdata *); +static CURLcode Curl_telnet(struct connectdata *conn, bool *done); +static CURLcode Curl_telnet_done(struct connectdata *conn, + CURLcode, bool premature); + /* For negotiation compliant to RFC 1143 */ #define CURL_NO 0 #define CURL_YES 1 @@ -170,6 +174,28 @@ struct TELNET { TelnetReceive telrcv_state; }; + +/* + * TELNET protocol handler. + */ + +const struct Curl_handler Curl_handler_telnet = { + "TELNET", /* scheme */ + NULL, /* setup_connection */ + Curl_telnet, /* do_it */ + Curl_telnet_done, /* done */ + NULL, /* do_more */ + NULL, /* connect_it */ + NULL, /* connecting */ + NULL, /* doing */ + NULL, /* proto_getsock */ + NULL, /* doing_getsock */ + NULL, /* disconnect */ + PORT_TELNET, /* defport */ + PROT_TELNET /* protocol */ +}; + + #ifdef USE_WINSOCK static CURLcode check_wsock2 ( struct SessionHandle *data ) @@ -1074,7 +1100,8 @@ void telrcv(struct connectdata *conn, } } -CURLcode Curl_telnet_done(struct connectdata *conn, CURLcode status, bool premature) +static CURLcode Curl_telnet_done(struct connectdata *conn, + CURLcode status, bool premature) { struct TELNET *tn = (struct TELNET *)conn->data->reqdata.proto.telnet; (void)status; /* unused */ @@ -1088,7 +1115,7 @@ CURLcode Curl_telnet_done(struct connectdata *conn, CURLcode status, bool premat return CURLE_OK; } -CURLcode Curl_telnet(struct connectdata *conn, bool *done) +static CURLcode Curl_telnet(struct connectdata *conn, bool *done) { CURLcode code; struct SessionHandle *data = conn->data; diff --git a/lib/telnet.h b/lib/telnet.h index 693abf3f8..44ec49bc0 100644 --- a/lib/telnet.h +++ b/lib/telnet.h @@ -24,7 +24,6 @@ * $Id$ ***************************************************************************/ #ifndef CURL_DISABLE_TELNET -CURLcode Curl_telnet(struct connectdata *conn, bool *done); -CURLcode Curl_telnet_done(struct connectdata *conn, CURLcode, bool premature); +extern const struct Curl_handler Curl_handler_telnet; #endif #endif diff --git a/lib/tftp.c b/lib/tftp.c index 938c2e239..81cd938c5 100644 --- a/lib/tftp.c +++ b/lib/tftp.c @@ -151,6 +151,33 @@ typedef struct tftp_state_data { /* Forward declarations */ static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event) ; static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event) ; +static CURLcode Curl_tftp_connect(struct connectdata *conn, bool *done); +static CURLcode Curl_tftp(struct connectdata *conn, bool *done); +static CURLcode Curl_tftp_done(struct connectdata *conn, + CURLcode, bool premature); +static CURLcode Curl_tftp_setup_connection(struct connectdata * conn); + + +/* + * TFTP protocol handler. + */ + +const struct Curl_handler Curl_handler_tftp = { + "TFTP", /* scheme */ + Curl_tftp_setup_connection, /* setup_connection */ + Curl_tftp, /* do_it */ + Curl_tftp_done, /* done */ + NULL, /* do_more */ + Curl_tftp_connect, /* connect_it */ + NULL, /* connecting */ + NULL, /* doing */ + NULL, /* proto_getsock */ + NULL, /* doing_getsock */ + NULL, /* disconnect */ + PORT_TFTP, /* defport */ + PROT_TFTP /* protocol */ +}; + /********************************************************** * @@ -575,7 +602,7 @@ static CURLcode tftp_state_machine(tftp_state_data_t *state, * The connect callback * **********************************************************/ -CURLcode Curl_tftp_connect(struct connectdata *conn, bool *done) +static CURLcode Curl_tftp_connect(struct connectdata *conn, bool *done) { CURLcode code; tftp_state_data_t *state; @@ -636,8 +663,8 @@ CURLcode Curl_tftp_connect(struct connectdata *conn, bool *done) * The done callback * **********************************************************/ -CURLcode Curl_tftp_done(struct connectdata *conn, CURLcode status, - bool premature) +static CURLcode Curl_tftp_done(struct connectdata *conn, CURLcode status, + bool premature) { (void)status; /* unused */ (void)premature; /* not used */ @@ -662,7 +689,7 @@ CURLcode Curl_tftp_done(struct connectdata *conn, CURLcode status, * **********************************************************/ -CURLcode Curl_tftp(struct connectdata *conn, bool *done) +static CURLcode Curl_tftp(struct connectdata *conn, bool *done) { struct SessionHandle *data = conn->data; tftp_state_data_t *state = @@ -836,4 +863,41 @@ CURLcode Curl_tftp(struct connectdata *conn, bool *done) code = CURLE_OK; return code; } + +static CURLcode Curl_tftp_setup_connection(struct connectdata * conn) +{ + struct SessionHandle *data = conn->data; + char * type; + char command; + + conn->socktype = SOCK_DGRAM; /* UDP datagram based */ + + /* TFTP URLs support an extension like ";mode=" that + * we'll try to get now! */ + type = strstr(data->reqdata.path, ";mode="); + + if (!type) + type = strstr(conn->host.rawalloc, ";mode="); + + if (type) { + *type = 0; /* it was in the middle of the hostname */ + command = (char) toupper((int) type[6]); + + switch (command) { + case 'A': /* ASCII mode */ + case 'N': /* NETASCII mode */ + data->set.prefer_ascii = TRUE; + break; + + case 'O': /* octet mode */ + case 'I': /* binary mode */ + default: + /* switch off ASCII */ + data->set.prefer_ascii = FALSE; + break; + } + } + + return CURLE_OK; +} #endif diff --git a/lib/tftp.h b/lib/tftp.h index c7125417b..c9d2ef3c9 100644 --- a/lib/tftp.h +++ b/lib/tftp.h @@ -24,8 +24,6 @@ * $Id$ ***************************************************************************/ #ifndef CURL_DISABLE_TFTP -CURLcode Curl_tftp_connect(struct connectdata *conn, bool *done); -CURLcode Curl_tftp(struct connectdata *conn, bool *done); -CURLcode Curl_tftp_done(struct connectdata *conn, CURLcode, bool premature); +extern const struct Curl_handler Curl_handler_tftp; #endif #endif diff --git a/lib/url.c b/lib/url.c index c74a1d858..bc3d235a8 100644 --- a/lib/url.c +++ b/lib/url.c @@ -178,6 +178,7 @@ static void flush_cookies(struct SessionHandle *data, int cleanup); #define ZERO_NULL 0 + #ifndef USE_ARES /* not for ares builds */ @@ -188,6 +189,82 @@ static void flush_cookies(struct SessionHandle *data, int cleanup); extern sigjmp_buf curl_jmpenv; #endif + +/* + * Protocol table. + */ + +static const struct Curl_handler * protocols[] = { + +#ifndef CURL_DISABLE_HTTP + &Curl_handler_http, +#endif + +#if defined(USE_SSL) && !defined(CURL_DISABLE_HTTP) + &Curl_handler_https, +#endif + +#ifndef CURL_DISABLE_FTP + &Curl_handler_ftp, +#endif + +#if defined(USE_SSL) && !defined(CURL_DISABLE_FTP) + &Curl_handler_ftps, +#endif + +#ifndef CURL_DISABLE_TELNET + &Curl_handler_telnet, +#endif + +#ifndef CURL_DISABLE_DICT + &Curl_handler_dict, +#endif + +#ifndef CURL_DISABLE_LDAP + &Curl_handler_ldap, +#endif + +#if defined(HAVE_LDAP_SSL) && !defined(CURL_DISABLE_SSL) + &Curl_handler_ldaps, +#endif + +#ifndef CURL_DISABLE_FILE + &Curl_handler_file, +#endif + +#ifndef CURL_DISABLE_TFTP + &Curl_handler_tftp, +#endif + +#ifdef USE_LIBSSH2 + &Curl_handler_scp, + &Curl_handler_sftp, +#endif + + (struct Curl_handler *) NULL +}; + +/* + * Dummy handler for undefined protocol schemes. + */ + +const struct Curl_handler Curl_handler_dummy = { + "", /* scheme */ + NULL, /* setup_connection */ + NULL, /* do_it */ + NULL, /* done */ + NULL, /* do_more */ + NULL, /* connect_it */ + NULL, /* connecting */ + NULL, /* doing */ + NULL, /* proto_getsock */ + NULL, /* doing_getsock */ + NULL, /* disconnect */ + 0, /* defport */ + 0 /* protocol */ +}; + + #ifdef SIGALRM static RETSIGTYPE alarmfunc(int sig) @@ -1999,9 +2076,9 @@ CURLcode Curl_disconnect(struct connectdata *conn) Curl_ntlm_cleanup(conn); } - if(conn->curl_disconnect) + if(conn->handler->disconnect) /* This is set if protocol-specific cleanups should be made */ - conn->curl_disconnect(conn); + conn->handler->disconnect(conn); if(-1 != conn->connectindex) { /* unlink ourselves! */ @@ -2519,8 +2596,8 @@ int Curl_protocol_getsock(struct connectdata *conn, curl_socket_t *socks, int numsocks) { - if(conn->curl_proto_getsock) - return conn->curl_proto_getsock(conn, socks, numsocks); + if(conn->handler->proto_getsock) + return conn->handler->proto_getsock(conn, socks, numsocks); return GETSOCK_BLANK; } @@ -2528,8 +2605,8 @@ int Curl_doing_getsock(struct connectdata *conn, curl_socket_t *socks, int numsocks) { - if(conn && conn->curl_doing_getsock) - return conn->curl_doing_getsock(conn, socks, numsocks); + if(conn && conn->handler && conn->handler->doing_getsock) + return conn->handler->doing_getsock(conn, socks, numsocks); return GETSOCK_BLANK; } @@ -2544,9 +2621,9 @@ CURLcode Curl_protocol_connecting(struct connectdata *conn, { CURLcode result=CURLE_OK; - if(conn && conn->curl_connecting) { + if(conn && conn->handler && conn->handler->connecting) { *done = FALSE; - result = conn->curl_connecting(conn, done); + result = conn->handler->connecting(conn, done); } else *done = TRUE; @@ -2563,9 +2640,9 @@ CURLcode Curl_protocol_doing(struct connectdata *conn, bool *done) { CURLcode result=CURLE_OK; - if(conn && conn->curl_doing) { + if(conn && conn->handler && conn->handler->doing) { *done = FALSE; - result = conn->curl_doing(conn, done); + result = conn->handler->doing(conn, done); } else *done = TRUE; @@ -2593,7 +2670,7 @@ CURLcode Curl_protocol_connect(struct connectdata *conn, Unless this protocol doesn't have any protocol-connect callback, as then we know we're done. */ - if(!conn->curl_connecting) + if(!conn->handler->connecting) *protocol_done = TRUE; return CURLE_OK; @@ -2608,7 +2685,7 @@ CURLcode Curl_protocol_connect(struct connectdata *conn, } if(!conn->bits.protoconnstart) { - if(conn->curl_connect) { + if(conn->handler->connect_it) { /* is there a protocol-specific connect() procedure? */ /* Set start time here for timeout purposes in the connect procedure, it @@ -2616,7 +2693,7 @@ CURLcode Curl_protocol_connect(struct connectdata *conn, conn->now = Curl_tvnow(); /* Call the protocol-specific connect function */ - result = conn->curl_connect(conn, protocol_done); + result = conn->handler->connect_it(conn, protocol_done); } else *protocol_done = TRUE; @@ -2943,285 +3020,39 @@ static CURLcode setup_range(struct SessionHandle *data) static CURLcode setup_connection_internals(struct SessionHandle *data, struct connectdata *conn) { - conn->socktype = SOCK_STREAM; /* most of them are TCP streams */ - - if (strequal(conn->protostr, "HTTP")) { -#ifndef CURL_DISABLE_HTTP - conn->port = PORT_HTTP; - conn->remote_port = PORT_HTTP; - conn->protocol |= PROT_HTTP; - conn->curl_do = Curl_http; - conn->curl_do_more = (Curl_do_more_func)ZERO_NULL; - conn->curl_done = Curl_http_done; - conn->curl_connect = Curl_http_connect; -#else - failf(data, LIBCURL_NAME - " was built with HTTP disabled, http: not supported!"); - return CURLE_UNSUPPORTED_PROTOCOL; -#endif - } + const struct Curl_handler * * pp; + const struct Curl_handler * p; + CURLcode result; - else if (strequal(conn->protostr, "HTTPS")) { -#if defined(USE_SSL) && !defined(CURL_DISABLE_HTTP) + conn->socktype = SOCK_STREAM; /* most of them are TCP streams */ - conn->port = PORT_HTTPS; - conn->remote_port = PORT_HTTPS; - conn->protocol |= PROT_HTTP|PROT_HTTPS|PROT_SSL; - - conn->curl_do = Curl_http; - conn->curl_do_more = (Curl_do_more_func)ZERO_NULL; - conn->curl_done = Curl_http_done; - conn->curl_connect = Curl_http_connect; - conn->curl_connecting = Curl_https_connecting; - conn->curl_proto_getsock = Curl_https_getsock; - -#else /* USE_SSL */ - failf(data, LIBCURL_NAME - " was built with SSL disabled, https: not supported!"); - return CURLE_UNSUPPORTED_PROTOCOL; -#endif /* !USE_SSL */ - } + /* Scan protocol handler table. */ - else if(strequal(conn->protostr, "FTP") || - strequal(conn->protostr, "FTPS")) { + for (pp = protocols; p = *pp; pp++) + if (strequal(p->scheme, conn->protostr)) { + /* Protocol found in table. Perform setup complement if some. */ + conn->handler = p; -#ifndef CURL_DISABLE_FTP - char *type; - int port = PORT_FTP; - - if(strequal(conn->protostr, "FTPS")) { -#ifdef USE_SSL - conn->protocol |= PROT_FTPS|PROT_SSL; - /* send data securely unless specifically requested otherwise */ - conn->ssl[SECONDARYSOCKET].use = data->set.ftp_ssl != CURLUSESSL_CONTROL; - port = PORT_FTPS; -#else - failf(data, LIBCURL_NAME - " was built with SSL disabled, ftps: not supported!"); - return CURLE_UNSUPPORTED_PROTOCOL; -#endif /* !USE_SSL */ - } + if (p->setup_connection) { + result = (*p->setup_connection)(conn); - conn->port = port; - conn->remote_port = (unsigned short)port; - conn->protocol |= PROT_FTP; + if (result != CURLE_OK) + return result; - if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) { - /* Unless we have asked to tunnel ftp operations through the proxy, we - switch and use HTTP operations only */ -#ifndef CURL_DISABLE_HTTP - conn->curl_do = Curl_http; - conn->curl_done = Curl_http_done; - conn->protocol = PROT_HTTP; /* switch to HTTP */ -#else - failf(data, "FTP over http proxy requires HTTP support built-in!"); - return CURLE_UNSUPPORTED_PROTOCOL; -#endif - } - 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_connecting = Curl_ftp_multi_statemach; - conn->curl_doing = Curl_ftp_doing; - conn->curl_proto_getsock = Curl_ftp_getsock; - conn->curl_doing_getsock = Curl_ftp_getsock; - conn->curl_disconnect = Curl_ftp_disconnect; - } - - data->reqdata.path++; /* don't include the initial slash */ - - /* FTP URLs support an extension like ";type=" that - * we'll try to get now! */ - type=strstr(data->reqdata.path, ";type="); - if(!type) { - type=strstr(conn->host.rawalloc, ";type="); - } - if(type) { - char command; - *type=0; /* it was in the middle of the hostname */ - command = (char)toupper((int)type[6]); - switch(command) { - case 'A': /* ASCII mode */ - data->set.prefer_ascii = TRUE; - break; - case 'D': /* directory mode */ - data->set.ftp_list_only = TRUE; - break; - case 'I': /* binary mode */ - default: - /* switch off ASCII */ - data->set.prefer_ascii = FALSE; - break; + p = conn->handler; /* May have changed. */ } - } -#else /* CURL_DISABLE_FTP */ - failf(data, LIBCURL_NAME - " was built with FTP disabled, ftp/ftps: not supported!"); - return CURLE_UNSUPPORTED_PROTOCOL; -#endif - } - - else if(strequal(conn->protostr, "TELNET")) { -#ifndef CURL_DISABLE_TELNET - /* telnet testing factory */ - conn->protocol |= PROT_TELNET; - - conn->port = PORT_TELNET; - conn->remote_port = PORT_TELNET; - conn->curl_do = Curl_telnet; - conn->curl_done = Curl_telnet_done; -#else - failf(data, LIBCURL_NAME - " was built with TELNET disabled!"); - return CURLE_UNSUPPORTED_PROTOCOL; -#endif - } - - else if (strequal(conn->protostr, "DICT")) { -#ifndef CURL_DISABLE_DICT - conn->protocol |= PROT_DICT; - conn->port = PORT_DICT; - conn->remote_port = PORT_DICT; - conn->curl_do = Curl_dict; - /* no DICT-specific done */ - conn->curl_done = (Curl_done_func)ZERO_NULL; -#else - failf(data, LIBCURL_NAME - " was built with DICT disabled!"); - return CURLE_UNSUPPORTED_PROTOCOL; -#endif - } - - else if (strequal(conn->protostr, "LDAP")) { -#ifndef CURL_DISABLE_LDAP - conn->protocol |= PROT_LDAP; - conn->port = PORT_LDAP; - conn->remote_port = PORT_LDAP; - conn->curl_do = Curl_ldap; - /* no LDAP-specific done */ - conn->curl_done = (Curl_done_func)ZERO_NULL; -#else - failf(data, LIBCURL_NAME - " was built with LDAP disabled!"); - return CURLE_UNSUPPORTED_PROTOCOL; -#endif - } - -#ifdef HAVE_LDAP_SSL - else if (strequal(conn->protostr, "LDAPS")) { -#ifndef CURL_DISABLE_LDAP - conn->protocol |= PROT_LDAP|PROT_SSL; - conn->port = PORT_LDAPS; - conn->remote_port = PORT_LDAPS; - conn->curl_do = Curl_ldap; - /* no LDAP-specific done */ - conn->curl_done = (Curl_done_func)ZERO_NULL; -#else - failf(data, LIBCURL_NAME - " was built with LDAP disabled!"); - return CURLE_UNSUPPORTED_PROTOCOL; -#endif - } -#endif /* CURL_LDAP_USE_SSL */ - - else if (strequal(conn->protostr, "FILE")) { -#ifndef CURL_DISABLE_FILE - conn->protocol |= PROT_FILE; - - conn->curl_do = Curl_file; - conn->curl_done = Curl_file_done; -#else - failf(data, LIBCURL_NAME - " was built with FILE disabled!"); - return CURLE_UNSUPPORTED_PROTOCOL; -#endif - } - else if (strequal(conn->protostr, "TFTP")) { -#ifndef CURL_DISABLE_TFTP - char *type; - conn->socktype = SOCK_DGRAM; /* UDP datagram based */ - conn->protocol |= PROT_TFTP; - conn->port = PORT_TFTP; - conn->remote_port = PORT_TFTP; - conn->curl_connect = Curl_tftp_connect; - conn->curl_do = Curl_tftp; - conn->curl_done = Curl_tftp_done; - /* TFTP URLs support an extension like ";mode=" that - * we'll try to get now! */ - type=strstr(data->reqdata.path, ";mode="); - if(!type) { - type=strstr(conn->host.rawalloc, ";mode="); + conn->port = p->defport; + conn->remote_port = p->defport; + conn->protocol |= p->protocol; + return CURLE_OK; } - if(type) { - char command; - *type=0; /* it was in the middle of the hostname */ - command = (char)toupper((int)type[6]); - switch(command) { - case 'A': /* ASCII mode */ - case 'N': /* NETASCII mode */ - data->set.prefer_ascii = TRUE; - break; - case 'O': /* octet mode */ - case 'I': /* binary mode */ - default: - /* switch off ASCII */ - data->set.prefer_ascii = FALSE; - break; - } - } -#else - failf(data, LIBCURL_NAME - " was built with TFTP disabled!"); - return CURLE_UNSUPPORTED_PROTOCOL; -#endif - } - - else if (strequal(conn->protostr, "SCP")) { -#ifdef USE_LIBSSH2 - conn->port = PORT_SSH; - conn->remote_port = PORT_SSH; - conn->protocol = PROT_SCP; - conn->curl_connect = Curl_ssh_connect; /* ssh_connect? */ - conn->curl_do = Curl_scp_do; - conn->curl_done = Curl_scp_done; - conn->curl_connecting = Curl_ssh_multi_statemach; - conn->curl_doing = Curl_scp_doing; - conn->curl_do_more = (Curl_do_more_func)ZERO_NULL; -#else - failf(data, LIBCURL_NAME - " was built without LIBSSH2, scp: not supported!"); - return CURLE_UNSUPPORTED_PROTOCOL; -#endif - } - else if (strequal(conn->protostr, "SFTP")) { -#ifdef USE_LIBSSH2 - conn->port = PORT_SSH; - conn->remote_port = PORT_SSH; - conn->protocol = PROT_SFTP; - conn->curl_connect = Curl_ssh_connect; /* ssh_connect? */ - conn->curl_do = Curl_sftp_do; - conn->curl_done = Curl_sftp_done; - conn->curl_connecting = Curl_ssh_multi_statemach; - conn->curl_doing = Curl_sftp_doing; - conn->curl_do_more = (Curl_do_more_func)ZERO_NULL; -#else - failf(data, LIBCURL_NAME - " was built without LIBSSH2, scp: not supported!"); - return CURLE_UNSUPPORTED_PROTOCOL; -#endif - } - - else { - /* We fell through all checks and thus we don't support the specified - protocol */ - failf(data, "Unsupported protocol: %s", conn->protostr); - return CURLE_UNSUPPORTED_PROTOCOL; - } - return CURLE_OK; + /* Protocol not found in table. */ + conn->handler = &Curl_handler_dummy; /* Be sure we have a handler defined. */ + failf(data, "Protocol %s not supported or disabled in " LIBCURL_NAME, + conn->protostr); + return CURLE_UNSUPPORTED_PROTOCOL; } /**************************************************************** @@ -4495,8 +4326,8 @@ CURLcode Curl_done(struct connectdata **connp, } /* this calls the protocol-specific function pointer previously set */ - if(conn->curl_done) - result = conn->curl_done(conn, status, premature); + if(conn->handler->done) + result = conn->handler->done(conn, status, premature); else result = CURLE_OK; @@ -4548,9 +4379,9 @@ CURLcode Curl_do(struct connectdata **connp, bool *done) 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 */ - if(conn->curl_do) { + if(conn->handler->do_it) { /* generic protocol-specific function pointer set in curl_connect() */ - result = conn->curl_do(conn, done); + result = conn->handler->do_it(conn, done); /* This was formerly done in transfer.c, but we better do it here */ @@ -4599,7 +4430,7 @@ CURLcode Curl_do(struct connectdata **connp, bool *done) } /* ... finally back to actually retry the DO phase */ - result = conn->curl_do(conn, done); + result = conn->handler->do_it(conn, done); } } } @@ -4611,8 +4442,8 @@ CURLcode Curl_do_more(struct connectdata *conn) { CURLcode result=CURLE_OK; - if(conn->curl_do_more) - result = conn->curl_do_more(conn); + if(conn->handler->do_more) + result = conn->handler->do_more(conn); return result; } diff --git a/lib/urldata.h b/lib/urldata.h index 52647a1cb..ef685e183 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -809,6 +809,59 @@ struct HandleData { } proto; }; +/* + * Specific protocol handler. + */ + +struct Curl_handler { + const char * scheme; /* URL scheme name. */ + + /* Complement to setup_connection_internals(). */ + CURLcode (*setup_connection)(struct connectdata *); + + /* These two functions MUST be set to be protocol dependent */ + CURLcode (*do_it)(struct connectdata *, bool *done); + Curl_done_func done; + + /* 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. + */ + Curl_do_more_func do_more; + + /* 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 (*connect_it)(struct connectdata *, bool *done); + + /* See above. Currently only used for FTP. */ + CURLcode (*connecting)(struct connectdata *, bool *done); + CURLcode (*doing)(struct connectdata *, bool *done); + + /* Called from the multi interface during the PROTOCONNECT phase, and it + should then return a proper fd set */ + int (*proto_getsock)(struct connectdata *conn, + curl_socket_t *socks, + int numsocks); + + /* Called from the multi interface during the DOING phase, and it should + then return a proper fd set */ + int (*doing_getsock)(struct connectdata *conn, + curl_socket_t *socks, + int numsocks); + + /* This function *MAY* be set to a protocol-dependent function that is run + * by the curl_disconnect(), as a step in the disconnection. + */ + CURLcode (*disconnect)(struct connectdata *); + + long defport; /* Default port. */ + long protocol; /* PROT_* flags concerning the protocol set */ +}; + /* * The connectdata struct contains all fields and variables that should be * unique for an entire connection. @@ -894,50 +947,7 @@ struct connectdata { struct ConnectBits bits; /* various state-flags for this connection */ - /* These two functions MUST be set by the curl_connect() function to be - be protocol dependent */ - CURLcode (*curl_do)(struct connectdata *, bool *done); - Curl_done_func curl_done; - - /* 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. - */ - Curl_do_more_func curl_do_more; - - /* 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 *, 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 */ - int (*curl_proto_getsock)(struct connectdata *conn, - curl_socket_t *socks, - int numsocks); - - /* Called from the multi interface during the DOING phase, and it should - then return a proper fd set */ - int (*curl_doing_getsock)(struct connectdata *conn, - curl_socket_t *socks, - int numsocks); - - /* This function *MAY* be set to a protocol-dependent function that is run - * by the curl_disconnect(), as a step in the disconnection. - */ - CURLcode (*curl_disconnect)(struct connectdata *); - - /* This function *MAY* be set to a protocol-dependent function that is run - * in the curl_close() function if protocol-specific cleanups are required. - */ - CURLcode (*curl_close)(struct connectdata *); + const struct Curl_handler * handler; /* Connection's protocol handler. */ /**** curl_get() phase fields */ -- cgit v1.2.3