Repository: kudu
Updated Branches:
  refs/heads/master abbde75e1 -> 1f380f279


KUDU-2351 Add IP/port for Recv() failure

Error messages like "Recv() got EOF from remote", "recv error:" and
"BlockingRecv error: failed to read from TLS socket" don't contain the
remote address, making it hard to locate the server the connection
failed to.

This change introduces adds the peer's IP address and port number to
these error messages.

Examples:

Recv() got EOF from remote 127.0.0.1:7050
recv error from 127.0.0.1:7050: Resource temporarily unavailable
BlockingRecv error: failed to read from TLS socket (remote: \
127.0.0.1:7050): Can't send after socket shutdown

Change-Id: I22436b13bb351b132e1c0b7159294dd0c980c2b3
Reviewed-on: http://gerrit.cloudera.org:8080/9818
Tested-by: Kudu Jenkins
Reviewed-by: Dan Burkert <danburk...@apache.org>


Project: http://git-wip-us.apache.org/repos/asf/kudu/repo
Commit: http://git-wip-us.apache.org/repos/asf/kudu/commit/1f380f27
Tree: http://git-wip-us.apache.org/repos/asf/kudu/tree/1f380f27
Diff: http://git-wip-us.apache.org/repos/asf/kudu/diff/1f380f27

Branch: refs/heads/master
Commit: 1f380f27960021b267766fcefb6764e95e1d98dc
Parents: abbde75
Author: Attila Bukor <abu...@cloudera.com>
Authored: Thu Apr 19 21:18:45 2018 +0200
Committer: Dan Burkert <danburk...@apache.org>
Committed: Thu Apr 19 20:07:16 2018 +0000

----------------------------------------------------------------------
 src/kudu/security/tls_socket-test.cc | 30 +++++++++++
 src/kudu/security/tls_socket.cc      | 11 +++-
 src/kudu/util/CMakeLists.txt         |  1 +
 src/kudu/util/net/socket-test.cc     | 89 +++++++++++++++++++++++++++++++
 src/kudu/util/net/socket.cc          | 12 +++--
 5 files changed, 138 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/kudu/blob/1f380f27/src/kudu/security/tls_socket-test.cc
----------------------------------------------------------------------
diff --git a/src/kudu/security/tls_socket-test.cc 
b/src/kudu/security/tls_socket-test.cc
index db4ff9b..001a206 100644
--- a/src/kudu/security/tls_socket-test.cc
+++ b/src/kudu/security/tls_socket-test.cc
@@ -45,6 +45,7 @@
 #include "kudu/util/random.h"
 #include "kudu/util/random_util.h"
 #include "kudu/util/scoped_cleanup.h"
+#include "kudu/util/slice.h"
 #include "kudu/util/status.h"
 #include "kudu/util/test_macros.h"
 #include "kudu/util/test_util.h"
@@ -171,6 +172,8 @@ class EchoServer {
             SleepFor(MonoDelta::FromMilliseconds(10));
           }
         }
+
+        CHECK_OK(listener_.Close());
       });
   }
 
