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