gem5-dev@gem5.org

The gem5 Developer List

View all threads

[M] Change in gem5/gem5[develop]: base: Add support for unix domain sockets in ListenSocket.

GB
Gabe Black (Gerrit)
Mon, Apr 10, 2023 2:42 AM

Gabe Black has submitted this change. (
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
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/69164
Tested-by: kokoro noreply+kokoro@google.com
Maintainer: Bobby Bruce bbruce@ucdavis.edu
Reviewed-by: Jui-min Lee fcrh@google.com

M src/base/socket.cc
M src/base/socket.hh
M src/base/socket.test.cc
3 files changed, 207 insertions(+), 4 deletions(-)

Approvals:
kokoro: Regressions pass
Jui-min Lee: Looks good to me, approved
Bobby Bruce: Looks good to me, approved

diff --git a/src/base/socket.cc b/src/base/socket.cc
index 13962d4..2e9f815 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;
    
    }
    @@ -285,4 +286,147 @@
    });
    }

+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"", name(), original, truncated);
  • return truncated;
    +}

+void
+ListenSocketUnix::listen()
+{

  • panic_if(listening, "%s: Socket already listening!", name());
  • // 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);
    
  • setListening();
    +}

+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) - 1))
    +{
    +}

+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()
+{

  • 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() + 1;
    +}

+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 761312b..33c1c3a 100644
    --- a/src/base/socket.hh
    +++ b/src/base/socket.hh
    @@ -184,6 +184,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 override;
  • 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 override;
  • 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: 8
Gerrit-Owner: Gabe Black gabe.black@gmail.com
Gerrit-Reviewer: Bobby Bruce bbruce@ucdavis.edu
Gerrit-Reviewer: Daniel Carvalho odanrc@yahoo.com.br
Gerrit-Reviewer: Gabe Black gabe.black@gmail.com
Gerrit-Reviewer: Jui-min Lee fcrh@google.com
Gerrit-Reviewer: kokoro noreply+kokoro@google.com
Gerrit-CC: Gabe Black gabeblack@google.com
Gerrit-MessageType: merged

Gabe Black has submitted this change. ( 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 Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/69164 Tested-by: kokoro <noreply+kokoro@google.com> Maintainer: Bobby Bruce <bbruce@ucdavis.edu> Reviewed-by: Jui-min Lee <fcrh@google.com> --- M src/base/socket.cc M src/base/socket.hh M src/base/socket.test.cc 3 files changed, 207 insertions(+), 4 deletions(-) Approvals: kokoro: Regressions pass Jui-min Lee: Looks good to me, approved Bobby Bruce: Looks good to me, approved diff --git a/src/base/socket.cc b/src/base/socket.cc index 13962d4..2e9f815 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; } @@ -285,4 +286,147 @@ }); } +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\"", name(), original, truncated); + return truncated; +} + +void +ListenSocketUnix::listen() +{ + panic_if(listening, "%s: Socket already listening!", name()); + + // 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); + + setListening(); +} + +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) - 1)) +{ +} + +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() +{ + 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() + 1; +} + +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 761312b..33c1c3a 100644 --- a/src/base/socket.hh +++ b/src/base/socket.hh @@ -184,6 +184,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 override; + + 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 override; + + 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: 8 Gerrit-Owner: Gabe Black <gabe.black@gmail.com> Gerrit-Reviewer: Bobby Bruce <bbruce@ucdavis.edu> Gerrit-Reviewer: Daniel Carvalho <odanrc@yahoo.com.br> Gerrit-Reviewer: Gabe Black <gabe.black@gmail.com> Gerrit-Reviewer: Jui-min Lee <fcrh@google.com> Gerrit-Reviewer: kokoro <noreply+kokoro@google.com> Gerrit-CC: Gabe Black <gabeblack@google.com> Gerrit-MessageType: merged