@@ -212,6 +215,33 @@ class EchoServer {
 
 void handler(int /* signal */) {}
 
+TEST_F(TlsSocketTest, TestRecvFailure) {
+    EchoServer server;
+    server.Start();
+    unique_ptr<Socket> client_sock;
+    NO_FATALS(ConnectClient(server.listen_addr(), &client_sock));
+    unique_ptr<uint8_t[]> buf(new uint8_t[kEchoChunkSize]);
+
+    SleepFor(MonoDelta::FromMilliseconds(100));
+    server.Stop();
+
+    size_t nwritten;
+    ASSERT_OK(client_sock->BlockingWrite(buf.get(), kEchoChunkSize, &nwritten,
+        MonoTime::Now() + kTimeout));
+    size_t nread;
+
+    ASSERT_OK(client_sock->BlockingRecv(buf.get(), kEchoChunkSize, &nread,
+        MonoTime::Now() + kTimeout));
+
+    Status s = client_sock->BlockingRecv(buf.get(), kEchoChunkSize, &nread,
+        MonoTime::Now() + kTimeout);
+
+    ASSERT_TRUE(!s.ok());
+    ASSERT_TRUE(s.IsNetworkError());
+    ASSERT_STR_MATCHES(s.message().ToString(), "BlockingRecv error: failed to 
read from "
+                                               "TLS socket \\(remote: 
127.0.0.1:[0-9]+\\): ");
+}
+
 // Test for failures to handle EINTR during TLS connection
 // negotiation and data send/receive.
 TEST_F(TlsSocketTest, TestTlsSocketInterrupted) {

http://git-wip-us.apache.org/repos/asf/kudu/blob/1f380f27/src/kudu/security/tls_socket.cc
----------------------------------------------------------------------
diff --git a/src/kudu/security/tls_socket.cc b/src/kudu/security/tls_socket.cc
index 4fce907..355f04b 100644
--- a/src/kudu/security/tls_socket.cc
+++ b/src/kudu/security/tls_socket.cc
@@ -20,14 +20,17 @@
 #include <sys/uio.h>
 
 #include <cerrno>
+#include <string>
 #include <utility>
 
 #include <glog/logging.h>
 #include <openssl/err.h>
 
 #include "kudu/gutil/basictypes.h"
+#include "kudu/gutil/strings/substitute.h"
 #include "kudu/security/openssl_util.h"
 #include "kudu/util/errno.h"
+#include "kudu/util/net/sockaddr.h"
 #include "kudu/util/net/socket.h"
 
 namespace kudu {
@@ -104,20 +107,24 @@ Status TlsSocket::Writev(const struct ::iovec *iov, int 
iov_len, int64_t *nwritt
 
 Status TlsSocket::Recv(uint8_t *buf, int32_t amt, int32_t *nread) {
   SCOPED_OPENSSL_NO_PENDING_ERRORS;
-  const char* kErrString = "failed to read from TLS socket";
 
   CHECK(ssl_);
   errno = 0;
   int32_t bytes_read = SSL_read(ssl_.get(), buf, amt);
   int save_errno = errno;
   if (bytes_read <= 0) {
+    Sockaddr remote;
+    Socket::GetPeerAddress(&remote);
+    std::string kErrString = strings::Substitute("failed to read from TLS 
socket (remote: $0)",
+                                                 remote.ToString());
+
     if (bytes_read == 0 && SSL_get_shutdown(ssl_.get()) == 
SSL_RECEIVED_SHUTDOWN) {
       return Status::NetworkError(kErrString, ErrnoToString(ESHUTDOWN), 
ESHUTDOWN);
     }
     auto error_code = SSL_get_error(ssl_.get(), bytes_read);
     if (error_code == SSL_ERROR_WANT_READ) {
       if (save_errno != 0) {
-        return Status::NetworkError("SSL_read error",
+        return Status::NetworkError("SSL_read error from " + remote.ToString(),
                                     ErrnoToString(save_errno), save_errno);
       }
       // Nothing available to read yet.

http://git-wip-us.apache.org/repos/asf/kudu/blob/1f380f27/src/kudu/util/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/src/kudu/util/CMakeLists.txt b/src/kudu/util/CMakeLists.txt
index c91a780..1302d30 100644
--- a/src/kudu/util/CMakeLists.txt
+++ b/src/kudu/util/CMakeLists.txt
@@ -372,6 +372,7 @@ ADD_KUDU_TEST(mt-metrics-test RUN_SERIAL true)
 ADD_KUDU_TEST(mt-threadlocal-test RUN_SERIAL true)
 ADD_KUDU_TEST(net/dns_resolver-test)
 ADD_KUDU_TEST(net/net_util-test)
+ADD_KUDU_TEST(net/socket-test)
 ADD_KUDU_TEST(object_pool-test)
 ADD_KUDU_TEST(oid_generator-test)
 ADD_KUDU_TEST(once-test)

http://git-wip-us.apache.org/repos/asf/kudu/blob/1f380f27/src/kudu/util/net/socket-test.cc
----------------------------------------------------------------------
diff --git a/src/kudu/util/net/socket-test.cc b/src/kudu/util/net/socket-test.cc
new file mode 100644
index 0000000..b69879f
--- /dev/null
+++ b/src/kudu/util/net/socket-test.cc
@@ -0,0 +1,89 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include "kudu/util/net/socket.h"
+
+#include <thread>
+
+#include <cstdint>
+#include <glog/logging.h>
+#include <gtest/gtest.h>
+#include <memory>
+#include <stddef.h>
+#include <string>
+
+#include "kudu/util/monotime.h"
+#include "kudu/util/net/sockaddr.h"
+#include "kudu/util/slice.h"
+#include "kudu/util/status.h"
+#include "kudu/util/test_macros.h"
+#include "kudu/util/test_util.h"
+
+
+namespace kudu {
+
+constexpr size_t kEchoChunkSize = 32 * 1024 * 1024;
+
+class SocketTest : public KuduTest {
+ protected:
+  void DoTest(bool accept, const std::string &message) {
+    Sockaddr address;
+    address.ParseString("0.0.0.0", 0);
+    Socket listener_;
+
+    CHECK_OK(listener_.Init(0));
+    CHECK_OK(listener_.BindAndListen(address, 0));
+    Sockaddr listen_address;
+    CHECK_OK(listener_.GetSocketAddress(&listen_address));
+
+    std::thread t([&]{
+      if (accept) {
+        Sockaddr new_addr;
+        Socket sock;
+        CHECK_OK(listener_.Accept(&sock, &new_addr, 0));
+        CHECK_OK(sock.Close());
+      } else {
+        SleepFor(MonoDelta::FromMilliseconds(200));
+        CHECK_OK(listener_.Close());
+      }
+    });
+
+    Socket client;
+    ASSERT_OK(client.Init(0));
+    ASSERT_OK(client.Connect(listen_address));
+    CHECK_OK(client.SetRecvTimeout(MonoDelta::FromMilliseconds(100)));
+
+    int n;
+    std::unique_ptr<uint8_t[]> buf(new uint8_t[kEchoChunkSize]);
+    Status s = client.Recv(buf.get(), kEchoChunkSize, &n);
+
+    ASSERT_TRUE(!s.ok());
+    ASSERT_TRUE(s.IsNetworkError());
+    ASSERT_STR_MATCHES(s.message().ToString(), message);
+
+    t.join();
+  }
+};
+
+TEST_F(SocketTest, TestRecvReset) {
+  DoTest(false, "recv error from 127.0.0.1:[0-9]+: Resource temporarily 
unavailable");
+}
+
+TEST_F(SocketTest, TestRecvEOF) {
+  DoTest(true, "Recv\\(\\) got EOF from remote 127.0.0.1:[0-9]+");
+}
+} // namespace kudu

http://git-wip-us.apache.org/repos/asf/kudu/blob/1f380f27/src/kudu/util/net/socket.cc
----------------------------------------------------------------------
diff --git a/src/kudu/util/net/socket.cc b/src/kudu/util/net/socket.cc
index cd37782..dd420b2 100644
--- a/src/kudu/util/net/socket.cc
+++ b/src/kudu/util/net/socket.cc
@@ -521,12 +521,18 @@ Status Socket::Recv(uint8_t *buf, int32_t amt, int32_t 
*nread) {
   int res;
   RETRY_ON_EINTR(res, recv(fd_, buf, amt, 0));
   if (res <= 0) {
+    Sockaddr remote;
+    GetPeerAddress(&remote);
     if (res == 0) {
-      return Status::NetworkError("Recv() got EOF from remote", Slice(), 
ESHUTDOWN);
+      std::string error_message = strings::Substitute("Recv() got EOF from 
remote $0",
+                                                      remote.ToString());
+      return Status::NetworkError(error_message, Slice(), ESHUTDOWN);
     }
     int err = errno;
-    return Status::NetworkError(std::string("recv error: ") +
-                                ErrnoToString(err), Slice(), err);
+    std::string error_message = strings::Substitute("recv error from $0: $1",
+                                                    remote.ToString(),
+                                                    ErrnoToString(err));
+    return Status::NetworkError(error_message, Slice(), err);
   }
   *nread = res;
   return Status::OK();

Reply via email to