tests,base: Added GTest for base/socket.cc
[gem5.git] / src / base / socket.cc
index 45a60e7e37b1c654795f4706fdcb1ff3700885ab..b188ac1f906ba9a2fa4ea7e8139c50afd82e6ada 100644 (file)
@@ -1,4 +1,7 @@
 /*
+ * Copyright (c) 2020 The Regents of the University of California
+ * All rights reserved
+ *
  * Copyright (c) 2002-2005 The Regents of The University of Michigan
  * All rights reserved.
  *
  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ *          Bobby R. Bruce
  */
 
-#include <sys/types.h>
-#include <sys/socket.h>
+#include "base/socket.hh"
 
 #include <netinet/in.h>
 #include <netinet/tcp.h>
-
-#include <errno.h>
+#include <sys/socket.h>
+#include <sys/types.h>
 #include <unistd.h>
 
-#include "sim/host.hh"
-#include "base/misc.hh"
-#include "base/socket.hh"
+#include <cerrno>
+
+#include "base/logging.hh"
+#include "base/types.hh"
+#include "sim/byteswap.hh"
 
 using namespace std;
 
+bool ListenSocket::listeningDisabled = false;
+bool ListenSocket::anyListening = false;
+
+bool ListenSocket::bindToLoopback = false;
+
+void
+ListenSocket::cleanup()
+{
+    listeningDisabled = false;
+    anyListening = false;
+    bindToLoopback = false;
+}
+
+void
+ListenSocket::disableAll()
+{
+    if (anyListening)
+        panic("Too late to disable all listeners, already have a listener");
+    listeningDisabled = true;
+}
+
+bool
+ListenSocket::allDisabled()
+{
+    return listeningDisabled;
+}
+
+void
+ListenSocket::loopbackOnly()
+{
+    if (anyListening)
+        panic("Too late to bind to loopback, already have a listener");
+    bindToLoopback = true;
+}
+
 ////////////////////////////////////////////////////////////////////////
 //
 //
@@ -75,9 +117,11 @@ ListenSocket::listen(int port, bool reuse)
 
     struct sockaddr_in sockaddr;
     sockaddr.sin_family = PF_INET;
-    sockaddr.sin_addr.s_addr = INADDR_ANY;
-
+    sockaddr.sin_addr.s_addr =
+        htobe<in_addr_t>(bindToLoopback ? INADDR_LOOPBACK : INADDR_ANY);
     sockaddr.sin_port = htons(port);
+    // finally clear sin_zero
+    memset(&sockaddr.sin_zero, 0, sizeof(sockaddr.sin_zero));
     int ret = ::bind(fd, (struct sockaddr *)&sockaddr, sizeof (sockaddr));
     if (ret != 0) {
         if (ret == -1 && errno != EADDRINUSE)
@@ -85,11 +129,15 @@ ListenSocket::listen(int port, bool reuse)
         return false;
     }
 
-    if (::listen(fd, 1) == -1)
-        panic("ListenSocket(listen): listen() failed!");
+    if (::listen(fd, 1) == -1) {
+        if (errno != EADDRINUSE)
+            panic("ListenSocket(listen): listen() failed!");
 
-    listening = true;
+        return false;
+    }
 
+    listening = true;
+    anyListening = true;
     return true;
 }
 
@@ -104,7 +152,9 @@ ListenSocket::accept(bool nodelay)
     int sfd = ::accept(fd, (struct sockaddr *)&sockaddr, &slen);
     if (sfd != -1 && nodelay) {
         int i = 1;
-        ::setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, (char *)&i, sizeof(i));
+        if (::setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, (char *)&i,
+                         sizeof(i)) < 0)
+            warn("ListenSocket(accept): setsockopt() TCP_NODELAY failed!");
     }
 
     return sfd;