]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
REORG: stream-interface: move sock_raw_read() to si_conn_recv_cb()
authorWilly Tarreau <wtarreau@exceliance.fr>
Mon, 20 Aug 2012 19:41:06 +0000 (21:41 +0200)
committerWilly Tarreau <w@1wt.eu>
Mon, 3 Sep 2012 18:47:30 +0000 (20:47 +0200)
The recv function is now generic and is usable to iterate any connection-to-buf
reading function from a stream interface. So let's move it to stream-interface.

include/proto/stream_interface.h
src/raw_sock.c
src/stream_interface.c

index 909d040961819451e565599cf851d77d2b45bf65..4f45c12659c447319cb9852f177dc99604f95d09 100644 (file)
@@ -41,6 +41,7 @@ int stream_int_shutr(struct stream_interface *si);
 int stream_int_shutw(struct stream_interface *si);
 void stream_int_chk_rcv_conn(struct stream_interface *si);
 void stream_int_chk_snd_conn(struct stream_interface *si);
+void si_conn_recv_cb(struct connection *conn);
 void si_conn_send_cb(struct connection *conn);
 void stream_sock_read0(struct stream_interface *si);
 
index 7dd90c9468ed078d6a7c36e2b1df51ca61cfe338..1bc40424af9e18b05d5530f98dd63d83f0a6ea7f 100644 (file)
@@ -42,9 +42,6 @@
 
 #include <types/global.h>
 
-/* main event functions used to move data between sockets and buffers */
-static void sock_raw_read(struct connection *conn);
-
 
 #if 0 && defined(CONFIG_HAP_LINUX_SPLICE)
 #include <common/splice.h>
@@ -282,203 +279,6 @@ static int raw_sock_to_buf(struct connection *conn, struct buffer *buf, int coun
 }
 
 
