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.nio;
21
22 import java.io.IOException;
23 import java.net.InetSocketAddress;
24 import java.net.SocketAddress;
25 import java.nio.ByteBuffer;
26 import java.nio.channels.SelectionKey;
27 import java.nio.channels.ServerSocketChannel;
28 import java.nio.channels.SocketChannel;
29
30 import org.apache.mina.api.IdleStatus;
31 import org.apache.mina.api.MinaRuntimeException;
32 import org.apache.mina.service.executor.IoHandlerExecutor;
33 import org.apache.mina.service.executor.OrderedHandlerExecutor;
34 import org.apache.mina.service.idlechecker.IdleChecker;
35 import org.apache.mina.service.idlechecker.IndexedIdleChecker;
36 import org.apache.mina.transport.tcp.AbstractTcpServer;
37 import org.apache.mina.transport.tcp.TcpSessionConfig;
38 import org.apache.mina.util.Assert;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41
42
43
44
45
46
47 public class NioTcpServer extends AbstractTcpServer implements SelectorListener {
48
49 static final Logger LOG = LoggerFactory.getLogger(NioTcpServer.class);
50
51
52 private SocketAddress address = null;
53
54 private final SelectorLoop acceptSelectorLoop;
55
56 private final SelectorLoopPool readWriteSelectorPool;
57
58
59 private SelectionKey acceptKey = null;
60
61
62 private ServerSocketChannel serverChannel = null;
63
64 private IdleChecker idleChecker;
65
66
67
68
69
70 public NioTcpServer() {
71 this(new NioSelectorLoop("accept", 0), new FixedSelectorLoopPool("Server", Runtime.getRuntime()
72 .availableProcessors() + 1), null);
73 }
74
75
76
77
78
79
80
81 public NioTcpServer(TcpSessionConfig config) {
82 this(config, new NioSelectorLoop("accept", 0), new FixedSelectorLoopPool("Server", Runtime.getRuntime()
83 .availableProcessors() + 1), null);
84 }
85
86
87
88
89
90
91
92
93
94
95
96 public NioTcpServer(SelectorLoopPool selectorLoopPool, IoHandlerExecutor handlerExecutor) {
97 this(selectorLoopPool.getSelectorLoop(), selectorLoopPool, handlerExecutor);
98 }
99
100
101
102
103
104
105
106
107
108
109
110
111 public NioTcpServer(TcpSessionConfig config, SelectorLoopPool selectorLoopPool, IoHandlerExecutor handlerExecutor) {
112 this(config, selectorLoopPool.getSelectorLoop(), selectorLoopPool, handlerExecutor);
113 }
114
115
116
117
118
119
120
121
122
123
124 public NioTcpServer(SelectorLoop acceptSelectorLoop, SelectorLoopPool readWriteSelectorLoop,
125 IoHandlerExecutor handlerExecutor) {
126 super(handlerExecutor);
127 this.acceptSelectorLoop = acceptSelectorLoop;
128 this.readWriteSelectorPool = readWriteSelectorLoop;
129 }
130
131
132
133
134
135
136
137
138
139
140
141 public NioTcpServer(TcpSessionConfig config, SelectorLoop acceptSelectorLoop,
142 SelectorLoopPool readWriteSelectorLoop, IoHandlerExecutor handlerExecutor) {
143 super(config, handlerExecutor);
144 this.acceptSelectorLoop = acceptSelectorLoop;
145 this.readWriteSelectorPool = readWriteSelectorLoop;
146 }
147
148
149
150
151
152
153 public synchronized ServerSocketChannel getServerSocketChannel() {
154 return serverChannel;
155 }
156
157 public synchronized void setServerSocketChannel(final ServerSocketChannel serverChannel) {
158 this.serverChannel = serverChannel;
159 }
160
161
162
163
164 @Override
165 public void bind(final int port) {
166 bind(new InetSocketAddress(port));
167 }
168
169
170
171
172 @Override
173 public synchronized void bind(SocketAddress localAddress) {
174 Assert.assertNotNull(localAddress, "localAddress");
175
176
177 if (address != null) {
178 throw new IllegalStateException("address " + address + " already bound");
179 }
180
181 LOG.info("binding address {}", localAddress);
182 address = localAddress;
183
184 try {
185 serverChannel = ServerSocketChannel.open();
186 serverChannel.socket().setReuseAddress(isReuseAddress());
187 serverChannel.socket().bind(address);
188 serverChannel.configureBlocking(false);
189 } catch (IOException e) {
190 throw new MinaRuntimeException("can't bind address" + address, e);
191 }
192
193 acceptSelectorLoop.register(true, false, false, false, this, serverChannel, null);
194
195 idleChecker = new IndexedIdleChecker();
196 idleChecker.start();
197
198
199 fireServiceActivated();
200 }
201
202
203
204
205 @Override
206 public SocketAddress getBoundAddress() {
207 return address;
208 }
209
210
211
212
213 @Override
214 public synchronized void unbind() {
215 LOG.info("unbinding {}", address);
216 if (this.address == null) {
217 throw new IllegalStateException("server not bound");
218 }
219 try {
220 serverChannel.socket().close();
221 serverChannel.close();
222 } catch (IOException e) {
223 throw new MinaRuntimeException("can't unbind server", e);
224 }
225
226 acceptSelectorLoop.unregister(this, serverChannel);
227
228 this.address = null;
229 this.fireServiceInactivated();
230
231
232 idleChecker.destroy();
233 }
234
235
236
237
238 public SelectionKey getAcceptKey() {
239 return acceptKey;
240 }
241
242
243
244
245 public void setAcceptKey(final SelectionKey acceptKey) {
246 this.acceptKey = acceptKey;
247 }
248
249
250
251
252 @Override
253 public void ready(final boolean accept, boolean connect, final boolean read, final ByteBuffer readBuffer,
254 final boolean write) {
255 if (accept) {
256 LOG.debug("acceptable new client");
257
258
259 try {
260 LOG.debug("new client accepted");
261 createSession(getServerSocketChannel().accept());
262
263 } catch (final IOException e) {
264 LOG.error("error while accepting new client", e);
265 }
266 }
267
268 if (read || write) {
269 throw new IllegalStateException("should not receive read or write events");
270 }
271 }
272
273 private synchronized void createSession(SocketChannel clientSocket) throws IOException {
274 LOG.debug("create session");
275 SocketChannel socketChannel = clientSocket;
276 TcpSessionConfig config = getSessionConfig();
277 SelectorLoop readWriteSelectorLoop = readWriteSelectorPool.getSelectorLoop();
278 final NioTcpSession session = new NioTcpSession(this, socketChannel, readWriteSelectorLoop, idleChecker);
279
280 socketChannel.configureBlocking(false);
281
282
283 session.getConfig().setIdleTimeInMillis(IdleStatus.READ_IDLE, config.getIdleTimeInMillis(IdleStatus.READ_IDLE));
284 session.getConfig().setIdleTimeInMillis(IdleStatus.WRITE_IDLE,
285 config.getIdleTimeInMillis(IdleStatus.WRITE_IDLE));
286
287
288 Boolean keepAlive = config.isKeepAlive();
289
290 if (keepAlive != null) {
291 session.getConfig().setKeepAlive(keepAlive);
292 }
293
294 Boolean oobInline = config.isOobInline();
295
296 if (oobInline != null) {
297 session.getConfig().setOobInline(oobInline);
298 }
299
300 Boolean reuseAddress = config.isReuseAddress();
301
302 if (reuseAddress != null) {
303 session.getConfig().setReuseAddress(reuseAddress);
304 }
305
306 Boolean tcpNoDelay = config.isTcpNoDelay();
307
308 if (tcpNoDelay != null) {
309 session.getConfig().setTcpNoDelay(tcpNoDelay);
310 }
311
312 Integer receiveBufferSize = config.getReadBufferSize();
313
314 if (receiveBufferSize != null) {
315 session.getConfig().setReadBufferSize(receiveBufferSize);
316 }
317
318 Integer sendBufferSize = config.getSendBufferSize();
319
320 if (sendBufferSize != null) {
321 session.getConfig().setSendBufferSize(sendBufferSize);
322 }
323
324 Integer trafficClass = config.getTrafficClass();
325
326 if (trafficClass != null) {
327 session.getConfig().setTrafficClass(trafficClass);
328 }
329
330 Integer soLinger = config.getSoLinger();
331
332 if (soLinger != null) {
333 session.getConfig().setSoLinger(soLinger);
334 }
335
336
337 if (config.isSecured()) {
338 session.initSecure(config.getSslContext());
339 }
340
341
342 readWriteSelectorLoop.register(false, false, true, false, session, socketChannel, new RegistrationCallback() {
343
344 @Override
345 public void done(SelectionKey selectionKey) {
346 session.setSelectionKey(selectionKey);
347 session.setConnected();
348 }
349 });
350
351 idleChecker.sessionRead(session, System.currentTimeMillis());
352 idleChecker.sessionWritten(session, System.currentTimeMillis());
353 }
354
355 }