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.nio;
21
22 import java.io.IOException;
23 import java.net.InetSocketAddress;
24 import java.net.SocketAddress;
25 import java.nio.channels.SelectionKey;
26 import java.nio.channels.Selector;
27 import java.nio.channels.ServerSocketChannel;
28 import java.nio.channels.SocketChannel;
29 import java.util.ArrayList;
30 import java.util.HashMap;
31 import java.util.Iterator;
32 import java.util.List;
33 import java.util.Map;
34 import java.util.Set;
35
36 import org.apache.mina.common.ExceptionMonitor;
37 import org.apache.mina.common.IoAcceptor;
38 import org.apache.mina.common.IoHandler;
39 import org.apache.mina.common.IoServiceConfig;
40 import org.apache.mina.common.support.BaseIoAcceptor;
41 import org.apache.mina.util.NamePreservingRunnable;
42 import org.apache.mina.util.NewThreadExecutor;
43 import org.apache.mina.util.Queue;
44
45 import edu.emory.mathcs.backport.java.util.concurrent.Executor;
46
47
48
49
50
51
52
53 public class SocketAcceptor extends BaseIoAcceptor {
54
55
56
57 private static volatile int nextId = 0;
58
59 private final Executor executor;
60
61 private final Object lock = new Object();
62
63 private final int id = nextId++;
64
65 private final String threadName = "SocketAcceptor-" + id;
66
67 private SocketAcceptorConfig defaultConfig = new SocketAcceptorConfig();
68
69 private final Map channels = new HashMap();
70
71 private final Queue registerQueue = new Queue();
72
73 private final Queue cancelQueue = new Queue();
74
75 private final SocketIoProcessor[] ioProcessors;
76
77 private final int processorCount;
78
79
80
81
82 private Selector selector;
83
84 private Worker worker;
85
86 private int processorDistributor = 0;
87
88
89
90
91 public SocketAcceptor() {
92 this(1, new NewThreadExecutor());
93 }
94
95
96
97
98
99
100
101 public SocketAcceptor(int processorCount, Executor executor) {
102 if (processorCount < 1) {
103 throw new IllegalArgumentException(
104 "Must have at least one processor");
105 }
106
107
108 ((SocketSessionConfig) defaultConfig.getSessionConfig())
109 .setReuseAddress(true);
110
111 this.executor = executor;
112 this.processorCount = processorCount;
113 ioProcessors = new SocketIoProcessor[processorCount];
114
115 for (int i = 0; i < processorCount; i++) {
116 ioProcessors[i] = new SocketIoProcessor(
117 "SocketAcceptorIoProcessor-" + id + "." + i, executor);
118 }
119 }
120
121
122
123
124
125
126
127 public void bind(SocketAddress address, IoHandler handler,
128 IoServiceConfig config) throws IOException {
129 if (handler == null) {
130 throw new NullPointerException("handler");
131 }
132
133 if (address != null && !(address instanceof InetSocketAddress)) {
134 throw new IllegalArgumentException("Unexpected address type: "
135 + address.getClass());
136 }
137
138 if (config == null) {
139 config = getDefaultConfig();
140 }
141
142 RegistrationRequest request = new RegistrationRequest(address, handler,
143 config);
144
145 synchronized (lock) {
146 startupWorker();
147
148 synchronized (registerQueue) {
149 registerQueue.push(request);
150 }
151
152 selector.wakeup();
153 }
154
155 synchronized (request) {
156 while (!request.done) {
157 try {
158 request.wait();
159 } catch (InterruptedException e) {
160 ExceptionMonitor.getInstance().exceptionCaught(e);
161 }
162 }
163 }
164
165 if (request.exception != null) {
166 throw request.exception;
167 }
168 }
169
170 private Selector getSelector() {
171 synchronized (lock) {
172 return this.selector;
173 }
174 }
175
176 private void startupWorker() throws IOException {
177 synchronized (lock) {
178 if (worker == null) {
179 selector = Selector.open();
180 worker = new Worker();
181
182 executor.execute(new NamePreservingRunnable(worker, threadName));
183 }
184 }
185 }
186
187 public void unbind(SocketAddress address) {
188 if (address == null) {
189 throw new NullPointerException("address");
190 }
191
192 CancellationRequest request = new CancellationRequest(address);
193
194 try {
195 startupWorker();
196 } catch (IOException e) {
197
198
199
200
201 throw new IllegalArgumentException("Address not bound: " + address);
202 }
203
204 synchronized (cancelQueue) {
205 cancelQueue.push(request);
206 }
207
208 selector.wakeup();
209
210 synchronized (request) {
211 while (!request.done) {
212 try {
213 request.wait();
214 } catch (InterruptedException e) {
215 ExceptionMonitor.getInstance().exceptionCaught(e);
216 }
217 }
218 }
219
220 if (request.exception != null) {
221 request.exception.fillInStackTrace();
222
223 throw request.exception;
224 }
225 }
226
227 public void unbindAll() {
228 List addresses;
229 synchronized (channels) {
230 addresses = new ArrayList(channels.keySet());
231 }
232
233 for (Iterator i = addresses.iterator(); i.hasNext();) {
234 unbind((SocketAddress) i.next());
235 }
236 }
237
238 private class Worker implements Runnable {
239 public void run() {
240 Selector selector = getSelector();
241 for (;;) {
242 try {
243 int nKeys = selector.select();
244
245 registerNew();
246
247 if (nKeys > 0) {
248 processSessions(selector.selectedKeys());
249 }
250
251 cancelKeys();
252
253 if (selector.keys().isEmpty()) {
254 synchronized (lock) {
255 if (selector.keys().isEmpty()
256 && registerQueue.isEmpty()
257 && cancelQueue.isEmpty()) {
258 worker = null;
259 try {
260 selector.close();
261 } catch (IOException e) {
262 ExceptionMonitor.getInstance()
263 .exceptionCaught(e);
264 } finally {
265 SocketAcceptor.this.selector = null;
266 }
267 break;
268 }
269 }
270 }
271 } catch (IOException e) {
272 ExceptionMonitor.getInstance().exceptionCaught(e);
273
274 try {
275 Thread.sleep(1000);
276 } catch (InterruptedException e1) {
277 ExceptionMonitor.getInstance().exceptionCaught(e1);
278 }
279 }
280 }
281 }
282
283 private void processSessions(Set keys) throws IOException {
284 Iterator it = keys.iterator();
285 while (it.hasNext()) {
286 SelectionKey key = (SelectionKey) it.next();
287
288 it.remove();
289
290 if (!key.isAcceptable()) {
291 continue;
292 }
293
294 ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
295
296 SocketChannel ch = ssc.accept();
297
298 if (ch == null) {
299 continue;
300 }
301
302 boolean success = false;
303 try {
304 RegistrationRequest req = (RegistrationRequest) key
305 .attachment();
306 SocketSessionImpl session = new SocketSessionImpl(
307 SocketAcceptor.this, nextProcessor(),
308 getListeners(), req.config, ch, req.handler,
309 req.address);
310 getFilterChainBuilder().buildFilterChain(
311 session.getFilterChain());
312 req.config.getFilterChainBuilder().buildFilterChain(
313 session.getFilterChain());
314 req.config.getThreadModel().buildFilterChain(
315 session.getFilterChain());
316 session.getIoProcessor().addNew(session);
317 success = true;
318 } catch (Throwable t) {
319 ExceptionMonitor.getInstance().exceptionCaught(t);
320 } finally {
321 if (!success) {
322 ch.close();
323 }
324 }
325 }
326 }
327 }
328
329 private SocketIoProcessor nextProcessor() {
330 if (this.processorDistributor == Integer.MAX_VALUE) {
331 this.processorDistributor = Integer.MAX_VALUE % this.processorCount;
332 }
333
334 return ioProcessors[processorDistributor++ % processorCount];
335 }
336
337 public IoServiceConfig getDefaultConfig() {
338 return defaultConfig;
339 }
340
341
342
343
344
345
346
347 public void setDefaultConfig(SocketAcceptorConfig defaultConfig) {
348 if (defaultConfig == null) {
349 throw new NullPointerException("defaultConfig");
350 }
351 this.defaultConfig = defaultConfig;
352 }
353
354 private void registerNew() {
355 if (registerQueue.isEmpty()) {
356 return;
357 }
358
359 Selector selector = getSelector();
360 for (;;) {
361 RegistrationRequest req;
362
363 synchronized (registerQueue) {
364 req = (RegistrationRequest) registerQueue.pop();
365 }
366
367 if (req == null) {
368 break;
369 }
370
371 ServerSocketChannel ssc = null;
372
373 try {
374 ssc = ServerSocketChannel.open();
375 ssc.configureBlocking(false);
376
377
378 SocketAcceptorConfig cfg;
379 if (req.config instanceof SocketAcceptorConfig) {
380 cfg = (SocketAcceptorConfig) req.config;
381 } else {
382 cfg = (SocketAcceptorConfig) getDefaultConfig();
383 }
384
385 ssc.socket().setReuseAddress(cfg.isReuseAddress());
386 ssc.socket().setReceiveBufferSize(
387 ((SocketSessionConfig) cfg.getSessionConfig())
388 .getReceiveBufferSize());
389
390
391 ssc.socket().bind(req.address, cfg.getBacklog());
392 if (req.address == null || req.address.getPort() == 0) {
393 req.address = (InetSocketAddress) ssc.socket()
394 .getLocalSocketAddress();
395 }
396 ssc.register(selector, SelectionKey.OP_ACCEPT, req);
397
398 synchronized (channels) {
399 channels.put(req.address, ssc);
400 }
401
402 getListeners().fireServiceActivated(this, req.address,
403 req.handler, req.config);
404 } catch (IOException e) {
405 req.exception = e;
406 } finally {
407 synchronized (req) {
408 req.done = true;
409
410 req.notifyAll();
411 }
412
413 if (ssc != null && req.exception != null) {
414 try {
415 ssc.close();
416 } catch (IOException e) {
417 ExceptionMonitor.getInstance().exceptionCaught(e);
418 }
419 }
420 }
421 }
422 }
423
424 private void cancelKeys() {
425 if (cancelQueue.isEmpty()) {
426 return;
427 }
428
429 Selector selector = getSelector();
430 for (;;) {
431 CancellationRequest request;
432
433 synchronized (cancelQueue) {
434 request = (CancellationRequest) cancelQueue.pop();
435 }
436
437 if (request == null) {
438 break;
439 }
440
441 ServerSocketChannel ssc;
442 synchronized (channels) {
443 ssc = (ServerSocketChannel) channels.remove(request.address);
444 }
445
446
447 try {
448 if (ssc == null) {
449 request.exception = new IllegalArgumentException(
450 "Address not bound: " + request.address);
451 } else {
452 SelectionKey key = ssc.keyFor(selector);
453 request.registrationRequest = (RegistrationRequest) key
454 .attachment();
455 key.cancel();
456
457 selector.wakeup();
458
459 ssc.close();
460 }
461 } catch (IOException e) {
462 ExceptionMonitor.getInstance().exceptionCaught(e);
463 } finally {
464 synchronized (request) {
465 request.done = true;
466 request.notifyAll();
467 }
468
469 if (request.exception == null) {
470 getListeners().fireServiceDeactivated(this,
471 request.address,
472 request.registrationRequest.handler,
473 request.registrationRequest.config);
474 }
475 }
476 }
477 }
478
479 private static class RegistrationRequest {
480 private InetSocketAddress address;
481
482 private final IoHandler handler;
483
484 private final IoServiceConfig config;
485
486 private IOException exception;
487
488 private boolean done;
489
490 private RegistrationRequest(SocketAddress address, IoHandler handler,
491 IoServiceConfig config) {
492 this.address = (InetSocketAddress) address;
493 this.handler = handler;
494 this.config = config;
495 }
496 }
497
498 private static class CancellationRequest {
499 private final SocketAddress address;
500
501 private boolean done;
502
503 private RegistrationRequest registrationRequest;
504
505 private RuntimeException exception;
506
507 private CancellationRequest(SocketAddress address) {
508 this.address = address;
509 }
510 }
511 }