]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MAJOR: tcp: remove the specific I/O callbacks for TCP connection probes
authorWilly Tarreau <wtarreau@exceliance.fr>
Mon, 23 Jul 2012 13:07:23 +0000 (15:07 +0200)
committerWilly Tarreau <w@1wt.eu>
Sun, 2 Sep 2012 19:51:29 +0000 (21:51 +0200)
Use a single tcp_connect_probe() instead of tcp_connect_write() and
tcp_connect_read(). We call this one only when no data layer function
have been processed, so this is a fallback to test for completion of
a connection attempt.

With this done, we don't have the need for any direct I/O callback
anymore.

The function still relies on ->write() to wake the stream interface up,
so it's not finished.

include/proto/proto_tcp.h
src/connection.c
src/proto_tcp.c

index c61fd86c97b3d17b6fe59e6bb85c6e07b6b35b12..66f29fcdbe53c1c24c9b55fdd1b066a76469925c 100644 (file)
@@ -31,6 +31,7 @@ int tcp_bind_socket(int fd, int flags, struct sockaddr_storage *local, struct so
 void tcpv4_add_listener(struct listener *listener);
 void tcpv6_add_listener(struct listener *listener);
 int tcp_connect_server(struct stream_interface *si);
+int tcp_connect_probe(int fd);
 int tcp_get_src(int fd, struct sockaddr *sa, socklen_t salen, int dir);
 int tcp_get_dst(int fd, struct sockaddr *sa, socklen_t salen, int dir);
 int tcp_inspect_request(struct session *s, struct buffer *req, int an_bit);
index c30e7395b6175a035c84fc729ba14c777965ccb8..679bc8944414cbf97ac8924748493a5ce6adcfab 100644 (file)
@@ -15,6 +15,7 @@
 
 #include <types/connection.h>
 
+#include <proto/proto_tcp.h>
 #include <proto/stream_interface.h>
 
 /* I/O callback for fd-based connections. It calls the read/write handlers
@@ -46,6 +47,18 @@ int conn_fd_handler(int fd)
        if (fdtab[fd].ev & (FD_POLL_OUT | FD_POLL_ERR))
                if (!conn->data->write(fd))
                        ret |= FD_WAIT_WRITE;
+
+       if (conn->flags & CO_FL_ERROR)
+               goto leave;
+
+       if (conn->flags & CO_FL_WAIT_L4_CONN) {
+               /* still waiting for a connection to establish and no data to
+                * send in order to probe it ? Then let's retry the connect().
+                */
+               if (!tcp_connect_probe(fd))
+                       ret |= FD_WAIT_WRITE;
+       }
+
  leave:
        /* remove the events before leaving */
        fdtab[fd].ev &= ~(FD_POLL_IN | FD_POLL_OUT | FD_POLL_HUP | FD_POLL_ERR);
index 86ef47b7cfd4479d082859bff3e8c776aab1d6de..db2fe031050ae707cac50b0edfeb436756a7da0e 100644 (file)
@@ -61,8 +61,6 @@
 
 static int tcp_bind_listeners(struct protocol *proto, char *errmsg, int errlen);
 static int tcp_bind_listener(struct listener *listener, char *errmsg, int errlen);
-static int tcp_connect_write(int fd);
-static int tcp_connect_read(int fd);
 
 /* Note: must not be declared <const> as its list will be overwritten */
 static struct protocol proto_tcpv4 = {
@@ -480,10 +478,6 @@ int tcp_connect_server(struct stream_interface *si)
 
        if (si->send_proxy_ofs)
                si->conn.flags |= CO_FL_SI_SEND_PROXY;
-       else if (si->ob->flags & BF_OUT_EMPTY) {
-               fdtab[fd].cb[DIR_RD].f = tcp_connect_read;
-               fdtab[fd].cb[DIR_WR].f = tcp_connect_write;
-       }
 
        fdtab[fd].iocb = conn_fd_handler;
        fd_insert(fd);
@@ -536,7 +530,7 @@ int tcp_get_dst(int fd, struct sockaddr *sa, socklen_t salen, int dir)
  * once the connection is established. It returns zero if it needs some polling
  * before being called again.
  */
-static int tcp_connect_write(int fd)
+int tcp_connect_probe(int fd)
 {
        struct connection *conn = fdtab[fd].owner;
        struct stream_interface *si = container_of(conn, struct stream_interface, conn);
@@ -549,6 +543,10 @@ static int tcp_connect_write(int fd)
        if (!(conn->flags & CO_FL_WAIT_L4_CONN))
                goto out_ignore; /* strange we were called while ready */
 
+       /* stop here if we reached the end of data */
+       if ((fdtab[fd].ev & (FD_POLL_IN|FD_POLL_HUP)) == FD_POLL_HUP)
+               goto out_error;
+
        /* we might have been called just after an asynchronous shutw */
        if (b->flags & BF_SHUTW)
                goto out_wakeup;
@@ -609,49 +607,6 @@ static int tcp_connect_write(int fd)
 }
 
 
-/* might be used on connect error */
-static int tcp_connect_read(int fd)
-{
-       struct connection *conn = fdtab[fd].owner;
-       struct stream_interface *si = container_of(conn, struct stream_interface, conn);
-       int retval;
-
-       retval = 1;
-
-       if (conn->flags & CO_FL_ERROR)
-               goto out_error;
-
-       if (!(conn->flags & CO_FL_WAIT_L4_CONN)) {
-               retval = 0;
-               goto out_ignore; /* strange we were called while ready */
-       }
-
-       /* stop here if we reached the end of data */
-       if ((fdtab[fd].ev & (FD_POLL_IN|FD_POLL_HUP)) == FD_POLL_HUP)
-               goto out_error;
-
- out_wakeup:
-       task_wakeup(si->owner, TASK_WOKEN_IO);
- out_ignore:
-       fdtab[fd].ev &= ~FD_POLL_IN;
-       return retval;
-
- out_error:
-       /* Read error on the file descriptor. We mark the FD as STERROR so
-        * that we don't use it anymore. The error is reported to the stream
-        * interface which will take proper action. We must not perturbate the
-        * buffer because the stream interface wants to ensure transparent
-        * connection retries.
-        */
-
-       conn->flags |= CO_FL_ERROR;
-       fdtab[fd].ev &= ~FD_POLL_STICKY;
-       EV_FD_REM(fd);
-       si->flags |= SI_FL_ERR;
-       goto out_wakeup;
-}
-
-
 /* This function tries to bind a TCPv4/v6 listener. It may return a warning or
  * an error message in <err> if the message is at most <errlen> bytes long
  * (including '\0'). The return value is composed from ERR_ABORT, ERR_WARN,