Jui-min Lee has uploaded this change for review. ( https://gem5-review.googlesource.com/c/public/gem5/+/55943 )

Change subject: base: Fix ListenSocket binding logic
......................................................................

base: Fix ListenSocket binding logic

The original implementation does not cleanup the socket after it failed
to listen. However, the API doesn't give our user a way to bypass the
bind part and the next try will always break at the bind call.
Furthermore, the next failure will be EINVAL instead of EADDRINUSE so
gem5 will just abort without giving any meaningful message.

In this CL we cleanup the socket if we failed to invoke listen, so the
user can retry with a clean state and even retry on another port.

Test: Try to launch two gem5 that both bind to gdb port (7000) and
    repeat it for 100 times.
Change-Id: I7272ea3c3b6ab56e4b904f3a3a45ed389d00dd05
---
M src/base/socket.cc
1 file changed, 49 insertions(+), 21 deletions(-)



diff --git a/src/base/socket.cc b/src/base/socket.cc
index 860249a..7a3a721 100644
--- a/src/base/socket.cc
+++ b/src/base/socket.cc
@@ -138,30 +138,38 @@
panic("ListenSocket(listen): setsockopt() SO_REUSEADDR failed!");
     }

-    struct sockaddr_in sockaddr;
-    sockaddr.sin_family = PF_INET;
-    sockaddr.sin_addr.s_addr =
-        htobe<in_addr_t>(bindToLoopback ? INADDR_LOOPBACK : INADDR_ANY);
-    sockaddr.sin_port = htons(port);
-    // finally clear sin_zero
-    std::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)
-            panic("ListenSocket(listen): bind() failed!");
-        return false;
-    }
+    do {
+        struct sockaddr_in sockaddr;
+        sockaddr.sin_family = PF_INET;
+        sockaddr.sin_addr.s_addr =
+ htobe<in_addr_t>(bindToLoopback ? INADDR_LOOPBACK : INADDR_ANY);
+        sockaddr.sin_port = htons(port);
+        // finally clear sin_zero
+        std::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)
+                panic("ListenSocket(listen): bind() failed!");
+            break;
+        }

-    if (::listen(fd, 1) == -1) {
-        if (errno != EADDRINUSE)
-            panic("ListenSocket(listen): listen() failed!");
+        if (::listen(fd, 1) == -1) {
+            if (errno != EADDRINUSE)
+                panic("ListenSocket(listen): listen() failed!");

-        return false;
-    }
+            break;
+        }

-    listening = true;
-    anyListening = true;
-    return true;
+        listening = true;
+        anyListening = true;
+        return true;
+    } while(false);
+
+ // If we reach here, something must have gone wrong while binding socket.
+    // We'll close the socket so our user can retry from a cleaner state.
+    close(fd);
+    fd = -1;
+    return false;
 }



--
To view, visit https://gem5-review.googlesource.com/c/public/gem5/+/55943
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: I7272ea3c3b6ab56e4b904f3a3a45ed389d00dd05
Gerrit-Change-Number: 55943
Gerrit-PatchSet: 1
Gerrit-Owner: Jui-min Lee <f...@google.com>
Gerrit-MessageType: newchange
_______________________________________________
gem5-dev mailing list -- gem5-dev@gem5.org
To unsubscribe send an email to gem5-dev-le...@gem5.org
%(web_page_url)slistinfo%(cgiext)s/%(_internal_name)s

Reply via email to