From 14f8e86da51c2be50d4920ca274ea4cb8e46d315 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Thu, 30 Aug 2012 22:23:13 +0200 Subject: [PATCH] MEDIUM: proto_tcp: remove any dependence on stream_interface The last uses of the stream interfaces were in tcp_connect_server() and could easily and more appropriately be moved to its callers, si_connect() and connect_server(), making a lot more sense. Now the function should theorically be usable for health checks. It also appears more obvious that the file is split into two distinct parts : - the protocol layer used at the connection level - the tcp analysers executing tcp-* rules and their samples/acls. --- include/proto/proto_tcp.h | 2 +- include/proto/stream_interface.h | 24 +++++++++++++++++++- include/types/connection.h | 2 ++ include/types/protocols.h | 4 ++-- src/backend.c | 7 ++++++ src/proto_tcp.c | 38 ++++++++++---------------------- 6 files changed, 47 insertions(+), 30 deletions(-) diff --git a/include/proto/proto_tcp.h b/include/proto/proto_tcp.h index cdc1d3744..5b6bf4499 100644 --- a/include/proto/proto_tcp.h +++ b/include/proto/proto_tcp.h @@ -30,7 +30,7 @@ int tcp_bind_socket(int fd, int flags, struct sockaddr_storage *local, struct sockaddr_storage *remote); 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_server(struct connection *conn, int data); int tcp_connect_probe(struct connection *conn); 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); diff --git a/include/proto/stream_interface.h b/include/proto/stream_interface.h index 8cd4a31bd..05a321028 100644 --- a/include/proto/stream_interface.h +++ b/include/proto/stream_interface.h @@ -27,6 +27,7 @@ #include #include #include +#include #include @@ -128,9 +129,30 @@ static inline void si_chk_snd(struct stream_interface *si) /* Calls chk_snd on the connection using the ctrl layer */ static inline int si_connect(struct stream_interface *si) { + int ret; + if (unlikely(!si_ctrl(si) || !si_ctrl(si)->connect)) return SN_ERR_INTERNAL; - return si_ctrl(si)->connect(si); + + ret = si_ctrl(si)->connect(&si->conn, !channel_is_empty(si->ob)); + if (ret != SN_ERR_NONE) + return ret; + + /* needs src ip/port for logging */ + if (si->flags & SI_FL_SRC_ADDR) + conn_get_from_addr(&si->conn); + + /* Prepare to send a few handshakes related to the on-wire protocol. */ + if (si->send_proxy_ofs) + si->conn.flags |= CO_FL_SI_SEND_PROXY; + + /* we need to be notified about connection establishment */ + si->conn.flags |= CO_FL_NOTIFY_SI; + + /* we're in the process of establishing a connection */ + si->state = SI_ST_CON; + + return ret; } #endif /* _PROTO_STREAM_INTERFACE_H */ diff --git a/include/types/connection.h b/include/types/connection.h index 2612eaf92..2fbd77930 100644 --- a/include/types/connection.h +++ b/include/types/connection.h @@ -80,6 +80,8 @@ enum { */ CO_FL_POLL_SOCK = CO_FL_HANDSHAKE | CO_FL_WAIT_L4_CONN | CO_FL_WAIT_L6_CONN, + /* This flag is set if lingering has already been disabled on the connection */ + /* These flags are used to report whether the from/to addresses are set or not */ CO_FL_ADDR_FROM_SET = 0x00001000, /* addr.from is set */ CO_FL_ADDR_TO_SET = 0x00002000, /* addr.to is set */ diff --git a/include/types/protocols.h b/include/types/protocols.h index 68696441d..275122fcb 100644 --- a/include/types/protocols.h +++ b/include/types/protocols.h @@ -135,7 +135,7 @@ struct listener { } conf; /* config information */ }; -struct stream_interface; +struct connection; /* This structure contains all information needed to easily handle a protocol. * Its primary goal is to ease listeners maintenance. Specifically, the @@ -157,7 +157,7 @@ struct protocol { int (*unbind_all)(struct protocol *proto); /* unbind all bound listeners */ int (*enable_all)(struct protocol *proto); /* enable all bound listeners */ int (*disable_all)(struct protocol *proto); /* disable all bound listeners */ - int (*connect)(struct stream_interface *); /* connect function if any */ + int (*connect)(struct connection *, int data); /* connect function if any */ int (*get_src)(int fd, struct sockaddr *, socklen_t, int dir); /* syscall used to retrieve src addr */ int (*get_dst)(int fd, struct sockaddr *, socklen_t, int dir); /* syscall used to retrieve dst addr */ diff --git a/src/backend.c b/src/backend.c index 3cb10fe86..c2ecda828 100644 --- a/src/backend.c +++ b/src/backend.c @@ -1009,11 +1009,18 @@ int connect_server(struct session *s) if (s->fe->options2 & PR_O2_SRC_ADDR) s->req->cons->flags |= SI_FL_SRC_ADDR; + /* disable lingering */ + if (s->be->options & PR_O_TCP_NOLING) + s->req->cons->flags |= SI_FL_NOLINGER; + err = si_connect(s->req->cons); if (err != SN_ERR_NONE) return err; + /* set connect timeout */ + s->req->cons->exp = tick_add_ifset(now_ms, s->be->timeout.connect); + srv = target_srv(&s->target); if (srv) { s->flags |= SN_CURR_SESS; diff --git a/src/proto_tcp.c b/src/proto_tcp.c index 7998f400f..b61d87e6c 100644 --- a/src/proto_tcp.c +++ b/src/proto_tcp.c @@ -49,7 +49,6 @@ #include #include #include -#include #include #ifdef CONFIG_HAP_CTTPROXY @@ -210,12 +209,15 @@ int tcp_bind_socket(int fd, int flags, struct sockaddr_storage *local, struct so /* - * This function initiates a connection to the target assigned to this session - * (si->{target,addr.to}). A source address may be pointed to by si->addr.from - * in case of transparent proxying. Normal source bind addresses are still - * determined locally (due to the possible need of a source port). - * si->target may point either to a valid server or to a backend, depending - * on si->target.type. Only TARG_TYPE_PROXY and TARG_TYPE_SERVER are supported. + * This function initiates a TCP connection establishment to the target assigned + * to connection using (si->{target,addr.to}). A source address may be + * pointed to by conn->addr.from in case of transparent proxying. Normal source + * bind addresses are still determined locally (due to the possible need of a + * source port). conn->target may point either to a valid server or to a backend, + * depending on conn->target.type. Only TARG_TYPE_PROXY and TARG_TYPE_SERVER are + * supported. The parameter is a boolean indicating whether there are data + * waiting for being sent or not, in order to adjust data write polling and on + * some platforms, the ability to avoid an empty initial ACK. * * It can return one of : * - SN_ERR_NONE if everything's OK @@ -227,12 +229,11 @@ int tcp_bind_socket(int fd, int flags, struct sockaddr_storage *local, struct so * Additionnally, in the case of SN_ERR_RESOURCE, an emergency log will be emitted. */ -int tcp_connect_server(struct stream_interface *si) +int tcp_connect_server(struct connection *conn, int data) { int fd; struct server *srv; struct proxy *be; - struct connection *conn = &si->conn; switch (conn->target.type) { case TARG_TYPE_PROXY: @@ -285,9 +286,6 @@ int tcp_connect_server(struct stream_interface *si) if (be->options & PR_O_TCP_SRV_KA) setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof(one)); - if (be->options & PR_O_TCP_NOLING) - si->flags |= SI_FL_NOLINGER; - /* allow specific binding : * - server-specific at first * - proxy-specific next @@ -409,7 +407,7 @@ int tcp_connect_server(struct stream_interface *si) * machine with the first ACK. We only do this if there are pending * data in the buffer. */ - if ((be->options2 & PR_O2_SMARTCON) && si->ob->buf.o) + if ((be->options2 & PR_O2_SMARTCON) && data) setsockopt(fd, IPPROTO_TCP, TCP_QUICKACK, &zero, sizeof(zero)); #endif @@ -453,28 +451,16 @@ int tcp_connect_server(struct stream_interface *si) } } - /* needs src ip/port for logging */ - if (si->flags & SI_FL_SRC_ADDR) - conn_get_from_addr(conn); - fdtab[fd].owner = conn; fdtab[fd].flags = FD_FL_TCP | FD_FL_TCP_NODELAY; conn->flags = CO_FL_WAIT_L4_CONN; /* connection in progress */ - conn->flags |= CO_FL_NOTIFY_SI; /* we're on a stream_interface */ - - /* Prepare to send a few handshakes related to the on-wire protocol. */ - if (si->send_proxy_ofs) - conn->flags |= CO_FL_SI_SEND_PROXY; fdtab[fd].iocb = conn_fd_handler; fd_insert(fd); conn_sock_want_send(conn); /* for connect status */ - if (!channel_is_empty(si->ob)) + if (data) conn_data_want_send(conn); /* prepare to send data if any */ - si->state = SI_ST_CON; - si->exp = tick_add_ifset(now_ms, be->timeout.connect); - return SN_ERR_NONE; /* connection is OK */ }