MEDIUM: connection: make xprt->snd_buf() take the byte count in argument

This way the senders don't need to modify the buffer's metadata anymore
nor to know about the output's split point. This way the functions can
take a const buffer and it's clearer who's in charge of updating the
buffer after a send. That's why the buffer realignment is now performed
by the caller of the transport's snd_buf() functions.

The return type was updated to return a size_t to comply with the count
argument.
diff --git a/include/types/connection.h b/include/types/connection.h
index 3dab54e..6cd8a3a 100644
--- a/include/types/connection.h
+++ b/include/types/connection.h
@@ -269,7 +269,7 @@
  */
 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 e36ca8f..2251a8e 100644
--- a/src/mux_h2.c
+++ b/src/mux_h2.c
@@ -2213,8 +2213,13 @@
 		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 @@
 	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 a68b962..688b7d8 100644
--- a/src/mux_pt.c
+++ b/src/mux_pt.c
@@ -174,7 +174,13 @@
 /* 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 16eb924..abf23bd 100644
--- a/src/raw_sock.c
+++ b/src/raw_sock.c
@@ -360,19 +360,22 @@
 }
 
 
-/* Send all pending bytes from buffer <buf> to connection <conn>'s socket.
- * <flags> may contain some CO_SFL_* flags to hint the system about other
- * pending data for example.
+/* Send up to <count> pending bytes from buffer <buf> to connection <conn>'s
+ * socket. <flags> 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 @@
 	 * 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 e694c87..8e38094 100644
--- a/src/ssl_sock.c
+++ b/src/ssl_sock.c
@@ -5493,19 +5493,22 @@
 }
 
 
-/* Send all pending bytes from buffer <buf> to connection <conn>'s socket.
- * <flags> 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 <count> pending bytes from buffer <buf> to connection <conn>'s
+ * socket. <flags> 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 @@
 	 * 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 @@
 					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 @@
 
 		} 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 @@
 		}
 		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);