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