Repository: netty/netty
Issue: Allow IP_FREEBIND option for UDP epoll
Labels: defect

### Expected behavior
while adding IP_FREEBIND option to boostrap it should work with EpollDatagramChannel
### Actual behavior
notification is logged that IP_FREEBIND is unknown option for this type of channel
### Steps to reproduce
set EpollChannelOption.IP_FREEBIND to true on ConnectionlessBootstrap

### Minimal yet complete reproducer code (or URL to code)
group = new EpollEventLoopGroup(poolSize);
connectionlessBootstrap=new Bootstrap();
connectionlessBootstrap.option(EpollChannelOption.SO_REUSEPORT, true);
connectionlessBootstrap.option(EpollChannelOption.IP_RECVORIGDSTADDR, true);
connectionlessBootstrap.option(EpollChannelOption.IP_FREEBIND, true);
connectionlessBootstrap.channel(EpollDatagramChannel.class);
connectionlessBootstrap.group(group);
connectionlessBootstrap.bind(new InetSocketAddress("0.0.0.0", port));

### Netty version
4.1.25

### JVM version (e.g. `java -version`)
1.8.0

### OS version (e.g. `uname -a`)
ubuntu

Issue comments:
@yulianoifa-mobius thanks a lot for the patch :)

Pull request review comments:
@yulianoifa-mobius please change to 2019
Add a CRLF.
i guess you meaned to remove CRLF

Patch that resolved the issue:
diff --git a/transport-native-epoll/src/main/java/io/netty/channel/epoll/EpollDatagramChannelConfig.java b/transport-native-epoll/src/main/java/io/netty/channel/epoll/EpollDatagramChannelConfig.java
index f3de6ac5947..778b555fa19 100644
--- a/transport-native-epoll/src/main/java/io/netty/channel/epoll/EpollDatagramChannelConfig.java
+++ b/transport-native-epoll/src/main/java/io/netty/channel/epoll/EpollDatagramChannelConfig.java
@@ -47,7 +47,7 @@ public Map<ChannelOption<?>, Object> getOptions() {
                 ChannelOption.SO_REUSEADDR, ChannelOption.IP_MULTICAST_LOOP_DISABLED,
                 ChannelOption.IP_MULTICAST_ADDR, ChannelOption.IP_MULTICAST_IF, ChannelOption.IP_MULTICAST_TTL,
                 ChannelOption.IP_TOS, ChannelOption.DATAGRAM_CHANNEL_ACTIVE_ON_REGISTRATION,
-                EpollChannelOption.SO_REUSEPORT, EpollChannelOption.IP_TRANSPARENT,
+                EpollChannelOption.SO_REUSEPORT, EpollChannelOption.IP_FREEBIND, EpollChannelOption.IP_TRANSPARENT,
                 EpollChannelOption.IP_RECVORIGDSTADDR);
     }
 
@@ -90,6 +90,9 @@ public <T> T getOption(ChannelOption<T> option) {
         if (option == EpollChannelOption.IP_TRANSPARENT) {
             return (T) Boolean.valueOf(isIpTransparent());
         }
+        if (option == EpollChannelOption.IP_FREEBIND) {
+            return (T) Boolean.valueOf(isFreeBind());
+        }
         if (option == EpollChannelOption.IP_RECVORIGDSTADDR) {
             return (T) Boolean.valueOf(isIpRecvOrigDestAddr());
         }
@@ -123,6 +126,8 @@ public <T> boolean setOption(ChannelOption<T> option, T value) {
             setActiveOnOpen((Boolean) value);
         } else if (option == EpollChannelOption.SO_REUSEPORT) {
             setReusePort((Boolean) value);
+        } else if (option == EpollChannelOption.IP_FREEBIND) {
+            setFreeBind((Boolean) value);
         } else if (option == EpollChannelOption.IP_TRANSPARENT) {
             setIpTransparent((Boolean) value);
         } else if (option == EpollChannelOption.IP_RECVORIGDSTADDR) {
@@ -407,6 +412,31 @@ public EpollDatagramChannelConfig setIpTransparent(boolean ipTransparent) {
         }
     }
 
+    /**
+     * Returns {@code true} if <a href="http://man7.org/linux/man-pages/man7/ip.7.html">IP_FREEBIND</a> is enabled,
+     * {@code false} otherwise.
+     */
+    public boolean isFreeBind() {
+        try {
+            return ((EpollDatagramChannel) channel).socket.isIpFreeBind();
+        } catch (IOException e) {
+            throw new ChannelException(e);
+        }
+    }
+
+    /**
+     * If {@code true} is used <a href="http://man7.org/linux/man-pages/man7/ip.7.html">IP_FREEBIND</a> is enabled,
+     * {@code false} for disable it. Default is disabled.
+     */
+    public EpollDatagramChannelConfig setFreeBind(boolean freeBind) {
+        try {
+            ((EpollDatagramChannel) channel).socket.setIpFreeBind(freeBind);
+            return this;
+        } catch (IOException e) {
+            throw new ChannelException(e);
+        }
+    }
+
     /**
      * Returns {@code true} if <a href="http://man7.org/linux/man-pages/man7/ip.7.html">IP_RECVORIGDSTADDR</a> is
      * enabled, {@code false} otherwise.


Test patch:
diff --git a/transport-native-epoll/src/test/java/io/netty/channel/epoll/EpollDatagramChannelConfigTest.java b/transport-native-epoll/src/test/java/io/netty/channel/epoll/EpollDatagramChannelConfigTest.java
new file mode 100644
index 00000000000..39cf7acd064
--- /dev/null
+++ b/transport-native-epoll/src/test/java/io/netty/channel/epoll/EpollDatagramChannelConfigTest.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2019 The Netty Project
+ *
+ * The Netty Project licenses this file to you under the Apache License,
+ * version 2.0 (the "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at:
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+package io.netty.channel.epoll;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertTrue;
+
+public class EpollDatagramChannelConfigTest {
+
+    @Test
+    public void testIpFreeBind() throws Exception {
+        Epoll.ensureAvailability();
+        EpollDatagramChannel channel = new EpollDatagramChannel();
+        assertTrue(channel.config().setOption(EpollChannelOption.IP_FREEBIND, true));
+        assertTrue(channel.config().getOption(EpollChannelOption.IP_FREEBIND));
+        channel.fd().close();
+    }
+}