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.DatagramChannel;
27 import java.nio.channels.SelectionKey;
28 import java.util.Map;
29 import java.util.concurrent.ConcurrentHashMap;
30
31 import org.apache.mina.api.IdleStatus;
32 import org.apache.mina.api.IoFuture;
33 import org.apache.mina.api.IoSession;
34 import org.apache.mina.api.MinaRuntimeException;
35 import org.apache.mina.service.executor.IoHandlerExecutor;
36 import org.apache.mina.service.executor.OrderedHandlerExecutor;
37 import org.apache.mina.service.idlechecker.IdleChecker;
38 import org.apache.mina.service.idlechecker.IndexedIdleChecker;
39 import org.apache.mina.transport.udp.AbstractUdpServer;
40 import org.apache.mina.transport.udp.UdpSessionConfig;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
43
44
45
46
47
48
49 public class NioUdpServer extends AbstractUdpServer implements SelectorListener {
50
51 static final Logger LOG = LoggerFactory.getLogger(NioUdpServer.class);
52
53 private static final boolean IS_DEBUG = LOG.isDebugEnabled();
54
55
56 private SocketAddress address = null;
57
58
59 private final IdleChecker idleChecker = new IndexedIdleChecker();
60
61
62 private DatagramChannel datagramChannel = null;
63
64
65 private SelectionKey readKey = null;
66
67
68 private final Map<SocketAddress
69
70
71 private final SelectorLoop readSelectorLoop;
72
73
74
75
76
77 public NioUdpServer() {
78 this(new NioSelectorLoop("accept", 0), null);
79 }
80
81
82
83
84
85
86
87 public NioUdpServer(UdpSessionConfig config) {
88 this(config, new NioSelectorLoop("accept", 0), null);
89 }
90
91
92
93
94
95
96
97
98
99
100 public NioUdpServer(SelectorLoop readSelectorLoop, IoHandlerExecutor handlerExecutor) {
101 super(handlerExecutor);
102 this.readSelectorLoop = readSelectorLoop;
103 }
104
105
106
107
108
109
110
111
112
113
114 public NioUdpServer(UdpSessionConfig config, SelectorLoop readSelectorLoop, IoHandlerExecutor handlerExecutor) {
115 super(config, handlerExecutor);
116 this.readSelectorLoop = readSelectorLoop;
117 }
118
119
120
121
122
123
124 public DatagramChannel getDatagramChannel() {
125 return datagramChannel;
126 }
127
128
129
130
131 @Override
132 public SocketAddress getBoundAddress() {
133 return address;
134 }
135
136
137
138
139 @Override
140 public void bind(final int port) {
141 bind(new InetSocketAddress(port));
142 }
143
144
145
146
147 @Override
148 public void bind(final SocketAddress localAddress) {
149 if (localAddress == null) {
150
151 throw new IllegalArgumentException("LocalAdress cannot be null");
152 }
153
154
155 if (this.address != null) {
156 throw new IllegalStateException("address " + address + " already bound");
157 }
158 address = localAddress;
159
160 LOG.info("binding address {}", localAddress);
161
162 try {
163 datagramChannel = DatagramChannel.open();
164 datagramChannel.socket().setReuseAddress(isReuseAddress());
165 datagramChannel.socket().bind(address);
166 datagramChannel.configureBlocking(false);
167 } catch (IOException e) {
168 throw new MinaRuntimeException("can't open the address " + address, e);
169 }
170
171 readSelectorLoop.register(false, false, true, false, this, datagramChannel, null);
172
173
174 this.fireServiceActivated();
175 }
176
177 @Override
178 public IoFuture<IoSession> connect(SocketAddress remoteAddress) {
179 throw new IllegalStateException("not supported");
180 }
181
182
183
184
185 @Override
186 public void unbind() {
187 LOG.info("unbinding {}", address);
188 if (this.address == null) {
189 throw new IllegalStateException("server not bound");
190 }
191
192 readSelectorLoop.unregister(this, datagramChannel);
193 datagramChannel.socket().close();
194 try {
195 datagramChannel.close();
196 } catch (IOException e) {
197 throw new MinaRuntimeException("can't close the datagram socket", e);
198 }
199
200 this.address = null;
201 this.fireServiceInactivated();
202 }
203
204
205
206
207 public SelectionKey getReadKey() {
208 return readKey;
209 }
210
211
212
213
214 public void setReadKey(final SelectionKey readKey) {
215 this.readKey = readKey;
216 }
217
218
219
220
221 @Override
222 public void ready(final boolean accept, boolean connect, final boolean read, final ByteBuffer readBuffer,
223 final boolean write) {
224
225 try {
226
227 final SocketAddress source = datagramChannel.receive(readBuffer);
228 NioUdpSession session = null;
229
230
231 if (source != null) {
232 session = sessions.get(source);
233
234 if (session == null) {
235 session = createSession(source, datagramChannel);
236 }
237 if (read) {
238 if (IS_DEBUG) {
239 LOG.debug("readable datagram for UDP service : {}", this);
240 }
241
242 readBuffer.flip();
243
244 if (IS_DEBUG) {
245 LOG.debug("read {} bytes form {}", readBuffer.remaining(), source);
246 }
247
248 session.receivedDatagram(readBuffer);
249
250 }
251
252
253 if (write) {
254 session.processWrite(readSelectorLoop);
255 }
256 } else {
257 if (IS_DEBUG) {
258 LOG.debug("Do data to read");
259 }
260 }
261
262 } catch (final IOException ex) {
263 LOG.error("IOException while reading the socket", ex);
264 }
265 }
266
267 private NioUdpSession createSession(SocketAddress remoteAddress, DatagramChannel datagramChannel)
268 throws IOException {
269 LOG.debug("create session");
270 UdpSessionConfig config = getSessionConfig();
271 SocketAddress localAddress = new InetSocketAddress(datagramChannel.socket().getLocalAddress(), datagramChannel
272 .socket().getLocalPort());
273 final NioUdpSession session = new NioUdpSession(this, idleChecker, datagramChannel, localAddress, remoteAddress);
274
275
276 session.getConfig().setIdleTimeInMillis(IdleStatus.READ_IDLE, config.getIdleTimeInMillis(IdleStatus.READ_IDLE));
277 session.getConfig().setIdleTimeInMillis(IdleStatus.WRITE_IDLE,
278 config.getIdleTimeInMillis(IdleStatus.WRITE_IDLE));
279
280
281
282 Boolean reuseAddress = config.isReuseAddress();
283
284 if (reuseAddress != null) {
285 session.getConfig().setReuseAddress(reuseAddress);
286 }
287
288 Integer readBufferSize = config.getReadBufferSize();
289
290 if (readBufferSize != null) {
291 session.getConfig().setReadBufferSize(readBufferSize);
292 }
293
294 Integer sendBufferSize = config.getSendBufferSize();
295
296 if (sendBufferSize != null) {
297 session.getConfig().setSendBufferSize(sendBufferSize);
298 }
299
300 Integer trafficClass = config.getTrafficClass();
301
302 if (trafficClass != null) {
303 session.getConfig().setTrafficClass(trafficClass);
304 }
305
306
307 idleChecker.sessionRead(session, System.currentTimeMillis());
308 idleChecker.sessionWritten(session, System.currentTimeMillis());
309
310 sessions.put(remoteAddress, session);
311
312
313 session.setConnected();
314
315 return session;
316 }
317 }