View Javadoc
1   /*
2    * Copyright 2013 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package io.netty.channel.epoll;
17  
18  
19  import io.netty.channel.ChannelException;
20  import io.netty.channel.DefaultFileRegion;
21  import io.netty.channel.unix.DomainSocketAddress;
22  import io.netty.util.internal.EmptyArrays;
23  import io.netty.util.internal.NativeLibraryLoader;
24  import io.netty.util.internal.PlatformDependent;
25  import io.netty.util.internal.SystemPropertyUtil;
26  
27  import java.io.IOException;
28  import java.net.Inet6Address;
29  import java.net.InetAddress;
30  import java.net.InetSocketAddress;
31  import java.net.SocketAddress;
32  import java.net.UnknownHostException;
33  import java.nio.ByteBuffer;
34  import java.nio.channels.ClosedChannelException;
35  import java.util.Locale;
36  
37  /**
38   * Native helper methods
39   *
40   * <strong>Internal usage only!</strong>
41   */
42  final class Native {
43  
44      static {
45          String name = SystemPropertyUtil.get("os.name").toLowerCase(Locale.UK).trim();
46          if (!name.startsWith("linux")) {
47              throw new IllegalStateException("Only supported on Linux");
48          }
49          NativeLibraryLoader.load("netty-transport-native-epoll", PlatformDependent.getClassLoader(Native.class));
50      }
51  
52      // EventLoop operations and constants
53      public static final int EPOLLIN = epollin();
54      public static final int EPOLLOUT = epollout();
55      public static final int EPOLLRDHUP = epollrdhup();
56      public static final int EPOLLET = epollet();
57  
58      public static final int IOV_MAX = iovMax();
59      public static final int UIO_MAX_IOV = uioMaxIov();
60      public static final boolean IS_SUPPORTING_SENDMMSG = isSupportingSendmmsg();
61  
62      private static final byte[] IPV4_MAPPED_IPV6_PREFIX = {
63              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0xff, (byte) 0xff };
64  
65      // As all our JNI methods return -errno on error we need to compare with the negative errno codes.
66      private static final int ERRNO_EBADF_NEGATIVE = -errnoEBADF();
67      private static final int ERRNO_EPIPE_NEGATIVE = -errnoEPIPE();
68      private static final int ERRNO_ECONNRESET_NEGATIVE = -errnoECONNRESET();
69      private static final int ERRNO_EAGAIN_NEGATIVE = -errnoEAGAIN();
70      private static final int ERRNO_EWOULDBLOCK_NEGATIVE = -errnoEWOULDBLOCK();
71      private static final int ERRNO_EINPROGRESS_NEGATIVE = -errnoEINPROGRESS();
72  
73      /**
74       * Holds the mappings for errno codes to String messages.
75       * This eliminates the need to call back into JNI to get the right String message on an exception
76       * and thus is faster.
77       *
78       * The array length of 1024 should be more then enough because errno.h only holds < 200 codes.
79       */
80      private static final String[] ERRORS = new String[1024]; //
81  
82      // Pre-instantiated exceptions which does not need any stacktrace and
83      // can be thrown multiple times for performance reasons.
84      private static final ClosedChannelException CLOSED_CHANNEL_EXCEPTION;
85      private static final IOException CONNECTION_RESET_EXCEPTION_WRITE;
86      private static final IOException CONNECTION_RESET_EXCEPTION_WRITEV;
87      private static final IOException CONNECTION_RESET_EXCEPTION_READ;
88      private static final IOException CONNECTION_RESET_EXCEPTION_SENDFILE;
89      private static final IOException CONNECTION_RESET_EXCEPTION_SENDTO;
90      private static final IOException CONNECTION_RESET_EXCEPTION_SENDMSG;
91      private static final IOException CONNECTION_RESET_EXCEPTION_SENDMMSG;
92  
93      static {
94          for (int i = 0; i < ERRORS.length; i++) {
95              // This is ok as strerror returns 'Unknown error i' when the message is not known.
96              ERRORS[i] = strError(i);
97          }
98  
99          CONNECTION_RESET_EXCEPTION_READ = newConnectionResetException("syscall:read(...)",
100                 ERRNO_ECONNRESET_NEGATIVE);
101         CONNECTION_RESET_EXCEPTION_WRITE = newConnectionResetException("syscall:write(...)",
102                 ERRNO_EPIPE_NEGATIVE);
103         CONNECTION_RESET_EXCEPTION_WRITEV = newConnectionResetException("syscall:writev(...)",
104                 ERRNO_EPIPE_NEGATIVE);
105         CONNECTION_RESET_EXCEPTION_SENDFILE = newConnectionResetException("syscall:sendfile(...)",
106                 ERRNO_EPIPE_NEGATIVE);
107         CONNECTION_RESET_EXCEPTION_SENDTO = newConnectionResetException("syscall:sendto(...)",
108                 ERRNO_EPIPE_NEGATIVE);
109         CONNECTION_RESET_EXCEPTION_SENDMSG = newConnectionResetException("syscall:sendmsg(...)",
110                 ERRNO_EPIPE_NEGATIVE);
111         CONNECTION_RESET_EXCEPTION_SENDMMSG = newConnectionResetException("syscall:sendmmsg(...)",
112                 ERRNO_EPIPE_NEGATIVE);
113         CLOSED_CHANNEL_EXCEPTION = new ClosedChannelException();
114         CLOSED_CHANNEL_EXCEPTION.setStackTrace(EmptyArrays.EMPTY_STACK_TRACE);
115     }
116 
117     private static IOException newConnectionResetException(String method, int errnoNegative) {
118         IOException exception = newIOException(method, errnoNegative);
119         exception.setStackTrace(EmptyArrays.EMPTY_STACK_TRACE);
120         return exception;
121     }
122 
123     private static IOException newIOException(String method, int err) {
124         return new IOException(method + "() failed: " + ERRORS[-err]);
125     }
126 
127     private static int ioResult(String method, int err, IOException resetCause) throws IOException {
128         // network stack saturated... try again later
129         if (err == ERRNO_EAGAIN_NEGATIVE || err == ERRNO_EWOULDBLOCK_NEGATIVE) {
130             return 0;
131         }
132         if (err == ERRNO_EPIPE_NEGATIVE || err == ERRNO_ECONNRESET_NEGATIVE) {
133             throw resetCause;
134         }
135         if (err == ERRNO_EBADF_NEGATIVE) {
136             throw CLOSED_CHANNEL_EXCEPTION;
137         }
138         // TODO: We could even go futher and use a pre-instanced IOException for the other error codes, but for
139         //       all other errors it may be better to just include a stacktrace.
140         throw newIOException(method, err);
141     }
142 
143     public static native int eventFd();
144     public static native void eventFdWrite(int fd, long value);
145     public static native void eventFdRead(int fd);
146     public static native int epollCreate();
147     public static int epollWait(int efd, EpollEventArray events, int timeout) throws IOException {
148         int ready = epollWait0(efd, events.memoryAddress(), events.length(), timeout);
149         if (ready < 0) {
150             throw newIOException("epoll_wait", ready);
151         }
152         return ready;
153     }
154     private static native int epollWait0(int efd, long address, int len, int timeout);
155 
156     public static native void epollCtlAdd(int efd, final int fd, final int flags);
157 
158     public static native void epollCtlMod(int efd, final int fd, final int flags);
159     public static native void epollCtlDel(int efd, final int fd);
160 
161     private static native int errnoEBADF();
162     private static native int errnoEPIPE();
163     private static native int errnoECONNRESET();
164 
165     private static native int errnoEAGAIN();
166     private static native int errnoEWOULDBLOCK();
167     private static native int errnoEINPROGRESS();
168     private static native String strError(int err);
169 
170     // File-descriptor operations
171     public static void close(int fd) throws IOException {
172         int res = close0(fd);
173         if (res < 0) {
174             throw newIOException("close", res);
175         }
176     }
177 
178     private static native int close0(int fd);
179 
180     public static int write(int fd, ByteBuffer buf, int pos, int limit) throws IOException {
181         int res = write0(fd, buf, pos, limit);
182         if (res >= 0) {
183             return res;
184         }
185         return ioResult("write", res, CONNECTION_RESET_EXCEPTION_WRITE);
186     }
187 
188     private static native int write0(int fd, ByteBuffer buf, int pos, int limit);
189 
190     public static int writeAddress(int fd, long address, int pos, int limit) throws IOException {
191         int res = writeAddress0(fd, address, pos, limit);
192         if (res >= 0) {
193             return res;
194         }
195         return ioResult("writeAddress", res, CONNECTION_RESET_EXCEPTION_WRITE);
196     }
197 
198     private static native int writeAddress0(int fd, long address, int pos, int limit);
199 
200     public static long writev(int fd, ByteBuffer[] buffers, int offset, int length) throws IOException {
201         long res = writev0(fd, buffers, offset, length);
202         if (res >= 0) {
203             return res;
204         }
205         return ioResult("writev", (int) res, CONNECTION_RESET_EXCEPTION_WRITEV);
206     }
207 
208     private static native long writev0(int fd, ByteBuffer[] buffers, int offset, int length);
209 
210     public static long writevAddresses(int fd, long memoryAddress, int length)
211             throws IOException {
212         long res = writevAddresses0(fd, memoryAddress, length);
213         if (res >= 0) {
214             return res;
215         }
216         return ioResult("writevAddresses", (int) res, CONNECTION_RESET_EXCEPTION_WRITEV);
217     }
218 
219     private static native long writevAddresses0(int fd, long memoryAddress, int length);
220 
221     public static int read(int fd, ByteBuffer buf, int pos, int limit) throws IOException {
222         int res = read0(fd, buf, pos, limit);
223         if (res > 0) {
224             return res;
225         }
226         if (res == 0) {
227             return -1;
228         }
229         return ioResult("read", res, CONNECTION_RESET_EXCEPTION_READ);
230     }
231 
232     private static native int read0(int fd, ByteBuffer buf, int pos, int limit);
233 
234     public static int readAddress(int fd, long address, int pos, int limit) throws IOException {
235         int res = readAddress0(fd, address, pos, limit);
236         if (res > 0) {
237             return res;
238         }
239         if (res == 0) {
240             return -1;
241         }
242         return ioResult("readAddress", res, CONNECTION_RESET_EXCEPTION_READ);
243     }
244 
245     private static native int readAddress0(int fd, long address, int pos, int limit);
246 
247     public static long sendfile(
248             int dest, DefaultFileRegion src, long baseOffset, long offset, long length) throws IOException {
249         // Open the file-region as it may be created via the lazy constructor. This is needed as we directly access
250         // the FileChannel field directly via JNI
251         src.open();
252 
253         long res = sendfile0(dest, src, baseOffset, offset, length);
254         if (res >= 0) {
255             return res;
256         }
257         return ioResult("sendfile", (int) res, CONNECTION_RESET_EXCEPTION_SENDFILE);
258     }
259 
260     private static native long sendfile0(
261             int dest, DefaultFileRegion src, long baseOffset, long offset, long length) throws IOException;
262 
263     public static int sendTo(
264             int fd, ByteBuffer buf, int pos, int limit, InetAddress addr, int port) throws IOException {
265         // just duplicate the toNativeInetAddress code here to minimize object creation as this method is expected
266         // to be called frequently
267         byte[] address;
268         int scopeId;
269         if (addr instanceof Inet6Address) {
270             address = addr.getAddress();
271             scopeId = ((Inet6Address) addr).getScopeId();
272         } else {
273             // convert to ipv4 mapped ipv6 address;
274             scopeId = 0;
275             address = ipv4MappedIpv6Address(addr.getAddress());
276         }
277         int res = sendTo0(fd, buf, pos, limit, address, scopeId, port);
278         if (res >= 0) {
279             return res;
280         }
281         return ioResult("sendTo", res, CONNECTION_RESET_EXCEPTION_SENDTO);
282     }
283 
284     private static native int sendTo0(
285             int fd, ByteBuffer buf, int pos, int limit, byte[] address, int scopeId, int port);
286 
287     public static int sendToAddress(
288             int fd, long memoryAddress, int pos, int limit, InetAddress addr, int port) throws IOException {
289         // just duplicate the toNativeInetAddress code here to minimize object creation as this method is expected
290         // to be called frequently
291         byte[] address;
292         int scopeId;
293         if (addr instanceof Inet6Address) {
294             address = addr.getAddress();
295             scopeId = ((Inet6Address) addr).getScopeId();
296         } else {
297             // convert to ipv4 mapped ipv6 address;
298             scopeId = 0;
299             address = ipv4MappedIpv6Address(addr.getAddress());
300         }
301         int res = sendToAddress0(fd, memoryAddress, pos, limit, address, scopeId, port);
302         if (res >= 0) {
303             return res;
304         }
305         return ioResult("sendToAddress", res, CONNECTION_RESET_EXCEPTION_SENDTO);
306     }
307 
308     private static native int sendToAddress0(
309             int fd, long memoryAddress, int pos, int limit, byte[] address, int scopeId, int port);
310 
311     public static int sendToAddresses(
312             int fd, long memoryAddress, int length, InetAddress addr, int port) throws IOException {
313         // just duplicate the toNativeInetAddress code here to minimize object creation as this method is expected
314         // to be called frequently
315         byte[] address;
316         int scopeId;
317         if (addr instanceof Inet6Address) {
318             address = addr.getAddress();
319             scopeId = ((Inet6Address) addr).getScopeId();
320         } else {
321             // convert to ipv4 mapped ipv6 address;
322             scopeId = 0;
323             address = ipv4MappedIpv6Address(addr.getAddress());
324         }
325         int res = sendToAddresses(fd, memoryAddress, length, address, scopeId, port);
326         if (res >= 0) {
327             return res;
328         }
329         return ioResult("sendToAddresses", res, CONNECTION_RESET_EXCEPTION_SENDMSG);
330     }
331 
332     private static native int sendToAddresses(
333             int fd, long memoryAddress, int length, byte[] address, int scopeId, int port);
334 
335     public static native EpollDatagramChannel.DatagramSocketAddress recvFrom(
336             int fd, ByteBuffer buf, int pos, int limit) throws IOException;
337 
338     public static native EpollDatagramChannel.DatagramSocketAddress recvFromAddress(
339             int fd, long memoryAddress, int pos, int limit) throws IOException;
340 
341     public static int sendmmsg(
342             int fd, NativeDatagramPacketArray.NativeDatagramPacket[] msgs, int offset, int len) throws IOException {
343         int res = sendmmsg0(fd, msgs, offset, len);
344         if (res >= 0) {
345             return res;
346         }
347         return ioResult("sendmmsg", res, CONNECTION_RESET_EXCEPTION_SENDMMSG);
348     }
349 
350     private static native int sendmmsg0(
351             int fd, NativeDatagramPacketArray.NativeDatagramPacket[] msgs, int offset, int len);
352 
353     private static native boolean isSupportingSendmmsg();
354 
355     // socket operations
356     public static int socketStreamFd() {
357         int res = socketStream();
358         if (res < 0) {
359             throw new ChannelException(newIOException("socketStreamFd", res));
360         }
361         return res;
362     }
363 
364     public static int socketDgramFd() {
365         int res = socketDgram();
366         if (res < 0) {
367             throw new ChannelException(newIOException("socketDgramFd", res));
368         }
369         return res;
370     }
371 
372     public static int socketDomainFd() {
373         int res = socketDomain();
374         if (res < 0) {
375             throw new ChannelException(newIOException("socketDomain", res));
376         }
377         return res;
378     }
379 
380     private static native int socketStream();
381     private static native int socketDgram();
382     private static native int socketDomain();
383 
384     public static void bind(int fd, SocketAddress socketAddress) throws IOException {
385         if (socketAddress instanceof InetSocketAddress) {
386             InetSocketAddress addr = (InetSocketAddress) socketAddress;
387             NativeInetAddress address = toNativeInetAddress(addr.getAddress());
388             int res = bind(fd, address.address, address.scopeId, addr.getPort());
389             if (res < 0) {
390                 throw newIOException("bind", res);
391             }
392         } else if (socketAddress instanceof DomainSocketAddress) {
393             DomainSocketAddress addr = (DomainSocketAddress) socketAddress;
394             int res = bindDomainSocket(fd, addr.path());
395             if (res < 0) {
396                 throw newIOException("bind", res);
397             }
398         } else {
399             throw new Error("Unexpected SocketAddress implementation " + socketAddress);
400         }
401     }
402 
403     private static native int bind(int fd, byte[] address, int scopeId, int port);
404     private static native int bindDomainSocket(int fd, String path);
405 
406     public static void listen(int fd, int backlog) throws IOException {
407         int res = listen0(fd, backlog);
408         if (res < 0) {
409             throw newIOException("listen", res);
410         }
411     }
412 
413     private static native int listen0(int fd, int backlog);
414 
415     public static boolean connect(int fd, SocketAddress socketAddress) throws IOException {
416         int res;
417         if (socketAddress instanceof InetSocketAddress) {
418             InetSocketAddress inetSocketAddress = (InetSocketAddress) socketAddress;
419             NativeInetAddress address = toNativeInetAddress(inetSocketAddress.getAddress());
420             res = connect(fd, address.address, address.scopeId, inetSocketAddress.getPort());
421         } else if (socketAddress instanceof DomainSocketAddress) {
422             DomainSocketAddress unixDomainSocketAddress = (DomainSocketAddress) socketAddress;
423             res = connectDomainSocket(fd, unixDomainSocketAddress.path());
424         } else {
425             throw new Error("Unexpected SocketAddress implementation " + socketAddress);
426         }
427         if (res < 0) {
428             if (res == ERRNO_EINPROGRESS_NEGATIVE) {
429                 // connect not complete yet need to wait for EPOLLOUT event
430                 return false;
431             }
432             throw newIOException("connect", res);
433         }
434         return true;
435     }
436 
437     private static native int connect(int fd, byte[] address, int scopeId, int port);
438     private static native int connectDomainSocket(int fd, String path);
439 
440     public static boolean finishConnect(int fd) throws IOException {
441         int res = finishConnect0(fd);
442         if (res < 0) {
443             if (res == ERRNO_EINPROGRESS_NEGATIVE) {
444                 // connect still in progress
445                 return false;
446             }
447             throw newIOException("finishConnect", res);
448         }
449         return true;
450     }
451 
452     private static native int finishConnect0(int fd);
453 
454     public static InetSocketAddress remoteAddress(int fd) {
455         byte[] addr = remoteAddress0(fd);
456         // addr may be null if getpeername failed.
457         // See https://github.com/netty/netty/issues/3328
458         if (addr == null) {
459             return null;
460         }
461         return address(addr, 0, addr.length);
462     }
463 
464     public static InetSocketAddress localAddress(int fd) {
465         byte[] addr = localAddress0(fd);
466         // addr may be null if getpeername failed.
467         // See https://github.com/netty/netty/issues/3328
468         if (addr == null) {
469             return null;
470         }
471         return address(addr, 0, addr.length);
472     }
473 
474     static InetSocketAddress address(byte[] addr, int offset, int len) {
475         // The last 4 bytes are always the port
476         final int port = decodeInt(addr, offset + len - 4);
477         final InetAddress address;
478 
479         try {
480             switch (len) {
481                 // 8 bytes:
482                 // - 4  == ipaddress
483                 // - 4  == port
484                 case 8:
485                     byte[] ipv4 = new byte[4];
486                     System.arraycopy(addr, offset, ipv4, 0, 4);
487                     address = InetAddress.getByAddress(ipv4);
488                     break;
489 
490                 // 24 bytes:
491                 // - 16  == ipaddress
492                 // - 4   == scopeId
493                 // - 4   == port
494                 case 24:
495                     byte[] ipv6 = new byte[16];
496                     System.arraycopy(addr, offset, ipv6, 0, 16);
497                     int scopeId = decodeInt(addr, offset + len  - 8);
498                     address = Inet6Address.getByAddress(null, ipv6, scopeId);
499                     break;
500                 default:
501                     throw new Error();
502             }
503             return new InetSocketAddress(address, port);
504         } catch (UnknownHostException e) {
505             throw new Error("Should never happen", e);
506         }
507     }
508 
509     static int decodeInt(byte[] addr, int index) {
510         return  (addr[index]     & 0xff) << 24 |
511                 (addr[index + 1] & 0xff) << 16 |
512                 (addr[index + 2] & 0xff) <<  8 |
513                 addr[index + 3] & 0xff;
514     }
515 
516     private static native byte[] remoteAddress0(int fd);
517     private static native byte[] localAddress0(int fd);
518 
519     public static int accept(int fd, byte[] addr) throws IOException {
520         int res = accept0(fd, addr);
521         if (res >= 0) {
522             return res;
523         }
524         if (res == ERRNO_EAGAIN_NEGATIVE || res == ERRNO_EWOULDBLOCK_NEGATIVE) {
525             // Everything consumed so just return -1 here.
526             return -1;
527         }
528         throw newIOException("accept", res);
529     }
530 
531     private static native int accept0(int fd, byte[] addr);
532 
533     public static int recvFd(int fd) throws IOException {
534         int res = recvFd0(fd);
535         if (res > 0) {
536             return res;
537         }
538         if (res == 0) {
539             return -1;
540         }
541 
542         if (res == ERRNO_EAGAIN_NEGATIVE || res == ERRNO_EWOULDBLOCK_NEGATIVE) {
543             // Everything consumed so just return -1 here.
544             return 0;
545         }
546         throw newIOException("recvFd", res);
547     }
548 
549     private static native int recvFd0(int fd);
550 
551     public static int sendFd(int socketFd, int fd) throws IOException {
552         int res = sendFd0(socketFd, fd);
553         if (res >= 0) {
554             return res;
555         }
556         if (res == ERRNO_EAGAIN_NEGATIVE || res == ERRNO_EWOULDBLOCK_NEGATIVE) {
557             // Everything consumed so just return -1 here.
558             return -1;
559         }
560         throw newIOException("sendFd", res);
561     }
562 
563     private static native int sendFd0(int socketFd, int fd);
564 
565     public static void shutdown(int fd, boolean read, boolean write) throws IOException {
566         int res = shutdown0(fd, read, write);
567         if (res < 0) {
568             throw newIOException("shutdown", res);
569         }
570     }
571 
572     private static native int shutdown0(int fd, boolean read, boolean write);
573 
574     // Socket option operations
575     public static native int getReceiveBufferSize(int fd);
576     public static native int getSendBufferSize(int fd);
577     public static native int isKeepAlive(int fd);
578     public static native int isReuseAddress(int fd);
579     public static native int isReusePort(int fd);
580     public static native int isTcpNoDelay(int fd);
581     public static native int isTcpCork(int fd);
582     public static native int getSoLinger(int fd);
583     public static native int getTrafficClass(int fd);
584     public static native int isBroadcast(int fd);
585     public static native int getTcpKeepIdle(int fd);
586     public static native int getTcpKeepIntvl(int fd);
587     public static native int getTcpKeepCnt(int fd);
588     public static native int getSoError(int fd);
589 
590     public static native void setKeepAlive(int fd, int keepAlive);
591     public static native void setReceiveBufferSize(int fd, int receiveBufferSize);
592     public static native void setReuseAddress(int fd, int reuseAddress);
593     public static native void setReusePort(int fd, int reuseAddress);
594     public static native void setSendBufferSize(int fd, int sendBufferSize);
595     public static native void setTcpNoDelay(int fd, int tcpNoDelay);
596     public static native void setTcpCork(int fd, int tcpCork);
597     public static native void setSoLinger(int fd, int soLinger);
598     public static native void setTrafficClass(int fd, int tcpNoDelay);
599     public static native void setBroadcast(int fd, int broadcast);
600     public static native void setTcpKeepIdle(int fd, int seconds);
601     public static native void setTcpKeepIntvl(int fd, int seconds);
602     public static native void setTcpKeepCnt(int fd, int probes);
603 
604     public static void tcpInfo(int fd, EpollTcpInfo info) {
605         tcpInfo0(fd, info.info);
606     }
607 
608     private static native void tcpInfo0(int fd, int[] array);
609 
610     private static NativeInetAddress toNativeInetAddress(InetAddress addr) {
611         byte[] bytes = addr.getAddress();
612         if (addr instanceof Inet6Address) {
613             return new NativeInetAddress(bytes, ((Inet6Address) addr).getScopeId());
614         } else {
615             // convert to ipv4 mapped ipv6 address;
616             return new NativeInetAddress(ipv4MappedIpv6Address(bytes));
617         }
618     }
619 
620     static byte[] ipv4MappedIpv6Address(byte[] ipv4) {
621         byte[] address = new byte[16];
622         System.arraycopy(IPV4_MAPPED_IPV6_PREFIX, 0, address, 0, IPV4_MAPPED_IPV6_PREFIX.length);
623         System.arraycopy(ipv4, 0, address, 12, ipv4.length);
624         return address;
625     }
626 
627     private static class NativeInetAddress {
628         final byte[] address;
629         final int scopeId;
630 
631         NativeInetAddress(byte[] address, int scopeId) {
632             this.address = address;
633             this.scopeId = scopeId;
634         }
635 
636         NativeInetAddress(byte[] address) {
637             this(address, 0);
638         }
639     }
640 
641     public static native String kernelVersion();
642 
643     private static native int iovMax();
644 
645     private static native int uioMaxIov();
646 
647     // epoll_event related
648     public static native int sizeofEpollEvent();
649     public static native int offsetofEpollData();
650 
651     private static native int epollin();
652     private static native int epollout();
653     private static native int epollrdhup();
654     private static native int epollet();
655 
656     private Native() {
657         // utility
658     }
659 }