Repository: netty/netty
Issue: trasport/native/epoll build failure
Labels: defect

Are their version requirements listed somewhere for netty's epoll?  I'm getting a build failure in some of the native code involving type redefinitions.

**OS info**
Ubuntu 12.04

> $uname -a
> Linux <name> 3.2.0-67-generic #101-Ubuntu SMP Tue Jul 15 17:46:11 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
> 
> $ mvn --version
> Apache Maven 3.1.1 (0728685237757ffbf44136acec0402957f723d9a; 2013-09-17 11:22:22-0400)
> Maven home: /home/smitchel/maven/apache-maven-3.1.1
> Java version: 1.7.0_67, vendor: Oracle Corporation
> Java home: /usr/lib/jvm/java-7-oracle/jre
> Default locale: en_US, platform encoding: ISO-8859-1
> OS name: "linux", version: "3.2.0-67-generic", arch: "amd64", family: "unix"

**Build failure**

> [INFO] executing: /bin/sh -c make install
> [INFO] /bin/sh ./libtool --tag=CC   --mode=compile gcc -DHAVE_CONFIG_H -I. -I./src     -g -O2 -I/usr/lib/jvm/java-7-oracle/include -I/usr/lib/jvm/java-7-oracle/include/linux -c -o src/io_netty_channel_epoll_Native.lo src/io_netty_channel_epoll_Native.c
> [INFO] libtool: compile:  gcc -DHAVE_CONFIG_H -I. -I./src -g -O2 -I/usr/lib/jvm/java-7-oracle/include -I/usr/lib/jvm/java-7-oracle/include/linux -c src/io_netty_channel_epoll_Native.c  -fPIC -DPIC -o src/.libs/io_netty_channel_epoll_Native.o
> [INFO] src/io_netty_channel_epoll_Native.c:37:40: warning: 'struct mmsghdr' declared inside parameter list [enabled by default]
> [INFO] src/io_netty_channel_epoll_Native.c:37:12: error: conflicting types for 'sendmmsg'
> [INFO] /usr/include/x86_64-linux-gnu/bits/socket.h:439:12: note: previous declaration of 'sendmmsg' was here
> [INFO] src/io_netty_channel_epoll_Native.c: In function 'getOption':
> [INFO] src/io_netty_channel_epoll_Native.c:128:5: warning: passing argument 4 of 'getsockopt' discards 'const' qualifier from pointer target type [enabled by default]
> [INFO] /usr/include/x86_64-linux-gnu/sys/socket.h:190:12: note: expected 'void \* **restrict**' but argument is of type 'const void _'
> [INFO] src/io_netty_channel_epoll_Native.c: In function 'Java_io_netty_channel_epoll_Native_sendmmsg':
> [INFO] src/io_netty_channel_epoll_Native.c:770:8: warning: passing argument 2 of 'sendmmsg' from incompatible pointer type [enabled by default]
> [INFO] src/io_netty_channel_epoll_Native.c:37:12: note: expected 'struct mmsghdr *' but argument is of type 'struct mmsghdr *'
> [INFO] src/io_netty_channel_epoll_Native.c: In function 'Java_io_netty_channel_epoll_Native_bind':
> [INFO] src/io_netty_channel_epoll_Native.c:990:9: warning: 'return' with a value, in function returning void [enabled by default]
> [INFO] make: *_\* [src/io_netty_channel_epoll_Native.lo] Error 1


Issue comments:
Here is my sendmmsg from bits/socket.h

> /\* Send a VLEN messages as described by VMESSAGES to socket FD.
>    Return the number of datagrams successfully written or -1 for errors.
> This function is a cancellation point and therefore not marked with
>    __THROW.  */
> extern int sendmmsg (int __fd, struct mmsghdr *__vmessages,
>              unsigned int __vlen, int __flags);

Here is the sendmmsg from io_netty_channel_epoll_Native.c

> extern int sendmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, unsigned int flags) **attribute**((weak));

> gcc --version
> gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3

