Repository: netty/netty
Issue: isKeepAlive is not supported by Epoll
Labels: defect

Calling isKeepAlive throws an exception

```
java.lang.UnsatisfiedLinkError: io.netty.channel.epoll.Native.isKeepAlive(I)I
    at io.netty.channel.epoll.Native.isKeepAlive(Native Method)
    at io.netty.channel.epoll.EpollSocketChannelConfig.isKeepAlive(EpollSocketChannelConfig.java:154)
```


Issue comments:
Sounds like an issue with loading the jni stuff. Can you show me how you specify the dependencies ?

```
    <dependency>
      <groupId>io.netty</groupId>
      <artifactId>netty-all</artifactId>
      <version>5.0.0.Alpha2</version>
      <scope>test</scope>
    </dependency>
```

it works if I comment out isKeepAlive() call. I think the problem is that isKeepAlive is missing in io_netty_channel_epoll_Native.h 

@vrozov please use 4.0.33.Final or 4.1.0.Beta8. It should work there. If not re-open

Actually It seems like there is still the bug. Reopen now

@vrozov fixed via https://github.com/netty/netty/pull/4619

Fixed


Pull request review comments:
consider making this a member variable and using a `@Before` to initialize and `@After` to tear it down.


Patch that resolved the issue:
diff --git a/transport-native-epoll/src/main/c/io_netty_channel_unix_Socket.c b/transport-native-epoll/src/main/c/io_netty_channel_unix_Socket.c
index 60d7c4bc752..2800a69075e 100644
--- a/transport-native-epoll/src/main/c/io_netty_channel_unix_Socket.c
+++ b/transport-native-epoll/src/main/c/io_netty_channel_unix_Socket.c
@@ -662,6 +662,14 @@ JNIEXPORT void JNICALL Java_io_netty_channel_unix_Socket_setSoLinger(JNIEnv* env
     netty_unix_socket_setOption(env, fd, SOL_SOCKET, SO_LINGER, &solinger, sizeof(solinger));
 }
 
+JNIEXPORT jint JNICALL Java_io_netty_channel_unix_Socket_isKeepAlive(JNIEnv* env, jclass clazz, jint fd) {
+    int optval;
+    if (netty_unix_socket_getOption(env, fd, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval)) == -1) {
+        return -1;
+    }
+    return optval;
+}
+
 JNIEXPORT jint JNICALL Java_io_netty_channel_unix_Socket_isTcpNoDelay(JNIEnv* env, jclass clazz, jint fd) {
     int optval;
     if (netty_unix_socket_getOption(env, fd, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof(optval)) == -1) {
diff --git a/transport-native-epoll/src/main/c/io_netty_channel_unix_Socket.h b/transport-native-epoll/src/main/c/io_netty_channel_unix_Socket.h
index af126bf6903..c82138252bc 100644
--- a/transport-native-epoll/src/main/c/io_netty_channel_unix_Socket.h
+++ b/transport-native-epoll/src/main/c/io_netty_channel_unix_Socket.h
@@ -51,6 +51,7 @@ void Java_io_netty_channel_unix_Socket_setSoLinger(JNIEnv* env, jclass clazz, ji
 jint Java_io_netty_channel_unix_Socket_isTcpNoDelay(JNIEnv* env, jclass clazz, jint fd);
 jint Java_io_netty_channel_unix_Socket_getReceiveBufferSize(JNIEnv* env, jclass clazz, jint fd);
 jint Java_io_netty_channel_unix_Socket_getSendBufferSize(JNIEnv* env, jclass clazz, jint fd);
+jint Java_io_netty_channel_unix_Socket_isKeepAlive(JNIEnv* env, jclass clazz, jint fd);
 jint Java_io_netty_channel_unix_Socket_isTcpCork(JNIEnv* env, jclass clazz, jint fd);
 jint Java_io_netty_channel_unix_Socket_getSoLinger(JNIEnv* env, jclass clazz, jint fd);
 jint Java_io_netty_channel_unix_Socket_getSoError(JNIEnv* env, jclass clazz, jint fd);


Test patch:
diff --git a/transport-native-epoll/src/test/java/io/netty/channel/unix/SocketTest.java b/transport-native-epoll/src/test/java/io/netty/channel/unix/SocketTest.java
new file mode 100644
index 00000000000..0fe9df0f385
--- /dev/null
+++ b/transport-native-epoll/src/test/java/io/netty/channel/unix/SocketTest.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2015 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.unix;
+
+import io.netty.channel.epoll.Epoll;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+
+import static org.junit.Assert.*;
+
+public class SocketTest {
+
+    static {
+        Epoll.ensureAvailability();
+    }
+
+    private Socket socket;
+
+    @Before
+    public void setup() {
+        socket = Socket.newSocketStream();
+    }
+
+    @After
+    public void tearDown() throws IOException {
+        socket.close();
+    }
+
+    @Test
+    public void testKeepAlive() throws Exception {
+        Socket socket = Socket.newSocketStream();
+        try {
+            assertFalse(socket.isKeepAlive());
+            socket.setKeepAlive(true);
+            assertTrue(socket.isKeepAlive());
+        } finally {
+            socket.close();
+        }
+    }
+
+    @Test
+    public void testTcpCork() throws Exception {
+        Socket socket = Socket.newSocketStream();
+        try {
+            assertFalse(socket.isTcpCork());
+            socket.setTcpCork(true);
+            assertTrue(socket.isTcpCork());
+        } finally {
+            socket.close();
+        }
+    }
+
+    @Test
+    public void testTcpNoDelay() throws Exception {
+        Socket socket = Socket.newSocketStream();
+        try {
+            assertFalse(socket.isTcpNoDelay());
+            socket.setTcpNoDelay(true);
+            assertTrue(socket.isTcpNoDelay());
+        } finally {
+            socket.close();
+        }
+    }
+
+    @Test
+    public void testReceivedBufferSize() throws Exception {
+        Socket socket = Socket.newSocketStream();
+        try {
+            int size = socket.getReceiveBufferSize();
+            int newSize = 65535;
+            assertTrue(size > 0);
+            socket.setReceiveBufferSize(newSize);
+            // Linux usually set it to double what is specified
+            assertTrue(newSize <= socket.getReceiveBufferSize());
+        } finally {
+            socket.close();
+        }
+    }
+
+    @Test
+    public void testSendBufferSize() throws Exception {
+        Socket socket = Socket.newSocketStream();
+        try {
+            int size = socket.getSendBufferSize();
+            int newSize = 65535;
+            assertTrue(size > 0);
+            socket.setSendBufferSize(newSize);
+            // Linux usually set it to double what is specified
+            assertTrue(newSize <= socket.getSendBufferSize());
+        } finally {
+            socket.close();
+        }
+    }
+
+    @Test
+    public void testSoLinger() throws Exception {
+        Socket socket = Socket.newSocketStream();
+        try {
+            assertEquals(-1, socket.getSoLinger());
+            socket.setSoLinger(10);
+            assertEquals(10, socket.getSoLinger());
+        } finally {
+            socket.close();
+        }
+    }
+}
+