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  import io.netty.channel.unix.Errors.NativeIoException;
19  import io.netty.channel.unix.FileDescriptor;
20  import io.netty.channel.unix.Socket;
21  import io.netty.util.internal.NativeLibraryLoader;
22  import io.netty.util.internal.PlatformDependent;
23  import io.netty.util.internal.SystemPropertyUtil;
24  import io.netty.util.internal.ThrowableUtil;
25  import io.netty.util.internal.logging.InternalLogger;
26  import io.netty.util.internal.logging.InternalLoggerFactory;
27  
28  import java.io.IOException;
29  import java.nio.channels.ClosedChannelException;
30  import java.util.Locale;
31  
32  import static io.netty.channel.epoll.NativeStaticallyReferencedJniMethods.epollerr;
33  import static io.netty.channel.epoll.NativeStaticallyReferencedJniMethods.epollet;
34  import static io.netty.channel.epoll.NativeStaticallyReferencedJniMethods.epollin;
35  import static io.netty.channel.epoll.NativeStaticallyReferencedJniMethods.epollout;
36  import static io.netty.channel.epoll.NativeStaticallyReferencedJniMethods.epollrdhup;
37  import static io.netty.channel.epoll.NativeStaticallyReferencedJniMethods.isSupportingSendmmsg;
38  import static io.netty.channel.epoll.NativeStaticallyReferencedJniMethods.isSupportingTcpFastopen;
39  import static io.netty.channel.epoll.NativeStaticallyReferencedJniMethods.kernelVersion;
40  import static io.netty.channel.epoll.NativeStaticallyReferencedJniMethods.tcpMd5SigMaxKeyLen;
41  import static io.netty.channel.unix.Errors.ERRNO_EPIPE_NEGATIVE;
42  import static io.netty.channel.unix.Errors.ioResult;
43  import static io.netty.channel.unix.Errors.newConnectionResetException;
44  import static io.netty.channel.unix.Errors.newIOException;
45  
46  /**
47   * Native helper methods
48   * <p><strong>Internal usage only!</strong>
49   * <p>Static members which call JNI methods must be defined in {@link NativeStaticallyReferencedJniMethods}.
50   */
51  public final class Native {
52      private static final InternalLogger logger = InternalLoggerFactory.getInstance(Native.class);
53  
54      static {
55          try {
56              // First, try calling a side-effect free JNI method to see if the library was already
57              // loaded by the application.
58              offsetofEpollData();
59          } catch (UnsatisfiedLinkError ignore) {
60              // The library was not previously loaded, load it now.
61              loadNativeLibrary();
62          }
63          Socket.initialize();
64      }
65  
66      // EventLoop operations and constants
67      public static final int EPOLLIN = epollin();
68      public static final int EPOLLOUT = epollout();
69      public static final int EPOLLRDHUP = epollrdhup();
70      public static final int EPOLLET = epollet();
71      public static final int EPOLLERR = epollerr();
72  
73      public static final boolean IS_SUPPORTING_SENDMMSG = isSupportingSendmmsg();
74      public static final boolean IS_SUPPORTING_TCP_FASTOPEN = isSupportingTcpFastopen();
75      public static final int TCP_MD5SIG_MAXKEYLEN = tcpMd5SigMaxKeyLen();
76      public static final String KERNEL_VERSION = kernelVersion();
77  
78      private static final NativeIoException SENDMMSG_CONNECTION_RESET_EXCEPTION;
79      private static final NativeIoException SPLICE_CONNECTION_RESET_EXCEPTION;
80      private static final ClosedChannelException SENDMMSG_CLOSED_CHANNEL_EXCEPTION = ThrowableUtil.unknownStackTrace(
81              new ClosedChannelException(), Native.class, "sendmmsg(...)");
82      private static final ClosedChannelException SPLICE_CLOSED_CHANNEL_EXCEPTION = ThrowableUtil.unknownStackTrace(
83              new ClosedChannelException(), Native.class, "splice(...)");
84  
85      static {
86          SENDMMSG_CONNECTION_RESET_EXCEPTION = newConnectionResetException("syscall:sendmmsg(...)",
87                  ERRNO_EPIPE_NEGATIVE);
88          SPLICE_CONNECTION_RESET_EXCEPTION = newConnectionResetException("syscall:splice(...)",
89                  ERRNO_EPIPE_NEGATIVE);
90      }
91  
92      public static FileDescriptor newEventFd() {
93          return new FileDescriptor(eventFd());
94      }
95  
96      public static FileDescriptor newTimerFd() {
97          return new FileDescriptor(timerFd());
98      }
99  
100     private static native int eventFd();
101     private static native int timerFd();
102     public static native void eventFdWrite(int fd, long value);
103     public static native void eventFdRead(int fd);
104     static native void timerFdRead(int fd);
105 
106     public static FileDescriptor newEpollCreate() {
107         return new FileDescriptor(epollCreate());
108     }
109 
110     private static native int epollCreate();
111 
112     public static int epollWait(FileDescriptor epollFd, EpollEventArray events, FileDescriptor timerFd,
113                                 int timeoutSec, int timeoutNs) throws IOException {
114         int ready = epollWait0(epollFd.intValue(), events.memoryAddress(), events.length(), timerFd.intValue(),
115                                timeoutSec, timeoutNs);
116         if (ready < 0) {
117             throw newIOException("epoll_wait", ready);
118         }
119         return ready;
120     }
121     private static native int epollWait0(int efd, long address, int len, int timerFd, int timeoutSec, int timeoutNs);
122 
123     public static void epollCtlAdd(int efd, final int fd, final int flags) throws IOException {
124         int res = epollCtlAdd0(efd, fd, flags);
125         if (res < 0) {
126             throw newIOException("epoll_ctl", res);
127         }
128     }
129     private static native int epollCtlAdd0(int efd, final int fd, final int flags);
130 
131     public static void epollCtlMod(int efd, final int fd, final int flags) throws IOException {
132         int res = epollCtlMod0(efd, fd, flags);
133         if (res < 0) {
134             throw newIOException("epoll_ctl", res);
135         }
136     }
137     private static native int epollCtlMod0(int efd, final int fd, final int flags);
138 
139     public static void epollCtlDel(int efd, final int fd) throws IOException {
140         int res = epollCtlDel0(efd, fd);
141         if (res < 0) {
142             throw newIOException("epoll_ctl", res);
143         }
144     }
145     private static native int epollCtlDel0(int efd, final int fd);
146 
147     // File-descriptor operations
148     public static int splice(int fd, long offIn, int fdOut, long offOut, long len) throws IOException {
149         int res = splice0(fd, offIn, fdOut, offOut, len);
150         if (res >= 0) {
151             return res;
152         }
153         return ioResult("splice", res, SPLICE_CONNECTION_RESET_EXCEPTION, SPLICE_CLOSED_CHANNEL_EXCEPTION);
154     }
155 
156     private static native int splice0(int fd, long offIn, int fdOut, long offOut, long len);
157 
158     public static int sendmmsg(
159             int fd, NativeDatagramPacketArray.NativeDatagramPacket[] msgs, int offset, int len) throws IOException {
160         int res = sendmmsg0(fd, msgs, offset, len);
161         if (res >= 0) {
162             return res;
163         }
164         return ioResult("sendmmsg", res, SENDMMSG_CONNECTION_RESET_EXCEPTION, SENDMMSG_CLOSED_CHANNEL_EXCEPTION);
165     }
166 
167     private static native int sendmmsg0(
168             int fd, NativeDatagramPacketArray.NativeDatagramPacket[] msgs, int offset, int len);
169 
170     // epoll_event related
171     public static native int sizeofEpollEvent();
172     public static native int offsetofEpollData();
173 
174     private static void loadNativeLibrary() {
175         String name = SystemPropertyUtil.get("os.name").toLowerCase(Locale.UK).trim();
176         if (!name.startsWith("linux")) {
177             throw new IllegalStateException("Only supported on Linux");
178         }
179         String staticLibName = "netty_transport_native_epoll";
180         String sharedLibName = staticLibName + '_' + PlatformDependent.normalizedArch();
181         ClassLoader cl = PlatformDependent.getClassLoader(Native.class);
182         try {
183             NativeLibraryLoader.load(sharedLibName, cl);
184         } catch (UnsatisfiedLinkError e1) {
185             try {
186                 NativeLibraryLoader.load(staticLibName, cl);
187                 logger.debug("Failed to load {}", sharedLibName, e1);
188             } catch (UnsatisfiedLinkError e2) {
189                 ThrowableUtil.addSuppressed(e1, e2);
190                 throw e1;
191             }
192         }
193     }
194 
195     private Native() {
196         // utility
197     }
198 }