diff --git a/lib/multi.c b/lib/multi.c index 91d92df90..d68c368f3 100644 --- a/lib/multi.c +++ b/lib/multi.c @@ -2105,35 +2105,41 @@ static CURLMcode multi_socket(struct Curl_multi *multi, and just move on. */ ; else { + struct connectdata *conn; data = entry->easy; if(data->magic != CURLEASY_MAGIC_NUMBER) /* bad bad bad bad bad bad bad */ return CURLM_INTERNAL_ERROR; + /* note that this can possibly be NULL at this point */ + conn = data->set.one_easy->easy_conn; + /* If the pipeline is enabled, take the handle which is in the head of the pipeline. If we should write into the socket, take the send_pipe head. If we should read from the socket, take the recv_pipe head. */ - if(data->set.one_easy->easy_conn) { + if(conn) { if ((ev_bitmask & CURL_POLL_OUT) && - data->set.one_easy->easy_conn->send_pipe && - data->set.one_easy->easy_conn->send_pipe->head) - data = data->set.one_easy->easy_conn->send_pipe->head->ptr; + conn->send_pipe && + conn->send_pipe->head) + data = conn->send_pipe->head->ptr; else if ((ev_bitmask & CURL_POLL_IN) && - data->set.one_easy->easy_conn->recv_pipe && - data->set.one_easy->easy_conn->recv_pipe->head) - data = data->set.one_easy->easy_conn->recv_pipe->head->ptr; + conn->recv_pipe && + conn->recv_pipe->head) + data = conn->recv_pipe->head->ptr; } - if(data->set.one_easy->easy_conn) /* set socket event bitmask */ - data->set.one_easy->easy_conn->cselect_bits = ev_bitmask; + if(conn && !(conn->handler->protocol & PROT_LOCKEDBITS)) + /* set socket event bitmask if they're not locked */ + conn->cselect_bits = ev_bitmask; do result = multi_runsingle(multi, now, data->set.one_easy); while (CURLM_CALL_MULTI_PERFORM == result); - if(data->set.one_easy->easy_conn) - data->set.one_easy->easy_conn->cselect_bits = 0; + if(conn && !(conn->handler->protocol & PROT_LOCKEDBITS)) + /* clear the bitmask only if not locked */ + conn->cselect_bits = 0; if(CURLM_OK >= result) /* get the socket(s) and check if the state has been changed since diff --git a/lib/ssh.c b/lib/ssh.c index 118611efc..e85ad2631 100644 --- a/lib/ssh.c +++ b/lib/ssh.c @@ -2028,8 +2028,9 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) /* not set by Curl_setup_transfer to preserve keepon bits */ conn->writesockfd = conn->sockfd; - /* FIXME: here should be explained why we need it to start the - * download */ + /* we want to use the _receiving_ function even when the socket turns + out writableable as the underlying libssh2 recv function will deal + with both accordingly */ conn->cselect_bits = CURL_CSELECT_IN; } if(result) { @@ -2161,6 +2162,11 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) sshc->actualcode = result; } else { + /* we want to use the _sending_ function even when the socket turns + out readable as the underlying libssh2 scp send function will deal + with both accordingly */ + conn->cselect_bits = CURL_CSELECT_OUT; + state(conn, SSH_STOP); } break; @@ -2207,8 +2213,9 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) /* not set by Curl_setup_transfer to preserve keepon bits */ conn->writesockfd = conn->sockfd; - /* FIXME: here should be explained why we need it to start the - * download */ + /* we want to use the _receiving_ function even when the socket turns + out writableable as the underlying libssh2 recv function will deal + with both accordingly */ conn->cselect_bits = CURL_CSELECT_IN; if(result) { diff --git a/lib/urldata.h b/lib/urldata.h index 1d27d2626..2f7fe5e41 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -775,6 +775,12 @@ struct connectdata { PROT_SFTP | PROT_SCP) #define PROT_DUALCHANNEL PROT_FTP /* these protocols use two connections */ +/* some protocols will have to call the underlying functions without regard to + what exact state the socket signals. IE even if the socket says "readable", + the send function might need to be called while uploading, or vice versa. +*/ +#define PROT_LOCKEDBITS (PROT_SCP | PROT_SFTP) + /* 'dns_entry' is the particular host we use. This points to an entry in the DNS cache and it will not get pruned while locked. It gets unlocked in Curl_done(). This entry will be NULL if the connection is re-used as then