Gabe Black has uploaded this change for review. (
https://gem5-review.googlesource.com/c/public/gem5/+/69164?usp=email )
Change subject: base: Add support for unix domain sockets in ListenSocket.
......................................................................
base: Add support for unix domain sockets in ListenSocket.
Change-Id: I6a5fa2cd3e4b567829203bf9d61ad2b55c259697
---
M src/base/socket.cc
M src/base/socket.hh
M src/base/socket.test.cc
3 files changed, 208 insertions(+), 4 deletions(-)
diff --git a/src/base/socket.cc b/src/base/socket.cc
index 0324788..c401a08 100644
--- a/src/base/socket.cc
+++ b/src/base/socket.cc
@@ -39,6 +39,7 @@
#include <unistd.h>
#include <cerrno>
+#include <filesystem>
#include "base/logging.hh"
#include "base/output.hh"
@@ -187,10 +188,10 @@
ListenSocket::accept()
{
struct sockaddr_in sockaddr;
- socklen_t slen = sizeof (sockaddr);
+ socklen_t slen = sizeof(sockaddr);
int sfd = acceptCloexec(fd, (struct sockaddr *)&sockaddr, &slen);
- if (sfd == -1)
- return -1;
+ panic_if(sfd == -1, "%s: Failed to accept connection: %s",
+ name(), strerror(errno));
return sfd;
}
@@ -286,4 +287,148 @@
});
}
+std::string
+ListenSocketUnix::truncate(const std::string &original, size_t max_len)
+{
+ if (original.size() <= max_len)
+ return original;
+
+ std::string truncated = original.substr(0, max_len);
+ warn("%s: Truncated \"%s\" to \"%s\"", original, truncated);
+ return truncated;
+}
+
+void
+ListenSocketUnix::listen()
+{
+ panic_if(listening, "Socket already listening!");
+
+ // only create socket if not already created by previous call
+ if (fd == -1) {
+ fd = socketCloexec(PF_UNIX, SOCK_STREAM, 0);
+ panic_if(fd < 0, "%s: Can't create unix socket:%s !",
+ name(), strerror(errno));
+ }
+
+ sockaddr_un serv_addr;
+ std::memset(&serv_addr, 0, sizeof(serv_addr));
+ size_t addr_size = prepSockaddrUn(serv_addr);
+
+ fatal_if(bind(fd, (struct sockaddr *)&(serv_addr), addr_size) != 0,
+ "%s: Cannot bind unix socket %s: %s", name(), *this,
+ strerror(errno));
+
+ fatal_if(::listen(fd, 1) == -1, "%s: Failed to listen on %s: %s\n",
+ name(), *this, strerror(errno));
+
+ ccprintf(std::cerr, "%s: Listening for connections on %s\n",
+ name(), *this);
+
+ listening = true;
+ anyListening = true;
+}
+
+ListenSocketUnixFile::ListenSocketUnixFile(const std::string &_name,
+ const std::string &_dir, const std::string &_fname) :
+ ListenSocketUnix(_name), dir(_dir),
+ fname(truncate(_fname, sizeof(sockaddr_un::sun_path)))
+{
+}
+
+ListenSocketUnixFile::~ListenSocketUnixFile()
+{
+ if (fd != -1) {
+ close(fd);
+ fd = -1;
+ unlink();
+ }
+}
+
+bool
+ListenSocketUnixFile::unlink() const
+{
+ auto path = resolvedDir + "/" + fname;
+ return ::unlink(path.c_str()) == 0;
+}
+
+size_t
+ListenSocketUnixFile::prepSockaddrUn(sockaddr_un &addr) const
+{
+ addr.sun_family = AF_UNIX;
+ std::memcpy(addr.sun_path, fname.c_str(), fname.size());
+ return sizeof(addr.sun_path);
+}
+
+void
+ListenSocketUnixFile::listen()
+{
+ auto resolvedDir = simout.resolve(dir);
+ warn_if(unlink(),
+ "%s: server path %s was occupied and will be replaced. Please "
+ "make sure there is no other server using the same path.",
+ name(), resolvedDir + "/" + fname);
+
+ // Make sure "dir" exists.
+ std::error_code ec;
+ std::filesystem::create_directory(resolvedDir, ec);
+ fatal_if(ec, "Failed to create directory %s", ec.message());
+
+ // Change the working directory to the directory containing the socket
so
+ // that we maximize the limited space in sockaddr_un.sun_path.
+ auto cwd = std::filesystem::current_path(ec);
+ panic_if(ec, "Failed to get current working directory %s",
ec.message());
+ std::filesystem::current_path(resolvedDir, ec);
+ fatal_if(ec, "Failed to change to directory %s: %s",
+ resolvedDir, ec.message());
+
+ ListenSocketUnix::listen();
+
+ std::filesystem::current_path(cwd, ec);
+ panic_if(ec, "Failed to change back working directory %s",
ec.message());
+}
+
+void
+ListenSocketUnixFile::output(std::ostream &os) const
+{
+ os << "socket \"" << dir << "/" << fname << "\"";
+}
+
+ListenSocketConfig
+listenSocketUnixFileConfig(std::string dir, std::string fname)
+{
+ return ListenSocketConfig([dir, fname](const std::string &name) {
+ return std::make_unique<ListenSocketUnixFile>(name, dir, fname);
+ });
+}
+
+size_t
+ListenSocketUnixAbstract::prepSockaddrUn(sockaddr_un &addr) const
+{
+ addr.sun_family = AF_UNIX;
+ addr.sun_path[0] = '\0';
+ std::memcpy(&addr.sun_path[1], path.c_str(), path.size());
+ return offsetof(sockaddr_un, sun_path) + path.size();
+}
+
+ListenSocketUnixAbstract::ListenSocketUnixAbstract(
+ const std::string &_name, const std::string &_path) :
+ ListenSocketUnix(_name),
+ path(truncate(_path, sizeof(sockaddr_un::sun_path) - 1))
+{
+}
+
+void
+ListenSocketUnixAbstract::output(std::ostream &os) const
+{
+ os << "abstract socket \"" << path << "\"";
+}
+
+ListenSocketConfig
+listenSocketUnixAbstractConfig(std::string path)
+{
+ return ListenSocketConfig([path](const std::string &name) {
+ return std::make_unique<ListenSocketUnixAbstract>(name, path);
+ });
+}
+
} // namespace gem5
diff --git a/src/base/socket.hh b/src/base/socket.hh
index e233d85..82e8375 100644
--- a/src/base/socket.hh
+++ b/src/base/socket.hh
@@ -177,6 +177,60 @@
ListenSocketConfig listenSocketInetConfig(int port);
+// AF_UNIX based sockets.
+
+class ListenSocketUnix : public ListenSocket
+{
+ protected:
+ virtual size_t prepSockaddrUn(sockaddr_un &addr) const = 0;
+
+ std::string truncate(const std::string &original, size_t max_len);
+
+ ListenSocketUnix(const std::string &_name) : ListenSocket(_name) {}
+
+ public:
+ void listen() override;
+};
+
+class ListenSocketUnixFile : public ListenSocketUnix
+{
+ protected:
+ std::string dir;
+ std::string resolvedDir;
+ std::string fname;
+
+ bool unlink() const;
+
+ size_t prepSockaddrUn(sockaddr_un &addr) const;
+
+ public:
+ ListenSocketUnixFile(const std::string &_name, const std::string &_dir,
+ const std::string &_fname);
+ ~ListenSocketUnixFile();
+
+ void listen() override;
+ void output(std::ostream &os) const override;
+};
+
+ListenSocketConfig listenSocketUnixFileConfig(
+ std::string dir, std::string fname);
+
+class ListenSocketUnixAbstract : public ListenSocketUnix
+{
+ protected:
+ std::string path;
+
+ size_t prepSockaddrUn(sockaddr_un &addr) const;
+
+ public:
+ ListenSocketUnixAbstract(
+ const std::string &_name, const std::string &_path);
+
+ void output(std::ostream &os) const override;
+};
+
+ListenSocketConfig listenSocketUnixAbstractConfig(std::string path);
+
} // namespace gem5
#endif //__SOCKET_HH__
diff --git a/src/base/socket.test.cc b/src/base/socket.test.cc
index 0f0de54..7bf9e18 100644
--- a/src/base/socket.test.cc
+++ b/src/base/socket.test.cc
@@ -207,5 +207,10 @@
TEST(SocketTest, AcceptError)
{
MockListenSocket listen_socket(-1);
- EXPECT_EQ(-1, listen_socket.accept());
+ EXPECT_ANY_THROW(listen_socket.accept());
+ std::string expected =
+ "panic: panic condition sfd == -1 occurred: mock: Failed to
accept "
+ "connection: Bad file descriptor\n";
+ std::string actual = gtestLogOutput.str();
+ EXPECT_EQ(expected, actual);
}
--
To view, visit
https://gem5-review.googlesource.com/c/public/gem5/+/69164?usp=email
To unsubscribe, or for help writing mail filters, visit
https://gem5-review.googlesource.com/settings
Gerrit-Project: public/gem5
Gerrit-Branch: develop
Gerrit-Change-Id: I6a5fa2cd3e4b567829203bf9d61ad2b55c259697
Gerrit-Change-Number: 69164
Gerrit-PatchSet: 1
Gerrit-Owner: Gabe Black <gabe.bl...@gmail.com>
Gerrit-CC: Gabe Black <gabebl...@google.com>
Gerrit-MessageType: newchange
_______________________________________________
gem5-dev mailing list -- gem5-dev@gem5.org
To unsubscribe send an email to gem5-dev-le...@gem5.org