lib: reorder protocol functions to avoid forward declarations (ssh)

Move protocol handler table to the end of sources, rearrange static
functions in reverse dependency order as necessary.

Closes #20290
This commit is contained in:
Viktor Szakats 2026-01-13 16:30:20 +01:00
parent 7d2c65e6ee
commit f6a83894eb
No known key found for this signature in database
GPG key ID: B5ABD165E2AEF201
2 changed files with 399 additions and 464 deletions

View file

@ -84,100 +84,6 @@
#define SSH_S_IFLNK 0120000
#endif
/* Local functions: */
static CURLcode myssh_connect(struct Curl_easy *data, bool *done);
static CURLcode myssh_multi_statemach(struct Curl_easy *data,
bool *done);
static CURLcode myssh_do_it(struct Curl_easy *data, bool *done);
static CURLcode scp_done(struct Curl_easy *data,
CURLcode, bool premature);
static CURLcode scp_doing(struct Curl_easy *data, bool *dophase_done);
static CURLcode scp_disconnect(struct Curl_easy *data,
struct connectdata *conn,
bool dead_connection);
static CURLcode sftp_done(struct Curl_easy *data,
CURLcode, bool premature);
static CURLcode sftp_doing(struct Curl_easy *data,
bool *dophase_done);
static CURLcode sftp_disconnect(struct Curl_easy *data,
struct connectdata *conn,
bool dead);
static CURLcode sftp_perform(struct Curl_easy *data,
bool *connected,
bool *dophase_done);
static CURLcode myssh_pollset(struct Curl_easy *data,
struct easy_pollset *ps);
static void myssh_block2waitfor(struct connectdata *conn,
struct ssh_conn *sshc,
bool block);
static CURLcode myssh_setup_connection(struct Curl_easy *data,
struct connectdata *conn);
static void sshc_cleanup(struct ssh_conn *sshc);
/*
* SCP protocol handler.
*/
const struct Curl_handler Curl_handler_scp = {
"SCP", /* scheme */
myssh_setup_connection, /* setup_connection */
myssh_do_it, /* do_it */
scp_done, /* done */
ZERO_NULL, /* do_more */
myssh_connect, /* connect_it */
myssh_multi_statemach, /* connecting */
scp_doing, /* doing */
myssh_pollset, /* proto_pollset */
myssh_pollset, /* doing_pollset */
ZERO_NULL, /* domore_pollset */
myssh_pollset, /* perform_pollset */
scp_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
ZERO_NULL, /* follow */
PORT_SSH, /* defport */
CURLPROTO_SCP, /* protocol */
CURLPROTO_SCP, /* family */
PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION | /* flags */
PROTOPT_NOURLQUERY | PROTOPT_CONN_REUSE
};
/*
* SFTP protocol handler.
*/
const struct Curl_handler Curl_handler_sftp = {
"SFTP", /* scheme */
myssh_setup_connection, /* setup_connection */
myssh_do_it, /* do_it */
sftp_done, /* done */
ZERO_NULL, /* do_more */
myssh_connect, /* connect_it */
myssh_multi_statemach, /* connecting */
sftp_doing, /* doing */
myssh_pollset, /* proto_pollset */
myssh_pollset, /* doing_pollset */
ZERO_NULL, /* domore_pollset */
myssh_pollset, /* perform_pollset */
sftp_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
ZERO_NULL, /* follow */
PORT_SSH, /* defport */
CURLPROTO_SFTP, /* protocol */
CURLPROTO_SFTP, /* family */
PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION | /* flags */
PROTOPT_NOURLQUERY | PROTOPT_CONN_REUSE
};
static CURLcode sftp_error_to_CURLE(int err)
{
switch(err) {
@ -876,6 +782,22 @@ static void myssh_state_init(struct Curl_easy *data,
myssh_to(data, sshc, SSH_S_STARTUP);
}
static void myssh_block2waitfor(struct connectdata *conn,
struct ssh_conn *sshc,
bool block)
{
(void)conn;
if(block) {
int dir = ssh_get_poll_flags(sshc->ssh_session);
/* translate the libssh define bits into our own bit defines */
sshc->waitfor =
((dir & SSH_READ_PENDING) ? KEEP_RECV : 0) |
((dir & SSH_WRITE_PENDING) ? KEEP_SEND : 0);
}
else
sshc->waitfor = 0;
}
static int myssh_in_S_STARTUP(struct Curl_easy *data,
struct ssh_conn *sshc)
{
@ -1957,6 +1879,62 @@ static int myssh_in_TRANS_INIT(struct Curl_easy *data, struct ssh_conn *sshc,
return rc;
}
static void sshc_cleanup(struct ssh_conn *sshc)
{
if(sshc->initialised) {
if(sshc->sftp_file) {
sftp_close(sshc->sftp_file);
sshc->sftp_file = NULL;
}
if(sshc->sftp_session) {
sftp_free(sshc->sftp_session);
sshc->sftp_session = NULL;
}
if(sshc->ssh_session) {
ssh_free(sshc->ssh_session);
sshc->ssh_session = NULL;
}
/* worst-case scenario cleanup */
DEBUGASSERT(sshc->ssh_session == NULL);
DEBUGASSERT(sshc->scp_session == NULL);
if(sshc->readdir_tmp) {
ssh_string_free_char(sshc->readdir_tmp);
sshc->readdir_tmp = NULL;
}
if(sshc->quote_attrs) {
sftp_attributes_free(sshc->quote_attrs);
sshc->quote_attrs = NULL;
}
if(sshc->readdir_attrs) {
sftp_attributes_free(sshc->readdir_attrs);
sshc->readdir_attrs = NULL;
}
if(sshc->readdir_link_attrs) {
sftp_attributes_free(sshc->readdir_link_attrs);
sshc->readdir_link_attrs = NULL;
}
if(sshc->privkey) {
ssh_key_free(sshc->privkey);
sshc->privkey = NULL;
}
if(sshc->pubkey) {
ssh_key_free(sshc->pubkey);
sshc->pubkey = NULL;
}
Curl_safefree(sshc->rsa_pub);
Curl_safefree(sshc->rsa);
Curl_safefree(sshc->quote_path1);
Curl_safefree(sshc->quote_path2);
curlx_dyn_free(&sshc->readdir_buf);
Curl_safefree(sshc->readdir_linkPath);
SSH_STRING_FREE_CHAR(sshc->homedir);
sshc->initialised = FALSE;
}
}
/*
* ssh_statemach_act() runs the SSH state machine as far as it can without
* blocking and without reaching the end. The data the pointer 'block' points
@ -2401,22 +2379,6 @@ static CURLcode myssh_pollset(struct Curl_easy *data,
return CURLE_OK;
}
static void myssh_block2waitfor(struct connectdata *conn,
struct ssh_conn *sshc,
bool block)
{
(void)conn;
if(block) {
int dir = ssh_get_poll_flags(sshc->ssh_session);
/* translate the libssh define bits into our own bit defines */
sshc->waitfor =
((dir & SSH_READ_PENDING) ? KEEP_RECV : 0) |
((dir & SSH_WRITE_PENDING) ? KEEP_SEND : 0);
}
else
sshc->waitfor = 0;
}
/* called repeatedly until done from multi.c */
static CURLcode myssh_multi_statemach(struct Curl_easy *data,
bool *done)
@ -2692,89 +2654,6 @@ static CURLcode scp_perform(struct Curl_easy *data,
return result;
}
static CURLcode myssh_do_it(struct Curl_easy *data, bool *done)
{
CURLcode result;
bool connected = FALSE;
struct connectdata *conn = data->conn;
struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
*done = FALSE; /* default to false */
if(!sshc)
return CURLE_FAILED_INIT;
data->req.size = -1; /* make sure this is unknown at this point */
sshc->actualcode = CURLE_OK; /* reset error code */
sshc->secondCreateDirs = 0; /* reset the create directory attempt state
variable */
Curl_pgrsReset(data);
if(conn->handler->protocol & CURLPROTO_SCP)
result = scp_perform(data, &connected, done);
else
result = sftp_perform(data, &connected, done);
return result;
}
static void sshc_cleanup(struct ssh_conn *sshc)
{
if(sshc->initialised) {
if(sshc->sftp_file) {
sftp_close(sshc->sftp_file);
sshc->sftp_file = NULL;
}
if(sshc->sftp_session) {
sftp_free(sshc->sftp_session);
sshc->sftp_session = NULL;
}
if(sshc->ssh_session) {
ssh_free(sshc->ssh_session);
sshc->ssh_session = NULL;
}
/* worst-case scenario cleanup */
DEBUGASSERT(sshc->ssh_session == NULL);
DEBUGASSERT(sshc->scp_session == NULL);
if(sshc->readdir_tmp) {
ssh_string_free_char(sshc->readdir_tmp);
sshc->readdir_tmp = NULL;
}
if(sshc->quote_attrs) {
sftp_attributes_free(sshc->quote_attrs);
sshc->quote_attrs = NULL;
}
if(sshc->readdir_attrs) {
sftp_attributes_free(sshc->readdir_attrs);
sshc->readdir_attrs = NULL;
}
if(sshc->readdir_link_attrs) {
sftp_attributes_free(sshc->readdir_link_attrs);
sshc->readdir_link_attrs = NULL;
}
if(sshc->privkey) {
ssh_key_free(sshc->privkey);
sshc->privkey = NULL;
}
if(sshc->pubkey) {
ssh_key_free(sshc->pubkey);
sshc->pubkey = NULL;
}
Curl_safefree(sshc->rsa_pub);
Curl_safefree(sshc->rsa);
Curl_safefree(sshc->quote_path1);
Curl_safefree(sshc->quote_path2);
curlx_dyn_free(&sshc->readdir_buf);
Curl_safefree(sshc->readdir_linkPath);
SSH_STRING_FREE_CHAR(sshc->homedir);
sshc->initialised = FALSE;
}
}
/* BLOCKING, but the function is using the state machine so the only reason
this is still blocking is that the multi interface code has no support for
disconnecting operations that takes a while */
@ -3136,6 +3015,33 @@ static CURLcode sftp_recv(struct Curl_easy *data, int sockindex,
}
}
static CURLcode myssh_do_it(struct Curl_easy *data, bool *done)
{
CURLcode result;
bool connected = FALSE;
struct connectdata *conn = data->conn;
struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
*done = FALSE; /* default to false */
if(!sshc)
return CURLE_FAILED_INIT;
data->req.size = -1; /* make sure this is unknown at this point */
sshc->actualcode = CURLE_OK; /* reset error code */
sshc->secondCreateDirs = 0; /* reset the create directory attempt state
variable */
Curl_pgrsReset(data);
if(conn->handler->protocol & CURLPROTO_SCP)
result = scp_perform(data, &connected, done);
else
result = sftp_perform(data, &connected, done);
return result;
}
CURLcode Curl_ssh_init(void)
{
if(ssh_init()) {
@ -3155,4 +3061,62 @@ void Curl_ssh_version(char *buffer, size_t buflen)
(void)curl_msnprintf(buffer, buflen, "libssh/%s", ssh_version(0));
}
/*
* SCP protocol handler.
*/
const struct Curl_handler Curl_handler_scp = {
"SCP", /* scheme */
myssh_setup_connection, /* setup_connection */
myssh_do_it, /* do_it */
scp_done, /* done */
ZERO_NULL, /* do_more */
myssh_connect, /* connect_it */
myssh_multi_statemach, /* connecting */
scp_doing, /* doing */
myssh_pollset, /* proto_pollset */
myssh_pollset, /* doing_pollset */
ZERO_NULL, /* domore_pollset */
myssh_pollset, /* perform_pollset */
scp_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
ZERO_NULL, /* follow */
PORT_SSH, /* defport */
CURLPROTO_SCP, /* protocol */
CURLPROTO_SCP, /* family */
PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION | /* flags */
PROTOPT_NOURLQUERY | PROTOPT_CONN_REUSE
};
/*
* SFTP protocol handler.
*/
const struct Curl_handler Curl_handler_sftp = {
"SFTP", /* scheme */
myssh_setup_connection, /* setup_connection */
myssh_do_it, /* do_it */
sftp_done, /* done */
ZERO_NULL, /* do_more */
myssh_connect, /* connect_it */
myssh_multi_statemach, /* connecting */
sftp_doing, /* doing */
myssh_pollset, /* proto_pollset */
myssh_pollset, /* doing_pollset */
ZERO_NULL, /* domore_pollset */
myssh_pollset, /* perform_pollset */
sftp_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
ZERO_NULL, /* follow */
PORT_SSH, /* defport */
CURLPROTO_SFTP, /* protocol */
CURLPROTO_SFTP, /* family */
PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION | /* flags */
PROTOPT_NOURLQUERY | PROTOPT_CONN_REUSE
};
#endif /* USE_LIBSSH */