Changeset: 9c688ba40d36 for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB/rev/9c688ba40d36
Modified Files:
        monetdb5/modules/mal/mal_mapi.c
        tools/merovingian/daemon/connections.c
Branch: Sep2022
Log Message:

Deal with bind() returning 1.

On current Fedora (37, kernel 6.0.16-300.fc37.x86_64), when binding to
both IPv4 and IPv6, things work a bit differently now then anywhere
else, or so it seems.

What we used to do if we want both IPv4 and IPv6:
- create socket for IPv6
- set option IPV6_V6ONLY to off (0)
- bind either port 0 (let the system figure out a free port) or a specified one
- listen
- create socket for IPv4
- bind the port that was used in the previous step
- listen

If we try that now, the second bind returns 1 (!) if the address that we
try to bind to is "all".  If it is "localhost", things work as before.
Not only does bind return 1, it also gives us a different port (!).

It turns out, if bind does return 1, we can close the socket since the
first bind already bound to both protocols.  You don't see that in the
netstat output, but you can connect using both IPv4 and IPv6.

On the mac, something similar seems to be happening (I didn't check the
bind return value), but netstat reports that the socket is bound to both
IPv4 and 6 (in the "all" case).


diffs (85 lines):

diff --git a/monetdb5/modules/mal/mal_mapi.c b/monetdb5/modules/mal/mal_mapi.c
--- a/monetdb5/modules/mal/mal_mapi.c
+++ b/monetdb5/modules/mal/mal_mapi.c
@@ -569,12 +569,25 @@ start_listen(SOCKET *sockp, int *portp, 
                                sock = INVALID_SOCKET;
                                continue;
                        }
-                       if (bind(sock, rp->ai_addr, (SOCKLEN) rp->ai_addrlen) 
== SOCKET_ERROR) {
+                       if ((e = bind(sock, rp->ai_addr, (SOCKLEN) 
rp->ai_addrlen)) != 0) {
+                               /* return value of 1 is currently undocumented, 
but
+                                * seems to occur when binding a port to an 
IPv4 socket
+                                * when the same port is already bound to an 
IPv6 socket
+                                * that already also listens to IPv4; in this 
case the
+                                * port that is actually bound to here is a 
different
+                                * one, and we don't want that, so we close the 
socket
+                                * without error (if bind returned 
SOCKET_ERROR, we do
+                                * report the error) */
+                               if (e == SOCKET_ERROR) {
 #ifdef _MSC_VER
-                               e = WSAGetLastError();
+                                       e = WSAGetLastError();
 #else
-                               e = errno;
+                                       e = errno;
 #endif
+                               } else if (nsock == 0) {
+                                       assert(e == 1);
+                                       e = 0;
+                               }
                                closesocket(sock);
                                sock = INVALID_SOCKET;
                                continue;
diff --git a/tools/merovingian/daemon/connections.c 
b/tools/merovingian/daemon/connections.c
--- a/tools/merovingian/daemon/connections.c
+++ b/tools/merovingian/daemon/connections.c
@@ -106,29 +106,35 @@ openConnectionIP(int *socks, bool udp, c
                                                   (const char *) &(int){0}, 
sizeof(int)) == -1)
                                Mlevelfprintf(ERROR, log, "setsockopt 
IPV6_V6ONLY: %s\n", strerror(e));
 
-                       if (!udp) {
-                               if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
-                                                          (const char *) &on, 
sizeof on) < 0) {
-                                       e = errno;
-                                       closesocket(sock);
-                                       continue;
-                               }
+                       if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
+                                                  (const char *) &on, sizeof 
on) < 0) {
+                               e = errno;
+                               closesocket(sock);
+                               continue;
+                       }
 #ifdef SO_EXCLUSIVEADDRUSE
-                               if (setsockopt(sock, SOL_SOCKET, 
SO_EXCLUSIVEADDRUSE,
-                                                          (const char *) &on, 
sizeof on) < 0)
-                                       Mlevelfprintf(ERROR, log, "setsockopt 
SO_EXCLUSIVEADDRUSE: %s\n", strerror(e));
+                       if (setsockopt(sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
+                                                  (const char *) &on, sizeof 
on) < 0)
+                               Mlevelfprintf(ERROR, log, "setsockopt 
SO_EXCLUSIVEADDRUSE: %s\n", strerror(e));
 #endif
 #ifdef SO_EXCLBIND
-                               if (setsockopt(sock, SOL_SOCKET, SO_EXCLBIND,
-                                                          (const char *) &on, 
sizeof on) < 0)
-                                       Mlevelfprintf(ERROR, log, "setsockopt 
SO_EXCLBIND: %s\n", strerror(e));
+                       if (setsockopt(sock, SOL_SOCKET, SO_EXCLBIND,
+                                                  (const char *) &on, sizeof 
on) < 0)
+                               Mlevelfprintf(ERROR, log, "setsockopt 
SO_EXCLBIND: %s\n", strerror(e));
 #endif
                        }
 
-                       if (bind(sock, rp->ai_addr, rp->ai_addrlen) == -1) {
+                       switch (bind(sock, rp->ai_addr, rp->ai_addrlen)) {
+                       case -1:
                                e = errno;
                                closesocket(sock);
                                continue;
+                       case 0:
+                               /* normal return */
+                               break;
+                       case 1:
+                               closesocket(sock);
+                               continue;
                        }
                        if (!udp && listen(sock, 5) == -1) {
                                e = errno;
_______________________________________________
checkin-list mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to