Hold on a second I found http://netty.io/wiki/native-transports.html and am giving this a read ;)

The above wiki did not help.  Issue still exists.

I opened up PR https://github.com/netty/netty/pull/2890 for this issue

@normanmaurer Cherry picked fix as 94deea409ec6788cb3705aae319be1fdfcbe85f8


Pull request review comments:

Patch that resolved the issue:
diff --git a/transport-native-epoll/pom.xml b/transport-native-epoll/pom.xml
index de1d4727578..02902caf6c4 100644
--- a/transport-native-epoll/pom.xml
+++ b/transport-native-epoll/pom.xml
@@ -78,6 +78,9 @@
               <platform>.</platform>
               <forceConfigure>true</forceConfigure>
               <forceAutogen>true</forceAutogen>
+              <configureArgs>
+                <arg>${jni.compiler.args}</arg>
+              </configureArgs>
             </configuration>
             <goals>
               <goal>generate</goal>
@@ -112,6 +115,104 @@
           </execution>
         </executions>
       </plugin>
+
+      <plugin>
+        <artifactId>maven-antrun-plugin</artifactId>
+        <version>1.7</version>
+        <executions>
+          <execution>
+            <!-- Phase must be before regex-glibc-sendmmsg and regex-linux-sendmmsg -->
+            <phase>validate</phase>
+            <goals>
+              <goal>run</goal>
+            </goals>
+            <id>ant-get-systeminfo</id>
+            <configuration>
+              <exportAntProperties>true</exportAntProperties>
+              <tasks>
+                <exec executable="sh" outputproperty="ldd_version">
+                  <arg value="-c"/>
+                  <arg value="ldd --version | head -1"/>
+                </exec>
+                <exec executable="uname" outputproperty="uname_os_version">
+                  <arg value="-r"/>
+                </exec>
+              </tasks>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>build-helper-maven-plugin</artifactId>
+        <version>1.7</version>
+        <executions>
+          <execution>
+            <!-- Phase must be before regex-combined-sendmmsg -->
+            <phase>initialize</phase>
+            <id>regex-glibc-sendmmsg</id>
+            <goals>
+              <goal>regex-property</goal>
+            </goals>
+            <configuration>
+              <name>glibc.sendmmsg.support</name>
+              <value>${ldd_version}</value>
+              <!-- Version must be >= 2.14 - set to IO_NETTY_SENDMSSG_NOT_FOUND if this version is not satisfied -->
+              <regex>^((?!^[^)]+\)\s+(0*2\.1[4-9]|0*2\.[2-9][0-9]+|0*[3-9][0-9]*|0*[1-9]+[0-9]+).*).)*$</regex>
+              <replacement>IO_NETTY_SENDMSSG_NOT_FOUND</replacement>
+              <failIfNoMatch>false</failIfNoMatch>
+            </configuration>
+          </execution>
+          <execution>
+            <!-- Phase must be before regex-combined-sendmmsg -->
+            <phase>initialize</phase>
+            <id>regex-linux-sendmmsg</id>
+            <goals>
+              <goal>regex-property</goal>
+            </goals>
+            <configuration>
+              <name>linux.sendmmsg.support</name>
+              <value>${uname_os_version}</value>
+              <!-- Version must be >= 3 - set to IO_NETTY_SENDMSSG_NOT_FOUND if this version is not satisfied -->
+              <regex>^((?!^[0-9]*[3-9]\.?.*).)*$</regex>
+              <replacement>IO_NETTY_SENDMSSG_NOT_FOUND</replacement>
+              <failIfNoMatch>false</failIfNoMatch>
+            </configuration>
+          </execution>
+          <execution>
+            <!-- Phase must be before regex-unset-if-needed-sendmmsg -->
+            <phase>generate-sources</phase>
+            <id>regex-combined-sendmmsg</id>
+            <goals>
+              <goal>regex-property</goal>
+            </goals>
+            <configuration>
+              <name>jni.compiler.args</name>
+              <value>${linux.sendmmsg.support}${glibc.sendmmsg.support}</value>
+              <!-- If glibc and linux kernel are both not sufficient...then define the CFLAGS -->
+              <regex>.*IO_NETTY_SENDMSSG_NOT_FOUND.*</regex>
+              <replacement>CFLAGS="-DIO_NETTY_SENDMMSG_NOT_FOUND"</replacement>
+              <failIfNoMatch>false</failIfNoMatch>
+            </configuration>
+          </execution>
+          <execution>
+            <!-- Phase must be before build-native-lib -->
+            <phase>generate-sources</phase>
+            <id>regex-unset-if-needed-sendmmsg</id>
+            <goals>
+              <goal>regex-property</goal>
+            </goals>
+            <configuration>
+              <name>jni.compiler.args</name>
+              <value>${jni.compiler.args}</value>
+              <!-- If glibc and linux kernel are both not sufficient...then define the CFLAGS -->
+              <regex>^((?!CFLAGS=).)*$</regex>
+              <replacement>CFLAGS=""</replacement>
+              <failIfNoMatch>false</failIfNoMatch>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
     </plugins>
   </build>
 </project>
