]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: connection: make xprt->snd_buf() take the byte count in argument
authorWilly Tarreau <w@1wt.eu>
Thu, 14 Jun 2018 16:31:46 +0000 (18:31 +0200)
committerWilly Tarreau <w@1wt.eu>
Thu, 19 Jul 2018 14:23:41 +0000 (16:23 +0200)
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.

include/types/connection.h
src/mux_h2.c
src/mux_pt.c
src/raw_sock.c
src/ssl_sock.c

index 3dab54e902e7d1150b6923126f3b7cafe45aa0c3..6cd8a3a2d33436838f22427e2718507162e41ea1 100644 (file)
@@ -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 */
index e36ca8f5face9706bc0a8c4e7aed37cd62db9480..2251a8e046f0a0cd1dc64352f5efe993bbe78d68 100644 (file)
@@ -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.
index a68b962154e6159d785bf5143d33c80a32ec71ff..688b7d8faba2aa03fd5f59e842a9fbcec4db1c9f 100644 (file)
@@ -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)
index 16eb924087bc78ff46590bf7b6ee73d2c305af55..abf23bd3f8511ada22d1f26e10bb34c034a09c9f 100644 (file)
@@ -360,19 +360,22 @@ static int raw_sock_to_buf(struct connection *conn, struct buffer *buf, int coun
 }
 
 
-/* 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 @@ 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;
index e694c8721e48620bc671aec9a34c1820301678e8..8e38094ebeacb9c58931014815a6a958db411712 100644 (file)
@@ -5493,19 +5493,22 @@ static int ssl_sock_to_buf(struct connection *conn, struct buffer *buf, int coun
 }
 
 
-/* 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 @@ 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);