9f5ccc
From 2c99b7db00a6238fd43053dd672c8ce519d8fd27 Mon Sep 17 00:00:00 2001
9f5ccc
From: Xavi Hernandez <xhernandez@redhat.com>
9f5ccc
Date: Wed, 11 Dec 2019 18:21:14 +0100
9f5ccc
Subject: [PATCH 341/344] socket: fix error handling
9f5ccc
9f5ccc
When __socket_proto_state_machine() detected a problem in the size of
9f5ccc
the request or it couldn't allocate an iobuf of the requested size, it
9f5ccc
returned -ENOMEM (-12). However the caller was expecting only -1 in
9f5ccc
case of error. For this reason the error passes undetected initially,
9f5ccc
adding back the socket to the epoll object. On further processing,
9f5ccc
however, the error is finally detected and the connection terminated.
9f5ccc
Meanwhile, another thread could receive a poll_in event from the same
9f5ccc
connection, which could cause races with the connection destruction.
9f5ccc
When this happened, the process crashed.
9f5ccc
9f5ccc
To fix this, all error detection conditions have been hardened to be
9f5ccc
more strict on what is valid and what not. Also, we don't return
9f5ccc
-ENOMEM anymore. We always return -1 in case of error.
9f5ccc
9f5ccc
An additional change has been done to prevent destruction of the
9f5ccc
transport object while it may still be needed.
9f5ccc
9f5ccc
Upstream patch:
9f5ccc
> Change-Id: I6e59cd81cbf670f7adfdde942625d4e6c3fbc82d
9f5ccc
> Upstream patch link: https://review.gluster.org/c/glusterfs/+/23861
9f5ccc
> Fixes: bz#1782495
9f5ccc
> Signed-off-by: Xavi Hernandez <xhernandez@redhat.com>
9f5ccc
9f5ccc
Change-Id: I6e59cd81cbf670f7adfdde942625d4e6c3fbc82d
9f5ccc
BUG: 1779696
9f5ccc
Signed-off-by: Xavi Hernandez <xhernandez@redhat.com>
9f5ccc
Reviewed-on: https://code.engineering.redhat.com/gerrit/187689
9f5ccc
Tested-by: RHGS Build Bot <nigelb@redhat.com>
9f5ccc
Reviewed-by: Raghavendra Gowdappa <rgowdapp@redhat.com>
9f5ccc
---
9f5ccc
 rpc/rpc-transport/socket/src/socket.c | 173 ++++++++++++++++++----------------
9f5ccc
 1 file changed, 90 insertions(+), 83 deletions(-)
9f5ccc
9f5ccc
diff --git a/rpc/rpc-transport/socket/src/socket.c b/rpc/rpc-transport/socket/src/socket.c
9f5ccc
index bf2fa71..f54ca83 100644
9f5ccc
--- a/rpc/rpc-transport/socket/src/socket.c
9f5ccc
+++ b/rpc/rpc-transport/socket/src/socket.c
9f5ccc
@@ -173,7 +173,7 @@ ssl_setup_connection_params(rpc_transport_t *this);
9f5ccc
                                                                                \
9f5ccc
         ret = __socket_readv(this, in->pending_vector, 1, &in->pending_vector, \
9f5ccc
                              &in->pending_count, &bytes_read);                 \
9f5ccc
-        if (ret == -1)                                                         \
9f5ccc
+        if (ret < 0)                                                           \
9f5ccc
             break;                                                             \
9f5ccc
         __socket_proto_update_priv_after_read(priv, ret, bytes_read);          \
9f5ccc
     }
9f5ccc
@@ -739,7 +739,7 @@ __socket_rwv(rpc_transport_t *this, struct iovec *vector, int count,
9f5ccc
                 ret = sys_writev(sock, opvector, IOV_MIN(opcount));
9f5ccc
             }
9f5ccc
 
