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.nio.ByteBuffer;
26 import java.util.HashMap;
27 import java.util.HashSet;
28 import java.util.Iterator;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Set;
32 import java.util.concurrent.Executor;
33
34 import org.apache.mina.core.RuntimeIoException;
35 import org.apache.mina.core.polling.AbstractPollingIoConnector;
36 import org.apache.mina.core.service.IoConnector;
37 import org.apache.mina.core.service.IoProcessor;
38 import org.apache.mina.core.service.IoService;
39 import org.apache.mina.core.service.SimpleIoProcessorPool;
40 import org.apache.mina.core.service.TransportMetadata;
41 import org.apache.mina.transport.socket.DefaultSocketSessionConfig;
42 import org.apache.mina.transport.socket.SocketConnector;
43 import org.apache.mina.transport.socket.SocketSessionConfig;
44 import org.apache.mina.util.CircularQueue;
45 import org.apache.tomcat.jni.Address;
46 import org.apache.tomcat.jni.Poll;
47 import org.apache.tomcat.jni.Pool;
48 import org.apache.tomcat.jni.Socket;
49 import org.apache.tomcat.jni.Status;
50
51
52
53
54
55
56
57 public final class AprSocketConnector extends AbstractPollingIoConnector<AprSession, Long> implements SocketConnector {
58
59
60
61
62
63 private static final int APR_TIMEUP_ERROR = -120001;
64
65 private static final int POLLSET_SIZE = 1024;
66
67 private final Map<Long, ConnectionRequest> requests =
68 new HashMap<Long, ConnectionRequest>(POLLSET_SIZE);
69
70 private final Object wakeupLock = new Object();
71 private volatile long wakeupSocket;
72 private volatile boolean toBeWakenUp;
73
74 private volatile long pool;
75 private volatile long pollset;
76 private final long[] polledSockets = new long[POLLSET_SIZE << 1];
77 private final List<Long> polledHandles = new CircularQueue<Long>(POLLSET_SIZE);
78 private final Set<Long> failedHandles = new HashSet<Long>(POLLSET_SIZE);
79 private volatile ByteBuffer dummyBuffer;
80
81
82
83
84 public AprSocketConnector() {
85 super(new DefaultSocketSessionConfig(), AprIoProcessor.class);
86 ((DefaultSocketSessionConfig) getSessionConfig()).init(this);
87 }
88
89
90
91
92
93
94
95 public AprSocketConnector(int processorCount) {
96 super(new DefaultSocketSessionConfig(), AprIoProcessor.class, processorCount);
97 ((DefaultSocketSessionConfig) getSessionConfig()).init(this);
98 }
99
100
101
102
103
104
105
106 public AprSocketConnector(IoProcessor<AprSession> processor) {
107 super(new DefaultSocketSessionConfig(), processor);
108 ((DefaultSocketSessionConfig) getSessionConfig()).init(this);
109 }
110
111
112
113
114
115
116
117
118 public AprSocketConnector(Executor executor, IoProcessor<AprSession> processor) {
119 super(new DefaultSocketSessionConfig(), executor, processor);
120 ((DefaultSocketSessionConfig) getSessionConfig()).init(this);
121 }
122
123
124
125
126 @Override
127 protected void init() throws Exception {
128
129 pool = Pool.create(AprLibrary.getInstance().getRootPool());
130
131 wakeupSocket = Socket.create(
132 Socket.APR_INET, Socket.SOCK_DGRAM, Socket.APR_PROTO_UDP, pool);
133
134 dummyBuffer = Pool.alloc(pool, 1);
135
136 pollset = Poll.create(
137 POLLSET_SIZE,
138 pool,
139 Poll.APR_POLLSET_THREADSAFE,
140 Long.MAX_VALUE);
141
142 if (pollset <= 0) {
143 pollset = Poll.create(
144 62,
145 pool,
146 Poll.APR_POLLSET_THREADSAFE,
147 Long.MAX_VALUE);
148 }
149
150 if (pollset <= 0) {
151 if (Status.APR_STATUS_IS_ENOTIMPL(- (int) pollset)) {
152 throw new RuntimeIoException(
153 "Thread-safe pollset is not supported in this platform.");
154 }
155 }
156 }
157
158
159
160
161 @Override
162 protected void destroy() throws Exception {
163 if (wakeupSocket > 0) {
164 Socket.close(wakeupSocket);
165 }
166 if (pollset > 0) {
167 Poll.destroy(pollset);
168 }
169 if (pool > 0) {
170 Pool.destroy(pool);
171 }
172 }
173
174
175
176
177 @Override
178 protected Iterator<Long> allHandles() {
179 return polledHandles.iterator();
180 }
181
182
183
184
185 @Override
186 protected boolean connect(Long handle, SocketAddress remoteAddress)
187 throws Exception {
188 InetSocketAddress ra = (InetSocketAddress) remoteAddress;
189 long sa;
190 if (ra != null) {
191 if (ra.getAddress() == null) {
192 sa = Address.info(Address.APR_ANYADDR, Socket.APR_INET, ra.getPort(), 0, pool);
193 } else {
194 sa = Address.info(ra.getAddress().getHostAddress(), Socket.APR_INET, ra.getPort(), 0, pool);
195 }
196 } else {
197 sa = Address.info(Address.APR_ANYADDR, Socket.APR_INET, 0, 0, pool);
198 }
199
200 int rv = Socket.connect(handle, sa);
201 if (rv == Status.APR_SUCCESS) {
202 return true;
203 }
204
205 if (Status.APR_STATUS_IS_EINPROGRESS(rv)) {
206 return false;
207 }
208
209 throwException(rv);
210 throw new InternalError();
211 }
212
213
214
215
216 @Override
217 protected ConnectionRequest getConnectionRequest(Long handle) {
218 return requests.get(handle);
219 }
220
221
222
223
224 @Override
225 protected void close(Long handle) throws Exception {
226 finishConnect(handle);
227 int rv = Socket.close(handle);
228 if (rv != Status.APR_SUCCESS) {
229 throwException(rv);
230 }
231 }
232
233
234
235
236 @Override
237 protected boolean finishConnect(Long handle) throws Exception {
238 Poll.remove(pollset, handle);
239 requests.remove(handle);
240 if (failedHandles.remove(handle)) {
241 int rv = Socket.recvb(handle, dummyBuffer, 0, 1);
242 throwException(rv);
243 throw new InternalError("Shouldn't reach here.");
244 }
245 return true;
246 }
247
248
249
250
251 @Override
252 protected Long newHandle(SocketAddress localAddress) throws Exception {
253 long handle = Socket.create(
254 Socket.APR_INET, Socket.SOCK_STREAM, Socket.APR_PROTO_TCP, pool);
255 boolean success = false;
256 try {
257 int result = Socket.optSet(handle, Socket.APR_SO_NONBLOCK, 1);
258 if (result != Status.APR_SUCCESS) {
259 throwException(result);
260 }
261 result = Socket.timeoutSet(handle, 0);
262 if (result != Status.APR_SUCCESS) {
263 throwException(result);
264 }
265
266 if (localAddress != null) {
267 InetSocketAddress la = (InetSocketAddress) localAddress;
268 long sa;
269
270 if (la.getAddress() == null) {
271 sa = Address.info(Address.APR_ANYADDR, Socket.APR_INET, la.getPort(), 0, pool);
272 } else {
273 sa = Address.info(la.getAddress().getHostAddress(), Socket.APR_INET, la.getPort(), 0, pool);
274 }
275
276 result = Socket.bind(handle, sa);
277 if (result != Status.APR_SUCCESS) {
278 throwException(result);
279 }
280 }
281
282 success = true;
283 return handle;
284 } finally {
285 if (!success) {
286 int rv = Socket.close(handle);
287 if (rv != Status.APR_SUCCESS) {
288 throwException(rv);
289 }
290 }
291 }
292 }
293
294
295
296
297 @Override
298 protected AprSession newSession(IoProcessor<AprSession> processor,
299 Long handle) throws Exception {
300 return new AprSocketSession(this, processor, handle);
301 }
302
303
304
305
306 @Override
307 protected void register(Long handle, ConnectionRequest request)
308 throws Exception {
309 int rv = Poll.add(pollset, handle, Poll.APR_POLLOUT);
310 if (rv != Status.APR_SUCCESS) {
311 throwException(rv);
312 }
313
314 requests.put(handle, request);
315 }
316
317
318
319
320 @Override
321 protected int select(int timeout) throws Exception {
322 int rv = Poll.poll(pollset, timeout * 1000, polledSockets, false);
323 if (rv <= 0) {
324 if (rv != APR_TIMEUP_ERROR) {
325 throwException(rv);
326 }
327
328 rv = Poll.maintain(pollset, polledSockets, true);
329 if (rv > 0) {
330 for (int i = 0; i < rv; i ++) {
331 Poll.add(pollset, polledSockets[i], Poll.APR_POLLOUT);
332 }
333 } else if (rv < 0) {
334 throwException(rv);
335 }
336
337 return 0;
338 } else {
339 rv <<= 1;
340 if (!polledHandles.isEmpty()) {
341 polledHandles.clear();
342 }
343
344 for (int i = 0; i < rv; i ++) {
345 long flag = polledSockets[i];
346 long socket = polledSockets[++i];
347 if (socket == wakeupSocket) {
348 synchronized (wakeupLock) {
349 Poll.remove(pollset, wakeupSocket);
350 toBeWakenUp = false;
351 }
352 continue;
353 }
354 polledHandles.add(socket);
355 if ((flag & Poll.APR_POLLOUT) == 0) {
356 failedHandles.add(socket);
357 }
358 }
359 return polledHandles.size();
360 }
361 }
362
363
364
365
366 @Override
367 protected Iterator<Long> selectedHandles() {
368 return polledHandles.iterator();
369 }
370
371
372
373
374 @Override
375 protected void wakeup() {
376 if (toBeWakenUp) {
377 return;
378 }
379
380
381 synchronized (wakeupLock) {
382 toBeWakenUp = true;
383 Poll.add(pollset, wakeupSocket, Poll.APR_POLLOUT);
384 }
385 }
386
387
388
389
390 public TransportMetadata getTransportMetadata() {
391 return AprSocketSession.METADATA;
392 }
393
394
395
396
397 @Override
398 public SocketSessionConfig getSessionConfig() {
399 return (SocketSessionConfig) super.getSessionConfig();
400 }
401
402
403
404
405 @Override
406 public InetSocketAddress getDefaultRemoteAddress() {
407 return (InetSocketAddress) super.getDefaultRemoteAddress();
408 }
409
410
411
412
413 public void setDefaultRemoteAddress(InetSocketAddress defaultRemoteAddress) {
414 super.setDefaultRemoteAddress(defaultRemoteAddress);
415 }
416
417
418
419
420
421
422 private void throwException(int code) throws IOException {
423 throw new IOException(
424 org.apache.tomcat.jni.Error.strerror(-code) +
425 " (code: " + code + ")");
426 }
427 }