-/*
- * this function is called on a read event from a stream socket.
- */
-static void sock_raw_read(struct connection *conn)
-{
-       struct stream_interface *si = container_of(conn, struct stream_interface, conn);
-       struct channel *b = si->ib;
-       int ret, max, cur_read;
-       int read_poll = MAX_READ_POLL_LOOPS;
-
-#ifdef DEBUG_FULL
-       fprintf(stderr,"sock_raw_read : fd=%d, ev=0x%02x, owner=%p\n", conn->t.sock.fd, fdtab[conn->t.sock.fd].ev, fdtab[conn->t.sock.fd].owner);
-#endif
-       /* stop immediately on errors. Note that we DON'T want to stop on
-        * POLL_ERR, as the poller might report a write error while there
-        * are still data available in the recv buffer. This typically
-        * happens when we send too large a request to a backend server
-        * which rejects it before reading it all.
-        */
-       if (conn->flags & CO_FL_ERROR)
-               goto out_error;
-
-       /* stop here if we reached the end of data */
-       if (conn_data_read0_pending(conn))
-               goto out_shutdown_r;
-
-       /* maybe we were called immediately after an asynchronous shutr */
-       if (b->flags & BF_SHUTR)
-               return;
-
-#if 0 && defined(CONFIG_HAP_LINUX_SPLICE)
-       if (b->to_forward >= MIN_SPLICE_FORWARD && b->flags & BF_KERN_SPLICING) {
-
-               /* Under Linux, if FD_POLL_HUP is set, we have reached the end.
-                * Since older splice() implementations were buggy and returned
-                * EAGAIN on end of read, let's bypass the call to splice() now.
-                */
-               if (fdtab[conn->t.sock.fd].ev & FD_POLL_HUP)
-                       goto out_shutdown_r;
-
-               if (sock_raw_splice_in(b, si) >= 0) {
-                       if (si->flags & SI_FL_ERR)
-                               goto out_error;
-                       if (b->flags & BF_READ_NULL)
-                               goto out_shutdown_r;
-                       return;
-               }
-               /* splice not possible (anymore), let's go on on standard copy */
-       }
-#endif
-       cur_read = 0;
-       conn->flags &= ~(CO_FL_WAIT_DATA | CO_FL_WAIT_ROOM);
-       while (!(conn->flags & (CO_FL_ERROR | CO_FL_SOCK_RD_SH | CO_FL_DATA_RD_SH | CO_FL_WAIT_DATA | CO_FL_WAIT_ROOM | CO_FL_HANDSHAKE))) {
-               max = bi_avail(b);
-
-               if (!max) {
-                       b->flags |= BF_FULL;
-                       si->flags |= SI_FL_WAIT_ROOM;
-                       break;
-               }
-
-               ret = conn->data->rcv_buf(conn, &b->buf, max);
-               if (ret <= 0)
-                       break;
-
-               cur_read += ret;
-
-               /* if we're allowed to directly forward data, we must update ->o */
-               if (b->to_forward && !(b->flags & (BF_SHUTW|BF_SHUTW_NOW))) {
-                       unsigned long fwd = ret;
-                       if (b->to_forward != BUF_INFINITE_FORWARD) {
-                               if (fwd > b->to_forward)
-                                       fwd = b->to_forward;
-                               b->to_forward -= fwd;
-                       }
-                       b_adv(b, fwd);
-               }
-
-               if (conn->flags & CO_FL_WAIT_L4_CONN) {
-                       conn->flags &= ~CO_FL_WAIT_L4_CONN;
-                       si->exp = TICK_ETERNITY;
-               }
-
-               b->flags |= BF_READ_PARTIAL;
-               b->total += ret;
-
-               if (bi_full(b)) {
-                       /* The buffer is now full, there's no point in going through
-                        * the loop again.
-                        */
-                       if (!(b->flags & BF_STREAMER_FAST) && (cur_read == buffer_len(&b->buf))) {
-                               b->xfer_small = 0;
-                               b->xfer_large++;
-                               if (b->xfer_large >= 3) {
-                                       /* we call this buffer a fast streamer if it manages
-                                        * to be filled in one call 3 consecutive times.
-                                        */
-                                       b->flags |= (BF_STREAMER | BF_STREAMER_FAST);
-                                       //fputc('+', stderr);
-                               }
-                       }
-                       else if ((b->flags & (BF_STREAMER | BF_STREAMER_FAST)) &&
-                                (cur_read <= b->buf.size / 2)) {
-                               b->xfer_large = 0;
-                               b->xfer_small++;
-                               if (b->xfer_small >= 2) {
-                                       /* if the buffer has been at least half full twice,
-                                        * we receive faster than we send, so at least it
-                                        * is not a "fast streamer".
-                                        */
-                                       b->flags &= ~BF_STREAMER_FAST;
-                                       //fputc('-', stderr);
-                               }
-                       }
-                       else {
-                               b->xfer_small = 0;
-                               b->xfer_large = 0;
-                       }
-
-                       b->flags |= BF_FULL;
-                       si->flags |= SI_FL_WAIT_ROOM;
-                       break;
-               }
-
-               if ((b->flags & BF_READ_DONTWAIT) || --read_poll <= 0)
-                       break;
-
-               /* if too many bytes were missing from last read, it means that
-                * it's pointless trying to read again because the system does
-                * not have them in buffers.
-                */
-               if (ret < max) {
-                       if ((b->flags & (BF_STREAMER | BF_STREAMER_FAST)) &&
-                           (cur_read <= b->buf.size / 2)) {
-                               b->xfer_large = 0;
-                               b->xfer_small++;
-                               if (b->xfer_small >= 3) {
-                                       /* we have read less than half of the buffer in
-                                        * one pass, and this happened at least 3 times.
-                                        * This is definitely not a streamer.
-                                        */
-                                       b->flags &= ~(BF_STREAMER | BF_STREAMER_FAST);
-                                       //fputc('!', stderr);
-                               }
-                       }
-
-                       /* if a streamer has read few data, it may be because we
-                        * have exhausted system buffers. It's not worth trying
-                        * again.
-                        */
-                       if (b->flags & BF_STREAMER)
-                               break;
-
-                       /* if we read a large block smaller than what we requested,
-                        * it's almost certain we'll never get anything more.
-                        */
-                       if (ret >= global.tune.recv_enough)
-                               break;
-               }
-       } /* while !flags */
-
-       if (conn->flags & CO_FL_ERROR)
-               goto out_error;
-
-       if (conn->flags & CO_FL_WAIT_DATA) {
-               /* we don't automatically ask for polling if we have
-                * read enough data, as it saves some syscalls with
-                * speculative pollers.
-                */
-               if (cur_read < MIN_RET_FOR_READ_LOOP)
-                       __conn_data_poll_recv(conn);
-               else
-                       __conn_data_want_recv(conn);
-       }
-
-       if (conn_data_read0_pending(conn))
-               /* connection closed */
-               goto out_shutdown_r;
-
-       return;
-
- out_shutdown_r:
-       /* we received a shutdown */
-       b->flags |= BF_READ_NULL;
-       if (b->flags & BF_AUTO_CLOSE)
-               buffer_shutw_now(b);
-       stream_sock_read0(si);
-       conn_data_read0(conn);
-       return;
-
- out_error:
-       /* Read error on the connection, report the error and stop I/O */
-       conn->flags |= CO_FL_ERROR;
-       conn_data_stop_both(conn);
-}
-
-
 /*
  * This function is called to send buffer data to a stream socket.
  * It returns -1 in case of unrecoverable error, otherwise zero.
@@ -631,7 +431,7 @@ struct sock_ops raw_sock = {
        .shutw   = NULL,
        .chk_rcv = stream_int_chk_rcv_conn,
        .chk_snd = stream_int_chk_snd_conn,
-       .read    = sock_raw_read,
+       .read    = si_conn_recv_cb,
        .write   = si_conn_send_cb,
        .snd_buf = sock_raw_write_loop,
        .rcv_buf = raw_sock_to_buf,
index ca06949fd5c9a7912cf8932e4469dc429a54b22c..2cc1962d196b1f87a7adda5a20939c6b9c65d8a9 100644 (file)
@@ -863,6 +863,199 @@ void stream_int_chk_snd_conn(struct stream_interface *si)
        }
 }
 
+/*
+ * This is the callback which is called by the connection layer to receive data
+ * into the buffer from the connection. It iterates over the data layer's rcv_buf
+ * function.
+ */
+void si_conn_recv_cb(struct connection *conn)
+{
+       struct stream_interface *si = container_of(conn, struct stream_interface, conn);
+       struct channel *b = si->ib;
+       int ret, max, cur_read;
+       int read_poll = MAX_READ_POLL_LOOPS;
+
+       /* stop immediately on errors. Note that we DON'T want to stop on
+        * POLL_ERR, as the poller might report a write error while there
+        * are still data available in the recv buffer. This typically
+        * happens when we send too large a request to a backend server
+        * which rejects it before reading it all.
+        */
+       if (conn->flags & CO_FL_ERROR)
+               goto out_error;
+
+       /* stop here if we reached the end of data */
+       if (conn_data_read0_pending(conn))
+               goto out_shutdown_r;
+
+       /* maybe we were called immediately after an asynchronous shutr */
+       if (b->flags & BF_SHUTR)
+               return;
+
+#if 0 && defined(CONFIG_HAP_LINUX_SPLICE)
+       if (b->to_forward >= MIN_SPLICE_FORWARD && b->flags & BF_KERN_SPLICING) {
+
+               /* Under Linux, if FD_POLL_HUP is set, we have reached the end.
+                * Since older splice() implementations were buggy and returned
+                * EAGAIN on end of read, let's bypass the call to splice() now.
+                */
+               if (fdtab[conn->t.sock.fd].ev & FD_POLL_HUP)
+                       goto out_shutdown_r;
+
+               if (sock_raw_splice_in(b, si) >= 0) {
+                       if (si->flags & SI_FL_ERR)
+                               goto out_error;
+                       if (b->flags & BF_READ_NULL)
+                               goto out_shutdown_r;
+                       return;
+               }
+               /* splice not possible (anymore), let's go on on standard copy */
+       }
+#endif
+       cur_read = 0;
+       conn->flags &= ~(CO_FL_WAIT_DATA | CO_FL_WAIT_ROOM);
+       while (!(conn->flags & (CO_FL_ERROR | CO_FL_SOCK_RD_SH | CO_FL_DATA_RD_SH | CO_FL_WAIT_DATA | CO_FL_WAIT_ROOM | CO_FL_HANDSHAKE))) {
+               max = bi_avail(b);
+
+               if (!max) {
+                       b->flags |= BF_FULL;
+                       si->flags |= SI_FL_WAIT_ROOM;
+                       break;
+               }
+
+               ret = conn->data->rcv_buf(conn, &b->buf, max);
+               if (ret <= 0)
+                       break;
+
+               cur_read += ret;
+
+               /* if we're allowed to directly forward data, we must update ->o */
+               if (b->to_forward && !(b->flags & (BF_SHUTW|BF_SHUTW_NOW))) {
+                       unsigned long fwd = ret;
+                       if (b->to_forward != BUF_INFINITE_FORWARD) {
+                               if (fwd > b->to_forward)
+                                       fwd = b->to_forward;
+                               b->to_forward -= fwd;
+                       }
+                       b_adv(b, fwd);
+               }
+
+               if (conn->flags & CO_FL_WAIT_L4_CONN)
+                       conn->flags &= ~CO_FL_WAIT_L4_CONN;
+
+               b->flags |= BF_READ_PARTIAL;
+               b->total += ret;
+
+               if (bi_full(b)) {
+                       /* The buffer is now full, there's no point in going through
+                        * the loop again.
+                        */
+                       if (!(b->flags & BF_STREAMER_FAST) && (cur_read == buffer_len(&b->buf))) {
+                               b->xfer_small = 0;
+                               b->xfer_large++;
+                               if (b->xfer_large >= 3) {
+                                       /* we call this buffer a fast streamer if it manages
+                                        * to be filled in one call 3 consecutive times.
+                                        */
+                                       b->flags |= (BF_STREAMER | BF_STREAMER_FAST);
+                                       //fputc('+', stderr);
+                               }
+                       }
+                       else if ((b->flags & (BF_STREAMER | BF_STREAMER_FAST)) &&
+                                (cur_read <= b->buf.size / 2)) {
+                               b->xfer_large = 0;
+                               b->xfer_small++;
+                               if (b->xfer_small >= 2) {
+                                       /* if the buffer has been at least half full twice,
+                                        * we receive faster than we send, so at least it
+                                        * is not a "fast streamer".
+                                        */
+                                       b->flags &= ~BF_STREAMER_FAST;
+                                       //fputc('-', stderr);
+                               }
+                       }
+                       else {
+                               b->xfer_small = 0;
+                               b->xfer_large = 0;
+                       }
+
+                       b->flags |= BF_FULL;
+                       si->flags |= SI_FL_WAIT_ROOM;
+                       break;
+               }
+
+               if ((b->flags & BF_READ_DONTWAIT) || --read_poll <= 0)
+                       break;
+
+               /* if too many bytes were missing from last read, it means that
+                * it's pointless trying to read again because the system does
+                * not have them in buffers.
+                */
+               if (ret < max) {
+                       if ((b->flags & (BF_STREAMER | BF_STREAMER_FAST)) &&
+                           (cur_read <= b->buf.size / 2)) {
+                               b->xfer_large = 0;
+                               b->xfer_small++;
+                               if (b->xfer_small >= 3) {
+                                       /* we have read less than half of the buffer in
+                                        * one pass, and this happened at least 3 times.
+                                        * This is definitely not a streamer.
+                                        */
+                                       b->flags &= ~(BF_STREAMER | BF_STREAMER_FAST);
+                                       //fputc('!', stderr);
+                               }
+                       }
+
+                       /* if a streamer has read few data, it may be because we
+                        * have exhausted system buffers. It's not worth trying
+                        * again.
+                        */
+                       if (b->flags & BF_STREAMER)
+                               break;
+
+                       /* if we read a large block smaller than what we requested,
+                        * it's almost certain we'll never get anything more.
+                        */
+                       if (ret >= global.tune.recv_enough)
+                               break;
+               }
+       } /* while !flags */
+
+       if (conn->flags & CO_FL_WAIT_DATA) {
+               /* we don't automatically ask for polling if we have
+                * read enough data, as it saves some syscalls with
+                * speculative pollers.
+                */
+               if (cur_read < MIN_RET_FOR_READ_LOOP)
+                       __conn_data_poll_recv(conn);
+               else
+                       __conn_data_want_recv(conn);
+       }
+
+       if (conn->flags & CO_FL_ERROR)
+               goto out_error;
+
+       if (conn_data_read0_pending(conn))
+               /* connection closed */
+               goto out_shutdown_r;
+
+       return;
+
+ out_shutdown_r:
+       /* we received a shutdown */
+       b->flags |= BF_READ_NULL;
+       if (b->flags & BF_AUTO_CLOSE)
+               buffer_shutw_now(b);
+       stream_sock_read0(si);
+       conn_data_read0(conn);
+       return;
+
+ out_error:
+       /* Read error on the connection, report the error and stop I/O */
+       conn->flags |= CO_FL_ERROR;
+       conn_data_stop_both(conn);
+}
+
 /*
  * This is the callback which is called by the connection layer to send data
  * from the buffer to the connection. It iterates over the data layer's snd_buf