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.bio;
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.AsynchronousCloseException;
27 import java.nio.channels.DatagramChannel;
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.idlechecker.IdleChecker;
37 import org.apache.mina.service.idlechecker.IndexedIdleChecker;
38 import org.apache.mina.transport.ConnectFuture;
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
50 public class BioUdpServer extends AbstractUdpServer {
51
52 private static final Logger LOG = LoggerFactory.getLogger(BioUdpServer.class);
53
54 private SocketAddress boundAddress = null;
55
56
57 DatagramChannel channel;
58
59
60 private Worker worker;
61 private boolean bound = false;
62
63
64 private IdleChecker idleChecker = new IndexedIdleChecker();
65
66
67 private final Map<SocketAddress
68
69
70
71
72 public BioUdpServer() {
73 super(null);
74 }
75
76 public BioUdpServer(IoHandlerExecutor executor) {
77 super(executor);
78 }
79
80 public BioUdpServer(UdpSessionConfig config, IoHandlerExecutor executor) {
81 super(config, executor);
82 }
83
84 public DatagramChannel getDatagramChannel() {
85 return channel;
86 }
87
88 @Override
89 public SocketAddress getBoundAddress() {
90 return boundAddress;
91 }
92
93 @Override
94 public void bind(SocketAddress localAddress) {
95 LOG.info("binding to address {}", localAddress);
96 if (bound) {
97 throw new IllegalStateException("already bound");
98 }
99 boundAddress = localAddress;
100 try {
101 channel = DatagramChannel.open();
102 channel.socket().bind(localAddress);
103 Boolean reuseAddress = config.isReuseAddress();
104
105 if (reuseAddress != null) {
106 channel.socket().setReuseAddress(reuseAddress);
107 }
108
109 Integer readBufferSize = config.getReadBufferSize();
110
111 if (readBufferSize != null) {
112 channel.socket().setReceiveBufferSize(readBufferSize);
113 }
114
115 Integer sendBufferSize = config.getSendBufferSize();
116
117 if (sendBufferSize != null) {
118 channel.socket().setSendBufferSize(sendBufferSize);
119 }
120
121 Integer trafficClass = config.getTrafficClass();
122
123 if (trafficClass != null) {
124 channel.socket().setTrafficClass(trafficClass);
125 }
126 } catch (IOException e) {
127 throw new MinaRuntimeException("Can't open and configure a new udp socket", e);
128 }
129
130 worker = new Worker();
131 bound = true;
132 worker.start();
133 idleChecker.start();
134 }
135
136 @Override
137 public void bind(int port) {
138 bind(new InetSocketAddress(port));
139 }
140
141 @Override
142 public void unbind() {
143 if (!bound) {
144 throw new IllegalStateException("not bound");
145 }
146 bound = false;
147 try {
148 try {
149 channel.close();
150 } catch (IOException e) {
151 throw new MinaRuntimeException("can't unbind the udp channel", e);
152 }
153 boundAddress = null;
154 idleChecker.destroy();
155 worker.join();
156 } catch (InterruptedException e) {
157 LOG.error("exception", e);
158 }
159
160 }
161
162 @Override
163 public IoFuture<IoSession> connect(SocketAddress remoteAddress) {
164 BioUdpSession session = new BioUdpSession(remoteAddress, BioUdpServer.this, idleChecker);
165 sessions.put(remoteAddress, session);
166 ConnectFuture cf = new ConnectFuture();
167 cf.complete(session);
168 return cf;
169 }
170
171 private class Worker extends Thread {
172
173 public Worker() {
174 super("BioUdpServerWorker");
175 }
176
177 @Override
178 public void run() {
179
180 ByteBuffer rcvdBuffer = ByteBuffer.allocate(64 * 1024);
181 while (bound) {
182
183 rcvdBuffer.clear();
184 try {
185 SocketAddress from = channel.receive(rcvdBuffer);
186 BioUdpSession session = sessions.get(from);
187 if (session == null) {
188
189 session = new BioUdpSession(from, BioUdpServer.this, idleChecker);
190 sessions.put(from, session);
191 session.getConfig().setIdleTimeInMillis(IdleStatus.READ_IDLE,
192 config.getIdleTimeInMillis(IdleStatus.READ_IDLE));
193 session.getConfig().setIdleTimeInMillis(IdleStatus.WRITE_IDLE,
194 config.getIdleTimeInMillis(IdleStatus.WRITE_IDLE));
195 idleChecker.sessionWritten(session, System.currentTimeMillis());
196
197 session.processSessionOpen();
198
199 }
200 rcvdBuffer.flip();
201 session.processMessageReceived(rcvdBuffer);
202
203 idleChecker.sessionRead(session, System.currentTimeMillis());
204 } catch (AsynchronousCloseException aec) {
205 LOG.debug("closed service");
206 break;
207 } catch (IOException e) {
208 LOG.error("Exception while reading", e);
209 }
210 }
211 }
212 }
213 }