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