MAJOR: connection: rearrange the polling flags.

Polling flags were set for data and sock layer, but while this does make
sense for the ENA flag, it does not for the POL flag which translates the
detection of an EAGAIN condition. So now we remove the {DATA,SOCK}_POL*
flags and instead introduce two new layer-independant flags (WANT_RD and
WANT_WR). These flags are only set when an EAGAIN is encountered so that
polling can be enabled.

In order for these flags to have any meaning they are not persistent and
have to be cleared by the connection handler before calling the I/O and
data callbacks. For this reason, changes detection has been slightly
improved. Instead of comparing the WANT_* flags with CURR_*_POL, we only
check if the ENA status changes, or if the polling appears, since we don't
want to detect the useless poll to ena transition. Tests show that this
has eliminated one useless call to __fd_clr().

Finally the conn_set_polling() function which was becoming complex and
required complex operations from the caller was split in two and replaced
its two only callers (conn_update_data_polling and conn_update_sock_polling).
The two functions are now much smaller due to the less complex conditions.
Note that it would be possible to re-merge them and only pass a mask but
this does not appear much interesting.
diff --git a/src/connection.c b/src/connection.c
index 44e675b..6ed4408 100644
--- a/src/connection.c
+++ b/src/connection.c
@@ -28,6 +28,11 @@
 	if (unlikely(!conn))
 		return 0;
 
+	/* before engaging there, we clear the new WAIT_* flags so that we can
+	 * more easily detect an EAGAIN condition from anywhere.
+	 */
+	conn->flags &= ~(CO_FL_WAIT_DATA|CO_FL_WAIT_ROOM|CO_FL_WAIT_RD|CO_FL_WAIT_WR);
+
  process_handshake:
 	/* The handshake callbacks are called in sequence. If either of them is
 	 * missing something, it must enable the required polling at the socket
@@ -115,33 +120,86 @@
 	return 0;
 }
 
-/* set polling depending on the change between the CURR part of the
- * flags and the new flags in connection C. The connection flags are
- * updated with the new flags at the end of the operation. Only the bits
- * relevant to CO_FL_CURR_* from <flags> are considered.
+/* Update polling on connection <c>'s file descriptor depending on its current
+ * state as reported in the connection's CO_FL_CURR_* flags, reports of EAGAIN
+ * in CO_FL_WAIT_*, and the data layer expectations indicated by CO_FL_DATA_*.
+ * The connection flags are updated with the new flags at the end of the
+ * operation.
  */
