Blob Blame History Raw
From 56a1142f033234e3ee3b6361e9a1bcdbe606f816 Mon Sep 17 00:00:00 2001
From: Simon Kelley <simon@thekelleys.org.uk>
Date: Tue, 2 Apr 2013 17:02:58 +0100
Subject: [PATCH 1/1] SO_REUSEPORT may be defined, but not supported.

---
 src/dhcp.c  |   16 ++++++++++++----
 src/dhcp6.c |   18 +++++++++++++-----
 2 files changed, 25 insertions(+), 9 deletions(-)

diff --git a/src/dhcp.c b/src/dhcp.c
index 6b8b803..dd25632 100644
--- a/src/dhcp.c
+++ b/src/dhcp.c
@@ -65,14 +65,22 @@ static int make_fd(int port)
   
   /* When bind-interfaces is set, there might be more than one dnmsasq
      instance binding port 67. That's OK if they serve different networks.
-     Need to set REUSEADDR to make this posible, or REUSEPORT on *BSD. */
+     Need to set REUSEADDR|REUSEPORT to make this posible.
+     Handle the case that REUSEPORT is defined, but the kernel doesn't 
+     support it. This handles the introduction of REUSEPORT on Linux. */
   if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
     {
+      int rc = -1, porterr = 0;
+
 #ifdef SO_REUSEPORT
-      int rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &oneopt, sizeof(oneopt));
-#else
-      int rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &oneopt, sizeof(oneopt));
+      if ((rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &oneopt, sizeof(oneopt))) == -1 && 
+	  errno != ENOPROTOOPT)
+	porterr = 1;
 #endif
+      
+      if (rc == -1 && !porterr)
+	rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &oneopt, sizeof(oneopt));
+      
       if (rc == -1)
 	die(_("failed to set SO_REUSE{ADDR|PORT} on DHCP socket: %s"), NULL, EC_BADNET);
     }
diff --git a/src/dhcp6.c b/src/dhcp6.c
index dd53f86..a827b2f 100644
--- a/src/dhcp6.c
+++ b/src/dhcp6.c
@@ -48,16 +48,24 @@ void dhcp6_init(void)
       !set_ipv6pktinfo(fd))
     die (_("cannot create DHCPv6 socket: %s"), NULL, EC_BADNET);
   
-  /* When bind-interfaces is set, there might be more than one dnmsasq
+ /* When bind-interfaces is set, there might be more than one dnmsasq
      instance binding port 547. That's OK if they serve different networks.
-     Need to set REUSEADDR to make this posible, or REUSEPORT on *BSD. */
+     Need to set REUSEADDR|REUSEPORT to make this posible.
+     Handle the case that REUSEPORT is defined, but the kernel doesn't 
+     support it. This handles the introduction of REUSEPORT on Linux. */
   if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
     {
+      int rc = -1, porterr = 0;
+
 #ifdef SO_REUSEPORT
-      int rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &oneopt, sizeof(oneopt));
-#else
-      int rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &oneopt, sizeof(oneopt));
+      if ((rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &oneopt, sizeof(oneopt))) == -1 &&
+	  errno != ENOPROTOOPT)
+	porterr = 1;
 #endif
+      
+      if (rc == -1 && !porterr)
+	rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &oneopt, sizeof(oneopt));
+      
       if (rc == -1)
 	die(_("failed to set SO_REUSE{ADDR|PORT} on DHCPv6 socket: %s"), NULL, EC_BADNET);
     }
-- 
1.7.2.5