CLEANUP: remove the now unused fdtab direct I/O callbacks

They were all left to NULL since last commit so we can safely remove them
all now and remove the temporary dual polling logic in pollers.
diff --git a/include/types/fd.h b/include/types/fd.h
index 54a78d6..684b77a 100644
--- a/include/types/fd.h
+++ b/include/types/fd.h
@@ -66,9 +66,6 @@
 /* info about one given fd */
 struct fdtab {
 	int (*iocb)(int fd);                 /* I/O handler, returns FD_WAIT_* */
-	struct {
-		int (*f)(int fd);            /* read/write function */
-	} cb[DIR_SIZE];
 	void *owner;                         /* the connection or listener associated with this fd, NULL if closed */
 	struct {                             /* used by pollers which support speculative polling */
 		unsigned char e;             /* read and write events status. 4 bits, may be merged into flags' lower bits */
diff --git a/src/checks.c b/src/checks.c
index d386168..f63edef 100644
--- a/src/checks.c
+++ b/src/checks.c
@@ -1482,8 +1482,6 @@
 						s->check_conn->flags = CO_FL_WAIT_L4_CONN; /* TCP connection pending */
 						fd_insert(fd);
 						fdtab[fd].owner = t;
-						fdtab[fd].cb[DIR_RD].f = NULL;
-						fdtab[fd].cb[DIR_WR].f = NULL;
 						fdtab[fd].iocb = &check_iocb;
 						fdtab[fd].flags = FD_FL_TCP | FD_FL_TCP_NODELAY;
 						EV_FD_SET(fd, DIR_WR);  /* for connect status */
diff --git a/src/ev_epoll.c b/src/ev_epoll.c
index 589932f..63782d3 100644
--- a/src/ev_epoll.c
+++ b/src/ev_epoll.c
@@ -245,6 +245,9 @@
 		int e = epoll_events[count].events;
 		fd = epoll_events[count].data.fd;
 
+		if (!fdtab[fd].owner)
+			continue;
+
 		/* it looks complicated but gcc can optimize it away when constants
 		 * have same values.
 		 */
@@ -256,22 +259,6 @@
 			((e & EPOLLERR) ? FD_POLL_ERR : 0) |
 			((e & EPOLLHUP) ? FD_POLL_HUP : 0);
 
-		if ((fd_evts[FD2OFS(fd)] >> FD2BIT(fd)) & DIR2MSK(DIR_RD)) {
-			if (!fdtab[fd].owner)
-				continue;
-			if (fdtab[fd].ev & (FD_POLL_IN|FD_POLL_HUP|FD_POLL_ERR))
-				if (fdtab[fd].cb[DIR_RD].f)
-					fdtab[fd].cb[DIR_RD].f(fd);
-		}
-
-		if ((fd_evts[FD2OFS(fd)] >> FD2BIT(fd)) & DIR2MSK(DIR_WR)) {
-			if (!fdtab[fd].owner)
-				continue;
-			if (fdtab[fd].ev & (FD_POLL_OUT|FD_POLL_ERR|FD_POLL_HUP))
-				if (fdtab[fd].cb[DIR_WR].f)
-					fdtab[fd].cb[DIR_WR].f(fd);
-		}
-
 		if (fdtab[fd].iocb && fdtab[fd].owner && fdtab[fd].ev)
 			fdtab[fd].iocb(fd);
 	}
diff --git a/src/ev_kqueue.c b/src/ev_kqueue.c
index 556abcc..3d12e36 100644
--- a/src/ev_kqueue.c
+++ b/src/ev_kqueue.c
@@ -139,25 +139,20 @@
 	for (count = 0; count < status; count++) {
 		fd = kev[count].ident;
 
+		if (!fdtab[fd].owner)
+			continue;
+
 		fdtab[fd].ev &= FD_POLL_STICKY;
 		if (kev[count].filter ==  EVFILT_READ) {
 			if (FD_ISSET(fd, fd_evts[DIR_RD])) {
-				if (!fdtab[fd].owner)
-					continue;
 				fdtab[fd].ev |= FD_POLL_IN;
-				if (fdtab[fd].cb[DIR_RD].f)
-					fdtab[fd].cb[DIR_RD].f(fd);
 			}
 		} else if (kev[count].filter ==  EVFILT_WRITE) {
 			if (FD_ISSET(fd, fd_evts[DIR_WR])) {
-				if (!fdtab[fd].owner)
-					continue;
 				fdtab[fd].ev |= FD_POLL_OUT;
-				if (fdtab[fd].cb[DIR_WR].f)
-					fdtab[fd].cb[DIR_WR].f(fd)
 			}
 		}
-		if (fdtab[fd].iocb && fdtab[fd].owner && fdtab[fd].ev)
+		if (fdtab[fd].iocb && fdtab[fd].ev)
 			fdtab[fd].iocb(fd);
 	}
 }
