mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-08 08:07:10 +02:00
MINOR: connection: make conn_sock_drain() work for all socket families
This patch improves the previous fix by implementing the socket draining code directly in conn_sock_drain() so that it always applies regardless of the protocol's family. Thus it gets rid of tcp_drain().
This commit is contained in:
parent
fe5d2ac65f
commit
e215bba956
@ -33,7 +33,6 @@ int tcp_connect_server(struct connection *conn, int data, int delack);
|
|||||||
int tcp_connect_probe(struct connection *conn);
|
int tcp_connect_probe(struct connection *conn);
|
||||||
int tcp_get_src(int fd, struct sockaddr *sa, socklen_t salen, int dir);
|
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_get_dst(int fd, struct sockaddr *sa, socklen_t salen, int dir);
|
||||||
int tcp_drain(int fd);
|
|
||||||
|
|
||||||
/* Export some samples. */
|
/* Export some samples. */
|
||||||
int smp_fetch_src(const struct arg *args, struct sample *smp, const char *kw, void *private);
|
int smp_fetch_src(const struct arg *args, struct sample *smp, const char *kw, void *private);
|
||||||
|
@ -359,29 +359,61 @@ int conn_subscribe(struct connection *conn, int event_type, void *param)
|
|||||||
*/
|
*/
|
||||||
int conn_sock_drain(struct connection *conn)
|
int conn_sock_drain(struct connection *conn)
|
||||||
{
|
{
|
||||||
|
int turns = 2;
|
||||||
|
int len;
|
||||||
|
|
||||||
if (!conn_ctrl_ready(conn))
|
if (!conn_ctrl_ready(conn))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if (conn->flags & (CO_FL_ERROR | CO_FL_SOCK_RD_SH))
|
if (conn->flags & (CO_FL_ERROR | CO_FL_SOCK_RD_SH))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if (fdtab[conn->handle.fd].ev & (FD_POLL_ERR|FD_POLL_HUP)) {
|
if (fdtab[conn->handle.fd].ev & (FD_POLL_ERR|FD_POLL_HUP))
|
||||||
fdtab[conn->handle.fd].linger_risk = 0;
|
goto shut;
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (!fd_recv_ready(conn->handle.fd))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* disable draining if we were called and have no drain function */
|
if (!fd_recv_ready(conn->handle.fd))
|
||||||
if (!conn->ctrl->drain) {
|
return 0;
|
||||||
__conn_xprt_stop_recv(conn);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (conn->ctrl->drain) {
|
||||||
if (conn->ctrl->drain(conn->handle.fd) <= 0)
|
if (conn->ctrl->drain(conn->handle.fd) <= 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
goto shut;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* no drain function defined, use the generic one */
|
||||||
|
|
||||||
|
while (turns) {
|
||||||
|
#ifdef MSG_TRUNC_CLEARS_INPUT
|
||||||
|
len = recv(conn->handle.fd, NULL, INT_MAX, MSG_DONTWAIT | MSG_NOSIGNAL | MSG_TRUNC);
|
||||||
|
if (len == -1 && errno == EFAULT)
|
||||||
|
#endif
|
||||||
|
len = recv(conn->handle.fd, trash.area, trash.size,
|
||||||
|
MSG_DONTWAIT | MSG_NOSIGNAL);
|
||||||
|
|
||||||
|
if (len == 0)
|
||||||
|
goto shut;
|
||||||
|
|
||||||
|
if (len < 0) {
|
||||||
|
if (errno == EAGAIN) {
|
||||||
|
/* connection not closed yet */
|
||||||
|
fd_cant_recv(conn->handle.fd);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (errno == EINTR) /* oops, try again */
|
||||||
|
continue;
|
||||||
|
/* other errors indicate a dead connection, fine. */
|
||||||
|
goto shut;
|
||||||
|
}
|
||||||
|
/* OK we read some data, let's try again once */
|
||||||
|
turns--;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* some data are still present, give up */
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
shut:
|
||||||
|
/* we're certain the connection was shut down */
|
||||||
|
fdtab[conn->handle.fd].linger_risk = 0;
|
||||||
conn->flags |= CO_FL_SOCK_RD_SH;
|
conn->flags |= CO_FL_SOCK_RD_SH;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -83,7 +83,6 @@ static struct protocol proto_tcpv4 = {
|
|||||||
.enable_all = enable_all_listeners,
|
.enable_all = enable_all_listeners,
|
||||||
.get_src = tcp_get_src,
|
.get_src = tcp_get_src,
|
||||||
.get_dst = tcp_get_dst,
|
.get_dst = tcp_get_dst,
|
||||||
.drain = tcp_drain,
|
|
||||||
.pause = tcp_pause_listener,
|
.pause = tcp_pause_listener,
|
||||||
.add = tcpv4_add_listener,
|
.add = tcpv4_add_listener,
|
||||||
.listeners = LIST_HEAD_INIT(proto_tcpv4.listeners),
|
.listeners = LIST_HEAD_INIT(proto_tcpv4.listeners),
|
||||||
@ -107,7 +106,6 @@ static struct protocol proto_tcpv6 = {
|
|||||||
.enable_all = enable_all_listeners,
|
.enable_all = enable_all_listeners,
|
||||||
.get_src = tcp_get_src,
|
.get_src = tcp_get_src,
|
||||||
.get_dst = tcp_get_dst,
|
.get_dst = tcp_get_dst,
|
||||||
.drain = tcp_drain,
|
|
||||||
.pause = tcp_pause_listener,
|
.pause = tcp_pause_listener,
|
||||||
.add = tcpv6_add_listener,
|
.add = tcpv6_add_listener,
|
||||||
.listeners = LIST_HEAD_INIT(proto_tcpv6.listeners),
|
.listeners = LIST_HEAD_INIT(proto_tcpv6.listeners),
|
||||||
@ -616,49 +614,6 @@ int tcp_get_dst(int fd, struct sockaddr *sa, socklen_t salen, int dir)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Tries to drain any pending incoming data from the socket to reach the
|
|
||||||
* receive shutdown. Returns positive if the shutdown was found, negative
|
|
||||||
* if EAGAIN was hit, otherwise zero. This is useful to decide whether we
|
|
||||||
* can close a connection cleanly are we must kill it hard.
|
|
||||||
*/
|
|
||||||
int tcp_drain(int fd)
|
|
||||||
{
|
|
||||||
int turns = 2;
|
|
||||||
int len;
|
|
||||||
|
|
||||||
while (turns) {
|
|
||||||
#ifdef MSG_TRUNC_CLEARS_INPUT
|
|
||||||
len = recv(fd, NULL, INT_MAX, MSG_DONTWAIT | MSG_NOSIGNAL | MSG_TRUNC);
|
|
||||||
if (len == -1 && errno == EFAULT)
|
|
||||||
#endif
|
|
||||||
len = recv(fd, trash.area, trash.size,
|
|
||||||
MSG_DONTWAIT | MSG_NOSIGNAL);
|
|
||||||
|
|
||||||
if (len == 0) {
|
|
||||||
/* cool, shutdown received */
|
|
||||||
fdtab[fd].linger_risk = 0;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (len < 0) {
|
|
||||||
if (errno == EAGAIN) {
|
|
||||||
/* connection not closed yet */
|
|
||||||
fd_cant_recv(fd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (errno == EINTR) /* oops, try again */
|
|
||||||
continue;
|
|
||||||
/* other errors indicate a dead connection, fine. */
|
|
||||||
fdtab[fd].linger_risk = 0;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
/* OK we read some data, let's try again once */
|
|
||||||
turns--;
|
|
||||||
}
|
|
||||||
/* some data are still present, give up */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This is the callback which is set when a connection establishment is pending
|
/* This is the callback which is set when a connection establishment is pending
|
||||||
* and we have nothing to send. It updates the FD polling status. It returns 0
|
* and we have nothing to send. It updates the FD polling status. It returns 0
|
||||||
* if it fails in a fatal way or needs to poll to go further, otherwise it
|
* if it fails in a fatal way or needs to poll to go further, otherwise it
|
||||||
|
@ -42,7 +42,6 @@
|
|||||||
#include <proto/listener.h>
|
#include <proto/listener.h>
|
||||||
#include <proto/log.h>
|
#include <proto/log.h>
|
||||||
#include <proto/protocol.h>
|
#include <proto/protocol.h>
|
||||||
#include <proto/proto_tcp.h>
|
|
||||||
#include <proto/task.h>
|
#include <proto/task.h>
|
||||||
|
|
||||||
static int uxst_bind_listener(struct listener *listener, char *errmsg, int errlen);
|
static int uxst_bind_listener(struct listener *listener, char *errmsg, int errlen);
|
||||||
@ -72,7 +71,6 @@ static struct protocol proto_unix = {
|
|||||||
.disable_all = disable_all_listeners,
|
.disable_all = disable_all_listeners,
|
||||||
.get_src = uxst_get_src,
|
.get_src = uxst_get_src,
|
||||||
.get_dst = uxst_get_dst,
|
.get_dst = uxst_get_dst,
|
||||||
.drain = tcp_drain,
|
|
||||||
.pause = uxst_pause_listener,
|
.pause = uxst_pause_listener,
|
||||||
.add = uxst_add_listener,
|
.add = uxst_add_listener,
|
||||||
.listeners = LIST_HEAD_INIT(proto_unix.listeners),
|
.listeners = LIST_HEAD_INIT(proto_unix.listeners),
|
||||||
|
Loading…
Reference in New Issue
Block a user