1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.mina.transport.socket.apr;
21
22 import java.io.IOException;
23 import java.net.InetSocketAddress;
24 import java.net.SocketAddress;
25 import java.util.Iterator;
26 import java.util.Queue;
27 import java.util.concurrent.ConcurrentLinkedQueue;
28 import java.util.concurrent.Executor;
29
30 import org.apache.mina.core.RuntimeIoException;
31 import org.apache.mina.core.polling.AbstractPollingIoAcceptor;
32 import org.apache.mina.core.service.IoAcceptor;
33 import org.apache.mina.core.service.IoProcessor;
34 import org.apache.mina.core.service.IoService;
35 import org.apache.mina.core.service.SimpleIoProcessorPool;
36 import org.apache.mina.core.service.TransportMetadata;
37 import org.apache.mina.transport.socket.DefaultSocketSessionConfig;
38 import org.apache.mina.transport.socket.SocketAcceptor;
39 import org.apache.mina.transport.socket.SocketSessionConfig;
40 import org.apache.tomcat.jni.Address;
41 import org.apache.tomcat.jni.Poll;
42 import org.apache.tomcat.jni.Pool;
43 import org.apache.tomcat.jni.Socket;
44 import org.apache.tomcat.jni.Status;
45
46
47
48
49
50
51 public final class AprSocketAcceptor extends AbstractPollingIoAcceptor<AprSession, Long> implements SocketAcceptor {
52
53
54
55
56 private static final int APR_TIMEUP_ERROR = -120001;
57
58 private static final int POLLSET_SIZE = 1024;
59
60 private final Object wakeupLock = new Object();
61
62 private volatile long wakeupSocket;
63
64 private volatile boolean toBeWakenUp;
65
66 private volatile long pool;
67
68 private volatile long pollset;
69
70 private final long[] polledSockets = new long[POLLSET_SIZE << 1];
71
72 private final Queue<Long> polledHandles = new ConcurrentLinkedQueue<Long>();
73
74
75
76
77 public AprSocketAcceptor() {
78 super(new DefaultSocketSessionConfig(), AprIoProcessor.class);
79 ((DefaultSocketSessionConfig) getSessionConfig()).init(this);
80 }
81
82
83
84
85
86
87
88
89 public AprSocketAcceptor(int processorCount) {
90 super(new DefaultSocketSessionConfig(), AprIoProcessor.class, processorCount);
91 ((DefaultSocketSessionConfig) getSessionConfig()).init(this);
92 }
93
94
95
96
97
98
99
100 public AprSocketAcceptor(IoProcessor<AprSession> processor) {
101 super(new DefaultSocketSessionConfig(), processor);
102 ((DefaultSocketSessionConfig) getSessionConfig()).init(this);
103 }
104
105
106
107
108
109
110
111
112 public AprSocketAcceptor(Executor executor, IoProcessor<AprSession> processor) {
113 super(new DefaultSocketSessionConfig(), executor, processor);
114 ((DefaultSocketSessionConfig) getSessionConfig()).init(this);
115 }
116
117
118
119
120 @Override
121 protected AprSession accept(IoProcessor<AprSession> processor, Long handle) throws Exception {
122 long s = Socket.accept(handle);
123 boolean success = false;
124 try {
125 AprSession result = new AprSocketSession(this, processor, s);
126 success = true;
127 return result;
128 } finally {
129 if (!success) {
130 Socket.close(s);
131 }
132 }
133 }
134
135
136
137
138 @Override
139 protected Long open(SocketAddress localAddress) throws Exception {
140 InetSocketAddress la = (InetSocketAddress) localAddress;
141 long handle = Socket.create(Socket.APR_INET, Socket.SOCK_STREAM, Socket.APR_PROTO_TCP, pool);
142
143 boolean success = false;
144 try {
145 int result = Socket.optSet(handle, Socket.APR_SO_NONBLOCK, 1);
146 if (result != Status.APR_SUCCESS) {
147 throwException(result);
148 }
149 result = Socket.timeoutSet(handle, 0);
150 if (result != Status.APR_SUCCESS) {
151 throwException(result);
152 }
153
154
155 result = Socket.optSet(handle, Socket.APR_SO_REUSEADDR, isReuseAddress() ? 1 : 0);
156 if (result != Status.APR_SUCCESS) {
157 throwException(result);
158 }
159 result = Socket.optSet(handle, Socket.APR_SO_RCVBUF, getSessionConfig().getReceiveBufferSize());
160 if (result != Status.APR_SUCCESS) {
161 throwException(result);
162 }
163
164
165 long sa;
166 if (la != null) {
167 if (la.getAddress() == null) {
168 sa = Address.info(Address.APR_ANYADDR, Socket.APR_INET, la.getPort(), 0, pool);
169 } else {
170 sa = Address.info(la.getAddress().getHostAddress(), Socket.APR_INET, la.getPort(), 0, pool);
171 }
172 } else {
173 sa = Address.info(Address.APR_ANYADDR, Socket.APR_INET, 0, 0, pool);
174 }
175
176 result = Socket.bind(handle, sa);
177 if (result != Status.APR_SUCCESS) {
178 throwException(result);
179 }
180 result = Socket.listen(handle, getBacklog());
181 if (result != Status.APR_SUCCESS) {
182 throwException(result);
183 }
184
185 result = Poll.add(pollset, handle, Poll.APR_POLLIN);
186 if (result != Status.APR_SUCCESS) {
187 throwException(result);
188 }
189 success = true;
190 } finally {
191 if (!success) {
192 close(handle);
193 }
194 }
195 return handle;
196 }
197
198
199
200
201 @Override
202 protected void init() throws Exception {
203
204 pool = Pool.create(AprLibrary.getInstance().getRootPool());
205
206 wakeupSocket = Socket.create(Socket.APR_INET, Socket.SOCK_DGRAM, Socket.APR_PROTO_UDP, pool);
207
208 pollset = Poll.create(POLLSET_SIZE, pool, Poll.APR_POLLSET_THREADSAFE, Long.MAX_VALUE);
209
210 if (pollset <= 0) {
211 pollset = Poll.create(62, pool, Poll.APR_POLLSET_THREADSAFE, Long.MAX_VALUE);
212 }
213
214 if (pollset <= 0) {
215 if (Status.APR_STATUS_IS_ENOTIMPL(-(int) pollset)) {
216 throw new RuntimeIoException("Thread-safe pollset is not supported in this platform.");
217 }
218 }
219 }
220
221
222
223
224 @Override
225 protected void destroy() throws Exception {
226 if (wakeupSocket > 0) {
227 Socket.close(wakeupSocket);
228 }
229 if (pollset > 0) {
230 Poll.destroy(pollset);
231 }
232 if (pool > 0) {
233 Pool.destroy(pool);
234 }
235 }
236
237
238
239
240 @Override
241 protected SocketAddress localAddress(Long handle) throws Exception {
242 long la = Address.get(Socket.APR_LOCAL, handle);
243 return new InetSocketAddress(Address.getip(la), Address.getInfo(la).port);
244 }
245
246
247
248
249 @Override
250 protected int select() throws Exception {
251 int rv = Poll.poll(pollset, Integer.MAX_VALUE, polledSockets, false);
252 if (rv <= 0) {
253
254
255 if (rv != APR_TIMEUP_ERROR) {
256
257 throwException(rv);
258 }
259
260 rv = Poll.maintain(pollset, polledSockets, true);
261 if (rv > 0) {
262 for (int i = 0; i < rv; i++) {
263 Poll.add(pollset, polledSockets[i], Poll.APR_POLLIN);
264 }
265 } else if (rv < 0) {
266 throwException(rv);
267 }
268
269 return 0;
270 } else {
271 rv <<= 1;
272 if (!polledHandles.isEmpty()) {
273 polledHandles.clear();
274 }
275
276 for (int i = 0; i < rv; i++) {
277 long flag = polledSockets[i];
278 long socket = polledSockets[++i];
279 if (socket == wakeupSocket) {
280 synchronized (wakeupLock) {
281 Poll.remove(pollset, wakeupSocket);
282 toBeWakenUp = false;
283 }
284 continue;
285 }
286
287 if ((flag & Poll.APR_POLLIN) != 0) {
288 polledHandles.add(socket);
289 }
290 }
291 return polledHandles.size();
292 }
293 }
294
295
296
297
298 @Override
299 protected Iterator<Long> selectedHandles() {
300 return polledHandles.iterator();
301 }
302
303
304
305
306 @Override
307 protected void close(Long handle) throws Exception {
308 Poll.remove(pollset, handle);
309 int result = Socket.close(handle);
310 if (result != Status.APR_SUCCESS) {
311 throwException(result);
312 }
313 }
314
315
316
317
318 @Override
319 protected void wakeup() {
320 if (toBeWakenUp) {
321 return;
322 }
323
324
325 synchronized (wakeupLock) {
326 toBeWakenUp = true;
327 Poll.add(pollset, wakeupSocket, Poll.APR_POLLOUT);
328 }
329 }
330
331
332
333
334 @Override
335 public InetSocketAddress getLocalAddress() {
336 return (InetSocketAddress) super.getLocalAddress();
337 }
338
339
340
341
342 @Override
343 public InetSocketAddress getDefaultLocalAddress() {
344 return (InetSocketAddress) super.getDefaultLocalAddress();
345 }
346
347
348
349
350 public void setDefaultLocalAddress(InetSocketAddress localAddress) {
351 super.setDefaultLocalAddress(localAddress);
352 }
353
354
355
356
357 public TransportMetadata getTransportMetadata() {
358 return AprSocketSession.METADATA;
359 }
360
361
362
363
364 @Override
365 public SocketSessionConfig getSessionConfig() {
366 return (SocketSessionConfig) super.getSessionConfig();
367 }
368
369
370
371
372
373
374 private void throwException(int code) throws IOException {
375 throw new IOException(org.apache.tomcat.jni.Error.strerror(-code) + " (code: " + code + ")");
376 }
377 }