-void conn_set_polling(struct connection *c, unsigned int new)
+void conn_update_data_polling(struct connection *c)
 {
-	unsigned int old = c->flags; /* for CO_FL_CURR_* */
+	unsigned int f = c->flags;
 
 	/* update read status if needed */
-	if ((old & (CO_FL_CURR_RD_ENA|CO_FL_CURR_RD_POL)) != (CO_FL_CURR_RD_ENA|CO_FL_CURR_RD_POL) &&
-	    (new & (CO_FL_CURR_RD_ENA|CO_FL_CURR_RD_POL)) == (CO_FL_CURR_RD_ENA|CO_FL_CURR_RD_POL))
+	if (unlikely((f & (CO_FL_CURR_RD_ENA|CO_FL_DATA_RD_ENA)) == CO_FL_CURR_RD_ENA)) {
+		f &= ~(CO_FL_CURR_RD_ENA|CO_FL_CURR_RD_POL);
+		fd_stop_recv(c->t.sock.fd);
+	}
+	else if (unlikely((f & (CO_FL_CURR_RD_ENA|CO_FL_CURR_RD_POL)) != (CO_FL_CURR_RD_ENA|CO_FL_CURR_RD_POL) &&
+	                  (f & (CO_FL_DATA_RD_ENA|CO_FL_WAIT_RD)) == (CO_FL_DATA_RD_ENA|CO_FL_WAIT_RD))) {
+		f |= (CO_FL_CURR_RD_ENA|CO_FL_CURR_RD_POL);
 		fd_poll_recv(c->t.sock.fd);
-	else if (!(old & CO_FL_CURR_RD_ENA) && (new & CO_FL_CURR_RD_ENA))
+	}
+	else if (unlikely((f & (CO_FL_CURR_RD_ENA|CO_FL_DATA_RD_ENA)) == CO_FL_DATA_RD_ENA)) {
+		f |= CO_FL_CURR_RD_ENA;
 		fd_want_recv(c->t.sock.fd);
-	else if ((old & CO_FL_CURR_RD_ENA) && !(new & CO_FL_CURR_RD_ENA))
-		fd_stop_recv(c->t.sock.fd);
+	}
 
 	/* update write status if needed */
-	if ((old & (CO_FL_CURR_WR_ENA|CO_FL_CURR_WR_POL)) != (CO_FL_CURR_WR_ENA|CO_FL_CURR_WR_POL) &&
-	    (new & (CO_FL_CURR_WR_ENA|CO_FL_CURR_WR_POL)) == (CO_FL_CURR_WR_ENA|CO_FL_CURR_WR_POL))
+	if (unlikely((f & (CO_FL_CURR_WR_ENA|CO_FL_DATA_WR_ENA)) == CO_FL_CURR_WR_ENA)) {
+		f &= ~(CO_FL_CURR_WR_ENA|CO_FL_CURR_WR_POL);
+		fd_stop_send(c->t.sock.fd);
+	}
+	else if (unlikely((f & (CO_FL_CURR_WR_ENA|CO_FL_CURR_WR_POL)) != (CO_FL_CURR_WR_ENA|CO_FL_CURR_WR_POL) &&
+	                  (f & (CO_FL_DATA_WR_ENA|CO_FL_WAIT_WR)) == (CO_FL_DATA_WR_ENA|CO_FL_WAIT_WR))) {
+		f |= (CO_FL_CURR_WR_ENA|CO_FL_CURR_WR_POL);
 		fd_poll_send(c->t.sock.fd);
-	else if (!(old & CO_FL_CURR_WR_ENA) && (new & CO_FL_CURR_WR_ENA))
+	}
+	else if (unlikely((f & (CO_FL_CURR_WR_ENA|CO_FL_DATA_WR_ENA)) == CO_FL_DATA_WR_ENA)) {
+		f |= CO_FL_CURR_WR_ENA;
 		fd_want_send(c->t.sock.fd);
-	else if ((old & CO_FL_CURR_WR_ENA) && !(new & CO_FL_CURR_WR_ENA))
-		fd_stop_send(c->t.sock.fd);
+	}
+	c->flags = f;
+}
+
+/* Update polling on connection <c>'s file descriptor depending on its current
+ * state as reported in the connection's CO_FL_CURR_* flags, reports of EAGAIN
+ * in CO_FL_WAIT_*, and the sock layer expectations indicated by CO_FL_SOCK_*.
+ * The connection flags are updated with the new flags at the end of the
+ * operation.
+ */
+void conn_update_sock_polling(struct connection *c)
+{
+	unsigned int f = c->flags;
 
-	c->flags &= ~(CO_FL_CURR_WR_POL|CO_FL_CURR_WR_ENA|CO_FL_CURR_RD_POL|CO_FL_CURR_RD_ENA);
-	c->flags |= new & (CO_FL_CURR_WR_POL|CO_FL_CURR_WR_ENA|CO_FL_CURR_RD_POL|CO_FL_CURR_RD_ENA);
+	/* update read status if needed */
+	if (unlikely((f & (CO_FL_CURR_RD_ENA|CO_FL_SOCK_RD_ENA)) == CO_FL_CURR_RD_ENA)) {
+		f &= ~(CO_FL_CURR_RD_ENA|CO_FL_CURR_RD_POL);
+		fd_stop_recv(c->t.sock.fd);
+	}
+	else if (unlikely((f & (CO_FL_CURR_RD_ENA|CO_FL_CURR_RD_POL)) != (CO_FL_CURR_RD_ENA|CO_FL_CURR_RD_POL) &&
+	                  (f & (CO_FL_SOCK_RD_ENA|CO_FL_WAIT_RD)) == (CO_FL_SOCK_RD_ENA|CO_FL_WAIT_RD))) {
+		f |= (CO_FL_CURR_RD_ENA|CO_FL_CURR_RD_POL);
+		fd_poll_recv(c->t.sock.fd);
+	}
+	else if (unlikely((f & (CO_FL_CURR_RD_ENA|CO_FL_SOCK_RD_ENA)) == CO_FL_SOCK_RD_ENA)) {
+		f |= CO_FL_CURR_RD_ENA;
+		fd_want_recv(c->t.sock.fd);
+	}
+
+	/* update write status if needed */
+	if (unlikely((f & (CO_FL_CURR_WR_ENA|CO_FL_SOCK_WR_ENA)) == CO_FL_CURR_WR_ENA)) {
+		f &= ~(CO_FL_CURR_WR_ENA|CO_FL_CURR_WR_POL);
+		fd_stop_send(c->t.sock.fd);
+	}
+	else if (unlikely((f & (CO_FL_CURR_WR_ENA|CO_FL_CURR_WR_POL)) != (CO_FL_CURR_WR_ENA|CO_FL_CURR_WR_POL) &&
+	                  (f & (CO_FL_SOCK_WR_ENA|CO_FL_WAIT_WR)) == (CO_FL_SOCK_WR_ENA|CO_FL_WAIT_WR))) {
+		f |= (CO_FL_CURR_WR_ENA|CO_FL_CURR_WR_POL);
+		fd_poll_send(c->t.sock.fd);
+	}
+	else if (unlikely((f & (CO_FL_CURR_WR_ENA|CO_FL_SOCK_WR_ENA)) == CO_FL_SOCK_WR_ENA)) {
+		f |= CO_FL_CURR_WR_ENA;
+		fd_want_send(c->t.sock.fd);
+	}
+	c->flags = f;
 }