From ee0958cb4d930cb4cdb167ea401699cbb9229afa Mon Sep 17 00:00:00 2001 From: Bill Nagel Date: Fri, 26 Sep 2014 18:55:01 +0000 Subject: smtp: Fixed intermittent "SSL3_WRITE_PENDING: bad write retry" error This patch fixes the "SSL3_WRITE_PENDING: bad write retry" error that sometimes occurs when sending an email over SMTPS with OpenSSL. OpenSSL appears to require the same pointer on a write that follows a retry (CURLE_AGAIN) as discussed here: http://stackoverflow.com/questions/2997218/why-am-i-getting-error1409f07fssl-routinesssl3-write-pending-bad-write-retr --- lib/smtp.c | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/lib/smtp.c b/lib/smtp.c index 9aa8b15bd..6d1aa0120 100644 --- a/lib/smtp.c +++ b/lib/smtp.c @@ -1807,7 +1807,7 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status, struct SessionHandle *data = conn->data; struct SMTP *smtp = data->req.protop; struct pingpong *pp = &conn->proto.smtpc.pp; - const char *eob; + char *eob; ssize_t len; ssize_t bytes_written; @@ -1827,30 +1827,45 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status, else if(!data->set.connect_only && data->set.upload && data->set.mail_rcpt) { /* Calculate the EOB taking into account any terminating CRLF from the previous line of the email or the CRLF of the DATA command when there - is "no mail data". RFC-5321, sect. 4.1.1.4. */ - eob = SMTP_EOB; - len = SMTP_EOB_LEN; + is "no mail data". RFC-5321, sect. 4.1.1.4. + + Note: As some SSL backends, such as OpenSSL, will cause Curl_write() to + fail when using a different pointer following a previous write, that + returned CURLE_AGAIN, we duplicate the EOB now rather than when the + bytes written doesn't equal len. */ if(smtp->trailing_crlf || !conn->data->state.infilesize) { - eob += 2; - len -= 2; + eob = strdup(SMTP_EOB + 2); + len = SMTP_EOB_LEN - 2; + } + else { + eob = strdup(SMTP_EOB); + len = SMTP_EOB_LEN; } + if(!eob) + return CURLE_OUT_OF_MEMORY; + /* Send the end of block data */ result = Curl_write(conn, conn->writesockfd, eob, len, &bytes_written); - if(result) + if(result) { + free(eob); return result; + } if(bytes_written != len) { /* The whole chunk was not sent so keep it around and adjust the pingpong structure accordingly */ - pp->sendthis = strdup(eob); + pp->sendthis = eob; pp->sendsize = len; pp->sendleft = len - bytes_written; } - else + else { /* Successfully sent so adjust the response timeout relative to now */ pp->response = Curl_tvnow(); + free(eob); + } + state(conn, SMTP_POSTDATA); /* Run the state-machine -- cgit v1.2.3