url: provide dead_connection flag in Curl_handler::disconnect

It helps to prevent a hangup with some FTP servers in case idle session
timeout has exceeded.  But it may be useful also for other protocols
that send any quit message on disconnect.  Currently used by FTP, POP3,
IMAP and SMTP.
This commit is contained in:
Kamil Dudka 2010-11-19 13:43:20 +01:00
parent bf1c102b80
commit 5c7c9a768d
14 changed files with 47 additions and 35 deletions

View File

@ -136,7 +136,7 @@ static CURLcode ftp_do(struct connectdata *conn, bool *done);
static CURLcode ftp_done(struct connectdata *conn,
CURLcode, bool premature);
static CURLcode ftp_connect(struct connectdata *conn, bool *done);
static CURLcode ftp_disconnect(struct connectdata *conn);
static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection);
static CURLcode ftp_nextconnect(struct connectdata *conn);
static CURLcode ftp_multi_statemach(struct connectdata *conn, bool *done);
static int ftp_getsock(struct connectdata *conn,
@ -3840,7 +3840,7 @@ static CURLcode ftp_quit(struct connectdata *conn)
* Disconnect from an FTP server. Cleanup protocol-specific per-connection
* resources. BLOCKING.
*/
static CURLcode ftp_disconnect(struct connectdata *conn)
static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection)
{
struct ftp_conn *ftpc= &conn->proto.ftpc;
struct pingpong *pp = &ftpc->pp;
@ -3852,6 +3852,8 @@ static CURLcode ftp_disconnect(struct connectdata *conn)
ftp_quit() will check the state of ftp->ctl_valid. If it's ok it
will try to send the QUIT command, otherwise it will just return.
*/
if(dead_connection)
ftpc->ctl_valid = FALSE;
/* The FTP session may or may not have been allocated/setup at this point! */
(void)ftp_quit(conn); /* ignore errors on the QUIT */

View File

@ -100,7 +100,7 @@ static CURLcode imap_do(struct connectdata *conn, bool *done);
static CURLcode imap_done(struct connectdata *conn,
CURLcode, bool premature);
static CURLcode imap_connect(struct connectdata *conn, bool *done);
static CURLcode imap_disconnect(struct connectdata *conn);
static CURLcode imap_disconnect(struct connectdata *conn, bool dead_connection);
static CURLcode imap_multi_statemach(struct connectdata *conn, bool *done);
static int imap_getsock(struct connectdata *conn,
curl_socket_t *socks,
@ -877,13 +877,13 @@ static CURLcode imap_logout(struct connectdata *conn)
* Disconnect from an IMAP server. Cleanup protocol-specific per-connection
* resources. BLOCKING.
*/
static CURLcode imap_disconnect(struct connectdata *conn)
static CURLcode imap_disconnect(struct connectdata *conn, bool dead_connection)
{
struct imap_conn *imapc= &conn->proto.imapc;
/* The IMAP session may or may not have been allocated/setup at this
point! */
if (imapc->pp.conn)
if(!dead_connection && imapc->pp.conn)
(void)imap_logout(conn); /* ignore errors on the LOGOUT */
Curl_pp_disconnect(&imapc->pp);

View File

@ -1634,7 +1634,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
if(disconnect_conn) {
Curl_disconnect(easy->easy_conn); /* disconnect properly */
/* disconnect properly */
Curl_disconnect(easy->easy_conn, /* dead_connection */ FALSE);
/* This is where we make sure that the easy_conn pointer is reset.
We don't have to do this in every case block above where a
@ -1759,7 +1760,7 @@ CURLMcode curl_multi_cleanup(CURLM *multi_handle)
for(i=0; i< multi->connc->num; i++) {
if(multi->connc->connects[i] &&
multi->connc->connects[i]->protocol & PROT_CLOSEACTION) {
Curl_disconnect(multi->connc->connects[i]);
Curl_disconnect(multi->connc->connects[i], /* dead_connection */ FALSE);
multi->connc->connects[i] = NULL;
}
}
@ -2665,7 +2666,7 @@ static void multi_connc_remove_handle(struct Curl_multi *multi,
data->state.shared_conn = multi;
else {
/* out of memory - so much for graceful shutdown */
Curl_disconnect(conn);
Curl_disconnect(conn, /* dead_connection */ FALSE);
multi->connc->connects[i] = NULL;
}
}

View File

@ -61,7 +61,7 @@ static CURLcode ldap_do(struct connectdata *conn, bool *done);
static CURLcode ldap_done(struct connectdata *conn, CURLcode, bool);
static CURLcode ldap_connect(struct connectdata *conn, bool *done);
static CURLcode ldap_connecting(struct connectdata *conn, bool *done);
static CURLcode ldap_disconnect(struct connectdata *conn);
static CURLcode ldap_disconnect(struct connectdata *conn, bool dead_connection);
static Curl_recv ldap_recv;
@ -344,9 +344,10 @@ retry:
return CURLE_OK;
}
static CURLcode ldap_disconnect(struct connectdata *conn)
static CURLcode ldap_disconnect(struct connectdata *conn, bool dead_connection)
{
ldapconninfo *li = conn->proto.generic;
(void) dead_connection;
if (li) {
if (li->ld) {

View File

@ -101,7 +101,7 @@ static CURLcode pop3_do(struct connectdata *conn, bool *done);
static CURLcode pop3_done(struct connectdata *conn,
CURLcode, bool premature);
static CURLcode pop3_connect(struct connectdata *conn, bool *done);
static CURLcode pop3_disconnect(struct connectdata *conn);
static CURLcode pop3_disconnect(struct connectdata *conn, bool dead_connection);
static CURLcode pop3_multi_statemach(struct connectdata *conn, bool *done);
static int pop3_getsock(struct connectdata *conn,
curl_socket_t *socks,
@ -817,7 +817,7 @@ static CURLcode pop3_quit(struct connectdata *conn)
* Disconnect from an POP3 server. Cleanup protocol-specific per-connection
* resources. BLOCKING.
*/
static CURLcode pop3_disconnect(struct connectdata *conn)
static CURLcode pop3_disconnect(struct connectdata *conn, bool dead_connection)
{
struct pop3_conn *pop3c= &conn->proto.pop3c;
@ -828,7 +828,7 @@ static CURLcode pop3_disconnect(struct connectdata *conn)
/* The POP3 session may or may not have been allocated/setup at this
point! */
if(pop3c->pp.conn)
if(!dead_connection && pop3c->pp.conn)
(void)pop3_quit(conn); /* ignore errors on the LOGOUT */

View File

@ -117,7 +117,9 @@ CURLcode Curl_rtsp_connect(struct connectdata *conn, bool *done)
return httpStatus;
}
CURLcode Curl_rtsp_disconnect(struct connectdata *conn) {
CURLcode Curl_rtsp_disconnect(struct connectdata *conn, bool dead_connection)
{
(void) dead_connection;
Curl_safefree(conn->proto.rtspc.rtp_buf);
return CURLE_OK;
}

View File

@ -43,7 +43,7 @@ CURLcode Curl_rtsp_rtp_readwrite(struct SessionHandle *data,
CURLcode Curl_rtsp(struct connectdata *conn, bool *done);
CURLcode Curl_rtsp_done(struct connectdata *conn, CURLcode, bool premature);
CURLcode Curl_rtsp_connect(struct connectdata *conn, bool *done);
CURLcode Curl_rtsp_disconnect(struct connectdata *conn);
CURLcode Curl_rtsp_disconnect(struct connectdata *conn, bool dead_connection);
CURLcode Curl_rtsp_parseheader(struct connectdata *conn, char *header);

View File

@ -107,7 +107,7 @@ static CURLcode smtp_do(struct connectdata *conn, bool *done);
static CURLcode smtp_done(struct connectdata *conn,
CURLcode, bool premature);
static CURLcode smtp_connect(struct connectdata *conn, bool *done);
static CURLcode smtp_disconnect(struct connectdata *conn);
static CURLcode smtp_disconnect(struct connectdata *conn, bool dead_connection);
static CURLcode smtp_multi_statemach(struct connectdata *conn, bool *done);
static int smtp_getsock(struct connectdata *conn,
curl_socket_t *socks,
@ -1310,7 +1310,7 @@ static CURLcode smtp_quit(struct connectdata *conn)
* Disconnect from an SMTP server. Cleanup protocol-specific per-connection
* resources. BLOCKING.
*/
static CURLcode smtp_disconnect(struct connectdata *conn)
static CURLcode smtp_disconnect(struct connectdata *conn, bool dead_connection)
{
struct smtp_conn *smtpc= &conn->proto.smtpc;
@ -1321,7 +1321,7 @@ static CURLcode smtp_disconnect(struct connectdata *conn)
/* The SMTP session may or may not have been allocated/setup at this
point! */
if(smtpc->pp.conn)
if(!dead_connection && smtpc->pp.conn)
(void)smtp_quit(conn); /* ignore errors on the LOGOUT */
Curl_pp_disconnect(&smtpc->pp);

View File

@ -135,13 +135,13 @@ static CURLcode scp_done(struct connectdata *conn,
CURLcode, bool premature);
static CURLcode scp_doing(struct connectdata *conn,
bool *dophase_done);
static CURLcode scp_disconnect(struct connectdata *conn);
static CURLcode scp_disconnect(struct connectdata *conn, bool dead_connection);
static CURLcode sftp_done(struct connectdata *conn,
CURLcode, bool premature);
static CURLcode sftp_doing(struct connectdata *conn,
bool *dophase_done);
static CURLcode sftp_disconnect(struct connectdata *conn);
static CURLcode sftp_disconnect(struct connectdata *conn, bool dead_connection);
static
CURLcode sftp_perform(struct connectdata *conn,
bool *connected,
@ -2689,10 +2689,11 @@ static CURLcode ssh_do(struct connectdata *conn, bool *done)
/* 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 */
static CURLcode scp_disconnect(struct connectdata *conn)
static CURLcode scp_disconnect(struct connectdata *conn, bool dead_connection)
{
CURLcode result = CURLE_OK;
struct ssh_conn *ssh = &conn->proto.sshc;
(void) dead_connection;
Curl_safefree(conn->data->state.proto.ssh);
conn->data->state.proto.ssh = NULL;
@ -2853,9 +2854,10 @@ static CURLcode sftp_doing(struct connectdata *conn,
/* 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 */
static CURLcode sftp_disconnect(struct connectdata *conn)
static CURLcode sftp_disconnect(struct connectdata *conn, bool dead_connection)
{
CURLcode result = CURLE_OK;
(void) dead_connection;
DEBUGF(infof(conn->data, "SSH DISCONNECT starts now\n"));

View File

@ -166,7 +166,7 @@ typedef struct tftp_state_data {
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 tftp_connect(struct connectdata *conn, bool *done);
static CURLcode tftp_disconnect(struct connectdata *conn);
static CURLcode tftp_disconnect(struct connectdata *conn, bool dead_connection);
static CURLcode tftp_do(struct connectdata *conn, bool *done);
static CURLcode tftp_done(struct connectdata *conn,
CURLcode, bool premature);
@ -925,9 +925,10 @@ static CURLcode tftp_state_machine(tftp_state_data_t *state,
* The disconnect callback
*
**********************************************************/
static CURLcode tftp_disconnect(struct connectdata *conn)
static CURLcode tftp_disconnect(struct connectdata *conn, bool dead_connection)
{
tftp_state_data_t *state = conn->proto.tftpc;
(void) dead_connection;
/* done, free dynamically allocated pkt buffers */
if(state) {

View File

@ -1959,7 +1959,7 @@ connect_host(struct SessionHandle *data,
res = Curl_async_resolved(*conn, &protocol_done);
else
/* if we can't resolve, we kill this "connection" now */
(void)Curl_disconnect(*conn);
(void)Curl_disconnect(*conn, /* dead_connection */ FALSE);
}
return res;

View File

@ -651,7 +651,7 @@ CURLcode Curl_ch_connc(struct SessionHandle *data,
close handles not in use.
*/
for(i=newamount; i< c->num; i++)
Curl_disconnect(c->connects[i]);
Curl_disconnect(c->connects[i], /* dead_connection */ FALSE);
/* If the most recent connection is no longer valid, mark it
invalid. */
@ -2587,7 +2587,7 @@ static void conn_free(struct connectdata *conn)
free(conn); /* free all the connection oriented data */
}
CURLcode Curl_disconnect(struct connectdata *conn)
CURLcode Curl_disconnect(struct connectdata *conn, bool dead_connection)
{
struct SessionHandle *data;
if(!conn)
@ -2647,7 +2647,7 @@ CURLcode Curl_disconnect(struct connectdata *conn)
if(conn->handler->disconnect)
/* This is set if protocol-specific cleanups should be made */
conn->handler->disconnect(conn);
conn->handler->disconnect(conn, dead_connection);
if(-1 != conn->connectindex) {
/* unlink ourselves! */
@ -2915,7 +2915,8 @@ ConnectionExists(struct SessionHandle *data,
check->data = data;
infof(data, "Connection #%ld seems to be dead!\n", i);
Curl_disconnect(check); /* disconnect resources */
/* disconnect resources */
Curl_disconnect(check, /* dead_connection */ TRUE);
data->state.connc->connects[i]=NULL; /* nothing here */
continue;
@ -3102,7 +3103,7 @@ ConnectionKillOne(struct SessionHandle *data)
conn->data = data;
/* the winner gets the honour of being disconnected */
(void)Curl_disconnect(conn);
(void)Curl_disconnect(conn, /* dead_connection */ FALSE);
/* clean the array entry */
data->state.connc->connects[connindex] = NULL;
@ -5116,7 +5117,7 @@ CURLcode Curl_connect(struct SessionHandle *data,
if(code && *in_connect) {
/* We're not allowed to return failure with memory left allocated
in the connectdata struct, free those here */
Curl_disconnect(*in_connect); /* close the connection */
Curl_disconnect(*in_connect, FALSE); /* close the connection */
*in_connect = NULL; /* return a NULL */
}
@ -5236,7 +5237,7 @@ CURLcode Curl_done(struct connectdata **connp,
*/
if(data->set.reuse_forbid || conn->bits.close || premature ||
(-1 == conn->connectindex)) {
CURLcode res2 = Curl_disconnect(conn); /* close the connection */
CURLcode res2 = Curl_disconnect(conn, FALSE); /* close the connection */
/* If we had an error already, make sure we return that one. But
if we got a new error, return that. */

View File

@ -42,7 +42,7 @@ CURLcode Curl_async_resolved(struct connectdata *conn,
CURLcode Curl_do(struct connectdata **, bool *done);
CURLcode Curl_do_more(struct connectdata *);
CURLcode Curl_done(struct connectdata **, CURLcode, bool premature);
CURLcode Curl_disconnect(struct connectdata *);
CURLcode Curl_disconnect(struct connectdata *, bool dead_connection);
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);

View File

@ -646,9 +646,11 @@ struct Curl_handler {
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.
* by the curl_disconnect(), as a step in the disconnection. If the handler
* is called because the connection has been considered dead, dead_connection
* is set to TRUE.
*/
CURLcode (*disconnect)(struct connectdata *);
CURLcode (*disconnect)(struct connectdata *, bool dead_connection);
long defport; /* Default port. */
long protocol; /* PROT_* flags concerning the protocol set */