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