From c00e3b2570c6f42b1cfbdda0aa2d453070aa1cde Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sat, 18 Mar 2023 09:13:56 -0700 Subject: [PATCH] base: Abstract the AF_INET-ness out of ListenSocket. Put them into a subclass called ListenSocketInet. Change-Id: I035621463a7f799c1d36a500ed933dc056238e5e Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/69163 Maintainer: Bobby Bruce Maintainer: Gabe Black Tested-by: kokoro Reviewed-by: Jui-min Lee Reviewed-by: Bobby Bruce --- src/base/socket.cc | 68 +++++++++++++++++++++++------------------ src/base/socket.hh | 50 +++++++++++++++++++++--------- src/base/socket.test.cc | 4 +-- 3 files changed, 75 insertions(+), 47 deletions(-) diff --git a/src/base/socket.cc b/src/base/socket.cc index 5fb8492d50..13962d4b5c 100644 --- a/src/base/socket.cc +++ b/src/base/socket.cc @@ -173,11 +173,7 @@ ListenSocket::acceptCloexec(int sockfd, struct sockaddr *addr, // // -ListenSocket::ListenSocket(const std::string &_name, int port) - : Named(_name), listening(false), fd(-1), _port(port) -{} - -ListenSocket::ListenSocket() : ListenSocket("", -1) {} +ListenSocket::ListenSocket(const std::string &_name) : Named(_name) {} ListenSocket::~ListenSocket() { @@ -185,9 +181,41 @@ ListenSocket::~ListenSocket() close(fd); } +// Open a connection. Accept will block, so if you don't want it to, +// make sure a connection is ready before you call accept. +int +ListenSocket::accept() +{ + struct sockaddr_in sockaddr; + socklen_t slen = sizeof (sockaddr); + int sfd = acceptCloexec(fd, (struct sockaddr *)&sockaddr, &slen); + if (sfd == -1) + return -1; + + return sfd; +} + +ListenSocketInet::ListenSocketInet(const std::string &_name, int port) + : ListenSocket(_name), _port(port) +{} + +int +ListenSocketInet::accept() +{ + int sfd = ListenSocket::accept(); + if (sfd == -1) + return -1; + + int i = 1; + int ret = ::setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, &i, sizeof(i)); + warn_if(ret < 0, "ListenSocket(accept): setsockopt() TCP_NODELAY failed!"); + + return sfd; +} + // Create a socket and configure it for listening bool -ListenSocket::listen(int port) +ListenSocketInet::listen(int port) { panic_if(listening, "Socket already listening!"); @@ -228,13 +256,12 @@ ListenSocket::listen(int port) return false; } - listening = true; - anyListening = true; + setListening(); return true; } void -ListenSocket::listen() +ListenSocketInet::listen() { while (!listen(_port)) { _port++; @@ -245,35 +272,16 @@ ListenSocket::listen() } void -ListenSocket::output(std::ostream &os) const +ListenSocketInet::output(std::ostream &os) const { os << "port " << _port; } - -// Open a connection. Accept will block, so if you don't want it to, -// make sure a connection is ready before you call accept. -int -ListenSocket::accept() -{ - struct sockaddr_in sockaddr; - socklen_t slen = sizeof (sockaddr); - int sfd = acceptCloexec(fd, (struct sockaddr *)&sockaddr, &slen); - if (sfd == -1) - return -1; - - int i = 1; - int ret = ::setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, &i, sizeof(i)); - warn_if(ret < 0, "ListenSocket(accept): setsockopt() TCP_NODELAY failed!"); - - return sfd; -} - ListenSocketConfig listenSocketInetConfig(int port) { return ListenSocketConfig([port](const std::string &name) { - return std::make_unique(name, port); + return std::make_unique(name, port); }); } diff --git a/src/base/socket.hh b/src/base/socket.hh index 638ce40f57..761312b291 100644 --- a/src/base/socket.hh +++ b/src/base/socket.hh @@ -93,31 +93,34 @@ class ListenSocket : public Named static void loopbackOnly(); protected: - bool listening; - int fd; - int _port; + bool listening = false; + int fd = -1; + + void + setListening() + { + listening = true; + anyListening = true; + } /* * cleanup resets the static variables back to their default values. */ static void cleanup(); - virtual bool listen(int port); + ListenSocket(const std::string &_name); public: /** * @ingroup api_socket * @{ */ - ListenSocket(const std::string &_name, int port); - ListenSocket(); virtual ~ListenSocket(); virtual int accept(); + virtual void listen() = 0; - virtual void listen(); - - virtual void output(std::ostream &os) const; + virtual void output(std::ostream &os) const = 0; int getfd() const { return fd; } bool islistening() const { return listening; } @@ -130,6 +133,13 @@ class ListenSocket : public Named /** @} */ // end of api_socket }; +inline static std::ostream & +operator << (std::ostream &os, const ListenSocket &socket) +{ + socket.output(os); + return os; +} + using ListenSocketPtr = std::unique_ptr; class ListenSocketConfig @@ -155,14 +165,24 @@ class ListenSocketConfig static inline ListenSocketConfig listenSocketEmptyConfig() { return {}; } -ListenSocketConfig listenSocketInetConfig(int port); +// AF_INET based sockets. -inline static std::ostream & -operator << (std::ostream &os, const ListenSocket &socket) +class ListenSocketInet : public ListenSocket { - socket.output(os); - return os; -} + protected: + int _port; + + virtual bool listen(int port); + + public: + ListenSocketInet(const std::string &_name, int port); + + int accept() override; + void listen() override; + void output(std::ostream &os) const override; +}; + +ListenSocketConfig listenSocketInetConfig(int port); } // namespace gem5 diff --git a/src/base/socket.test.cc b/src/base/socket.test.cc index 8e1c25b4b1..0f0de54b6c 100644 --- a/src/base/socket.test.cc +++ b/src/base/socket.test.cc @@ -118,10 +118,10 @@ TEST(UnixSocketAddrTest, TruncatedFileBasedSocket) EXPECT_EQ(truncated_addr, sock_addr.formattedPath); } -class MockListenSocket : public ListenSocket +class MockListenSocket : public ListenSocketInet { public: - MockListenSocket(int port) : ListenSocket("mock", port) {} + MockListenSocket(int port) : ListenSocketInet("mock", port) {} /* * This mock Listen Socket is used to ensure the static variables are reset * back to their default values after deconstruction (i.e., after a test