9f5ccc
-            if (ret == 0 || (ret == -1 && errno == EAGAIN)) {
9f5ccc
+            if ((ret == 0) || ((ret < 0) && (errno == EAGAIN))) {
9f5ccc
                 /* done for now */
9f5ccc
                 break;
9f5ccc
             } else if (ret > 0)
9f5ccc
@@ -754,7 +754,7 @@ __socket_rwv(rpc_transport_t *this, struct iovec *vector, int count,
9f5ccc
                 errno = ENODATA;
9f5ccc
                 ret = -1;
9f5ccc
             }
9f5ccc
-            if (ret == -1 && errno == EAGAIN) {
9f5ccc
+            if ((ret < 0) && (errno == EAGAIN)) {
9f5ccc
                 /* done for now */
9f5ccc
                 break;
9f5ccc
             } else if (ret > 0)
9f5ccc
@@ -770,7 +770,7 @@ __socket_rwv(rpc_transport_t *this, struct iovec *vector, int count,
9f5ccc
             errno = ENOTCONN;
9f5ccc
             break;
9f5ccc
         }
9f5ccc
-        if (ret == -1) {
9f5ccc
+        if (ret < 0) {
9f5ccc
             if (errno == EINTR)
9f5ccc
                 continue;
9f5ccc
 
9f5ccc
@@ -907,7 +907,7 @@ __socket_disconnect(rpc_transport_t *this)
9f5ccc
     gf_log(this->name, GF_LOG_TRACE, "disconnecting %p, sock=%d", this,
9f5ccc
            priv->sock);
9f5ccc
 
9f5ccc
-    if (priv->sock != -1) {
9f5ccc
+    if (priv->sock >= 0) {
9f5ccc
         gf_log_callingfn(this->name, GF_LOG_TRACE,
9f5ccc
                          "tearing down socket connection");
9f5ccc
         ret = __socket_teardown_connection(this);
9f5ccc
@@ -942,7 +942,7 @@ __socket_server_bind(rpc_transport_t *this)
9f5ccc
 
9f5ccc
     ret = setsockopt(priv->sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
9f5ccc
 
9f5ccc
-    if (ret == -1) {
9f5ccc
+    if (ret != 0) {
9f5ccc
         gf_log(this->name, GF_LOG_ERROR,
9f5ccc
                "setsockopt() for SO_REUSEADDR failed (%s)", strerror(errno));
9f5ccc
     }
9f5ccc
@@ -955,7 +955,7 @@ __socket_server_bind(rpc_transport_t *this)
9f5ccc
         if (reuse_check_sock >= 0) {
9f5ccc
             ret = connect(reuse_check_sock, SA(&unix_addr),
9f5ccc
                           this->myinfo.sockaddr_len);
9f5ccc
-            if ((ret == -1) && (ECONNREFUSED == errno)) {
9f5ccc
+            if ((ret != 0) && (ECONNREFUSED == errno)) {
9f5ccc
                 sys_unlink(((struct sockaddr_un *)&unix_addr)->sun_path);
9f5ccc
             }
9f5ccc
             gf_log(this->name, GF_LOG_INFO,
9f5ccc
@@ -967,7 +967,7 @@ __socket_server_bind(rpc_transport_t *this)
9f5ccc
     ret = bind(priv->sock, (struct sockaddr *)&this->myinfo.sockaddr,
9f5ccc
                this->myinfo.sockaddr_len);
9f5ccc
 
9f5ccc
-    if (ret == -1) {
9f5ccc
+    if (ret != 0) {
9f5ccc
         gf_log(this->name, GF_LOG_ERROR, "binding to %s failed: %s",
9f5ccc
                this->myinfo.identifier, strerror(errno));
9f5ccc
         if (errno == EADDRINUSE) {
9f5ccc
@@ -976,7 +976,7 @@ __socket_server_bind(rpc_transport_t *this)
9f5ccc
     }
9f5ccc
     if (AF_UNIX != SA(&this->myinfo.sockaddr)->sa_family) {
9f5ccc
         if (getsockname(priv->sock, SA(&this->myinfo.sockaddr),
9f5ccc
-                        &this->myinfo.sockaddr_len) == -1) {
9f5ccc
+                        &this->myinfo.sockaddr_len) != 0) {
9f5ccc
             gf_log(this->name, GF_LOG_WARNING,
9f5ccc
                    "getsockname on (%d) failed (%s)", priv->sock,
9f5ccc
                    strerror(errno));
9f5ccc
@@ -1004,7 +1004,7 @@ __socket_nonblock(int fd)
9f5ccc
 
9f5ccc
     flags = fcntl(fd, F_GETFL);
9f5ccc
 
9f5ccc
-    if (flags != -1)
9f5ccc
+    if (flags >= 0)
9f5ccc
         ret = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
9f5ccc
 
9f5ccc
     return ret;
9f5ccc
@@ -1034,7 +1034,7 @@ __socket_keepalive(int fd, int family, int keepaliveintvl, int keepaliveidle,
9f5ccc
 #endif
9f5ccc
 
9f5ccc
     ret = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on));
9f5ccc
-    if (ret == -1) {
9f5ccc
+    if (ret != 0) {
9f5ccc
         gf_log("socket", GF_LOG_WARNING,
9f5ccc
                "failed to set keep alive option on socket %d", fd);
9f5ccc
         goto err;
9f5ccc
@@ -1051,7 +1051,7 @@ __socket_keepalive(int fd, int family, int keepaliveintvl, int keepaliveidle,
9f5ccc
     ret = setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &keepaliveintvl,
9f5ccc
                      sizeof(keepaliveintvl));
9f5ccc
 #endif
9f5ccc
-    if (ret == -1) {
9f5ccc
+    if (ret != 0) {
9f5ccc
         gf_log("socket", GF_LOG_WARNING,
9f5ccc
                "failed to set keep alive interval on socket %d", fd);
9f5ccc
         goto err;
9f5ccc
@@ -1062,7 +1062,7 @@ __socket_keepalive(int fd, int family, int keepaliveintvl, int keepaliveidle,
9f5ccc
 
9f5ccc
     ret = setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &keepaliveidle,
9f5ccc
                      sizeof(keepaliveidle));
9f5ccc
-    if (ret == -1) {
9f5ccc
+    if (ret != 0) {
9f5ccc
         gf_log("socket", GF_LOG_WARNING,
9f5ccc
                "failed to set keep idle %d on socket %d, %s", keepaliveidle, fd,
9f5ccc
                strerror(errno));
9f5ccc
@@ -1070,7 +1070,7 @@ __socket_keepalive(int fd, int family, int keepaliveintvl, int keepaliveidle,
9f5ccc
     }
9f5ccc
     ret = setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &keepaliveintvl,
9f5ccc
                      sizeof(keepaliveintvl));
9f5ccc
-    if (ret == -1) {
9f5ccc
+    if (ret != 0) {
9f5ccc
         gf_log("socket", GF_LOG_WARNING,
9f5ccc
                "failed to set keep interval %d on socket %d, %s",
9f5ccc
                keepaliveintvl, fd, strerror(errno));
9f5ccc
@@ -1082,7 +1082,7 @@ __socket_keepalive(int fd, int family, int keepaliveintvl, int keepaliveidle,
9f5ccc
         goto done;
9f5ccc
     ret = setsockopt(fd, IPPROTO_TCP, TCP_USER_TIMEOUT, &timeout_ms,
9f5ccc
                      sizeof(timeout_ms));
9f5ccc
-    if (ret == -1) {
9f5ccc
+    if (ret != 0) {
9f5ccc
         gf_log("socket", GF_LOG_WARNING,
9f5ccc
                "failed to set "
9f5ccc
                "TCP_USER_TIMEOUT %d on socket %d, %s",
9f5ccc
@@ -1093,7 +1093,7 @@ __socket_keepalive(int fd, int family, int keepaliveintvl, int keepaliveidle,
9f5ccc
 #if defined(TCP_KEEPCNT)
9f5ccc
     ret = setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &keepalivecnt,
9f5ccc
                      sizeof(keepalivecnt));
9f5ccc
-    if (ret == -1) {
9f5ccc
+    if (ret != 0) {
9f5ccc
         gf_log("socket", GF_LOG_WARNING,
9f5ccc
                "failed to set "
9f5ccc
                "TCP_KEEPCNT %d on socket %d, %s",
9f5ccc
@@ -1366,7 +1366,7 @@ socket_event_poll_err(rpc_transport_t *this, int gen, int idx)
9f5ccc
 
9f5ccc
     pthread_mutex_lock(&priv->out_lock);
9f5ccc
     {
9f5ccc
-        if ((priv->gen == gen) && (priv->idx == idx) && (priv->sock != -1)) {
9f5ccc
+        if ((priv->gen == gen) && (priv->idx == idx) && (priv->sock >= 0)) {
9f5ccc
             __socket_ioq_flush(this);
9f5ccc
             __socket_reset(this);
9f5ccc
             socket_closed = _gf_true;
9f5ccc
@@ -1405,7 +1405,7 @@ socket_event_poll_out(rpc_transport_t *this)
9f5ccc
         if (priv->connected == 1) {
9f5ccc
             ret = __socket_ioq_churn(this);
9f5ccc
 
9f5ccc
-            if (ret == -1) {
9f5ccc
+            if (ret < 0) {
9f5ccc
                 gf_log(this->name, GF_LOG_TRACE,
9f5ccc
                        "__socket_ioq_churn returned -1; "
9f5ccc
                        "disconnecting socket");
9f5ccc
@@ -1463,7 +1463,7 @@ __socket_read_simple_msg(rpc_transport_t *this)
9f5ccc
                                      &bytes_read);
9f5ccc
             }
9f5ccc
 
9f5ccc
-            if (ret == -1) {
9f5ccc
+            if (ret < 0) {
9f5ccc
                 gf_log(this->name, GF_LOG_WARNING,
9f5ccc
                        "reading from socket failed. Error (%s), "
9f5ccc
                        "peer (%s)",
9f5ccc
@@ -1661,8 +1661,8 @@ __socket_read_vectored_request(rpc_transport_t *this,
9f5ccc
 
9f5ccc
             remaining_size = RPC_FRAGSIZE(in->fraghdr) - frag->bytes_read;
9f5ccc
 
9f5ccc
-            if ((ret == -1) || ((ret == 0) && (remaining_size == 0) &&
9f5ccc
-                                RPC_LASTFRAG(in->fraghdr))) {
9f5ccc
+            if ((ret < 0) || ((ret == 0) && (remaining_size == 0) &&
9f5ccc
+                              RPC_LASTFRAG(in->fraghdr))) {
9f5ccc
                 request->vector_state = SP_STATE_VECTORED_REQUEST_INIT;
9f5ccc
                 in->payload_vector.iov_len = ((unsigned long)frag->fragcurrent -
9f5ccc
                                               (unsigned long)
9f5ccc
@@ -1739,8 +1739,8 @@ __socket_read_request(rpc_transport_t *this)
9f5ccc
 
9f5ccc
             remaining_size = RPC_FRAGSIZE(in->fraghdr) - frag->bytes_read;
9f5ccc
 
9f5ccc
-            if ((ret == -1) || ((ret == 0) && (remaining_size == 0) &&
9f5ccc
-                                (RPC_LASTFRAG(in->fraghdr)))) {
9f5ccc
+            if ((ret < 0) || ((ret == 0) && (remaining_size == 0) &&
9f5ccc
+                              (RPC_LASTFRAG(in->fraghdr)))) {
9f5ccc
                 request->header_state = SP_STATE_REQUEST_HEADER_INIT;
9f5ccc
             }
9f5ccc
 
9f5ccc
@@ -1870,8 +1870,8 @@ __socket_read_accepted_successful_reply(rpc_transport_t *this)
9f5ccc
             /* now read the entire remaining msg into new iobuf */
9f5ccc
             ret = __socket_read_simple_msg(this);
9f5ccc
             remaining_size = RPC_FRAGSIZE(in->fraghdr) - frag->bytes_read;
9f5ccc
-            if ((ret == -1) || ((ret == 0) && (remaining_size == 0) &&
9f5ccc
-                                RPC_LASTFRAG(in->fraghdr))) {
9f5ccc
+            if ((ret < 0) || ((ret == 0) && (remaining_size == 0) &&
9f5ccc
+                              RPC_LASTFRAG(in->fraghdr))) {
9f5ccc
                 frag->call_body.reply.accepted_success_state =
9f5ccc
                     SP_STATE_ACCEPTED_SUCCESS_REPLY_INIT;
9f5ccc
             }
9f5ccc
@@ -2003,8 +2003,8 @@ __socket_read_accepted_successful_reply_v2(rpc_transport_t *this)
9f5ccc
             /* now read the entire remaining msg into new iobuf */
9f5ccc
             ret = __socket_read_simple_msg(this);
9f5ccc
             remaining_size = RPC_FRAGSIZE(in->fraghdr) - frag->bytes_read;
9f5ccc
-            if ((ret == -1) || ((ret == 0) && (remaining_size == 0) &&
9f5ccc
-                                RPC_LASTFRAG(in->fraghdr))) {
9f5ccc
+            if ((ret < 0) || ((ret == 0) && (remaining_size == 0) &&
9f5ccc
+                              RPC_LASTFRAG(in->fraghdr))) {
9f5ccc
                 frag->call_body.reply.accepted_success_state =
9f5ccc
                     SP_STATE_ACCEPTED_SUCCESS_REPLY_INIT;
9f5ccc
             }
9f5ccc
@@ -2103,8 +2103,8 @@ __socket_read_accepted_reply(rpc_transport_t *this)
9f5ccc
 
9f5ccc
             remaining_size = RPC_FRAGSIZE(in->fraghdr) - frag->bytes_read;
9f5ccc
 
9f5ccc
-            if ((ret == -1) || ((ret == 0) && (remaining_size == 0) &&
9f5ccc
-                                (RPC_LASTFRAG(in->fraghdr)))) {
9f5ccc
+            if ((ret < 0) || ((ret == 0) && (remaining_size == 0) &&
9f5ccc
+                              (RPC_LASTFRAG(in->fraghdr)))) {
9f5ccc
                 frag->call_body.reply
9f5ccc
                     .accepted_state = SP_STATE_ACCEPTED_REPLY_INIT;
9f5ccc
             }
9f5ccc
@@ -2169,8 +2169,8 @@ __socket_read_vectored_reply(rpc_transport_t *this)
9f5ccc
 
9f5ccc
             remaining_size = RPC_FRAGSIZE(in->fraghdr) - frag->bytes_read;
9f5ccc
 
9f5ccc
-            if ((ret == -1) || ((ret == 0) && (remaining_size == 0) &&
9f5ccc
-                                (RPC_LASTFRAG(in->fraghdr)))) {
9f5ccc
+            if ((ret < 0) || ((ret == 0) && (remaining_size == 0) &&
9f5ccc
+                              (RPC_LASTFRAG(in->fraghdr)))) {
9f5ccc
                 frag->call_body.reply
9f5ccc
                     .status_state = SP_STATE_VECTORED_REPLY_STATUS_INIT;
9f5ccc
                 in->payload_vector.iov_len = (unsigned long)frag->fragcurrent -
9f5ccc
@@ -2237,7 +2237,7 @@ __socket_read_reply(rpc_transport_t *this)
9f5ccc
         /* Transition back to externally visible state. */
9f5ccc
         frag->state = SP_STATE_READ_MSGTYPE;
9f5ccc
 
9f5ccc
-        if (ret == -1) {
9f5ccc
+        if (ret < 0) {
9f5ccc
             gf_log(this->name, GF_LOG_WARNING,
9f5ccc
                    "notify for event MAP_XID failed for %s",
9f5ccc
                    this->peerinfo.identifier);
9f5ccc
@@ -2315,8 +2315,8 @@ __socket_read_frag(rpc_transport_t *this)
9f5ccc
 
9f5ccc
             remaining_size = RPC_FRAGSIZE(in->fraghdr) - frag->bytes_read;
9f5ccc
 
9f5ccc
-            if ((ret == -1) || ((ret == 0) && (remaining_size == 0) &&
9f5ccc
-                                (RPC_LASTFRAG(in->fraghdr)))) {
9f5ccc
+            if ((ret < 0) || ((ret == 0) && (remaining_size == 0) &&
9f5ccc
+                              (RPC_LASTFRAG(in->fraghdr)))) {
9f5ccc
                 /* frag->state = SP_STATE_NADA; */
9f5ccc
                 frag->state = SP_STATE_RPCFRAG_INIT;
9f5ccc
             }
9f5ccc
@@ -2400,7 +2400,7 @@ __socket_proto_state_machine(rpc_transport_t *this,
9f5ccc
                 ret = __socket_readv(this, in->pending_vector, 1,
9f5ccc
                                      &in->pending_vector, &in->pending_count,
9f5ccc
                                      NULL);
9f5ccc
-                if (ret == -1)
9f5ccc
+                if (ret < 0)
9f5ccc
                     goto out;
9f5ccc
 
9f5ccc
                 if (ret > 0) {
9f5ccc
@@ -2422,7 +2422,7 @@ __socket_proto_state_machine(rpc_transport_t *this,
9f5ccc
                 in->total_bytes_read += RPC_FRAGSIZE(in->fraghdr);
9f5ccc
 
9f5ccc
                 if (in->total_bytes_read >= GF_UNIT_GB) {
9f5ccc
-                    ret = -ENOMEM;
9f5ccc
+                    ret = -1;
9f5ccc
                     goto out;
9f5ccc
                 }
9f5ccc
 
9f5ccc
@@ -2430,7 +2430,7 @@ __socket_proto_state_machine(rpc_transport_t *this,
9f5ccc
                     this->ctx->iobuf_pool,
9f5ccc
                     (in->total_bytes_read + sizeof(in->fraghdr)));
9f5ccc
                 if (!iobuf) {
9f5ccc
-                    ret = -ENOMEM;
9f5ccc
+                    ret = -1;
9f5ccc
                     goto out;
9f5ccc
                 }
9f5ccc
 
9f5ccc
@@ -2457,7 +2457,7 @@ __socket_proto_state_machine(rpc_transport_t *this,
9f5ccc
             case SP_STATE_READING_FRAG:
9f5ccc
                 ret = __socket_read_frag(this);
9f5ccc
 
9f5ccc
-                if ((ret == -1) ||
9f5ccc
+                if ((ret < 0) ||
9f5ccc
                     (frag->bytes_read != RPC_FRAGSIZE(in->fraghdr))) {
9f5ccc
                     goto out;
9f5ccc
                 }
9f5ccc
@@ -2575,7 +2575,7 @@ socket_event_poll_in(rpc_transport_t *this, gf_boolean_t notify_handled)
9f5ccc
         pthread_mutex_unlock(&priv->notify.lock);
9f5ccc
     }
9f5ccc
 
9f5ccc
-    if (notify_handled && (ret != -1))
9f5ccc
+    if (notify_handled && (ret >= 0))
9f5ccc
         event_handled(ctx->event_pool, priv->sock, priv->idx, priv->gen);
9f5ccc
 
9f5ccc
     if (pollin) {
9f5ccc
@@ -2618,10 +2618,10 @@ socket_connect_finish(rpc_transport_t *this)
9f5ccc
 
9f5ccc
         ret = __socket_connect_finish(priv->sock);
9f5ccc
 
9f5ccc
-        if (ret == -1 && errno == EINPROGRESS)
9f5ccc
+        if ((ret < 0) && (errno == EINPROGRESS))
9f5ccc
             ret = 1;
9f5ccc
 
9f5ccc
-        if (ret == -1 && errno != EINPROGRESS) {
9f5ccc
+        if ((ret < 0) && (errno != EINPROGRESS)) {
9f5ccc
             if (!priv->connect_finish_log) {
9f5ccc
                 gf_log(this->name, GF_LOG_ERROR,
9f5ccc
                        "connection to %s failed (%s); "
9f5ccc
@@ -2640,7 +2640,7 @@ socket_connect_finish(rpc_transport_t *this)
9f5ccc
 
9f5ccc
             ret = getsockname(priv->sock, SA(&this->myinfo.sockaddr),
9f5ccc
                               &this->myinfo.sockaddr_len);
9f5ccc
-            if (ret == -1) {
9f5ccc
+            if (ret != 0) {
9f5ccc
                 gf_log(this->name, GF_LOG_WARNING,
9f5ccc
                        "getsockname on (%d) failed (%s) - "
9f5ccc
                        "disconnecting socket",
9f5ccc
@@ -2924,6 +2924,13 @@ socket_event_handler(int fd, int idx, int gen, void *data, int poll_in,
9f5ccc
         return;
9f5ccc
     }
9f5ccc
 
9f5ccc
+    /* At this point we are sure no other thread is using the transport because
9f5ccc
+     * we cannot receive more events until we call gf_event_handled(). However
9f5ccc
+     * this function may call gf_event_handled() in some cases. When this is
9f5ccc
+     * done, the transport may be destroyed at any moment if another thread
9f5ccc
+     * handled an error event. To prevent that we take a reference here. */
9f5ccc
+    rpc_transport_ref(this);
9f5ccc
+
9f5ccc
     GF_VALIDATE_OR_GOTO("socket", this, out);
9f5ccc
     GF_VALIDATE_OR_GOTO("socket", this->private, out);
9f5ccc
     GF_VALIDATE_OR_GOTO("socket", this->xl, out);
9f5ccc
@@ -2960,7 +2967,7 @@ socket_event_handler(int fd, int idx, int gen, void *data, int poll_in,
9f5ccc
             if (ret > 0) {
9f5ccc
                 gf_log(this->name, GF_LOG_TRACE,
9f5ccc
                        "(sock:%d) returning to wait on socket", priv->sock);
9f5ccc
-                return;
9f5ccc
+                goto out;
9f5ccc
             }
9f5ccc
         } else {
9f5ccc
             char *sock_type = (priv->is_server ? "Server" : "Client");
9f5ccc
@@ -3015,7 +3022,7 @@ socket_event_handler(int fd, int idx, int gen, void *data, int poll_in,
9f5ccc
     }
9f5ccc
 
9f5ccc
 out:
9f5ccc
-    return;
9f5ccc
+    rpc_transport_unref(this);
9f5ccc
 }
9f5ccc
 
9f5ccc
 static void
9f5ccc
@@ -3074,7 +3081,7 @@ socket_server_event_handler(int fd, int idx, int gen, void *data, int poll_in,
9f5ccc
 
9f5ccc
         event_handled(ctx->event_pool, fd, idx, gen);
9f5ccc
 
9f5ccc
-        if (new_sock == -1) {
9f5ccc
+        if (new_sock < 0) {
9f5ccc
             gf_log(this->name, GF_LOG_WARNING, "accept on %d failed (%s)",
9f5ccc
                    priv->sock, strerror(errno));
9f5ccc
             goto out;
9f5ccc
@@ -3082,7 +3089,7 @@ socket_server_event_handler(int fd, int idx, int gen, void *data, int poll_in,
9f5ccc
 
9f5ccc
         if (priv->nodelay && (new_sockaddr.ss_family != AF_UNIX)) {
9f5ccc
             ret = __socket_nodelay(new_sock);
9f5ccc
-            if (ret == -1) {
9f5ccc
+            if (ret != 0) {
9f5ccc
                 gf_log(this->name, GF_LOG_WARNING,
9f5ccc
                        "setsockopt() failed for "
9f5ccc
                        "NODELAY (%s)",
9f5ccc
@@ -3094,7 +3101,7 @@ socket_server_event_handler(int fd, int idx, int gen, void *data, int poll_in,
9f5ccc
             ret = __socket_keepalive(new_sock, new_sockaddr.ss_family,
9f5ccc
                                      priv->keepaliveintvl, priv->keepaliveidle,
9f5ccc
                                      priv->keepalivecnt, priv->timeout);
9f5ccc
-            if (ret == -1)
9f5ccc
+            if (ret != 0)
9f5ccc
                 gf_log(this->name, GF_LOG_WARNING,
9f5ccc
                        "Failed to set keep-alive: %s", strerror(errno));
9f5ccc
         }
9f5ccc
@@ -3110,7 +3117,7 @@ socket_server_event_handler(int fd, int idx, int gen, void *data, int poll_in,
9f5ccc
         }
9f5ccc
 
9f5ccc
         ret = pthread_mutex_init(&new_trans->lock, NULL);
9f5ccc
-        if (ret == -1) {
9f5ccc
+        if (ret != 0) {
9f5ccc
             gf_log(this->name, GF_LOG_WARNING,
9f5ccc
                    "pthread_mutex_init() failed: %s; closing newly accepted "
9f5ccc
                    "socket %d",
9f5ccc
@@ -3130,7 +3137,7 @@ socket_server_event_handler(int fd, int idx, int gen, void *data, int poll_in,
9f5ccc
 
9f5ccc
         ret = getsockname(new_sock, SA(&new_trans->myinfo.sockaddr),
9f5ccc
                           &new_trans->myinfo.sockaddr_len);
9f5ccc
-        if (ret == -1) {
9f5ccc
+        if (ret != 0) {
9f5ccc
             gf_log(this->name, GF_LOG_WARNING,
9f5ccc
                    "getsockname on socket %d "
9f5ccc
                    "failed (errno:%s); closing newly accepted socket",
9f5ccc
@@ -3237,7 +3244,7 @@ socket_server_event_handler(int fd, int idx, int gen, void *data, int poll_in,
9f5ccc
              */
9f5ccc
             ret = rpc_transport_notify(this, RPC_TRANSPORT_ACCEPT, new_trans);
9f5ccc
 
9f5ccc
-            if (ret != -1) {
9f5ccc
+            if (ret >= 0) {
9f5ccc
                 new_priv->idx = event_register(
9f5ccc
                     ctx->event_pool, new_sock, socket_event_handler, new_trans,
9f5ccc
                     1, 0, new_trans->notify_poller_death);
9f5ccc
@@ -3275,7 +3282,7 @@ socket_server_event_handler(int fd, int idx, int gen, void *data, int poll_in,
9f5ccc
             rpc_transport_unref(new_trans);
9f5ccc
         }
9f5ccc
 
9f5ccc
-        if (ret == -1) {
9f5ccc
+        if (ret < 0) {
9f5ccc
             gf_log(this->name, GF_LOG_WARNING, "closing newly accepted socket");
9f5ccc
             sys_close(new_sock);
9f5ccc
             /* this unref is to actually cause the destruction of
9f5ccc
@@ -3406,7 +3413,7 @@ socket_connect(rpc_transport_t *this, int port)
9f5ccc
 
9f5ccc
     pthread_mutex_lock(&priv->out_lock);
9f5ccc
     {
9f5ccc
-        if (priv->sock != -1) {
9f5ccc
+        if (priv->sock >= 0) {
9f5ccc
             gf_log_callingfn(this->name, GF_LOG_TRACE,
9f5ccc
                              "connect () called on transport "
9f5ccc
                              "already connected");
9f5ccc
@@ -3420,7 +3427,7 @@ socket_connect(rpc_transport_t *this, int port)
9f5ccc
 
9f5ccc
         ret = socket_client_get_remote_sockaddr(this, &sock_union.sa,
9f5ccc
                                                 &sockaddr_len, &sa_family);
9f5ccc
-        if (ret == -1) {
9f5ccc
+        if (ret < 0) {
9f5ccc
             /* logged inside client_get_remote_sockaddr */
9f5ccc
             goto unlock;
9f5ccc
         }
9f5ccc
@@ -3439,7 +3446,7 @@ socket_connect(rpc_transport_t *this, int port)
9f5ccc
         this->peerinfo.sockaddr_len = sockaddr_len;
9f5ccc
 
9f5ccc
         priv->sock = sys_socket(sa_family, SOCK_STREAM, 0);
9f5ccc
-        if (priv->sock == -1) {
9f5ccc
+        if (priv->sock < 0) {
9f5ccc
             gf_log(this->name, GF_LOG_ERROR, "socket creation failed (%s)",
9f5ccc
                    strerror(errno));
9f5ccc
             ret = -1;
9f5ccc
@@ -3451,7 +3458,7 @@ socket_connect(rpc_transport_t *this, int port)
9f5ccc
          */
9f5ccc
         if (priv->windowsize != 0) {
9f5ccc
             if (setsockopt(priv->sock, SOL_SOCKET, SO_RCVBUF, &priv->windowsize,
9f5ccc
-                           sizeof(priv->windowsize)) < 0) {
9f5ccc
+                           sizeof(priv->windowsize)) != 0) {
9f5ccc
                 gf_log(this->name, GF_LOG_ERROR,
9f5ccc
                        "setting receive window "
9f5ccc
                        "size failed: %d: %d: %s",
9f5ccc
@@ -3459,7 +3466,7 @@ socket_connect(rpc_transport_t *this, int port)
9f5ccc
             }
9f5ccc
 
9f5ccc
             if (setsockopt(priv->sock, SOL_SOCKET, SO_SNDBUF, &priv->windowsize,
9f5ccc
-                           sizeof(priv->windowsize)) < 0) {
9f5ccc
+                           sizeof(priv->windowsize)) != 0) {
9f5ccc
                 gf_log(this->name, GF_LOG_ERROR,
9f5ccc
                        "setting send window size "
9f5ccc
                        "failed: %d: %d: %s",
9f5ccc
@@ -3484,7 +3491,7 @@ socket_connect(rpc_transport_t *this, int port)
9f5ccc
         if (priv->nodelay && (sa_family != AF_UNIX)) {
9f5ccc
             ret = __socket_nodelay(priv->sock);
9f5ccc
 
9f5ccc
-            if (ret == -1) {
9f5ccc
+            if (ret != 0) {
9f5ccc
                 gf_log(this->name, GF_LOG_ERROR, "NODELAY on %d failed (%s)",
9f5ccc
                        priv->sock, strerror(errno));
9f5ccc
             }
9f5ccc
@@ -3494,7 +3501,7 @@ socket_connect(rpc_transport_t *this, int port)
9f5ccc
             ret = __socket_keepalive(priv->sock, sa_family,
9f5ccc
                                      priv->keepaliveintvl, priv->keepaliveidle,
9f5ccc
                                      priv->keepalivecnt, priv->timeout);
9f5ccc
-            if (ret == -1)
9f5ccc
+            if (ret != 0)
9f5ccc
                 gf_log(this->name, GF_LOG_ERROR, "Failed to set keep-alive: %s",
9f5ccc
                        strerror(errno));
9f5ccc
         }
9f5ccc
@@ -3516,7 +3523,7 @@ socket_connect(rpc_transport_t *this, int port)
9f5ccc
 
9f5ccc
         ret = client_bind(this, SA(&this->myinfo.sockaddr),
9f5ccc
                           &this->myinfo.sockaddr_len, priv->sock);
9f5ccc
-        if (ret == -1) {
9f5ccc
+        if (ret < 0) {
9f5ccc
             gf_log(this->name, GF_LOG_WARNING, "client bind failed: %s",
9f5ccc
                    strerror(errno));
9f5ccc
             goto handler;
9f5ccc
@@ -3525,7 +3532,7 @@ socket_connect(rpc_transport_t *this, int port)
9f5ccc
         /* make socket non-blocking for all types of sockets */
9f5ccc
         if (!priv->bio) {
9f5ccc
             ret = __socket_nonblock(priv->sock);
9f5ccc
-            if (ret == -1) {
9f5ccc
+            if (ret != 0) {
9f5ccc
                 gf_log(this->name, GF_LOG_ERROR, "NBIO on %d failed (%s)",
9f5ccc
                        priv->sock, strerror(errno));
9f5ccc
                 goto handler;
9f5ccc
@@ -3552,7 +3559,7 @@ socket_connect(rpc_transport_t *this, int port)
9f5ccc
 
9f5ccc
         connect_attempted = _gf_true;
9f5ccc
 
9f5ccc
-        if (ret == -1 && errno == ENOENT && ign_enoent) {
9f5ccc
+        if ((ret != 0) && (errno == ENOENT) && ign_enoent) {
9f5ccc
             gf_log(this->name, GF_LOG_WARNING,
9f5ccc
                    "Ignore failed connection attempt on %s, (%s) ",
9f5ccc
                    this->peerinfo.identifier, strerror(errno));
9f5ccc
@@ -3570,7 +3577,7 @@ socket_connect(rpc_transport_t *this, int port)
9f5ccc
             goto handler;
9f5ccc
         }
9f5ccc
 
9f5ccc
-        if (ret == -1 && ((errno != EINPROGRESS) && (errno != ENOENT))) {
9f5ccc
+        if ((ret != 0) && (errno != EINPROGRESS) && (errno != ENOENT)) {
9f5ccc
             /* For unix path based sockets, the socket path is
9f5ccc
              * cryptic (md5sum of path) and may not be useful for
9f5ccc
              * the user in debugging so log it in DEBUG
9f5ccc
@@ -3634,8 +3641,8 @@ socket_connect(rpc_transport_t *this, int port)
9f5ccc
     pthread_mutex_unlock(&priv->out_lock);
9f5ccc
 
9f5ccc
 err:
9f5ccc
-    /* if sock != -1, then cleanup is done from the event handler */
9f5ccc
-    if (ret == -1 && sock == -1) {
9f5ccc
+    /* if sock >= 0, then cleanup is done from the event handler */
9f5ccc
+    if ((ret < 0) && (sock < 0)) {
9f5ccc
         /* Cleaup requires to send notification to upper layer which
9f5ccc
            intern holds the big_lock. There can be dead-lock situation
9f5ccc
            if big_lock is already held by the current thread.
9f5ccc
@@ -3689,20 +3696,20 @@ socket_listen(rpc_transport_t *this)
9f5ccc
     }
9f5ccc
     pthread_mutex_unlock(&priv->out_lock);
9f5ccc
 
9f5ccc
-    if (sock != -1) {
9f5ccc
+    if (sock >= 0) {
9f5ccc
         gf_log_callingfn(this->name, GF_LOG_DEBUG, "already listening");
9f5ccc
         return ret;
9f5ccc
     }
9f5ccc
 
9f5ccc
     ret = socket_server_get_local_sockaddr(this, SA(&sockaddr), &sockaddr_len,
9f5ccc
                                            &sa_family);
9f5ccc
-    if (ret == -1) {
9f5ccc
+    if (ret < 0) {
9f5ccc
         return ret;
9f5ccc
     }
9f5ccc
 
9f5ccc
     pthread_mutex_lock(&priv->out_lock);
9f5ccc
     {
9f5ccc
-        if (priv->sock != -1) {
9f5ccc
+        if (priv->sock >= 0) {
9f5ccc
             gf_log(this->name, GF_LOG_DEBUG, "already listening");
9f5ccc
             goto unlock;
9f5ccc
         }
9f5ccc
@@ -3712,7 +3719,7 @@ socket_listen(rpc_transport_t *this)
9f5ccc
 
9f5ccc
         priv->sock = sys_socket(sa_family, SOCK_STREAM, 0);
9f5ccc
 
9f5ccc
-        if (priv->sock == -1) {
9f5ccc
+        if (priv->sock < 0) {
9f5ccc
             gf_log(this->name, GF_LOG_ERROR, "socket creation failed (%s)",
9f5ccc
                    strerror(errno));
9f5ccc
             goto unlock;
9f5ccc
@@ -3723,7 +3730,7 @@ socket_listen(rpc_transport_t *this)
9f5ccc
          */
9f5ccc
         if (priv->windowsize != 0) {
9f5ccc
             if (setsockopt(priv->sock, SOL_SOCKET, SO_RCVBUF, &priv->windowsize,
9f5ccc
-                           sizeof(priv->windowsize)) < 0) {
9f5ccc
+                           sizeof(priv->windowsize)) != 0) {
9f5ccc
                 gf_log(this->name, GF_LOG_ERROR,
9f5ccc
                        "setting receive window size "
9f5ccc
                        "failed: %d: %d: %s",
9f5ccc
@@ -3731,7 +3738,7 @@ socket_listen(rpc_transport_t *this)
9f5ccc
             }
9f5ccc
 
9f5ccc
             if (setsockopt(priv->sock, SOL_SOCKET, SO_SNDBUF, &priv->windowsize,
9f5ccc
-                           sizeof(priv->windowsize)) < 0) {
9f5ccc
+                           sizeof(priv->windowsize)) != 0) {
9f5ccc
                 gf_log(this->name, GF_LOG_ERROR,
9f5ccc
                        "setting send window size failed:"
9f5ccc
                        " %d: %d: %s",
9f5ccc
@@ -3741,7 +3748,7 @@ socket_listen(rpc_transport_t *this)
9f5ccc
 
9f5ccc
         if (priv->nodelay && (sa_family != AF_UNIX)) {
9f5ccc
             ret = __socket_nodelay(priv->sock);
9f5ccc
-            if (ret == -1) {
9f5ccc
+            if (ret != 0) {
9f5ccc
                 gf_log(this->name, GF_LOG_ERROR,
9f5ccc
                        "setsockopt() failed for NODELAY (%s)", strerror(errno));
9f5ccc
             }
9f5ccc
@@ -3750,7 +3757,7 @@ socket_listen(rpc_transport_t *this)
9f5ccc
         if (!priv->bio) {
9f5ccc
             ret = __socket_nonblock(priv->sock);
9f5ccc
 
9f5ccc
-            if (ret == -1) {
9f5ccc
+            if (ret != 0) {
9f5ccc
                 gf_log(this->name, GF_LOG_ERROR,
9f5ccc
                        "NBIO on socket %d failed "
9f5ccc
                        "(errno:%s); closing socket",
9f5ccc
@@ -3763,7 +3770,7 @@ socket_listen(rpc_transport_t *this)
9f5ccc
 
9f5ccc
         ret = __socket_server_bind(this);
9f5ccc
 
9f5ccc
-        if ((ret == -EADDRINUSE) || (ret == -1)) {
9f5ccc
+        if (ret < 0) {
9f5ccc
             /* logged inside __socket_server_bind() */
9f5ccc
             gf_log(this->name, GF_LOG_ERROR,
9f5ccc
                    "__socket_server_bind failed;"
9f5ccc
@@ -3779,7 +3786,7 @@ socket_listen(rpc_transport_t *this)
9f5ccc
 
9f5ccc
         ret = listen(priv->sock, priv->backlog);
9f5ccc
 
9f5ccc
-        if (ret == -1) {
9f5ccc
+        if (ret != 0) {
9f5ccc
             gf_log(this->name, GF_LOG_ERROR,
9f5ccc
                    "could not set socket %d to listen mode (errno:%s); "
9f5ccc
                    "closing socket",
9f5ccc
@@ -4025,7 +4032,7 @@ reconfigure(rpc_transport_t *this, dict_t *options)
9f5ccc
     priv = this->private;
9f5ccc
 
9f5ccc
     if (dict_get_str(options, "transport.socket.keepalive", &optstr) == 0) {
9f5ccc
-        if (gf_string2boolean(optstr, &tmp_bool) == -1) {
9f5ccc
+        if (gf_string2boolean(optstr, &tmp_bool) != 0) {
9f5ccc
             gf_log(this->name, GF_LOG_ERROR,
9f5ccc
                    "'transport.socket.keepalive' takes only "
9f5ccc
                    "boolean options, not taking any action");
9f5ccc
@@ -4094,7 +4101,7 @@ reconfigure(rpc_transport_t *this, dict_t *options)
9f5ccc
     if (dict_get(options, "non-blocking-io")) {
9f5ccc
         optstr = data_to_str(dict_get(options, "non-blocking-io"));
9f5ccc
 
9f5ccc
-        if (gf_string2boolean(optstr, &tmp_bool) == -1) {
9f5ccc
+        if (gf_string2boolean(optstr, &tmp_bool) != 0) {
9f5ccc
             gf_log(this->name, GF_LOG_ERROR,
9f5ccc
                    "'non-blocking-io' takes only boolean options,"
9f5ccc
                    " not taking any action");
9f5ccc
@@ -4109,7 +4116,7 @@ reconfigure(rpc_transport_t *this, dict_t *options)
9f5ccc
 
9f5ccc
     if (!priv->bio) {
9f5ccc
         ret = __socket_nonblock(priv->sock);
9f5ccc
-        if (ret == -1) {
9f5ccc
+        if (ret != 0) {
9f5ccc
             gf_log(this->name, GF_LOG_WARNING, "NBIO on %d failed (%s)",
9f5ccc
                    priv->sock, strerror(errno));
9f5ccc
             goto out;
9f5ccc
@@ -4508,7 +4515,7 @@ socket_init(rpc_transport_t *this)
9f5ccc
     if (dict_get(this->options, "non-blocking-io")) {
9f5ccc
         optstr = data_to_str(dict_get(this->options, "non-blocking-io"));
9f5ccc
 
9f5ccc
-        if (gf_string2boolean(optstr, &tmp_bool) == -1) {
9f5ccc
+        if (gf_string2boolean(optstr, &tmp_bool) != 0) {
9f5ccc
             gf_log(this->name, GF_LOG_ERROR,
9f5ccc
                    "'non-blocking-io' takes only boolean options,"
9f5ccc
                    " not taking any action");
9f5ccc
@@ -4528,7 +4535,7 @@ socket_init(rpc_transport_t *this)
9f5ccc
         optstr = data_to_str(
9f5ccc
             dict_get(this->options, "transport.socket.nodelay"));
9f5ccc
 
9f5ccc
-        if (gf_string2boolean(optstr, &tmp_bool) == -1) {
9f5ccc
+        if (gf_string2boolean(optstr, &tmp_bool) != 0) {
9f5ccc
             gf_log(this->name, GF_LOG_ERROR,
9f5ccc
                    "'transport.socket.nodelay' takes only "
9f5ccc
                    "boolean options, not taking any action");
9f5ccc
@@ -4559,7 +4566,7 @@ socket_init(rpc_transport_t *this)
9f5ccc
     priv->keepalivecnt = GF_KEEPALIVE_COUNT;
9f5ccc
     if (dict_get_str(this->options, "transport.socket.keepalive", &optstr) ==
9f5ccc
         0) {
9f5ccc
-        if (gf_string2boolean(optstr, &tmp_bool) == -1) {
9f5ccc
+        if (gf_string2boolean(optstr, &tmp_bool) != 0) {
9f5ccc
             gf_log(this->name, GF_LOG_ERROR,
9f5ccc
                    "'transport.socket.keepalive' takes only "
9f5ccc
                    "boolean options, not taking any action");
9f5ccc
@@ -4609,7 +4616,7 @@ socket_init(rpc_transport_t *this)
9f5ccc
     if (dict_get(this->options, "transport.socket.read-fail-log")) {
9f5ccc
         optstr = data_to_str(
9f5ccc
             dict_get(this->options, "transport.socket.read-fail-log"));
9f5ccc
-        if (gf_string2boolean(optstr, &tmp_bool) == -1) {
9f5ccc
+        if (gf_string2boolean(optstr, &tmp_bool) != 0) {
9f5ccc
             gf_log(this->name, GF_LOG_WARNING,
9f5ccc
                    "'transport.socket.read-fail-log' takes only "
9f5ccc
                    "boolean options; logging socket read fails");
9f5ccc
@@ -4646,7 +4653,7 @@ fini(rpc_transport_t *this)
9f5ccc
 
9f5ccc
     priv = this->private;
9f5ccc
     if (priv) {
9f5ccc
-        if (priv->sock != -1) {
9f5ccc
+        if (priv->sock >= 0) {
9f5ccc
             pthread_mutex_lock(&priv->out_lock);
9f5ccc
             {
9f5ccc
                 __socket_ioq_flush(this);
9f5ccc
@@ -4683,7 +4690,7 @@ init(rpc_transport_t *this)
9f5ccc
 
9f5ccc
     ret = socket_init(this);
9f5ccc
 
9f5ccc
-    if (ret == -1) {
9f5ccc
+    if (ret < 0) {
9f5ccc
         gf_log(this->name, GF_LOG_DEBUG, "socket_init() failed");
9f5ccc
     }
9f5ccc
 
9f5ccc
-- 
9f5ccc
1.8.3.1
9f5ccc