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.Errors.NativeIoException;
20 import io.netty.channel.unix.NativeInetAddress;
21 import io.netty.channel.unix.Socket;
22 import io.netty.util.internal.NativeLibraryLoader;
23 import io.netty.util.internal.PlatformDependent;
24 import io.netty.util.internal.SystemPropertyUtil;
25 import io.netty.channel.unix.FileDescriptor;
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.nio.channels.ClosedChannelException;
33 import java.util.Locale;
34
35 import static io.netty.channel.epoll.NativeStaticallyReferencedJniMethods.epollerr;
36 import static io.netty.channel.epoll.NativeStaticallyReferencedJniMethods.epollet;
37 import static io.netty.channel.epoll.NativeStaticallyReferencedJniMethods.epollin;
38 import static io.netty.channel.epoll.NativeStaticallyReferencedJniMethods.epollout;
39 import static io.netty.channel.epoll.NativeStaticallyReferencedJniMethods.epollrdhup;
40 import static io.netty.channel.epoll.NativeStaticallyReferencedJniMethods.iovMax;
41 import static io.netty.channel.epoll.NativeStaticallyReferencedJniMethods.isSupportingSendmmsg;
42 import static io.netty.channel.epoll.NativeStaticallyReferencedJniMethods.isSupportingTcpFastopen;
43 import static io.netty.channel.epoll.NativeStaticallyReferencedJniMethods.kernelVersion;
44 import static io.netty.channel.epoll.NativeStaticallyReferencedJniMethods.ssizeMax;
45 import static io.netty.channel.epoll.NativeStaticallyReferencedJniMethods.tcpMd5SigMaxKeyLen;
46 import static io.netty.channel.epoll.NativeStaticallyReferencedJniMethods.uioMaxIov;
47 import static io.netty.channel.unix.Errors.ERRNO_EAGAIN_NEGATIVE;
48 import static io.netty.channel.unix.Errors.ERRNO_EPIPE_NEGATIVE;
49 import static io.netty.channel.unix.Errors.ERRNO_EWOULDBLOCK_NEGATIVE;
50 import static io.netty.channel.unix.Errors.ioResult;
51 import static io.netty.channel.unix.Errors.newConnectionResetException;
52 import static io.netty.channel.unix.Errors.newIOException;
53
54
55
56
57
58
59 public final class Native {
60 private static final InternalLogger logger = InternalLoggerFactory.getInstance(Native.class);
61
62 static {
63 try {
64
65
66 offsetofEpollData();
67 } catch (UnsatisfiedLinkError ignore) {
68
69 loadNativeLibrary();
70 }
71 Socket.initialize();
72 }
73
74
75 public static final int EPOLLIN = epollin();
76 public static final int EPOLLOUT = epollout();
77 public static final int EPOLLRDHUP = epollrdhup();
78 public static final int EPOLLET = epollet();
79 public static final int EPOLLERR = epollerr();
80
81 public static final int IOV_MAX = iovMax();
82 public static final int UIO_MAX_IOV = uioMaxIov();
83 public static final boolean IS_SUPPORTING_SENDMMSG = isSupportingSendmmsg();
84 public static final boolean IS_SUPPORTING_TCP_FASTOPEN = isSupportingTcpFastopen();
85 public static final long SSIZE_MAX = ssizeMax();
86 public static final int TCP_MD5SIG_MAXKEYLEN = tcpMd5SigMaxKeyLen();
87 public static final String KERNEL_VERSION = kernelVersion();
88
89 private static final NativeIoException SENDFILE_CONNECTION_RESET_EXCEPTION;
90 private static final NativeIoException SENDMMSG_CONNECTION_RESET_EXCEPTION;
91 private static final NativeIoException SPLICE_CONNECTION_RESET_EXCEPTION;
92 private static final ClosedChannelException SENDFILE_CLOSED_CHANNEL_EXCEPTION = ThrowableUtil.unknownStackTrace(
93 new ClosedChannelException(), Native.class, "sendfile(...)");
94 private static final ClosedChannelException SENDMMSG_CLOSED_CHANNEL_EXCEPTION = ThrowableUtil.unknownStackTrace(
95 new ClosedChannelException(), Native.class, "sendmmsg(...)");
96 private static final ClosedChannelException SPLICE_CLOSED_CHANNEL_EXCEPTION = ThrowableUtil.unknownStackTrace(
97 new ClosedChannelException(), Native.class, "splice(...)");
98
99 static {
100 SENDFILE_CONNECTION_RESET_EXCEPTION = newConnectionResetException("syscall:sendfile(...)",
101 ERRNO_EPIPE_NEGATIVE);
102 SENDMMSG_CONNECTION_RESET_EXCEPTION = newConnectionResetException("syscall:sendmmsg(...)",
103 ERRNO_EPIPE_NEGATIVE);
104 SPLICE_CONNECTION_RESET_EXCEPTION = newConnectionResetException("syscall:splice(...)",
105 ERRNO_EPIPE_NEGATIVE);
106 }
107
108 public static FileDescriptor newEventFd() {
109 return new FileDescriptor(eventFd());
110 }
111
112 public static FileDescriptor newTimerFd() {
113 return new FileDescriptor(timerFd());
114 }
115
116 private static native int eventFd();
117 private static native int timerFd();
118 public static native void eventFdWrite(int fd, long value);
119 public static native void eventFdRead(int fd);
120 static native void timerFdRead(int fd);
121
122 public static FileDescriptor newEpollCreate() {
123 return new FileDescriptor(epollCreate());
124 }
125
126 private static native int epollCreate();
127
128 public static int epollWait(FileDescriptor epollFd, EpollEventArray events, FileDescriptor timerFd,
129 int timeoutSec, int timeoutNs) throws IOException {
130 int ready = epollWait0(epollFd.intValue(), events.memoryAddress(), events.length(), timerFd.intValue(),
131 timeoutSec, timeoutNs);
132 if (ready < 0) {
133 throw newIOException("epoll_wait", ready);
134 }
135 return ready;
136 }
137 private static native int epollWait0(int efd, long address, int len, int timerFd, int timeoutSec, int timeoutNs);
138
139 public static void epollCtlAdd(int efd, final int fd, final int flags) throws IOException {
140 int res = epollCtlAdd0(efd, fd, flags);
141 if (res < 0) {
142 throw newIOException("epoll_ctl", res);
143 }
144 }
145 private static native int epollCtlAdd0(int efd, final int fd, final int flags);
146
147 public static void epollCtlMod(int efd, final int fd, final int flags) throws IOException {
148 int res = epollCtlMod0(efd, fd, flags);
149 if (res < 0) {
150 throw newIOException("epoll_ctl", res);
151 }
152 }
153 private static native int epollCtlMod0(int efd, final int fd, final int flags);
154
155 public static void epollCtlDel(int efd, final int fd) throws IOException {
156 int res = epollCtlDel0(efd, fd);
157 if (res < 0) {
158 throw newIOException("epoll_ctl", res);
159 }
160 }
161 private static native int epollCtlDel0(int efd, final int fd);
162
163
164 public static int splice(int fd, long offIn, int fdOut, long offOut, long len) throws IOException {
165 int res = splice0(fd, offIn, fdOut, offOut, len);
166 if (res >= 0) {
167 return res;
168 }
169 return ioResult("splice", res, SPLICE_CONNECTION_RESET_EXCEPTION, SPLICE_CLOSED_CHANNEL_EXCEPTION);
170 }
171
172 private static native int splice0(int fd, long offIn, int fdOut, long offOut, long len);
173
174 public static long sendfile(
175 int dest, DefaultFileRegion src, long baseOffset, long offset, long length) throws IOException {
176
177
178 src.open();
179
180 long res = sendfile0(dest, src, baseOffset, offset, length);
181 if (res >= 0) {
182 return res;
183 }
184 return ioResult("sendfile", (int) res, SENDFILE_CONNECTION_RESET_EXCEPTION, SENDFILE_CLOSED_CHANNEL_EXCEPTION);
185 }
186
187 private static native long sendfile0(
188 int dest, DefaultFileRegion src, long baseOffset, long offset, long length) throws IOException;
189
190 public static int sendmmsg(
191 int fd, NativeDatagramPacketArray.NativeDatagramPacket[] msgs, int offset, int len) throws IOException {
192 int res = sendmmsg0(fd, msgs, offset, len);
193 if (res >= 0) {
194 return res;
195 }
196 return ioResult("sendmmsg", res, SENDMMSG_CONNECTION_RESET_EXCEPTION, SENDMMSG_CLOSED_CHANNEL_EXCEPTION);
197 }
198
199 private static native int sendmmsg0(
200 int fd, NativeDatagramPacketArray.NativeDatagramPacket[] msgs, int offset, int len);
201
202 public static int recvFd(int fd) throws IOException {
203 int res = recvFd0(fd);
204 if (res > 0) {
205 return res;
206 }
207 if (res == 0) {
208 return -1;
209 }
210
211 if (res == ERRNO_EAGAIN_NEGATIVE || res == ERRNO_EWOULDBLOCK_NEGATIVE) {
212
213 return 0;
214 }
215 throw newIOException("recvFd", res);
216 }
217
218 private static native int recvFd0(int fd);
219
220 public static int sendFd(int socketFd, int fd) throws IOException {
221 int res = sendFd0(socketFd, fd);
222 if (res >= 0) {
223 return res;
224 }
225 if (res == ERRNO_EAGAIN_NEGATIVE || res == ERRNO_EWOULDBLOCK_NEGATIVE) {
226
227 return -1;
228 }
229 throw newIOException("sendFd", res);
230 }
231
232 private static native int sendFd0(int socketFd, int fd);
233
234
235 public static native int isReuseAddress(int fd) throws IOException;
236 public static native int isReusePort(int fd) throws IOException;
237 public static native int getTcpNotSentLowAt(int fd) throws IOException;
238 public static native int getTrafficClass(int fd) throws IOException;
239 public static native int isBroadcast(int fd) throws IOException;
240 public static native int getTcpKeepIdle(int fd) throws IOException;
241 public static native int getTcpKeepIntvl(int fd) throws IOException;
242 public static native int getTcpKeepCnt(int fd) throws IOException;
243 public static native int getTcpUserTimeout(int milliseconds) throws IOException;
244 public static native int isIpFreeBind(int fd)throws IOException;
245
246 public static native void setReuseAddress(int fd, int reuseAddress) throws IOException;
247 public static native void setReusePort(int fd, int reuseAddress) throws IOException;
248 public static native void setTcpFastopen(int fd, int tcpFastopenBacklog) throws IOException;
249 public static native void setTcpNotSentLowAt(int fd, int tcpNotSentLowAt) throws IOException;
250 public static native void setTrafficClass(int fd, int tcpNoDelay) throws IOException;
251 public static native void setBroadcast(int fd, int broadcast) throws IOException;
252 public static native void setTcpKeepIdle(int fd, int seconds) throws IOException;
253 public static native void setTcpKeepIntvl(int fd, int seconds) throws IOException;
254 public static native void setTcpKeepCnt(int fd, int probes) throws IOException;
255 public static native void setTcpUserTimeout(int fd, int milliseconds)throws IOException;
256 public static native void setIpFreeBind(int fd, int freeBind) throws IOException;
257 public static void tcpInfo(int fd, EpollTcpInfo info) throws IOException {
258 tcpInfo0(fd, info.info);
259 }
260
261 private static native void tcpInfo0(int fd, long[] array) throws IOException;
262
263 public static void setTcpMd5Sig(int fd, InetAddress address, byte[] key) throws IOException {
264 final NativeInetAddress a = NativeInetAddress.newInstance(address);
265 setTcpMd5Sig0(fd, a.address(), a.scopeId(), key);
266 }
267
268 private static native void setTcpMd5Sig0(int fd, byte[] address, int scopeId, byte[] key) throws IOException;
269
270
271 public static native int sizeofEpollEvent();
272 public static native int offsetofEpollData();
273
274 private Native() {
275
276 }
277
278 private static void loadNativeLibrary() {
279 String name = SystemPropertyUtil.get("os.name").toLowerCase(Locale.UK).trim();
280 if (!name.startsWith("linux")) {
281 throw new IllegalStateException("Only supported on Linux");
282 }
283 String staticLibName = "netty_transport_native_epoll";
284 String sharedLibName = staticLibName + '_' + PlatformDependent.normalizedArch();
285 ClassLoader cl = PlatformDependent.getClassLoader(Native.class);
286 try {
287 NativeLibraryLoader.load(sharedLibName, cl);
288 } catch (UnsatisfiedLinkError e1) {
289 try {
290 NativeLibraryLoader.load(staticLibName, cl);
291 logger.debug("Failed to load {}", sharedLibName, e1);
292 } catch (UnsatisfiedLinkError e2) {
293 ThrowableUtil.addSuppressed(e1, e2);
294 throw e1;
295 }
296 }
297 }
298 }