ssh: tracing and better pollset handling
No binary (build failed)
—
(log yok)
| @@ -130,6 +130,10 @@ states. | |
| Traces reading of upload data from the application in order to send it to the | |
| server. | |
| + | ## `ssh` |
| + | |
| + | Tracing of SSH related protocols SCP and SFTP. |
| + | |
| ## `ssls` | |
| Tracing of SSL Session handling, e.g. caching/import/export. | |
| @@ -453,6 +453,24 @@ void Curl_trc_ssls(struct Curl_easy *data, const char *fmt, ...) | |
| } | |
| #endif /* USE_SSL */ | |
| + | #ifdef USE_SSH |
| + | struct curl_trc_feat Curl_trc_feat_ssh = { |
| + | "SSH", |
| + | CURL_LOG_LVL_NONE, |
| + | }; |
| + | |
| + | void Curl_trc_ssh(struct Curl_easy *data, const char *fmt, ...) |
| + | { |
| + | DEBUGASSERT(!strchr(fmt, '\n')); |
| + | if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ssh)) { |
| + | va_list ap; |
| + | va_start(ap, fmt); |
| + | trc_infof(data, &Curl_trc_feat_ssh, NULL, 0, fmt, ap); |
| + | va_end(ap); |
| + | } |
| + | } |
| + | #endif /* USE_SSH */ |
| + | |
| #if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP) | |
| struct curl_trc_feat Curl_trc_feat_ws = { | |
| "WS", | |
| @@ -500,6 +518,9 @@ static struct trc_feat_def trc_feats[] = { | |
| #ifdef USE_SSL | |
| { &Curl_trc_feat_ssls, TRC_CT_NETWORK }, | |
| #endif | |
| + | #ifdef USE_SSH |
| + | { &Curl_trc_feat_ssh, TRC_CT_PROTOCOL }, |
| + | #endif |
| #if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP) | |
| { &Curl_trc_feat_ws, TRC_CT_PROTOCOL }, | |
| #endif | |
| @@ -696,6 +717,13 @@ void Curl_trc_ws(struct Curl_easy *data, const char *fmt, ...) | |
| (void)data; (void)fmt; | |
| } | |
| #endif | |
| + | #ifdef USE_SSH |
| + | void Curl_trc_ssh(struct Curl_easy *data, const char *fmt, ...) |
| + | { |
| + | (void)data; |
| + | (void)fmt; |
| + | } |
| + | #endif |
| #ifdef USE_SSL | |
| void Curl_trc_ssls(struct Curl_easy *data, const char *fmt, ...) | |
| { | |
| @@ -117,6 +117,11 @@ extern struct curl_trc_feat Curl_trc_feat_ssls; | |
| void Curl_trc_ssls(struct Curl_easy *data, | |
| const char *fmt, ...) CURL_PRINTF(2, 3); | |
| #endif | |
| + | #ifdef USE_SSH |
| + | extern struct curl_trc_feat Curl_trc_feat_ssh; |
| + | void Curl_trc_ssh(struct Curl_easy *data, |
| + | const char *fmt, ...) CURL_PRINTF(2, 3); |
| + | #endif |
| #if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP) | |
| extern struct curl_trc_feat Curl_trc_feat_ws; | |
| void Curl_trc_ws(struct Curl_easy *data, | |
| @@ -168,6 +173,11 @@ void Curl_trc_ws(struct Curl_easy *data, | |
| do { if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ssls)) \ | |
| Curl_trc_ssls(data, __VA_ARGS__); } while(0) | |
| #endif /* USE_SSL */ | |
| + | #ifdef USE_SSH |
| + | #define CURL_TRC_SSH(data, ...) \ |
| + | do { if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ssh)) \ |
| + | Curl_trc_ssh(data, __VA_ARGS__); } while(0) |
| + | #endif /* USE_SSH */ |
| #if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP) | |
| #define CURL_TRC_WS(data, ...) \ | |
| do { if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ws)) \ | |
| @@ -193,6 +203,9 @@ void Curl_trc_ws(struct Curl_easy *data, | |
| #ifdef USE_SSL | |
| #define CURL_TRC_SSLS Curl_trc_ssls | |
| #endif | |
| + | #ifdef USE_SSH |
| + | #define CURL_TRC_SSH Curl_trc_ssh |
| + | #endif |
| #if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP) | |
| #define CURL_TRC_WS Curl_trc_ws | |
| #endif | |
| @@ -713,7 +713,6 @@ struct connectdata { | |
| wrong connections. */ | |
| char *localdev; | |
| unsigned short localportrange; | |
| - | int waitfor; /* current READ/WRITE bits to wait for */ |
| #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) | |
| int socks5_gssapi_enctype; | |
| #endif | |
| @@ -210,26 +210,9 @@ static CURLcode sftp_error_to_CURLE(int err) | |
| return CURLE_SSH; | |
| } | |
| - | #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) |
| - | #define myssh_to(x,y,z) myssh_set_state(x,y,z, __LINE__) |
| - | #else |
| - | #define myssh_to(x,y,z) myssh_set_state(x,y,z) |
| - | #endif |
| - | |
| - | /* |
| - | * SSH State machine related code |
| - | */ |
| - | /* This is the ONLY way to change SSH state! */ |
| - | static void myssh_set_state(struct Curl_easy *data, |
| - | struct ssh_conn *sshc, |
| - | sshstate nowstate |
| - | #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) |
| - | , int lineno |
| - | #endif |
| - | ) |
| + | #if !defined(CURL_DISABLE_VERBOSE_STRINGS) |
| + | static const char *myssh_statename(sshstate state) |
| { | |
| - | #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) |
| - | /* for debug purposes */ |
| static const char *const names[] = { | |
| "SSH_STOP", | |
| "SSH_INIT", | |
| @@ -292,14 +275,34 @@ static void myssh_set_state(struct Curl_easy *data, | |
| "SSH_SESSION_FREE", | |
| "QUIT" | |
| }; | |
| + | /* a precaution to make sure the lists are in sync */ |
| + | DEBUGASSERT(CURL_ARRAYSIZE(names) == SSH_LAST); |
| + | return ((size_t)state < CURL_ARRAYSIZE(names)) ? names[state] : ""; |
| + | } |
| + | #else |
| + | #define myssh_statename(x) "" |
| + | #endif /* !CURL_DISABLE_VERBOSE_STRINGS */ |
| + | |
| + | #define myssh_to(x,y,z) myssh_set_state(x,y,z) |
| + | |
| + | /* |
| + | * SSH State machine related code |
| + | */ |
| + | /* This is the ONLY way to change SSH state! */ |
| + | static void myssh_set_state(struct Curl_easy *data, |
| + | struct ssh_conn *sshc, |
| + | sshstate nowstate) |
| + | { |
| + | #if !defined(CURL_DISABLE_VERBOSE_STRINGS) |
| if(sshc->state != nowstate) { | |
| - | infof(data, "SSH %p state change from %s to %s (line %d)", |
| - | (void *) sshc, names[sshc->state], names[nowstate], |
| - | lineno); |
| + | CURL_TRC_SSH(data, "[%s] -> [%s]", |
| + | myssh_statename(sshc->state), |
| + | myssh_statename(nowstate)); |
| } | |
| - | #endif |
| + | #else |
| (void)data; | |
| + | #endif |
| sshc->state = nowstate; | |
| } | |
| @@ -887,7 +890,7 @@ static int myssh_in_S_STARTUP(struct Curl_easy *data, | |
| myssh_block2waitfor(conn, sshc, (rc == SSH_AGAIN)); | |
| if(rc == SSH_AGAIN) { | |
| - | DEBUGF(infof(data, "ssh_connect -> EAGAIN")); |
| + | CURL_TRC_SSH(data, "connect -> EAGAIN"); |
| } | |
| else if(rc != SSH_OK) { | |
| failf(data, "Failure establishing ssh session"); | |
| @@ -1259,10 +1262,6 @@ static int myssh_in_UPLOAD_INIT(struct Curl_easy *data, | |
| /* not set by Curl_xfer_setup to preserve keepon bits */ | |
| data->conn->recv_idx = FIRSTSOCKET; | |
| - | /* store this original bitmask setup to use later on if we cannot |
| - | figure out a "real" bitmask */ |
| - | sshc->orig_waitfor = data->req.keepon; |
| - | |
| /* since we do not really wait for anything at this point, we want the | |
| state machine to move on as soon as possible so we mark this as dirty */ | |
| Curl_multi_mark_dirty(data); | |
| @@ -1401,7 +1400,7 @@ static int myssh_in_SFTP_CLOSE(struct Curl_easy *data, | |
| } | |
| Curl_safefree(sshp->path); | |
| - | DEBUGF(infof(data, "SFTP DONE done")); |
| + | CURL_TRC_SSH(data, "SFTP DONE done"); |
| /* Check if nextstate is set and move .nextstate could be POSTQUOTE_INIT | |
| After nextstate is executed, the control should come back to | |
| @@ -1485,7 +1484,7 @@ static int myssh_in_SFTP_REALPATH(struct Curl_easy *data, | |
| we get the homedir here, we get the "workingpath" in the DO action | |
| since the homedir will remain the same between request but the | |
| working path will not. */ | |
| - | DEBUGF(infof(data, "SSH CONNECT phase done")); |
| + | CURL_TRC_SSH(data, "CONNECT phase done"); |
| myssh_to(data, sshc, SSH_STOP); | |
| return SSH_NO_ERROR; | |
| } | |
| @@ -2285,10 +2284,6 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, | |
| /* not set by Curl_xfer_setup to preserve keepon bits */ | |
| data->conn->recv_idx = FIRSTSOCKET; | |
| - | /* store this original bitmask setup to use later on if we cannot |
| - | figure out a "real" bitmask */ |
| - | sshc->orig_waitfor = data->req.keepon; |
| - | |
| myssh_to(data, sshc, SSH_STOP); | |
| break; | |
| @@ -2357,7 +2352,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, | |
| ssh_scp_free(sshc->scp_session); | |
| sshc->scp_session = NULL; | |
| } | |
| - | DEBUGF(infof(data, "SCP DONE phase complete")); |
| + | CURL_TRC_SSH(data, "SCP DONE phase complete"); |
| ssh_set_blocking(sshc->ssh_session, 0); | |
| @@ -2422,7 +2417,8 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, | |
| } | |
| if(!result && (sshc->state == SSH_STOP)) | |
| result = sshc->actualcode; | |
| - | DEBUGF(infof(data, "SSH: myssh_statemach_act -> %d", result)); |
| + | CURL_TRC_SSH(data, "[%s] statemachine() -> %d, block=%d", |
| + | myssh_statename(sshc->state), result, *block); |
| return result; | |
| } | |
| @@ -2432,33 +2428,45 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, | |
| static CURLcode myssh_pollset(struct Curl_easy *data, | |
| struct easy_pollset *ps) | |
| { | |
| - | int flags = 0; |
| struct connectdata *conn = data->conn; | |
| - | if(conn->waitfor & KEEP_RECV) |
| - | flags |= CURL_POLL_IN; |
| - | if(conn->waitfor & KEEP_SEND) |
| - | flags |= CURL_POLL_OUT; |
| - | if(!conn->waitfor) |
| - | flags |= CURL_POLL_OUT; |
| - | return flags ? |
| - | Curl_pollset_change(data, ps, conn->sock[FIRSTSOCKET], flags, 0) : |
| - | CURLE_OK; |
| + | struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); |
| + | curl_socket_t sock = conn->sock[FIRSTSOCKET]; |
| + | int waitfor; |
| + | |
| + | if(!sshc || (sock == CURL_SOCKET_BAD)) |
| + | return CURLE_FAILED_INIT; |
| + | |
| + | waitfor = sshc->waitfor ? sshc->waitfor : data->req.keepon; |
| + | if(waitfor) { |
| + | int flags = 0; |
| + | if(waitfor & KEEP_RECV) |
| + | flags |= CURL_POLL_IN; |
| + | if(waitfor & KEEP_SEND) |
| + | flags |= CURL_POLL_OUT; |
| + | DEBUGASSERT(flags); |
| + | CURL_TRC_SSH(data, "pollset, flags=%x", flags); |
| + | return Curl_pollset_change(data, ps, sock, flags, 0); |
| + | } |
| + | /* While we still have a session, we listen incoming data. */ |
| + | if(sshc->ssh_session) |
| + | return Curl_pollset_change(data, ps, sock, CURL_POLL_IN, 0); |
| + | 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 */ | |
| - | conn->waitfor = |
| + | sshc->waitfor = |
| ((dir & SSH_READ_PENDING) ? KEEP_RECV : 0) | | |
| ((dir & SSH_WRITE_PENDING) ? KEEP_SEND : 0); | |
| } | |
| else | |
| - | /* if it did not block, use the original set */ |
| - | conn->waitfor = sshc->orig_waitfor; |
| + | sshc->waitfor = 0; |
| } | |
| /* called repeatedly until done from multi.c */ | |
| @@ -2584,6 +2592,7 @@ static CURLcode myssh_connect(struct Curl_easy *data, bool *done) | |
| if(!sshc || !ssh) | |
| return CURLE_FAILED_INIT; | |
| + | CURL_TRC_SSH(data, "myssh_connect"); |
| if(conn->handler->protocol & CURLPROTO_SCP) { | |
| conn->recv[FIRSTSOCKET] = scp_recv; | |
| conn->send[FIRSTSOCKET] = scp_send; | |
| @@ -2618,6 +2627,7 @@ static CURLcode myssh_connect(struct Curl_easy *data, bool *done) | |
| /* ignore */ | |
| } | |
| + | CURL_TRC_SSH(data, "myssh_connect, set socket=%" FMT_SOCKET_T, sock); |
| rc = ssh_options_set(sshc->ssh_session, SSH_OPTIONS_FD, &sock); | |
| if(rc != SSH_OK) { | |
| failf(data, "Could not set socket"); | |
| @@ -2691,7 +2701,7 @@ static CURLcode scp_doing(struct Curl_easy *data, bool *dophase_done) | |
| result = myssh_multi_statemach(data, dophase_done); | |
| if(*dophase_done) { | |
| - | DEBUGF(infof(data, "DO phase is complete")); |
| + | CURL_TRC_SSH(data, "DO phase is complete"); |
| } | |
| return result; | |
| } | |
| @@ -2712,7 +2722,7 @@ CURLcode scp_perform(struct Curl_easy *data, | |
| CURLcode result = CURLE_OK; | |
| struct ssh_conn *sshc = Curl_conn_meta_get(data->conn, CURL_META_SSH_CONN); | |
| - | DEBUGF(infof(data, "DO phase starts")); |
| + | CURL_TRC_SSH(data, "DO phase starts"); |
| *dophase_done = FALSE; /* not done yet */ | |
| if(!sshc) | |
| @@ -2726,7 +2736,7 @@ CURLcode scp_perform(struct Curl_easy *data, | |
| *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET); | |
| if(*dophase_done) { | |
| - | DEBUGF(infof(data, "DO phase is complete")); |
| + | CURL_TRC_SSH(data, "DO phase is complete"); |
| } | |
| return result; | |
| @@ -2959,7 +2969,7 @@ CURLcode sftp_perform(struct Curl_easy *data, | |
| struct ssh_conn *sshc = Curl_conn_meta_get(data->conn, CURL_META_SSH_CONN); | |
| CURLcode result = CURLE_OK; | |
| - | DEBUGF(infof(data, "DO phase starts")); |
| + | CURL_TRC_SSH(data, "DO phase starts"); |
| *dophase_done = FALSE; /* not done yet */ | |
| if(!sshc) | |
| @@ -2974,7 +2984,7 @@ CURLcode sftp_perform(struct Curl_easy *data, | |
| *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET); | |
| if(*dophase_done) { | |
| - | DEBUGF(infof(data, "DO phase is complete")); |
| + | CURL_TRC_SSH(data, "DO phase is complete"); |
| } | |
| return result; | |
| @@ -2986,7 +2996,7 @@ static CURLcode sftp_doing(struct Curl_easy *data, | |
| { | |
| CURLcode result = myssh_multi_statemach(data, dophase_done); | |
| if(*dophase_done) { | |
| - | DEBUGF(infof(data, "DO phase is complete")); |
| + | CURL_TRC_SSH(data, "DO phase is complete"); |
| } | |
| return result; | |
| } | |
| @@ -3003,7 +3013,7 @@ static CURLcode sftp_disconnect(struct Curl_easy *data, | |
| CURLcode result = CURLE_OK; | |
| (void)dead_connection; | |
| - | DEBUGF(infof(data, "SSH DISCONNECT starts now")); |
| + | CURL_TRC_SSH(data, "DISCONNECT starts now"); |
| if(sshc && sshc->ssh_session) { | |
| /* only if there is a session still around to use! */ | |
| @@ -3011,7 +3021,7 @@ static CURLcode sftp_disconnect(struct Curl_easy *data, | |
| result = myssh_block_statemach(data, sshc, sshp, TRUE); | |
| } | |
| - | DEBUGF(infof(data, "SSH DISCONNECT is done")); |
| + | CURL_TRC_SSH(data, "DISCONNECT is done"); |
| return result; | |
| } | |
| @@ -280,17 +280,10 @@ static LIBSSH2_FREE_FUNC(my_libssh2_free) | |
| Curl_cfree(ptr); | |
| } | |
| - | /* |
| - | * SSH State machine related code |
| - | */ |
| - | /* This is the ONLY way to change SSH state! */ |
| - | static void myssh_state(struct Curl_easy *data, |
| - | struct ssh_conn *sshc, |
| - | sshstate nowstate) |
| + | #if !defined(CURL_DISABLE_VERBOSE_STRINGS) |
| + | static const char *myssh_statename(sshstate state) |
| { | |
| - | #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) |
| - | /* for debug purposes */ |
| - | static const char * const names[] = { |
| + | static const char *const names[] = { |
| "SSH_STOP", | |
| "SSH_INIT", | |
| "SSH_S_STARTUP", | |
| @@ -352,16 +345,34 @@ static void myssh_state(struct Curl_easy *data, | |
| "SSH_SESSION_FREE", | |
| "QUIT" | |
| }; | |
| - | |
| /* a precaution to make sure the lists are in sync */ | |
| DEBUGASSERT(CURL_ARRAYSIZE(names) == SSH_LAST); | |
| + | return ((size_t)state < CURL_ARRAYSIZE(names)) ? names[state] : ""; |
| + | } |
| + | #else |
| + | #define myssh_statename(x) "" |
| + | #endif /* !CURL_DISABLE_VERBOSE_STRINGS */ |
| + | |
| + | #define myssh_state(x,y,z) myssh_set_state(x,y,z) |
| + | |
| + | /* |
| + | * SSH State machine related code |
| + | */ |
| + | /* This is the ONLY way to change SSH state! */ |
| + | static void myssh_set_state(struct Curl_easy *data, |
| + | struct ssh_conn *sshc, |
| + | sshstate nowstate) |
| + | { |
| + | #if !defined(CURL_DISABLE_VERBOSE_STRINGS) |
| if(sshc->state != nowstate) { | |
| - | infof(data, "SFTP %p state change from %s to %s", |
| - | (void *)sshc, names[sshc->state], names[nowstate]); |
| + | CURL_TRC_SSH(data, "[%s] -> [%s]", |
| + | myssh_statename(sshc->state), |
| + | myssh_statename(nowstate)); |
| } | |
| - | #endif |
| + | #else |
| (void)data; | |
| + | #endif |
| sshc->state = nowstate; | |
| } | |
| @@ -1172,10 +1183,6 @@ sftp_upload_init(struct Curl_easy *data, | |
| /* not set by Curl_xfer_setup to preserve keepon bits */ | |
| data->conn->recv_idx = FIRSTSOCKET; | |
| - | /* store this original bitmask setup to use later on if we cannot |
| - | figure out a "real" bitmask */ |
| - | sshc->orig_waitfor = data->req.keepon; |
| - | |
| /* since we do not really wait for anything at this point, we want the | |
| state machine to move on as soon as possible so mark this as dirty */ | |
| Curl_multi_mark_dirty(data); | |
| @@ -1951,8 +1958,7 @@ static CURLcode ssh_state_sftp_realpath(struct Curl_easy *data, | |
| /* in this case, the error was not in the SFTP level but for example a | |
| time-out or similar */ | |
| result = CURLE_SSH; | |
| - | DEBUGF(infof(data, "error = %lu makes libcurl = %d", |
| - | sftperr, (int)result)); |
| + | CURL_TRC_SSH(data, "error = %lu makes libcurl = %d", sftperr, (int)result); |
| return result; | |
| } | |
| @@ -1960,7 +1966,7 @@ static CURLcode ssh_state_sftp_realpath(struct Curl_easy *data, | |
| get the homedir here, we get the "workingpath" in the DO action since the | |
| homedir will remain the same between request but the working path will | |
| not. */ | |
| - | DEBUGF(infof(data, "SSH CONNECT phase done")); |
| + | CURL_TRC_SSH(data, "CONNECT phase done"); |
| return CURLE_OK; | |
| } | |
| @@ -2418,7 +2424,7 @@ static CURLcode ssh_state_sftp_close(struct Curl_easy *data, | |
| Curl_safefree(sshp->path); | |
| - | DEBUGF(infof(data, "SFTP DONE done")); |
| + | CURL_TRC_SSH(data, "SFTP DONE done"); |
| /* Check if nextstate is set and move .nextstate could be POSTQUOTE_INIT | |
| After nextstate is executed, the control should come back to | |
| @@ -2542,10 +2548,6 @@ static CURLcode ssh_state_scp_upload_init(struct Curl_easy *data, | |
| /* not set by Curl_xfer_setup to preserve keepon bits */ | |
| data->conn->recv_idx = FIRSTSOCKET; | |
| - | /* store this original bitmask setup to use later on if we cannot |
| - | figure out a "real" bitmask */ |
| - | sshc->orig_waitfor = data->req.keepon; |
| - | |
| myssh_state(data, sshc, SSH_STOP); | |
| return CURLE_OK; | |
| @@ -3008,7 +3010,7 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, | |
| } | |
| sshc->ssh_channel = NULL; | |
| } | |
| - | DEBUGF(infof(data, "SCP DONE phase complete")); |
| + | CURL_TRC_SSH(data, "SCP DONE phase complete"); |
| myssh_state(data, sshc, SSH_STOP); | |
| break; | |
| @@ -3042,6 +3044,8 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, | |
| *block = TRUE; | |
| result = CURLE_OK; | |
| } | |
| + | CURL_TRC_SSH(data, "[%s] statemachine() -> %d, block=%d", |
| + | myssh_statename(sshc->state), result, *block); |
| return result; | |
| } | |
| @@ -3051,15 +3055,29 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, | |
| static CURLcode ssh_pollset(struct Curl_easy *data, | |
| struct easy_pollset *ps) | |
| { | |
| - | int flags = 0; |
| struct connectdata *conn = data->conn; | |
| - | if(conn->waitfor & KEEP_RECV) |
| - | flags |= CURL_POLL_IN; |
| - | if(conn->waitfor & KEEP_SEND) |
| - | flags |= CURL_POLL_OUT; |
| - | return flags ? |
| - | Curl_pollset_change(data, ps, conn->sock[FIRSTSOCKET], flags, 0) : |
| - | CURLE_OK; |
| + | struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); |
| + | curl_socket_t sock = conn->sock[FIRSTSOCKET]; |
| + | int waitfor; |
| + | |
| + | if(!sshc || (sock == CURL_SOCKET_BAD)) |
| + | return CURLE_FAILED_INIT; |
| + | |
| + | waitfor = sshc->waitfor ? sshc->waitfor : data->req.keepon; |
| + | if(waitfor) { |
| + | int flags = 0; |
| + | if(waitfor & KEEP_RECV) |
| + | flags |= CURL_POLL_IN; |
| + | if(waitfor & KEEP_SEND) |
| + | flags |= CURL_POLL_OUT; |
| + | DEBUGASSERT(flags); |
| + | CURL_TRC_SSH(data, "pollset, flags=%x", flags); |
| + | return Curl_pollset_change(data, ps, sock, flags, 0); |
| + | } |
| + | /* While we still have a session, we listen incoming data. */ |
| + | if(sshc->ssh_session) |
| + | return Curl_pollset_change(data, ps, sock, CURL_POLL_IN, 0); |
| + | return CURLE_OK; |
| } | |
| /* | |
| @@ -3073,20 +3091,18 @@ static void ssh_block2waitfor(struct Curl_easy *data, | |
| struct ssh_conn *sshc, | |
| bool block) | |
| { | |
| - | struct connectdata *conn = data->conn; |
| int dir = 0; | |
| + | (void)data; |
| if(block) { | |
| dir = libssh2_session_block_directions(sshc->ssh_session); | |
| if(dir) { | |
| /* translate the libssh2 define bits into our own bit defines */ | |
| - | conn->waitfor = ((dir&LIBSSH2_SESSION_BLOCK_INBOUND) ? KEEP_RECV : 0) | |
| + | sshc->waitfor = ((dir&LIBSSH2_SESSION_BLOCK_INBOUND) ? KEEP_RECV : 0) | |
| ((dir&LIBSSH2_SESSION_BLOCK_OUTBOUND) ? KEEP_SEND : 0); | |
| } | |
| } | |
| if(!dir) | |
| - | /* It did not block or libssh2 did not reveal in which direction, put back |
| - | the original set */ |
| - | conn->waitfor = sshc->orig_waitfor; |
| + | sshc->waitfor = 0; |
| } | |
| /* called repeatedly until done from multi.c */ | |
| @@ -3468,7 +3484,7 @@ CURLcode scp_perform(struct Curl_easy *data, | |
| struct ssh_conn *sshc = Curl_conn_meta_get(data->conn, CURL_META_SSH_CONN); | |
| CURLcode result = CURLE_OK; | |
| - | DEBUGF(infof(data, "DO phase starts")); |
| + | CURL_TRC_SSH(data, "DO phase starts"); |
| *dophase_done = FALSE; /* not done yet */ | |
| if(!sshc) | |
| @@ -3483,7 +3499,7 @@ CURLcode scp_perform(struct Curl_easy *data, | |
| *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET); | |
| if(*dophase_done) { | |
| - | DEBUGF(infof(data, "DO phase is complete")); |
| + | CURL_TRC_SSH(data, "DO phase is complete"); |
| } | |
| return result; | |
| @@ -3497,7 +3513,7 @@ static CURLcode scp_doing(struct Curl_easy *data, | |
| result = ssh_multi_statemach(data, dophase_done); | |
| if(*dophase_done) { | |
| - | DEBUGF(infof(data, "DO phase is complete")); |
| + | CURL_TRC_SSH(data, "DO phase is complete"); |
| } | |
| return result; | |
| } | |
| @@ -3778,7 +3794,7 @@ CURLcode sftp_perform(struct Curl_easy *data, | |
| struct ssh_conn *sshc = Curl_conn_meta_get(data->conn, CURL_META_SSH_CONN); | |
| CURLcode result = CURLE_OK; | |
| - | DEBUGF(infof(data, "DO phase starts")); |
| + | CURL_TRC_SSH(data, "DO phase starts"); |
| *dophase_done = FALSE; /* not done yet */ | |
| if(!sshc) | |
| @@ -3793,7 +3809,7 @@ CURLcode sftp_perform(struct Curl_easy *data, | |
| *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET); | |
| if(*dophase_done) { | |
| - | DEBUGF(infof(data, "DO phase is complete")); |
| + | CURL_TRC_SSH(data, "DO phase is complete"); |
| } | |
| return result; | |
| @@ -3806,7 +3822,7 @@ static CURLcode sftp_doing(struct Curl_easy *data, | |
| CURLcode result = ssh_multi_statemach(data, dophase_done); | |
| if(*dophase_done) { | |
| - | DEBUGF(infof(data, "DO phase is complete")); |
| + | CURL_TRC_SSH(data, "DO phase is complete"); |
| } | |
| return result; | |
| } | |
| @@ -3825,10 +3841,10 @@ static CURLcode sftp_disconnect(struct Curl_easy *data, | |
| if(sshc) { | |
| if(sshc->ssh_session) { | |
| /* only if there is a session still around to use! */ | |
| - | DEBUGF(infof(data, "SSH DISCONNECT starts now")); |
| + | CURL_TRC_SSH(data, "DISCONNECT starts now"); |
| myssh_state(data, sshc, SSH_SFTP_SHUTDOWN); | |
| result = ssh_block_statemach(data, sshc, sshp, TRUE); | |
| - | DEBUGF(infof(data, "SSH DISCONNECT is done -> %d", result)); |
| + | CURL_TRC_SSH(data, "DISCONNECT is done -> %d", result); |
| } | |
| sshc_cleanup(sshc, data, TRUE); | |
| } | |
| @@ -156,7 +156,8 @@ struct ssh_conn { | |
| int secondCreateDirs; /* counter use by the code to see if the | |
| second attempt has been made to change | |
| to/create a directory */ | |
| - | int orig_waitfor; /* default READ/WRITE bits wait for */ |
| + | int waitfor; /* KEEP_RECV/KEEP_SEND bits overriding |
| + | pollset given flags */ |
| char *slash_pos; /* used by the SFTP_CREATE_DIRS state */ | |
| #ifdef USE_LIBSSH | |