diff --git a/transport-native-epoll/src/main/c/io_netty_channel_epoll_Native.c b/transport-native-epoll/src/main/c/io_netty_channel_epoll_Native.c
index 5dc7eb5825d..03501c5a93f 100644
--- a/transport-native-epoll/src/main/c/io_netty_channel_epoll_Native.c
+++ b/transport-native-epoll/src/main/c/io_netty_channel_epoll_Native.c
@@ -13,6 +13,7 @@
  * License for the specific language governing permissions and limitations
  * under the License.
  */
+#define _GNU_SOURCE
 #include <jni.h>
 #include <stdlib.h>
 #include <string.h>
@@ -30,19 +31,20 @@
 #include <sys/utsname.h>
 #include "io_netty_channel_epoll_Native.h"
 
-
 // optional
 extern int accept4(int sockFd, struct sockaddr *addr, socklen_t *addrlen, int flags) __attribute__((weak));
 extern int epoll_create1(int flags) __attribute__((weak));
+
+#ifdef IO_NETTY_SENDMMSG_NOT_FOUND
 extern int sendmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, unsigned int flags) __attribute__((weak));
 
-// Just define it here and NOT use #define _GNU_SOURCE as we also want to be able to build on systems that not support
-// sendmmsg yet. The problem is if we use _GNU_SOURCE we will not be able to declare sendmmsg as extern
+#ifndef __USE_GNU
 struct mmsghdr {
     struct msghdr msg_hdr;  /* Message header */
     unsigned int  msg_len;  /* Number of bytes transmitted */
 };
-
+#endif
+#endif
 
 // Those are initialized in the init(...) method and cached for performance reasons
 jmethodID updatePosId = NULL;
@@ -123,7 +125,7 @@ jint epollCtl(JNIEnv * env, jint efd, int op, jint fd, jint flags, jint id) {
     return epoll_ctl(efd, op, fd, &ev);
 }
 
-jint getOption(JNIEnv *env, jint fd, int level, int optname, const void *optval, socklen_t optlen) {
+jint getOption(JNIEnv *env, jint fd, int level, int optname, void *optval, socklen_t optlen) {
     int code;
     code = getsockopt(fd, level, optname, optval, &optlen);
     if (code == 0) {
@@ -987,7 +989,7 @@ JNIEXPORT jint JNICALL Java_io_netty_channel_epoll_Native_socketStream(JNIEnv *
 JNIEXPORT void JNICALL Java_io_netty_channel_epoll_Native_bind(JNIEnv * env, jclass clazz, jint fd, jbyteArray address, jint scopeId, jint port) {
     struct sockaddr_storage addr;
     if (init_sockaddr(env, address, scopeId, port, &addr) == -1) {
-        return -1;
+        return;
     }
 
     if(bind(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1){


Test patch: