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:
33
lib/smtp.c
33
lib/smtp.c
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user