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

Reply via email to