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.List;
27 import java.util.concurrent.Executor;
28
29 import org.apache.mina.core.RuntimeIoException;
30 import org.apache.mina.core.polling.AbstractPollingIoAcceptor;
31 import org.apache.mina.core.service.IoAcceptor;
32 import org.apache.mina.core.service.IoProcessor;
33 import org.apache.mina.core.service.IoService;
34 import org.apache.mina.core.service.SimpleIoProcessorPool;
35 import org.apache.mina.core.service.TransportMetadata;
36 import org.apache.mina.transport.socket.DefaultSocketSessionConfig;
37 import org.apache.mina.transport.socket.SocketAcceptor;
38 import org.apache.mina.transport.socket.SocketSessionConfig;
39 import org.apache.mina.util.CircularQueue;
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
52 public final class AprSocketAcceptor extends AbstractPollingIoAcceptor<AprSession, Long> implements SocketAcceptor {
53
54
55
56
57 private static final int APR_TIMEUP_ERROR = -120001;
58
59 private static final int POLLSET_SIZE = 1024;
60
61 private final Object wakeupLock = new Object();
62 private volatile long wakeupSocket;
63 private volatile boolean toBeWakenUp;
64
65 private int backlog = 50;
66 private boolean reuseAddress = false;
67
68 private volatile long pool;
69 private volatile long pollset;
70 private final long[] polledSockets = new long[POLLSET_SIZE << 1];
71 private final List<Long> polledHandles =
72 new CircularQueue<Long>(POLLSET_SIZE);
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,
113 IoProcessor<AprSession> processor) {
114 super(new DefaultSocketSessionConfig(), executor, processor);
115 ((DefaultSocketSessionConfig) getSessionConfig()).init(this);
116 }
117
118
119
120
121 @Override
122 protected AprSession accept(IoProcessor<AprSession> processor, Long handle) throws Exception {
123 long s = Socket.accept(handle);
124 boolean success = false;
125 try {
126 AprSession result = new AprSocketSession(this, processor, s);
127 success = true;
128 return result;
129 } finally {
130 if (!success) {
131 Socket.close(s);
132 }
133 }
134 }
135
136
137
138
139 @Override
140 protected Long open(SocketAddress localAddress) throws Exception {
141 InetSocketAddress la = (InetSocketAddress) localAddress;
142 long handle = Socket.create(
143 Socket.APR_INET, Socket.SOCK_STREAM, Socket.APR_PROTO_TCP, pool);
144
145 boolean success = false;
146 try {
147 int result = Socket.optSet(handle, Socket.APR_SO_NONBLOCK, 1);
148 if (result != Status.APR_SUCCESS) {
149 throwException(result);
150 }
151 result = Socket.timeoutSet(handle, 0);
152 if (result != Status.APR_SUCCESS) {
153 throwException(result);
154 }
155
156
157 result = Socket.optSet(handle, Socket.APR_SO_REUSEADDR, isReuseAddress()? 1 : 0);
158 if (result != Status.APR_SUCCESS) {
159 throwException(result);
160 }
161 result = Socket.optSet(handle, Socket.APR_SO_RCVBUF, getSessionConfig().getReceiveBufferSize());
162 if (result != Status.APR_SUCCESS) {
163 throwException(result);
164 }
165
166
167 long sa;
168 if (la != null) {
169 if (la.getAddress() == null) {
170 sa = Address.info(Address.APR_ANYADDR, Socket.APR_INET, la.getPort(), 0, pool);
171 } else {
172 sa = Address.info(la.getAddress().getHostAddress(), Socket.APR_INET, la.getPort(), 0, pool);
173 }
174 } else {
175 sa = Address.info(Address.APR_ANYADDR, Socket.APR_INET, 0, 0, pool);
176 }
177
178 result = Socket.bind(handle, sa);
179 if (result != Status.APR_SUCCESS) {
180 throwException(result);
181 }
182 result = Socket.listen(handle, getBacklog());
183 if (result != Status.APR_SUCCESS) {
184 throwException(result);
185 }
186
187 result = Poll.add(pollset, handle, Poll.APR_POLLIN);
188 if (result != Status.APR_SUCCESS) {
189 throwException(result);
190 }
191 success = true;
192 } finally {
193 if (!success) {
194 close(handle);
195 }
196 }
197 return handle;
198 }
199
200
201
202
203 @Override
204 protected void init() throws Exception {
205
206 pool = Pool.create(AprLibrary.getInstance().getRootPool());
207
208 wakeupSocket = Socket.create(
209 Socket.APR_INET, Socket.SOCK_DGRAM, Socket.APR_PROTO_UDP, pool);
210
211 pollset = Poll.create(
212 POLLSET_SIZE,
213 pool,
214 Poll.APR_POLLSET_THREADSAFE,
215 Long.MAX_VALUE);
216
217 if (pollset <= 0) {
218 pollset = Poll.create(
219 62,
220 pool,
221 Poll.APR_POLLSET_THREADSAFE,
222 Long.MAX_VALUE);
223 }
224
225 if (pollset <= 0) {
226 if (Status.APR_STATUS_IS_ENOTIMPL(- (int) pollset)) {
227 throw new RuntimeIoException(
228 "Thread-safe pollset is not supported in this platform.");
229 }
230 }
231 }
232
233
234
235
236 @Override
237 protected void destroy() throws Exception {
238 if (wakeupSocket > 0) {
239 Socket.close(wakeupSocket);
240 }
241 if (pollset > 0) {
242 Poll.destroy(pollset);
243 }
244 if (pool > 0) {
245 Pool.destroy(pool);
246 }
247 }
248
249
250
251
252 @Override
253 protected SocketAddress localAddress(Long handle) throws Exception {
254 long la = Address.get(Socket.APR_LOCAL, handle);
255 return new InetSocketAddress(Address.getip(la), Address.getInfo(la).port);
256 }
257
258
259
260
261 @Override
262 protected int select() throws Exception {
263 int rv = Poll.poll(pollset, Integer.MAX_VALUE, polledSockets, false);
264 if (rv <= 0) {
265
266
267 if (rv != APR_TIMEUP_ERROR) {
268
269 throwException(rv);
270 }
271
272 rv = Poll.maintain(pollset, polledSockets, true);
273 if (rv > 0) {
274 for (int i = 0; i < rv; i ++) {
275 Poll.add(pollset, polledSockets[i], Poll.APR_POLLIN);
276 }
277 } else if (rv < 0) {
278 throwException(rv);
279 }
280
281 return 0;
282 } else {
283 rv <<= 1;
284 if (!polledHandles.isEmpty()) {
285 polledHandles.clear();
286 }
287
288 for (int i = 0; i < rv; i ++) {
289 long flag = polledSockets[i];
290 long socket = polledSockets[++i];
291 if (socket == wakeupSocket) {
292 synchronized (wakeupLock) {
293 Poll.remove(pollset, wakeupSocket);
294 toBeWakenUp = false;
295 }
296 continue;
297 }
298
299 if ((flag & Poll.APR_POLLIN) != 0) {
300 polledHandles.add(socket);
301 }
302 }
303 return polledHandles.size();
304 }
305 }
306
307
308
309
310 @Override
311 protected Iterator<Long> selectedHandles() {
312 return polledHandles.iterator();
313 }
314
315
316
317
318 @Override
319 protected void close(Long handle) throws Exception {
320 Poll.remove(pollset, handle);
321 int result = Socket.close(handle);
322 if (result != Status.APR_SUCCESS) {
323 throwException(result);
324 }
325 }
326
327
328
329
330 @Override
331 protected void wakeup() {
332 if (toBeWakenUp) {
333 return;
334 }
335
336
337 synchronized (wakeupLock) {
338 toBeWakenUp = true;
339 Poll.add(pollset, wakeupSocket, Poll.APR_POLLOUT);
340 }
341 }
342
343
344
345
346 public int getBacklog() {
347 return backlog;
348 }
349
350
351
352
353 public boolean isReuseAddress() {
354 return reuseAddress;
355 }
356
357
358
359
360 public void setBacklog(int backlog) {
361 synchronized (bindLock) {
362 if (isActive()) {
363 throw new IllegalStateException(
364 "backlog can't be set while the acceptor is bound.");
365 }
366
367 this.backlog = backlog;
368 }
369 }
370
371
372
373
374 @Override
375 public InetSocketAddress getLocalAddress() {
376 return (InetSocketAddress) super.getLocalAddress();
377 }
378
379
380
381
382 @Override
383 public InetSocketAddress getDefaultLocalAddress() {
384 return (InetSocketAddress) super.getDefaultLocalAddress();
385 }
386
387
388
389
390 public void setDefaultLocalAddress(InetSocketAddress localAddress) {
391 super.setDefaultLocalAddress(localAddress);
392 }
393
394 public void setReuseAddress(boolean reuseAddress) {
395 synchronized (bindLock) {
396 if (isActive()) {
397 throw new IllegalStateException(
398 "backlog can't be set while the acceptor is bound.");
399 }
400
401 this.reuseAddress = reuseAddress;
402 }
403 }
404
405
406
407
408 public TransportMetadata getTransportMetadata() {
409 return AprSocketSession.METADATA;
410 }
411
412
413
414
415 @Override
416 public SocketSessionConfig getSessionConfig() {
417 return (SocketSessionConfig) super.getSessionConfig();
418 }
419
420
421
422
423
424
425 private void throwException(int code) throws IOException {
426 throw new IOException(
427 org.apache.tomcat.jni.Error.strerror(-code) +
428 " (code: " + code + ")");
429 }
430 }