async_req: check for errors when monitoring socket for readability
authorUri Simchoni <urisimchoni@gmail.com>
Thu, 25 Jun 2015 06:46:24 +0000 (09:46 +0300)
committerJeremy Allison <jra@samba.org>
Wed, 15 Jul 2015 20:41:13 +0000 (22:41 +0200)
Add an option to wait_for_read_send(), so that the request, upon
calling back, report whether the socket actually contains data
or is in EOF/error state. EOF is signalled via the EPIPE error.

This is useful for clients which do not expect data to arrive but
wait for readability to detect a closed socket (i.e. they do not
intend to actually read the socket when it's readable). Actual data
arrival would indicate a bug in this case, so the check can
be used to print an error message.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11397

Signed-off-by: Uri Simchoni <urisimchoni@gmail.com>
Reviewed-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Volker Lendecke <vl@samba.org>
lib/async_req/async_sock.c
lib/async_req/async_sock.h
source3/smbd/process.c
source3/winbindd/winbindd.c

index d2cda15..bc3780c 100644 (file)
@@ -534,6 +534,8 @@ ssize_t read_packet_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
 
 struct wait_for_read_state {
        struct tevent_fd *fde;
+       int fd;
+       bool check_errors;
 };
 
 static void wait_for_read_cleanup(struct tevent_req *req,
@@ -544,8 +546,8 @@ static void wait_for_read_done(struct tevent_context *ev,
                               void *private_data);
 
 struct tevent_req *wait_for_read_send(TALLOC_CTX *mem_ctx,
-                                     struct tevent_context *ev,
-                                     int fd)
+                                     struct tevent_context *ev, int fd,
+                                     bool check_errors)
 {
        struct tevent_req *req;
        struct wait_for_read_state *state;
@@ -562,6 +564,9 @@ struct tevent_req *wait_for_read_send(TALLOC_CTX *mem_ctx,
        if (tevent_req_nomem(state->fde, req)) {
                return tevent_req_post(req, ev);
        }
+
+       state->fd = fd;
+       state->check_errors = check_errors;
        return req;
 }
 
@@ -581,10 +586,44 @@ static void wait_for_read_done(struct tevent_context *ev,
 {
        struct tevent_req *req = talloc_get_type_abort(
                private_data, struct tevent_req);
+       struct wait_for_read_state *state =
+           tevent_req_data(req, struct wait_for_read_state);
+       ssize_t nread;
+       char c;
 
-       if (flags & TEVENT_FD_READ) {
+       if ((flags & TEVENT_FD_READ) == 0) {
+               return;
+       }
+
+       if (!state->check_errors) {
                tevent_req_done(req);
+               return;
        }
+
+       nread = recv(state->fd, &c, 1, MSG_PEEK);
+
+       if (nread == 0) {
+               tevent_req_error(req, EPIPE);
+               return;
+       }
+
+       if ((nread == -1) && (errno == EINTR)) {
+               /* come back later */
+               return;
+       }
+
+       if ((nread == -1) && (errno == ENOTSOCK)) {
+               /* Ignore this specific error on pipes */
+               tevent_req_done(req);
+               return;
+       }
+
+       if (nread == -1) {
+               tevent_req_error(req, errno);
+               return;
+       }
+
+       tevent_req_done(req);
 }
 
 bool wait_for_read_recv(struct tevent_req *req, int *perr)
index 1b76fab..abbf822 100644 (file)
@@ -53,8 +53,8 @@ ssize_t read_packet_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
                         uint8_t **pbuf, int *perrno);
 
 struct tevent_req *wait_for_read_send(TALLOC_CTX *mem_ctx,
-                                     struct tevent_context *ev,
-                                     int fd);
+                                     struct tevent_context *ev, int fd,
+                                     bool check_errors);
 bool wait_for_read_recv(struct tevent_req *req, int *perr);
 
 #endif
index 12ce0d1..6c8a31c 100644 (file)
@@ -2859,7 +2859,7 @@ static struct tevent_req *smbd_echo_read_send(
        state->ev = ev;
        state->xconn = xconn;
 
-       subreq = wait_for_read_send(state, ev, xconn->transport.sock);
+       subreq = wait_for_read_send(state, ev, xconn->transport.sock, false);
        if (tevent_req_nomem(subreq, req)) {
                return tevent_req_post(req, ev);
        }
@@ -2934,7 +2934,7 @@ static void smbd_echo_read_waited(struct tevent_req *subreq)
                }
 
                subreq = wait_for_read_send(state, state->ev,
-                                           xconn->transport.sock);
+                                           xconn->transport.sock, false);
                if (tevent_req_nomem(subreq, req)) {
                        return;
                }
index a03b5b4..07faadf 100644 (file)
@@ -972,7 +972,8 @@ static void winbind_client_request_read(struct tevent_req *req)
                return;
        }
 
-       req = wait_for_read_send(state, winbind_event_context(), state->sock);
+       req = wait_for_read_send(state, winbind_event_context(), state->sock,
+                                false);
        if (req == NULL) {
                DEBUG(0, ("winbind_client_request_read[%d:%s]:"
                          " wait_for_read_send failed - removing client\n",