MINOR: protocol: add a ->drain() function at the connection control layer

This is what we need to drain pending incoming data from an connection.
The code was taken from conn_sock_drain() without the connection-specific
stuff. It still takes a connection for now for API simplicity.
diff --git a/src/proto_sockpair.c b/src/proto_sockpair.c
index 7124f56..9c16b2b 100644
--- a/src/proto_sockpair.c
+++ b/src/proto_sockpair.c
@@ -77,6 +77,7 @@
 	.ctrl_init      = sock_conn_ctrl_init,
 	.ctrl_close     = sock_conn_ctrl_close,
 	.connect        = sockpair_connect_server,
+	.drain          = sock_drain,
 
 	/* binding layer */
 	/* Note: suspend/resume not supported */
diff --git a/src/proto_tcp.c b/src/proto_tcp.c
index 4a5e9c2..dcc524d 100644
--- a/src/proto_tcp.c
+++ b/src/proto_tcp.c
@@ -67,6 +67,7 @@
 	.ctrl_init      = sock_conn_ctrl_init,
 	.ctrl_close     = sock_conn_ctrl_close,
 	.connect        = tcp_connect_server,
+	.drain          = sock_drain,
 
 	/* binding layer */
 	.rx_suspend     = tcp_suspend_receiver,
@@ -106,6 +107,7 @@
 	.ctrl_init      = sock_conn_ctrl_init,
 	.ctrl_close     = sock_conn_ctrl_close,
 	.connect        = tcp_connect_server,
+	.drain          = sock_drain,
 
 	/* binding layer */
 	.rx_suspend     = tcp_suspend_receiver,
diff --git a/src/proto_uxst.c b/src/proto_uxst.c
index 1c6ea77..9b1fc38 100644
--- a/src/proto_uxst.c
+++ b/src/proto_uxst.c
@@ -63,6 +63,7 @@
 	.ctrl_init      = sock_conn_ctrl_init,
 	.ctrl_close     = sock_conn_ctrl_close,
 	.connect        = uxst_connect_server,
+	.drain          = sock_drain,
 
 	/* binding layer */
 	.rx_suspend     = uxst_suspend_receiver,
diff --git a/src/sock.c b/src/sock.c
index 5a072f0..cd1e3ff 100644
--- a/src/sock.c
+++ b/src/sock.c
@@ -819,6 +819,59 @@
 	}
 }
 
+/* Drains possibly pending incoming data on the file descriptor attached to the
+ * connection. This is used to know whether we need to disable lingering on
+ * close. Returns non-zero if it is safe to close without disabling lingering,
+ * otherwise zero.
+ */
+int sock_drain(struct connection *conn)
+{
+	int turns = 2;
+	int fd = conn->handle.fd;
+	int len;
+
+	if (fdtab[fd].ev & (FD_POLL_ERR|FD_POLL_HUP))
+		goto shut;
+
+	if (!fd_recv_ready(fd))
+		return 0;
+
+	/* no drain function defined, use the generic one */
+
+	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)
+			goto shut;
+
+		if (len < 0) {
+			if (errno == EAGAIN) {
+				/* connection not closed yet */
+				fd_cant_recv(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[fd].linger_risk = 0;
+	return 1;
+}
+
 /*
  * Local variables:
  *  c-indent-level: 8