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