1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.channel.kqueue;
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.Unix;
22 import io.netty.util.internal.ClassInitializerUtil;
23 import io.netty.util.internal.NativeLibraryLoader;
24 import io.netty.util.internal.PlatformDependent;
25 import io.netty.util.internal.ThrowableUtil;
26 import io.netty.util.internal.logging.InternalLogger;
27 import io.netty.util.internal.logging.InternalLoggerFactory;
28
29 import java.io.IOException;
30 import java.net.InetAddress;
31 import java.net.UnknownHostException;
32 import java.nio.channels.FileChannel;
33
34 import static io.netty.channel.kqueue.KQueueStaticallyReferencedJniMethods.connectDataIdempotent;
35 import static io.netty.channel.kqueue.KQueueStaticallyReferencedJniMethods.connectResumeOnReadWrite;
36 import static io.netty.channel.kqueue.KQueueStaticallyReferencedJniMethods.evAdd;
37 import static io.netty.channel.kqueue.KQueueStaticallyReferencedJniMethods.evClear;
38 import static io.netty.channel.kqueue.KQueueStaticallyReferencedJniMethods.evDelete;
39 import static io.netty.channel.kqueue.KQueueStaticallyReferencedJniMethods.evDisable;
40 import static io.netty.channel.kqueue.KQueueStaticallyReferencedJniMethods.evEOF;
41 import static io.netty.channel.kqueue.KQueueStaticallyReferencedJniMethods.evEnable;
42 import static io.netty.channel.kqueue.KQueueStaticallyReferencedJniMethods.evError;
43 import static io.netty.channel.kqueue.KQueueStaticallyReferencedJniMethods.evfiltRead;
44 import static io.netty.channel.kqueue.KQueueStaticallyReferencedJniMethods.evfiltSock;
45 import static io.netty.channel.kqueue.KQueueStaticallyReferencedJniMethods.evfiltUser;
46 import static io.netty.channel.kqueue.KQueueStaticallyReferencedJniMethods.evfiltWrite;
47 import static io.netty.channel.kqueue.KQueueStaticallyReferencedJniMethods.fastOpenClient;
48 import static io.netty.channel.kqueue.KQueueStaticallyReferencedJniMethods.fastOpenServer;
49 import static io.netty.channel.kqueue.KQueueStaticallyReferencedJniMethods.noteConnReset;
50 import static io.netty.channel.kqueue.KQueueStaticallyReferencedJniMethods.noteDisconnected;
51 import static io.netty.channel.kqueue.KQueueStaticallyReferencedJniMethods.noteReadClosed;
52 import static io.netty.channel.unix.Errors.newIOException;
53
54
55
56
57
58 final class Native {
59 private static final InternalLogger logger = InternalLoggerFactory.getInstance(Native.class);
60 static final InetAddress INET6_ANY;
61
62 static {
63
64
65
66
67
68 ClassInitializerUtil.tryLoadClasses(Native.class,
69
70 PeerCredentials.class, DefaultFileRegion.class, FileChannel.class, java.io.FileDescriptor.class
71 );
72
73 try {
74 INET6_ANY = InetAddress.getByName("::");
75 } catch (UnknownHostException e) {
76 throw new ExceptionInInitializerError(e);
77 }
78
79 try {
80
81
82 sizeofKEvent();
83 } catch (UnsatisfiedLinkError ignore) {
84
85 loadNativeLibrary();
86 }
87 Unix.registerInternal(new Runnable() {
88 @Override
89 public void run() {
90 registerUnix();
91 }
92 });
93 }
94
95 private static native int registerUnix();
96
97 static final short EV_ADD = evAdd();
98 static final short EV_ENABLE = evEnable();
99 static final short EV_DISABLE = evDisable();
100 static final short EV_DELETE = evDelete();
101 static final short EV_CLEAR = evClear();
102 static final short EV_ERROR = evError();
103 static final short EV_EOF = evEOF();
104
105 static final int NOTE_READCLOSED = noteReadClosed();
106 static final int NOTE_CONNRESET = noteConnReset();
107 static final int NOTE_DISCONNECTED = noteDisconnected();
108
109 static final int NOTE_RDHUP = NOTE_READCLOSED | NOTE_CONNRESET | NOTE_DISCONNECTED;
110
111
112 static final short EV_ADD_ENABLE = (short) (EV_ADD | EV_ENABLE);
113 static final short EV_DELETE_DISABLE = (short) (EV_DELETE | EV_DISABLE);
114
115 static final short EVFILT_READ = evfiltRead();
116 static final short EVFILT_WRITE = evfiltWrite();
117 static final short EVFILT_USER = evfiltUser();
118 static final short EVFILT_SOCK = evfiltSock();
119
120
121 private static final int CONNECT_RESUME_ON_READ_WRITE = connectResumeOnReadWrite();
122 private static final int CONNECT_DATA_IDEMPOTENT = connectDataIdempotent();
123 static final int CONNECT_TCP_FASTOPEN = CONNECT_RESUME_ON_READ_WRITE | CONNECT_DATA_IDEMPOTENT;
124 static final boolean IS_SUPPORTING_TCP_FASTOPEN_CLIENT = isSupportingFastOpenClient();
125 static final boolean IS_SUPPORTING_TCP_FASTOPEN_SERVER = isSupportingFastOpenServer();
126
127 static final KQueueIoOps READ_ENABLED_OPS =
128 KQueueIoOps.newOps(Native.EVFILT_READ, Native.EV_ADD_ENABLE, 0);
129 static final KQueueIoOps WRITE_ENABLED_OPS =
130 KQueueIoOps.newOps(Native.EVFILT_WRITE, Native.EV_ADD_ENABLE, 0);
131 static final KQueueIoOps READ_DISABLED_OPS =
132 KQueueIoOps.newOps(Native.EVFILT_READ, Native.EV_DELETE_DISABLE, 0);
133 static final KQueueIoOps WRITE_DISABLED_OPS =
134 KQueueIoOps.newOps(Native.EVFILT_WRITE, Native.EV_DELETE_DISABLE, 0);
135
136 static FileDescriptor newKQueue() {
137 return new FileDescriptor(kqueueCreate());
138 }
139
140 static int keventWait(int kqueueFd, KQueueEventArray changeList, KQueueEventArray eventList,
141 int tvSec, int tvNsec) throws IOException {
142 int ready = keventWait(kqueueFd, changeList.memoryAddress(), changeList.size(),
143 eventList.memoryAddress(), eventList.capacity(), tvSec, tvNsec);
144 if (ready < 0) {
145 throw newIOException("kevent", ready);
146 }
147 return ready;
148 }
149
150 private static native int kqueueCreate();
151 private static native int keventWait(int kqueueFd, long changeListAddress, int changeListLength,
152 long eventListAddress, int eventListLength, int tvSec, int tvNsec);
153 static native int keventTriggerUserEvent(int kqueueFd, int ident);
154 static native int keventAddUserEvent(int kqueueFd, int ident);
155
156
157 static native int sizeofKEvent();
158 static native int offsetofKEventIdent();
159 static native int offsetofKEventFlags();
160 static native int offsetofKEventFFlags();
161 static native int offsetofKEventFilter();
162 static native int offsetofKeventData();
163 static native int offsetofKeventUdata();
164
165 private static void loadNativeLibrary() {
166 String name = PlatformDependent.normalizedOs();
167 if (!"osx".equals(name) && !name.contains("bsd")) {
168 throw new IllegalStateException("Only supported on OSX/BSD");
169 }
170 String staticLibName = "netty_transport_native_kqueue";
171 String sharedLibName = staticLibName + '_' + PlatformDependent.normalizedArch();
172 ClassLoader cl = PlatformDependent.getClassLoader(Native.class);
173 try {
174 NativeLibraryLoader.load(sharedLibName, cl);
175 } catch (UnsatisfiedLinkError e1) {
176 try {
177 NativeLibraryLoader.load(staticLibName, cl);
178 logger.debug("Failed to load {}", sharedLibName, e1);
179 } catch (UnsatisfiedLinkError e2) {
180 ThrowableUtil.addSuppressed(e1, e2);
181 throw e1;
182 }
183 }
184 }
185
186 private static boolean isSupportingFastOpenClient() {
187 try {
188 return fastOpenClient() == 1;
189 } catch (Exception e) {
190 logger.debug("Failed to probe fastOpenClient sysctl, assuming client-side TCP FastOpen cannot be used.", e);
191 }
192 return false;
193 }
194
195 private static boolean isSupportingFastOpenServer() {
196 try {
197 return fastOpenServer() == 1;
198 } catch (Exception e) {
199 logger.debug("Failed to probe fastOpenServer sysctl, assuming server-side TCP FastOpen cannot be used.", e);
200 }
201 return false;
202 }
203
204 private Native() {
205
206 }
207 }