diff --git a/src/ev_poll.c b/src/ev_poll.c
index 015ff76..cb210f7 100644
--- a/src/ev_poll.c
+++ b/src/ev_poll.c
@@ -149,6 +149,12 @@
 		if (!(e & ( POLLOUT | POLLIN | POLLERR | POLLHUP )))
 			continue;
 
+		/* ok, we found one active fd */
+		status--;
+
+		if (!fdtab[fd].owner)
+			continue;
+
 		fdtab[fd].ev &= FD_POLL_STICKY;
 		fdtab[fd].ev |=
 			((e & POLLIN ) ? FD_POLL_IN  : 0) |
@@ -156,25 +162,6 @@
 			((e & POLLERR) ? FD_POLL_ERR : 0) |
 			((e & POLLHUP) ? FD_POLL_HUP : 0);
 
-		/* ok, we found one active fd */
-		status--;
-
-		if (FD_ISSET(fd, fd_evts[DIR_RD])) {
-			if (!fdtab[fd].owner)
-				continue;
-			if (fdtab[fd].ev & (FD_POLL_IN|FD_POLL_HUP|FD_POLL_ERR))
-				if (fdtab[fd].cb[DIR_RD].f)
-					fdtab[fd].cb[DIR_RD].f(fd);
-		}
-	  
-		if (FD_ISSET(fd, fd_evts[DIR_WR])) {
-			if (!fdtab[fd].owner)
-				continue;
-			if (fdtab[fd].ev & (FD_POLL_OUT|FD_POLL_ERR|FD_POLL_HUP))
-				if (fdtab[fd].cb[DIR_WR].f)
-					fdtab[fd].cb[DIR_WR].f(fd);
-		}
-
 		if (fdtab[fd].iocb && fdtab[fd].owner && fdtab[fd].ev)
 			fdtab[fd].iocb(fd);
 	}
diff --git a/src/ev_select.c b/src/ev_select.c
index b1c41bc..c5d3936 100644
--- a/src/ev_select.c
+++ b/src/ev_select.c
@@ -146,22 +146,15 @@
 			/* if we specify read first, the accepts and zero reads will be
 			 * seen first. Moreover, system buffers will be flushed faster.
 			 */
+			if (!fdtab[fd].owner)
+				continue;
+
 			fdtab[fd].ev &= FD_POLL_STICKY;
-			if (FD_ISSET(fd, tmp_evts[DIR_RD])) {
-				if (!fdtab[fd].owner)
-					continue;
+			if (FD_ISSET(fd, tmp_evts[DIR_RD]))
 				fdtab[fd].ev |= FD_POLL_IN;
-				if (fdtab[fd].cb[DIR_RD].f)
-					fdtab[fd].cb[DIR_RD].f(fd);
-			}
 
-			if (FD_ISSET(fd, tmp_evts[DIR_WR])) {
-				if (!fdtab[fd].owner)
-					continue;
+			if (FD_ISSET(fd, tmp_evts[DIR_WR]))
 				fdtab[fd].ev |= FD_POLL_OUT;
-				if (fdtab[fd].cb[DIR_WR].f)
-					fdtab[fd].cb[DIR_WR].f(fd);
-			}
 
 			if (fdtab[fd].iocb && fdtab[fd].owner && fdtab[fd].ev)
 				fdtab[fd].iocb(fd);
diff --git a/src/ev_sepoll.c b/src/ev_sepoll.c
index 55c81ea..5d93bf2 100644
--- a/src/ev_sepoll.c
+++ b/src/ev_sepoll.c
@@ -398,6 +398,9 @@
 		int e = epoll_events[count].events;
 		fd = epoll_events[count].data.fd;
 
+		if (!fdtab[fd].owner)
+			continue;
+
 		/* it looks complicated but gcc can optimize it away when constants
 		 * have same values.
 		 */
@@ -409,22 +412,6 @@
 			((e & EPOLLERR) ? FD_POLL_ERR : 0) |
 			((e & EPOLLHUP) ? FD_POLL_HUP : 0);
 
-		if ((fdtab[fd].spec.e & FD_EV_MASK_R) == FD_EV_WAIT_R) {
-			if (!fdtab[fd].owner)
-				continue;
-			if (fdtab[fd].ev & (FD_POLL_IN|FD_POLL_HUP|FD_POLL_ERR))
-				if (fdtab[fd].cb[DIR_RD].f)
-					fdtab[fd].cb[DIR_RD].f(fd);
-		}
-
-		if ((fdtab[fd].spec.e & FD_EV_MASK_W) == FD_EV_WAIT_W) {
-			if (!fdtab[fd].owner)
-				continue;
-			if (fdtab[fd].ev & (FD_POLL_OUT|FD_POLL_ERR))
-				if (fdtab[fd].cb[DIR_WR].f)
-					fdtab[fd].cb[DIR_WR].f(fd);
-		}
-
 		if (fdtab[fd].iocb && fdtab[fd].owner && fdtab[fd].ev)
 			fdtab[fd].iocb(fd);
 	}
