diff --git a/include/types/connection.h b/include/types/connection.h index 3dab54e90..6cd8a3a2d 100644 --- a/include/types/connection.h +++ b/include/types/connection.h @@ -269,7 +269,7 @@ enum { */ struct xprt_ops { int (*rcv_buf)(struct connection *conn, struct buffer *buf, int count); /* recv callback */ - int (*snd_buf)(struct connection *conn, struct buffer *buf, int flags); /* send callback */ + size_t (*snd_buf)(struct connection *conn, const struct buffer *buf, size_t count, int flags); /* send callback */ int (*rcv_pipe)(struct connection *conn, struct pipe *pipe, unsigned int count); /* recv-to-pipe callback */ int (*snd_pipe)(struct connection *conn, struct pipe *pipe); /* send-to-pipe callback */ void (*shutr)(struct connection *, int); /* shutr function */ diff --git a/src/mux_h2.c b/src/mux_h2.c index e36ca8f5f..2251a8e04 100644 --- a/src/mux_h2.c +++ b/src/mux_h2.c @@ -2213,8 +2213,13 @@ static void h2_send(struct connection *conn) if (h2c->flags & (H2_CF_MUX_MFULL | H2_CF_DEM_MBUSY | H2_CF_DEM_MROOM)) flags |= CO_SFL_MSG_MORE; - if (h2c->mbuf->o && conn->xprt->snd_buf(conn, h2c->mbuf, flags) <= 0) - break; + if (h2c->mbuf->o) { + int ret = conn->xprt->snd_buf(conn, h2c->mbuf, h2c->mbuf->o, flags); + if (!ret) + break; + b_del(h2c->mbuf, ret); + b_realign_if_empty(h2c->mbuf); + } /* wrote at least one byte, the buffer is not full anymore */ h2c->flags &= ~(H2_CF_MUX_MFULL | H2_CF_DEM_MROOM); @@ -2369,8 +2374,13 @@ static struct task *h2_timeout_task(struct task *t, void *context, unsigned shor if (h2c_send_goaway_error(h2c, NULL) <= 0) h2c->flags |= H2_CF_GOAWAY_FAILED; - if (h2c->mbuf->o && !(h2c->flags & H2_CF_GOAWAY_FAILED) && conn_xprt_ready(h2c->conn)) - h2c->conn->xprt->snd_buf(h2c->conn, h2c->mbuf, 0); + if (h2c->mbuf->o && !(h2c->flags & H2_CF_GOAWAY_FAILED) && conn_xprt_ready(h2c->conn)) { + int ret = h2c->conn->xprt->snd_buf(h2c->conn, h2c->mbuf, h2c->mbuf->o, 0); + if (ret > 0) { + b_del(h2c->mbuf, ret); + b_realign_if_empty(h2c->mbuf); + } + } /* either we can release everything now or it will be done later once * the last stream closes. diff --git a/src/mux_pt.c b/src/mux_pt.c index a68b96215..688b7d8fa 100644 --- a/src/mux_pt.c +++ b/src/mux_pt.c @@ -174,7 +174,13 @@ static int mux_pt_rcv_buf(struct conn_stream *cs, struct buffer *buf, int count) /* Called from the upper layer, to send data */ static int mux_pt_snd_buf(struct conn_stream *cs, struct buffer *buf, int flags) { - return (cs->conn->xprt->snd_buf(cs->conn, buf, flags)); + int ret = cs->conn->xprt->snd_buf(cs->conn, buf, buf->o, flags); + + if (ret > 0) + b_del(buf, ret); + + b_realign_if_empty(buf); + return ret; } #if defined(CONFIG_HAP_LINUX_SPLICE) diff --git a/src/raw_sock.c b/src/raw_sock.c index 16eb92408..abf23bd3f 100644 --- a/src/raw_sock.c +++ b/src/raw_sock.c @@ -360,19 +360,22 @@ static int raw_sock_to_buf(struct connection *conn, struct buffer *buf, int coun } -/* Send all pending bytes from buffer to connection 's socket. - * may contain some CO_SFL_* flags to hint the system about other - * pending data for example. +/* Send up to pending bytes from buffer to connection 's + * socket. may contain some CO_SFL_* flags to hint the system about + * other pending data for example, but this flag is ignored at the moment. * Only one call to send() is performed, unless the buffer wraps, in which case * a second call may be performed. The connection's flags are updated with * whatever special event is detected (error, empty). The caller is responsible * for taking care of those events and avoiding the call if inappropriate. The * function does not call the connection's polling update function, so the caller - * is responsible for this. + * is responsible for this. It's up to the caller to update the buffer's contents + * based on the return value. */ -static int raw_sock_from_buf(struct connection *conn, struct buffer *buf, int flags) +static size_t raw_sock_from_buf(struct connection *conn, const struct buffer *buf, size_t count, int flags) { - int ret, try, done, send_flag; + ssize_t ret; + size_t try, done; + int send_flag; if (!conn_ctrl_ready(conn)) return 0; @@ -386,26 +389,21 @@ static int raw_sock_from_buf(struct connection *conn, struct buffer *buf, int fl * to send() unless the buffer wraps and we exactly fill the first hunk, * in which case we accept to do it once again. */ - while (buf->o) { - try = buf->o; - /* outgoing data may wrap at the end */ - if (buf->data + try > buf->p) - try = buf->data + try - buf->p; + while (count) { + try = b_contig_data(buf, done); + if (try > count) + try = count; send_flag = MSG_DONTWAIT | MSG_NOSIGNAL; - if (try < buf->o || flags & CO_SFL_MSG_MORE) + if (try < count || flags & CO_SFL_MSG_MORE) send_flag |= MSG_MORE; - ret = send(conn->handle.fd, b_head(buf), try, send_flag); + ret = send(conn->handle.fd, b_peek(buf, done), try, send_flag); if (ret > 0) { - buf->o -= ret; + count -= ret; done += ret; - if (likely(buffer_empty(buf))) - /* optimize data alignment in the buffer */ - buf->p = buf->data; - /* if the system buffer is full, don't insist */ if (ret < try) break; diff --git a/src/ssl_sock.c b/src/ssl_sock.c index e694c8721..8e38094eb 100644 --- a/src/ssl_sock.c +++ b/src/ssl_sock.c @@ -5493,19 +5493,22 @@ static int ssl_sock_to_buf(struct connection *conn, struct buffer *buf, int coun } -/* Send all pending bytes from buffer to connection 's socket. - * may contain some CO_SFL_* flags to hint the system about other - * pending data for example, but this flag is ignored at the moment. +/* Send up to pending bytes from buffer to connection 's + * socket. may contain some CO_SFL_* flags to hint the system about + * other pending data for example, but this flag is ignored at the moment. * Only one call to send() is performed, unless the buffer wraps, in which case * a second call may be performed. The connection's flags are updated with * whatever special event is detected (error, empty). The caller is responsible * for taking care of those events and avoiding the call if inappropriate. The * function does not call the connection's polling update function, so the caller - * is responsible for this. + * is responsible for this. The buffer's output is not adjusted, it's up to the + * caller to take care of this. It's up to the caller to update the buffer's + * contents based on the return value. */ -static int ssl_sock_from_buf(struct connection *conn, struct buffer *buf, int flags) +static size_t ssl_sock_from_buf(struct connection *conn, const struct buffer *buf, size_t count, int flags) { - int ret, try, done; + ssize_t ret; + size_t try, done; done = 0; conn_refresh_polling_flags(conn); @@ -5521,14 +5524,14 @@ static int ssl_sock_from_buf(struct connection *conn, struct buffer *buf, int fl * to send() unless the buffer wraps and we exactly fill the first hunk, * in which case we accept to do it once again. */ - while (buf->o) { + while (count) { #if (OPENSSL_VERSION_NUMBER >= 0x10101000L) size_t written_data; #endif - try = b_contig_data(buf, 0); - if (try > buf->o) - try = buf->o; + try = b_contig_data(buf, done); + if (try > count) + try = count; if (!(flags & CO_SFL_STREAMER) && !(conn->xprt_st & SSL_SOCK_SEND_UNLIMITED) && @@ -5564,7 +5567,7 @@ static int ssl_sock_from_buf(struct connection *conn, struct buffer *buf, int fl break; } } - ret = SSL_write_early_data(conn->xprt_ctx, b_head(buf), try, &written_data); + ret = SSL_write_early_data(conn->xprt_ctx, b_peek(buf, done), try, &written_data); if (ret == 1) { ret = written_data; conn->sent_early_data += ret; @@ -5577,7 +5580,7 @@ static int ssl_sock_from_buf(struct connection *conn, struct buffer *buf, int fl } else #endif - ret = SSL_write(conn->xprt_ctx, b_head(buf), try); + ret = SSL_write(conn->xprt_ctx, b_peek(buf, done), try); if (conn->flags & CO_FL_ERROR) { /* CO_FL_ERROR may be set by ssl_sock_infocbk */ @@ -5585,13 +5588,8 @@ static int ssl_sock_from_buf(struct connection *conn, struct buffer *buf, int fl } if (ret > 0) { conn->xprt_st &= ~SSL_SOCK_SEND_UNLIMITED; - - buf->o -= ret; + count -= ret; done += ret; - - if (likely(buffer_empty(buf))) - /* optimize data alignment in the buffer */ - buf->p = buf->data; } else { ret = SSL_get_error(conn->xprt_ctx, ret);