summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzhenhaonong <zhenhaonong@tencent.com>2023-03-17 19:53:50 +0800
committerAzat Khuzhin <a3at.mail@gmail.com>2023-03-29 06:19:10 +0200
commitfc568ff045e6a8956221c3f095ed8e7200fa5f74 (patch)
treebcd66778fdb731d98c591015793d021386cd4157
parent9203d98ff8f8f0a37d4d06d986ce75c299ed6444 (diff)
downloadlibevent-fc568ff045e6a8956221c3f095ed8e7200fa5f74.tar.gz
Deal with partial writes on SSL write
SSL write may do partial writes in some cases. For example, document of mbedtls_ssl_write says: If the return value is non-negative but less than length, the function must be called again with updated arguments: buf + ret, len - ret (if ret is the return value) until it returns a value equal to the last 'len' argument. In case of partial writes, we should continue writing the same chain of buffer, not the next chain.
-rw-r--r--bufferevent_ssl.c10
1 files changed, 8 insertions, 2 deletions
diff --git a/bufferevent_ssl.c b/bufferevent_ssl.c
index 837b84c4..64c36ae6 100644
--- a/bufferevent_ssl.c
+++ b/bufferevent_ssl.c
@@ -339,15 +339,17 @@ do_write(struct bufferevent_ssl *bev_ssl, int atmost)
if (n > 8)
n = 8;
- for (i=0; i < n; ++i) {
+ for (i=0; i < n;) {
if (bev_ssl->bev.write_suspended)
break;
/* SSL_write will (reasonably) return 0 if we tell it to
send 0 data. Skip this case so we don't interpret the
result as an error */
- if (space[i].iov_len == 0)
+ if (space[i].iov_len == 0) {
+ ++i;
continue;
+ }
bev_ssl->ssl_ops->clear_error();
r = bev_ssl->ssl_ops->write(bev_ssl->ssl, space[i].iov_base,
@@ -360,6 +362,10 @@ do_write(struct bufferevent_ssl *bev_ssl, int atmost)
n_written += r;
bev_ssl->last_write = -1;
bev_ssl->ssl_ops->decrement_buckets(bev_ssl);
+ space[i].iov_base = (unsigned char *)space[i].iov_base + r;
+ space[i].iov_len -= r;
+ if (space[i].iov_len == 0)
+ ++i;
} else {
int err = bev_ssl->ssl_ops->get_error(bev_ssl->ssl, r);
bev_ssl->ssl_ops->print_err(err);