@@ -455,21 +442,11 @@
 		 */
 
 		fdtab[fd].ev &= FD_POLL_STICKY;
-		if ((eo & FD_EV_MASK_R) == FD_EV_SPEC_R) {
-			/* The owner is interested in reading from this FD */
-			/* Pretend there is something to read */
+		if ((eo & FD_EV_MASK_R) == FD_EV_SPEC_R)
 			fdtab[fd].ev |= FD_POLL_IN;
-			if (fdtab[fd].cb[DIR_RD].f && !fdtab[fd].cb[DIR_RD].f(fd))
-				fdtab[fd].spec.e ^= (FD_EV_WAIT_R ^ FD_EV_SPEC_R);
-		}
 
-		if ((eo & FD_EV_MASK_W) == FD_EV_SPEC_W) {
-			/* The owner is interested in writing to this FD */
-			/* Pretend there is something to write */
+		if ((eo & FD_EV_MASK_W) == FD_EV_SPEC_W)
 			fdtab[fd].ev |= FD_POLL_OUT;
-			if (fdtab[fd].cb[DIR_WR].f && !fdtab[fd].cb[DIR_WR].f(fd))
-				fdtab[fd].spec.e ^= (FD_EV_WAIT_W ^ FD_EV_SPEC_W);
-		}
 
 		if (fdtab[fd].iocb && fdtab[fd].owner && fdtab[fd].ev) {
 			int wait = fdtab[fd].iocb(fd);
diff --git a/src/proto_tcp.c b/src/proto_tcp.c
index db2fe03..c1a3e6f 100644
--- a/src/proto_tcp.c
+++ b/src/proto_tcp.c
@@ -468,14 +468,7 @@
 	fdtab[fd].flags = FD_FL_TCP | FD_FL_TCP_NODELAY;
 	si->conn.flags  = CO_FL_WAIT_L4_CONN; /* connection in progress */
 
-	/* Prepare to send a few handshakes related to the on-wire protocol.
-	 * If we have nothing to send, we want to confirm that the TCP
-	 * connection is established before doing so, so we use our own write
-	 * callback then switch to the sock layer.
-	 */
-	fdtab[fd].cb[DIR_RD].f = NULL;
-	fdtab[fd].cb[DIR_WR].f = NULL;
-
+	/* 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;
 
@@ -575,11 +568,10 @@
 	 */
 	b->flags |= BF_WRITE_NULL;
 
-	/* The FD is ready now, we can hand the handlers to the socket layer
-	 * and forward the event there to start working on the socket.
+	/* The FD is ready now, we'll mark the connection as complete and
+	 * forward the event to the data layer which will update the stream
+	 * interface flags.
 	 */
-	fdtab[fd].cb[DIR_RD].f = NULL;
-	fdtab[fd].cb[DIR_WR].f = NULL;
 	conn->flags &= ~CO_FL_WAIT_L4_CONN;
 	si->exp = TICK_ETERNITY;
 	return si_data(si)->write(fd);
@@ -739,8 +731,6 @@
 	fdtab[fd].owner = listener; /* reference the listener instead of a task */
 	fdtab[fd].flags = FD_FL_TCP | ((listener->options & LI_O_NOLINGER) ? FD_FL_TCP_NOLING : 0);
 	fdtab[fd].iocb = listener->proto->accept;
-	fdtab[fd].cb[DIR_RD].f = NULL; /* never called */
-	fdtab[fd].cb[DIR_WR].f = NULL; /* never called */
 	fd_insert(fd);
 
  tcp_return:
diff --git a/src/proto_uxst.c b/src/proto_uxst.c
index b1484b6..bd0d788 100644
--- a/src/proto_uxst.c
+++ b/src/proto_uxst.c
@@ -263,8 +263,6 @@
 	/* the function for the accept() event */
 	fd_insert(fd);
 	fdtab[fd].iocb = listener->proto->accept;
-	fdtab[fd].cb[DIR_RD].f = NULL; /* never called */
-	fdtab[fd].cb[DIR_WR].f = NULL; /* never called */
 	fdtab[fd].owner = listener; /* reference the listener instead of a task */
 	return ERR_NONE;
  err_rename:
diff --git a/src/session.c b/src/session.c
index 998270b..8c649e7 100644
--- a/src/session.c
+++ b/src/session.c
@@ -283,8 +283,6 @@
 	fd_insert(cfd);
 	fdtab[cfd].owner = &s->si[0].conn;
 	fdtab[cfd].flags = 0;
-	fdtab[cfd].cb[DIR_RD].f = NULL;
-	fdtab[cfd].cb[DIR_WR].f = NULL;
 	fdtab[cfd].iocb = conn_fd_handler;
 	EV_FD_SET(cfd, DIR_RD);