Fix Unix socket usage on macOS
macOS does not support abstract namespaces for sockets.
This patch fixes the socket usage by using a real path instead
of abstract namespaces.
Change-Id: I434e92e86fb87d1085c35b5d707d1238295192fb
Reviewed-on: http://gerrit.cloudera.org:8080/16458
Tested-by: Grant Henke <granthenke@apache.org>
Reviewed-by: Alexey Serbin <aserbin@cloudera.com>
diff --git a/src/kudu/rpc/rpc-test.cc b/src/kudu/rpc/rpc-test.cc
index 92279f2..ce16f0d 100644
--- a/src/kudu/rpc/rpc-test.cc
+++ b/src/kudu/rpc/rpc-test.cc
@@ -112,9 +112,11 @@
}
Sockaddr bind_addr() const {
if (use_unix_socket()) {
+ // Ensure multiple calls to bind_addr work by unlinking the socket file.
+ // The only way to reuse a socket file is to remove it with unlink().
+ unlink(socket_path_.c_str());
Sockaddr addr;
- string path = Substitute("@kudu-test-$0", getpid());
- CHECK_OK(addr.ParseUnixDomainPath(path));
+ CHECK_OK(addr.ParseUnixDomainPath(socket_path_));
return addr;
}
return Sockaddr::Wildcard();
@@ -125,6 +127,13 @@
}
return bound_addr.ToString();
}
+ void TearDown() override {
+ RpcTestBase::TearDown();
+ // Ensure we cleanup the socket file on teardown.
+ unlink(socket_path_.c_str());
+ }
+
+ std::string socket_path_ = GetTestSocketPath("rpc-test");
};
// This is used to run all parameterized tests with and without SSL, on Unix sockets
diff --git a/src/kudu/server/server_base.cc b/src/kudu/server/server_base.cc
index c030e22..dcc8afd 100644
--- a/src/kudu/server/server_base.cc
+++ b/src/kudu/server/server_base.cc
@@ -536,8 +536,13 @@
if (FLAGS_rpc_listen_on_unix_domain_socket) {
VLOG(1) << "Enabling listening on unix domain socket.";
Sockaddr addr;
+#if !defined(__APPLE__)
RETURN_NOT_OK_PREPEND(addr.ParseUnixDomainPath(Substitute("@kudu-$0", fs_manager_->uuid())),
"unable to parse provided UNIX socket path");
+#else
+ RETURN_NOT_OK_PREPEND(addr.ParseUnixDomainPath(Substitute("/tmp/kudu-$0", fs_manager_->uuid())),
+ "unable to parse provided UNIX socket path");
+#endif
RETURN_NOT_OK_PREPEND(rpc_server_->AddBindAddress(addr),
"unable to add configured UNIX socket path to list of bind addresses "
"for RPC server");
diff --git a/src/kudu/util/net/socket-test.cc b/src/kudu/util/net/socket-test.cc
index df966d5..fb22db0 100644
--- a/src/kudu/util/net/socket-test.cc
+++ b/src/kudu/util/net/socket-test.cc
@@ -29,6 +29,7 @@
#include <gtest/gtest.h>
#include "kudu/gutil/strings/substitute.h"
+#include "kudu/gutil/strings/util.h"
#include "kudu/util/monotime.h"
#include "kudu/util/net/sockaddr.h"
#include "kudu/util/scoped_cleanup.h"
@@ -112,8 +113,7 @@
// Test GetPeerAddress from server side.
Sockaddr peer_addr;
CHECK_OK(sock.GetPeerAddress(&peer_addr));
- CHECK_EQ("unix:<unnamed>", peer_addr.ToString());
-
+ CHECK(HasPrefixString(peer_addr.ToString(), "unix:"));
size_t n_written;
CHECK_OK(sock.BlockingWrite(
reinterpret_cast<const uint8_t*>(kData.data()), kData.size(), &n_written,
@@ -149,17 +149,18 @@
DoTestServerDisconnects(true, "recv got EOF from 127.0.0.1:[0-9]+");
}
+// Apple does not support abstract namespaces in sockets.
+#if !defined(__APPLE__)
TEST_F(SocketTest, TestUnixSocketAbstractNamespace) {
DoUnixSocketTest(strings::Substitute("@kudu-test-pid-$0", getpid()));
}
+#endif
+
TEST_F(SocketTest, TestUnixSocketFilesystemPath) {
- // Use a path in /tmp/ instead of the normal GetTestPath approach because
- // unix domain socket paths are limited in length. The test directory
- // may be too long.
- string path = strings::Substitute("/tmp/kudu-test-pid-$0", getpid());
+ string path = GetTestSocketPath("socket-test");
SCOPED_CLEANUP({
- unlink(path.c_str());
- });
+ unlink(path.c_str());
+ });
DoUnixSocketTest(path);
}
diff --git a/src/kudu/util/test_util.cc b/src/kudu/util/test_util.cc
index bce1693..48fa73a 100644
--- a/src/kudu/util/test_util.cc
+++ b/src/kudu/util/test_util.cc
@@ -51,6 +51,7 @@
#include "kudu/gutil/walltime.h"
#include "kudu/util/env.h"
#include "kudu/util/faststring.h"
+#include "kudu/util/oid_generator.h"
#include "kudu/util/path_util.h"
#include "kudu/util/scoped_cleanup.h"
#include "kudu/util/slice.h"
@@ -280,6 +281,14 @@
return dir;
}
+string GetTestSocketPath(const string& name) {
+ string dir;
+ CHECK_OK(Env::Default()->GetTestDirectory(&dir));
+ ObjectIdGenerator generator;
+ string uuid = generator.Next();
+ return JoinPathSegments(dir, Substitute("$0-$1.sock", name, uuid));
+}
+
string GetTestExecutableDirectory() {
string exec;
CHECK_OK(Env::Default()->GetExecutablePath(&exec));
diff --git a/src/kudu/util/test_util.h b/src/kudu/util/test_util.h
index 9f60aef..a8139f8 100644
--- a/src/kudu/util/test_util.h
+++ b/src/kudu/util/test_util.h
@@ -112,6 +112,13 @@
// if a KuduTest instance is available.
std::string GetTestDataDirectory();
+// Returns a unique socket path for use in tests in the form of:
+// <test-dir>/<name>-<uuid>.sock
+//
+// The path is in the base test directory because the path to Unix domain
+// socket file cannot be longer than ~100 bytes.
+std::string GetTestSocketPath(const std::string& name);
+
// Return the directory which contains the test's executable.
std::string GetTestExecutableDirectory();