Simon Park has uploaded this change for review. (
https://gem5-review.googlesource.com/c/public/gem5/+/66471?usp=email )
Change subject: base: socket: add SocketPath for resolving socket paths
......................................................................
base: socket: add SocketPath for resolving socket paths
Added UnixSocketAddr that wraps around sockaddr_un, and SocketPath that
can build UnixSocketAddr. Using this wrapper, users can create both file
based sockets as well as abstract sockets.
Change-Id: Ibf105b92a6a6ac7fc9136ed307f824c83e45c06c
---
M src/base/socket.cc
M src/base/socket.hh
M src/base/str.hh
M src/mem/shared_memory_server.cc
M src/mem/shared_memory_server.hh
5 files changed, 157 insertions(+), 31 deletions(-)
diff --git a/src/base/socket.cc b/src/base/socket.cc
index 5cf67fd..bbc580b 100644
--- a/src/base/socket.cc
+++ b/src/base/socket.cc
@@ -35,22 +35,88 @@
#include <netinet/tcp.h>
#include <sys/socket.h>
#include <sys/types.h>
+#include <sys/un.h>
#include <unistd.h>
#include <cerrno>
#include "base/logging.hh"
+#include "base/output.hh"
+#include "base/str.hh"
#include "base/types.hh"
#include "sim/byteswap.hh"
namespace gem5
{
+namespace
+{
+
+bool
+isSocketNameAbstract(const std::string &path)
+{
+ if (path.empty()) {
+ return false;
+ }
+ // No null byte should be present in the path
+ return path.front() == '@';
+}
+
+std::string
+resolve(const std::string &path)
+{
+ if (path.empty()) {
+ return path;
+ }
+ if (isSocketNameAbstract(path)) {
+ return '\0' + path.substr(1);
+ }
+ return simout.resolve(path);
+}
+
+} // namespace
bool ListenSocket::listeningDisabled = false;
bool ListenSocket::anyListening = false;
bool ListenSocket::bindToLoopback = false;
+UnixSocketAddr
+SocketPath::buildUnix(const std::string &path)
+{
+ sockaddr_un addr = {.sun_family = AF_UNIX, .sun_path = {}};
+
+ const bool is_abstract = isSocketNameAbstract(path);
+ size_t max_len = sizeof(addr.sun_path);
+ if (!is_abstract) {
+ // File based socket names need to be null terminated
+ max_len -= 1;
+ }
+
+ std::string resolved_path = resolve(path);
+ std::string fmt_path = replace(resolved_path, '\0', '@');
+ if (resolved_path.size() > max_len) {
+ resolved_path = resolved_path.substr(0, max_len);
+ const std::string untruncated_path = std::move(fmt_path);
+ fmt_path = replace(resolved_path, '\0', '@');
+ warn("SocketPath: unix socket path truncated from '%s' to '%s'",
+ untruncated_path, fmt_path);
+ }
+
+ // We can't use strncpy here, since abstract sockets start with \0
which
+ // will make strncpy think that the string is empty.
+ memcpy(addr.sun_path, resolved_path.c_str(), resolved_path.size());
+ // We can't use sizeof(sockaddr_un) for abstract sockets, since all
+ // sizeof(sun_path) bytes are used in representing the path.
+ const size_t path_size =
+ is_abstract ? resolved_path.size() : sizeof(addr.sun_path);
+ const size_t addr_size = offsetof(sockaddr_un, sun_path) + path_size;
+
+ return UnixSocketAddr{.addr = std::move(addr),
+ .addrSize = addr_size,
+ .isAbstract = is_abstract,
+ .formattedPath = std::move(fmt_path)};
+}
+
void
ListenSocket::cleanup()
{
diff --git a/src/base/socket.hh b/src/base/socket.hh
index 3375ccc..81dbe65 100644
--- a/src/base/socket.hh
+++ b/src/base/socket.hh
@@ -31,10 +31,51 @@
#include <sys/socket.h>
#include <sys/types.h>
+#include <sys/un.h>
+
+#include <ostream>
+#include <string>
namespace gem5
{
+/**
+ * @brief Wrapper around sockaddr_un, so that it can be used for both file
+ * based unix sockets as well as abstract unix sockets.
+ */
+struct UnixSocketAddr
+{
+ sockaddr_un addr;
+ // Size of `sockaddr_un addr`. This is equal to sizeof(sockaddr_un) if
+ // `addr` represents a normal file based unix socket. For abstract
sockets
+ // however, the size could be different. Because all sizeof(sun_path)
is
+ // used to represent the name of an abstract socket, addrSize for
abstract
+ // sockets only count the number of characters actually used by
sun_path,
+ // excluding any trailing null bytes.
+ size_t addrSize;
+ bool isAbstract;
+ // Formatted string for file based sockets look the same as
addr.sun_path.
+ // For abstract sockets however, all null bytes are replaced with @
+ std::string formattedPath;
+};
+
+class SocketPath final
+{
+ public:
+ SocketPath() = delete;
+
+ /**
+ * @brief Builds UnixSocketAddr from the given path.
+ * @pre: `path` either represents a file based unix socket, or an
abstract
+ * unix socket. If `path` represents an abstract socket, it
should
+ * start with the character '@', and it should not have any null
+ * bytes in the name.
+ * @param path: Pathname, where the socket should be instantiated.
+ * @return UnixSocketAddr
+ */
+ static UnixSocketAddr buildUnix(const std::string &path);
+};
+
class ListenSocket
{
protected:
diff --git a/src/base/str.hh b/src/base/str.hh
index 00409ff..855fb43 100644
--- a/src/base/str.hh
+++ b/src/base/str.hh
@@ -32,6 +32,7 @@
#ifndef __BASE_STR_HH__
#define __BASE_STR_HH__
+#include <algorithm>
#include <cstring>
#include <limits>
#include <locale>
@@ -251,6 +252,14 @@
return (s.compare(0, prefix.size(), prefix) == 0);
}
+inline std::string
+replace(const std::string &s, char from, char to)
+{
+ std::string replaced = s;
+ std::replace(replaced.begin(), replaced.end(), from, to);
+ return replaced;
+}
+
} // namespace gem5
#endif //__BASE_STR_HH__
diff --git a/src/mem/shared_memory_server.cc
b/src/mem/shared_memory_server.cc
index bee663b..b98412f 100644
--- a/src/mem/shared_memory_server.cc
+++ b/src/mem/shared_memory_server.cc
@@ -34,7 +34,6 @@
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
-#include <sys/un.h>
#include <unistd.h>
#include <algorithm>
@@ -44,7 +43,6 @@
#include "base/logging.hh"
#include "base/output.hh"
#include "base/pollevent.hh"
-#include "base/socket.hh"
namespace gem5
{
@@ -52,51 +50,49 @@
{
SharedMemoryServer::SharedMemoryServer(const SharedMemoryServerParams&
params)
- : SimObject(params),
unixSocketPath(simout.resolve(params.server_path)),
- system(params.system), serverFd(-1)
+ : SimObject(params),
+ sockAddr(SocketPath::buildUnix(params.server_path)),
+ system(params.system),
+ serverFd(-1)
{
fatal_if(system == nullptr, "Requires a system to share memory from!");
// Create a new unix socket.
serverFd = ListenSocket::socketCloexec(AF_UNIX, SOCK_STREAM, 0);
panic_if(serverFd < 0, "%s: cannot create unix socket: %s", name(),
strerror(errno));
- // Bind to the specified path.
- sockaddr_un serv_addr = {};
- serv_addr.sun_family = AF_UNIX;
- strncpy(serv_addr.sun_path, unixSocketPath.c_str(),
- sizeof(serv_addr.sun_path) - 1);
- // If the target path is truncated, warn the user that the actual path
is
- // different and update the target path.
- if (strlen(serv_addr.sun_path) != unixSocketPath.size()) {
- warn("%s: unix socket path truncated, expect '%s' but get '%s'",
- name(), unixSocketPath, serv_addr.sun_path);
- unixSocketPath = serv_addr.sun_path;
+
+ const auto& [serv_addr, addr_size, is_abstract, formatted_path] =
sockAddr;
+
+ if (!is_abstract) {
+ // Ensure the unix socket path to use is not occupied. Also, if
there's
+ // actually anything to be removed, warn the user something might
be
+ // off.
+ bool old_sock_removed = unlink(serv_addr.sun_path) == 0;
+ warn_if(old_sock_removed,
+ "%s: server path %s was occupied and will be replaced.
Please "
+ "make sure there is no other server using the same path.",
+ name(), serv_addr.sun_path);
}
- // Ensure the unix socket path to use is not occupied. Also, if there's
- // actually anything to be removed, warn the user something might be
off.
- bool old_sock_removed = unlink(unixSocketPath.c_str()) == 0;
- warn_if(old_sock_removed,
- "%s: the server path %s was occupied and will be replaced.
Please "
- "make sure there is no other server using the same path.",
- name(), unixSocketPath);
- int bind_retv = bind(serverFd, reinterpret_cast<sockaddr*>(&serv_addr),
- sizeof(serv_addr));
- fatal_if(bind_retv != 0, "%s: cannot bind unix socket: %s", name(),
- strerror(errno));
+ int bind_retv = bind(
+ serverFd, reinterpret_cast<const sockaddr*>(&serv_addr),
addr_size);
+ fatal_if(bind_retv != 0, "%s: cannot bind unix socket '%s': %s",
name(),
+ formatted_path, strerror(errno));
// Start listening.
int listen_retv = listen(serverFd, 1);
fatal_if(listen_retv != 0, "%s: listen failed: %s", name(),
strerror(errno));
listenSocketEvent.reset(new ListenSocketEvent(serverFd, this));
pollQueue.schedule(listenSocketEvent.get());
- inform("%s: listening at %s", name(), unixSocketPath);
+ inform("%s: listening at %s", name(), formatted_path);
}
SharedMemoryServer::~SharedMemoryServer()
{
- int unlink_retv = unlink(unixSocketPath.c_str());
- warn_if(unlink_retv != 0, "%s: cannot unlink unix socket: %s", name(),
- strerror(errno));
+ if (!sockAddr.isAbstract) {
+ int unlink_retv = unlink(sockAddr.addr.sun_path);
+ warn_if(unlink_retv != 0, "%s: cannot unlink unix socket: %s",
name(),
+ strerror(errno));
+ }
int close_retv = close(serverFd);
warn_if(close_retv != 0, "%s: cannot close unix socket: %s", name(),
strerror(errno));
diff --git a/src/mem/shared_memory_server.hh
b/src/mem/shared_memory_server.hh
index 8f573fe..d9fbeb3 100644
--- a/src/mem/shared_memory_server.hh
+++ b/src/mem/shared_memory_server.hh
@@ -33,6 +33,7 @@
#include <unordered_map>
#include "base/pollevent.hh"
+#include "base/socket.hh"
#include "params/SharedMemoryServer.hh"
#include "sim/sim_object.hh"
#include "sim/system.hh"
@@ -82,7 +83,7 @@
void process(int revent) override;
};
- std::string unixSocketPath;
+ UnixSocketAddr sockAddr;
System* system;
int serverFd;
--
To view, visit
https://gem5-review.googlesource.com/c/public/gem5/+/66471?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: Ibf105b92a6a6ac7fc9136ed307f824c83e45c06c
Gerrit-Change-Number: 66471
Gerrit-PatchSet: 1
Gerrit-Owner: Simon Park <seminp...@google.com>
Gerrit-MessageType: newchange
_______________________________________________
gem5-dev mailing list -- gem5-dev@gem5.org
To unsubscribe send an email to gem5-dev-le...@gem5.org