Fix: partial recv lead to client disconnect
authorJonathan Rajotte <jonathan.rajotte-julien@efficios.com>
Thu, 9 Jul 2020 18:57:57 +0000 (14:57 -0400)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Mon, 27 Jul 2020 20:29:25 +0000 (16:29 -0400)
On EWOULDBLOCK and EAGAIN, the ret value from
`lttcomm_send_unix_sock_non_block` and
`lttcomm_recv_unix_sock_non_block` would be equal to -1.

Solution
=====

For such cases, set ret equal to zero since it is effectively what was
received/sent. Caller should treat ret  >= 0 as `success` anyway.

Signed-off-by: Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
Change-Id: I47677f26850bf544f672d270972de7cc2c6a2817

src/bin/lttng-sessiond/notification-thread-events.c
src/common/unix.c

index 2cb6ad68ab814b63bc77c2792c17e5a05c147a0f..7b86fb39c3902e2ac15d8aecae3d38dffea9ef85 100644 (file)
@@ -2564,8 +2564,7 @@ int client_flush_outgoing_queue(struct notification_client *client,
        ret = lttcomm_send_unix_sock_non_block(client->socket,
                        client->communication.outbound.buffer.data,
                        to_send_count);
-       if ((ret < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) ||
-                       (ret > 0 && ret < to_send_count)) {
+       if ((ret >= 0 && ret < to_send_count)) {
                DBG("[notification-thread] Client (socket fd = %i) outgoing queue could not be completely flushed",
                                client->socket);
                to_send_count -= max(ret, 0);
index 26eda52d97d1ad992c7b534b461c121eee9b6d00..df92b7a0698ef699ed31a5bbc82b6741362cedfb 100644 (file)
@@ -210,6 +210,9 @@ ssize_t lttcomm_recv_unix_sock(int sock, void *buf, size_t len)
  * Receive data of size len in put that data into the buf param. Using recvmsg
  * API. Only use with sockets set in non-blocking mode.
  *
+ * NOTE: EPIPE errors are NOT reported. This call expects the socket to be in a
+ * poll set. The poll loop will handle the EPIPE original cause.
+ *
  * Return the size of received data.
  */
 LTTNG_HIDDEN
@@ -232,11 +235,21 @@ retry:
                if (errno == EINTR) {
                        goto retry;
                } else {
-                       /* We consider EPIPE and EAGAIN as expected. */
-                       if (!lttng_opt_quiet &&
-                                       (errno != EPIPE && errno != EAGAIN)) {
-                               PERROR("recvmsg");
+                       /*
+                        * We consider EPIPE and EAGAIN/EWOULDBLOCK as expected.
+                        */
+                       if (errno == EAGAIN || errno == EWOULDBLOCK ||
+                                       errno == EPIPE) {
+                               /*
+                                * Nothing was recv.
+                                */
+                               ret = 0;
+                               goto end;
                        }
+
+                       /* Unexpected error */
+                       PERROR("recvmsg");
+                       ret = -1;
                        goto end;
                }
        }
@@ -295,6 +308,9 @@ end:
  * of the function is that this one does not retry to send on partial sends,
  * except if the interruption was caused by a signal (EINTR).
  *
+ * NOTE: EPIPE errors are NOT reported. This call expects the socket to be in a
+ * poll set. The poll loop will handle the EPIPE original cause.
+ *
  * Return the size of sent data.
  */
 LTTNG_HIDDEN
@@ -317,11 +333,22 @@ retry:
                if (errno == EINTR) {
                        goto retry;
                } else {
-                       /* We consider EPIPE and EAGAIN as expected. */
-                       if (!lttng_opt_quiet &&
-                                       (errno != EPIPE && errno != EAGAIN)) {
-                               PERROR("sendmsg");
+                       /*
+                        * We consider EPIPE and EAGAIN/EWOULDBLOCK as expected.
+                        */
+                       if (errno == EAGAIN || errno == EWOULDBLOCK ||
+                                       errno == EPIPE) {
+                               /*
+                                * This can happen in non blocking mode.
+                                * Nothing was sent.
+                                */
+                               ret = 0;
+                               goto end;
                        }
+
+                       /* Unexpected error */
+                       PERROR("sendmsg");
+                       ret = -1;
                        goto end;
                }
        }
This page took 0.04037 seconds and 4 git commands to generate.