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
This commit is contained in:
Bill Nagel
2014-09-26 18:55:01 +00:00
committed by Steve Holme
parent 0e1590b3dd
commit ee0958cb4d

View File

@@ -1807,7 +1807,7 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
struct SessionHandle *data = conn->data; struct SessionHandle *data = conn->data;
struct SMTP *smtp = data->req.protop; struct SMTP *smtp = data->req.protop;
struct pingpong *pp = &conn->proto.smtpc.pp; struct pingpong *pp = &conn->proto.smtpc.pp;
const char *eob; char *eob;
ssize_t len; ssize_t len;
ssize_t bytes_written; 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) { else if(!data->set.connect_only && data->set.upload && data->set.mail_rcpt) {
/* Calculate the EOB taking into account any terminating CRLF from the /* 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 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. */ is "no mail data". RFC-5321, sect. 4.1.1.4.
eob = SMTP_EOB;
len = SMTP_EOB_LEN; 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) { if(smtp->trailing_crlf || !conn->data->state.infilesize) {
eob += 2; eob = strdup(SMTP_EOB + 2);
len -= 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 */ /* Send the end of block data */
result = Curl_write(conn, conn->writesockfd, eob, len, &bytes_written); result = Curl_write(conn, conn->writesockfd, eob, len, &bytes_written);
if(result) if(result) {
free(eob);
return result; return result;
}
if(bytes_written != len) { if(bytes_written != len) {
/* The whole chunk was not sent so keep it around and adjust the /* The whole chunk was not sent so keep it around and adjust the
pingpong structure accordingly */ pingpong structure accordingly */
pp->sendthis = strdup(eob); pp->sendthis = eob;
pp->sendsize = len; pp->sendsize = len;
pp->sendleft = len - bytes_written; pp->sendleft = len - bytes_written;
} }
else else {
/* Successfully sent so adjust the response timeout relative to now */ /* Successfully sent so adjust the response timeout relative to now */
pp->response = Curl_tvnow(); pp->response = Curl_tvnow();
free(eob);
}
state(conn, SMTP_POSTDATA); state(conn, SMTP_POSTDATA);
/* Run the state-machine /* Run the state-machine