MAJOR: tcp: remove the specific I/O callbacks for TCP connection probes
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.
diff --git a/include/proto/proto_tcp.h b/include/proto/proto_tcp.h
index c61fd86..66f29fc 100644
--- a/include/proto/proto_tcp.h
+++ b/include/proto/proto_tcp.h
@@ -31,6 +31,7 @@
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);
diff --git a/src/connection.c b/src/connection.c
index c30e739..679bc89 100644
--- a/src/connection.c
+++ b/src/connection.c
@@ -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 @@
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);
diff --git a/src/proto_tcp.c b/src/proto_tcp.c
index 86ef47b..db2fe03 100644
--- a/src/proto_tcp.c
+++ b/src/proto_tcp.c
@@ -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 @@
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 @@
* 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 @@
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;
@@ -605,49 +603,6 @@
EV_FD_REM(fd);
si->flags |= SI_FL_ERR;
retval = 1;
- goto out_wakeup;
-}
-
-
-/* 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;
}