1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.channel.epoll;
17
18 import io.netty.channel.DefaultFileRegion;
19 import io.netty.channel.unix.FileDescriptor;
20 import io.netty.channel.unix.PeerCredentials;
21 import io.netty.channel.unix.Socket;
22 import io.netty.channel.unix.Unix;
23 import io.netty.util.internal.ClassInitializerUtil;
24 import io.netty.util.internal.NativeLibraryLoader;
25 import io.netty.util.internal.PlatformDependent;
26 import io.netty.util.internal.ThrowableUtil;
27 import io.netty.util.internal.logging.InternalLogger;
28 import io.netty.util.internal.logging.InternalLoggerFactory;
29
30 import java.io.IOException;
31 import java.net.InetAddress;
32 import java.net.UnknownHostException;
33 import java.nio.channels.FileChannel;
34 import java.nio.channels.Selector;
35
36 import static io.netty.channel.epoll.NativeStaticallyReferencedJniMethods.epollerr;
37 import static io.netty.channel.epoll.NativeStaticallyReferencedJniMethods.epollet;
38 import static io.netty.channel.epoll.NativeStaticallyReferencedJniMethods.epollin;
39 import static io.netty.channel.epoll.NativeStaticallyReferencedJniMethods.epollout;
40 import static io.netty.channel.epoll.NativeStaticallyReferencedJniMethods.epollrdhup;
41 import static io.netty.channel.epoll.NativeStaticallyReferencedJniMethods.isSupportingRecvmmsg;
42 import static io.netty.channel.epoll.NativeStaticallyReferencedJniMethods.isSupportingSendmmsg;
43 import static io.netty.channel.epoll.NativeStaticallyReferencedJniMethods.kernelVersion;
44 import static io.netty.channel.epoll.NativeStaticallyReferencedJniMethods.tcpFastopenMode;
45 import static io.netty.channel.epoll.NativeStaticallyReferencedJniMethods.tcpMd5SigMaxKeyLen;
46 import static io.netty.channel.unix.Errors.ioResult;
47 import static io.netty.channel.unix.Errors.newIOException;
48
49
50
51
52
53
54 public final class Native {
55 private static final InternalLogger logger = InternalLoggerFactory.getInstance(Native.class);
56 static final InetAddress INET6_ANY;
57 static final InetAddress INET_ANY;
58
59 static {
60 Selector selector = null;
61 try {
62
63
64
65
66 selector = Selector.open();
67 } catch (IOException ignore) {
68
69 }
70
71 try {
72 INET_ANY = InetAddress.getByName("0.0.0.0");
73 INET6_ANY = InetAddress.getByName("::");
74 } catch (UnknownHostException e) {
75 throw new ExceptionInInitializerError(e);
76 }
77
78
79
80
81
82
83 ClassInitializerUtil.tryLoadClasses(Native.class,
84
85 PeerCredentials.class, DefaultFileRegion.class, FileChannel.class, java.io.FileDescriptor.class,
86
87 NativeDatagramPacketArray.NativeDatagramPacket.class
88 );
89
90 try {
91
92
93 offsetofEpollData();
94 } catch (UnsatisfiedLinkError ignore) {
95
96 loadNativeLibrary();
97 } finally {
98 try {
99 if (selector != null) {
100 selector.close();
101 }
102 } catch (IOException ignore) {
103
104 }
105 }
106 Unix.registerInternal(new Runnable() {
107 @Override
108 public void run() {
109 registerUnix();
110 }
111 });
112 }
113
114 private static native int registerUnix();
115
116
117 public static final int EPOLLIN = epollin();
118 public static final int EPOLLOUT = epollout();
119 public static final int EPOLLRDHUP = epollrdhup();
120 public static final int EPOLLET = epollet();
121 public static final int EPOLLERR = epollerr();
122
123 public static final boolean IS_SUPPORTING_SENDMMSG = isSupportingSendmmsg();
124 static final boolean IS_SUPPORTING_RECVMMSG = isSupportingRecvmmsg();
125 static final boolean IS_SUPPORTING_UDP_SEGMENT = isSupportingUdpSegment();
126 private static final int TFO_ENABLED_CLIENT_MASK = 0x1;
127 private static final int TFO_ENABLED_SERVER_MASK = 0x2;
128 private static final int TCP_FASTOPEN_MODE = tcpFastopenMode();
129
130
131
132
133 static final boolean IS_SUPPORTING_TCP_FASTOPEN_CLIENT =
134 (TCP_FASTOPEN_MODE & TFO_ENABLED_CLIENT_MASK) == TFO_ENABLED_CLIENT_MASK;
135
136
137
138
139 static final boolean IS_SUPPORTING_TCP_FASTOPEN_SERVER =
140 (TCP_FASTOPEN_MODE & TFO_ENABLED_SERVER_MASK) == TFO_ENABLED_SERVER_MASK;
141
142
143
144
145 @Deprecated
146 public static final boolean IS_SUPPORTING_TCP_FASTOPEN = IS_SUPPORTING_TCP_FASTOPEN_CLIENT ||
147 IS_SUPPORTING_TCP_FASTOPEN_SERVER;
148 public static final int TCP_MD5SIG_MAXKEYLEN = tcpMd5SigMaxKeyLen();
149 public static final String KERNEL_VERSION = kernelVersion();
150
151 public static FileDescriptor newEventFd() {
152 return new FileDescriptor(eventFd());
153 }
154
155 public static FileDescriptor newTimerFd() {
156 return new FileDescriptor(timerFd());
157 }
158
159 private static native boolean isSupportingUdpSegment();
160 private static native int eventFd();
161 private static native int timerFd();
162 public static native void eventFdWrite(int fd, long value);
163 public static native void eventFdRead(int fd);
164
165 public static FileDescriptor newEpollCreate() {
166 return new FileDescriptor(epollCreate());
167 }
168
169 private static native int epollCreate();
170
171
172
173
174 @Deprecated
175 public static int epollWait(FileDescriptor epollFd, EpollEventArray events, FileDescriptor timerFd,
176 int timeoutSec, int timeoutNs) throws IOException {
177 long result = epollWait(epollFd, events, timerFd, timeoutSec, timeoutNs, -1);
178 return epollReady(result);
179 }
180
181 static long epollWait(FileDescriptor epollFd, EpollEventArray events, FileDescriptor timerFd,
182 int timeoutSec, int timeoutNs, long millisThreshold) throws IOException {
183 if (timeoutSec == 0 && timeoutNs == 0) {
184
185
186 return ((long) epollWait(epollFd, events, 0)) << 32;
187 }
188 if (timeoutSec == Integer.MAX_VALUE) {
189
190 timeoutSec = 0;
191 timeoutNs = 0;
192 }
193 long result = epollWait0(epollFd.intValue(), events.memoryAddress(), events.length(), timerFd.intValue(),
194 timeoutSec, timeoutNs, millisThreshold);
195 int ready = epollReady(result);
196 if (ready < 0) {
197 throw newIOException("epoll_wait", ready);
198 }
199 return result;
200 }
201
202
203 static int epollReady(long result) {
204 return (int) (result >> 32);
205 }
206
207
208 static boolean epollTimerWasUsed(long result) {
209 return (result & 0xff) != 0;
210 }
211
212 static int epollWait(FileDescriptor epollFd, EpollEventArray events, boolean immediatePoll) throws IOException {
213 return epollWait(epollFd, events, immediatePoll ? 0 : -1);
214 }
215
216
217
218
219 static int epollWait(FileDescriptor epollFd, EpollEventArray events, int timeoutMillis) throws IOException {
220 int ready = epollWait(epollFd.intValue(), events.memoryAddress(), events.length(), timeoutMillis);
221 if (ready < 0) {
222 throw newIOException("epoll_wait", ready);
223 }
224 return ready;
225 }
226
227
228
229
230
231
232 public static int epollBusyWait(FileDescriptor epollFd, EpollEventArray events) throws IOException {
233 int ready = epollBusyWait0(epollFd.intValue(), events.memoryAddress(), events.length());
234 if (ready < 0) {
235 throw newIOException("epoll_wait", ready);
236 }
237 return ready;
238 }
239
240 private static native long epollWait0(
241 int efd, long address, int len, int timerFd, int timeoutSec, int timeoutNs, long millisThreshold);
242 private static native int epollWait(int efd, long address, int len, int timeout);
243 private static native int epollBusyWait0(int efd, long address, int len);
244
245 public static void epollCtlAdd(int efd, final int fd, final int flags) throws IOException {
246 int res = epollCtlAdd0(efd, fd, flags);
247 if (res < 0) {
248 throw newIOException("epoll_ctl", res);
249 }
250 }
251 private static native int epollCtlAdd0(int efd, int fd, int flags);
252
253 public static void epollCtlMod(int efd, final int fd, final int flags) throws IOException {
254 int res = epollCtlMod0(efd, fd, flags);
255 if (res < 0) {
256 throw newIOException("epoll_ctl", res);
257 }
258 }
259 private static native int epollCtlMod0(int efd, int fd, int flags);
260
261 public static void epollCtlDel(int efd, final int fd) throws IOException {
262 int res = epollCtlDel0(efd, fd);
263 if (res < 0) {
264 throw newIOException("epoll_ctl", res);
265 }
266 }
267 private static native int epollCtlDel0(int efd, int fd);
268
269
270 public static int splice(int fd, long offIn, int fdOut, long offOut, long len) throws IOException {
271 int res = splice0(fd, offIn, fdOut, offOut, len);
272 if (res >= 0) {
273 return res;
274 }
275 return ioResult("splice", res);
276 }
277
278 private static native int splice0(int fd, long offIn, int fdOut, long offOut, long len);
279
280 @Deprecated
281 public static int sendmmsg(int fd, NativeDatagramPacketArray.NativeDatagramPacket[] msgs,
282 int offset, int len) throws IOException {
283 return sendmmsg(fd, Socket.isIPv6Preferred(), msgs, offset, len);
284 }
285
286 static int sendmmsg(int fd, boolean ipv6, NativeDatagramPacketArray.NativeDatagramPacket[] msgs,
287 int offset, int len) throws IOException {
288 int res = sendmmsg0(fd, ipv6, msgs, offset, len);
289 if (res >= 0) {
290 return res;
291 }
292 return ioResult("sendmmsg", res);
293 }
294
295 private static native int sendmmsg0(
296 int fd, boolean ipv6, NativeDatagramPacketArray.NativeDatagramPacket[] msgs, int offset, int len);
297
298 static int recvmmsg(int fd, boolean ipv6, NativeDatagramPacketArray.NativeDatagramPacket[] msgs,
299 int offset, int len) throws IOException {
300 int res = recvmmsg0(fd, ipv6, msgs, offset, len);
301 if (res >= 0) {
302 return res;
303 }
304 return ioResult("recvmmsg", res);
305 }
306
307 private static native int recvmmsg0(
308 int fd, boolean ipv6, NativeDatagramPacketArray.NativeDatagramPacket[] msgs, int offset, int len);
309
310 static int recvmsg(int fd, boolean ipv6, NativeDatagramPacketArray.NativeDatagramPacket packet) throws IOException {
311 int res = recvmsg0(fd, ipv6, packet);
312 if (res >= 0) {
313 return res;
314 }
315 return ioResult("recvmsg", res);
316 }
317
318 private static native int recvmsg0(
319 int fd, boolean ipv6, NativeDatagramPacketArray.NativeDatagramPacket msg);
320
321
322 public static native int sizeofEpollEvent();
323 public static native int offsetofEpollData();
324
325 private static void loadNativeLibrary() {
326 String name = PlatformDependent.normalizedOs();
327 if (!"linux".equals(name)) {
328 throw new IllegalStateException("Only supported on Linux");
329 }
330 String staticLibName = "netty_transport_native_epoll";
331 String sharedLibName = staticLibName + '_' + PlatformDependent.normalizedArch();
332 ClassLoader cl = PlatformDependent.getClassLoader(Native.class);
333 try {
334 NativeLibraryLoader.load(sharedLibName, cl);
335 } catch (UnsatisfiedLinkError e1) {
336 try {
337 NativeLibraryLoader.load(staticLibName, cl);
338 logger.debug("Failed to load {}", sharedLibName, e1);
339 } catch (UnsatisfiedLinkError e2) {
340 ThrowableUtil.addSuppressed(e1, e2);
341 throw e1;
342 }
343 }
344 }
345
346 private Native() {
347
348 }
349 }