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.net.InetSocketAddress;
23 import java.net.SocketAddress;
24 import java.nio.channels.DatagramChannel;
25 import java.nio.channels.SelectionKey;
26 import java.nio.channels.Selector;
27 import java.util.Collection;
28 import java.util.Iterator;
29 import java.util.concurrent.Executor;
30
31 import org.apache.mina.common.AbstractPollingConnectionlessIoAcceptor;
32 import org.apache.mina.common.IoAcceptor;
33 import org.apache.mina.common.IoBuffer;
34 import org.apache.mina.common.IoProcessor;
35 import org.apache.mina.common.TransportMetadata;
36 import org.apache.mina.transport.socket.DatagramAcceptor;
37 import org.apache.mina.transport.socket.DatagramSessionConfig;
38 import org.apache.mina.transport.socket.DefaultDatagramSessionConfig;
39
40
41
42
43
44
45
46 public final class NioDatagramAcceptor
47 extends AbstractPollingConnectionlessIoAcceptor<NioSession, DatagramChannel>
48 implements DatagramAcceptor {
49
50 private volatile Selector selector;
51
52
53
54
55 public NioDatagramAcceptor() {
56 super(new DefaultDatagramSessionConfig());
57 }
58
59
60
61
62 public NioDatagramAcceptor(Executor executor) {
63 super(new DefaultDatagramSessionConfig(), executor);
64 }
65
66 @Override
67 protected void init() throws Exception {
68 this.selector = Selector.open();
69 }
70
71 @Override
72 protected void destroy() throws Exception {
73 if (selector != null) {
74 selector.close();
75 }
76 }
77
78 public TransportMetadata getTransportMetadata() {
79 return NioDatagramSession.METADATA;
80 }
81
82 @Override
83 public DatagramSessionConfig getSessionConfig() {
84 return (DatagramSessionConfig) super.getSessionConfig();
85 }
86
87 @Override
88 public InetSocketAddress getLocalAddress() {
89 return (InetSocketAddress) super.getLocalAddress();
90 }
91
92 @Override
93 public InetSocketAddress getDefaultLocalAddress() {
94 return (InetSocketAddress) super.getDefaultLocalAddress();
95 }
96
97 public void setDefaultLocalAddress(InetSocketAddress localAddress) {
98 setDefaultLocalAddress((SocketAddress) localAddress);
99 }
100
101 @Override
102 protected DatagramChannel open(SocketAddress localAddress) throws Exception {
103 DatagramChannel c = DatagramChannel.open();
104 boolean success = false;
105 try {
106 DatagramSessionConfig cfg = getSessionConfig();
107 c.socket().setReuseAddress(cfg.isReuseAddress());
108 c.socket().setBroadcast(cfg.isBroadcast());
109 c.socket().setReceiveBufferSize(cfg.getReceiveBufferSize());
110 c.socket().setSendBufferSize(cfg.getSendBufferSize());
111
112 if (c.socket().getTrafficClass() != cfg.getTrafficClass()) {
113 c.socket().setTrafficClass(cfg.getTrafficClass());
114 }
115
116 c.configureBlocking(false);
117 c.socket().bind(localAddress);
118 c.register(selector, SelectionKey.OP_READ);
119 success = true;
120 } finally {
121 if (!success) {
122 close(c);
123 }
124 }
125
126 return c;
127 }
128
129 @Override
130 protected boolean isReadable(DatagramChannel handle) {
131 SelectionKey key = handle.keyFor(selector);
132 if (key == null) {
133 return false;
134 }
135 if (!key.isValid()) {
136 return false;
137 }
138 return key.isReadable();
139 }
140
141 @Override
142 protected boolean isWritable(DatagramChannel handle) {
143 SelectionKey key = handle.keyFor(selector);
144 if (key == null) {
145 return false;
146 }
147 if (!key.isValid()) {
148 return false;
149 }
150 return key.isWritable();
151 }
152
153 @Override
154 protected SocketAddress localAddress(DatagramChannel handle)
155 throws Exception {
156 return handle.socket().getLocalSocketAddress();
157 }
158
159 @Override
160 protected NioSession newSession(
161 IoProcessor<NioSession> processor, DatagramChannel handle,
162 SocketAddress remoteAddress) {
163 SelectionKey key = handle.keyFor(selector);
164 if (key == null) {
165 return null;
166 }
167 NioDatagramSession newSession = new NioDatagramSession(
168 this, handle, processor, remoteAddress);
169 newSession.setSelectionKey(key);
170
171 return newSession;
172 }
173
174 @Override
175 protected SocketAddress receive(DatagramChannel handle, IoBuffer buffer)
176 throws Exception {
177 return handle.receive(buffer.buf());
178 }
179
180 @Override
181 protected boolean select(int timeout) throws Exception {
182 return selector.select(timeout) > 0;
183 }
184
185 @Override
186 protected Iterator<DatagramChannel> selectedHandles() {
187 return new DatagramChannelIterator(selector.selectedKeys());
188 }
189
190 @Override
191 protected int send(NioSession session, IoBuffer buffer,
192 SocketAddress remoteAddress) throws Exception {
193 return ((DatagramChannel) session.getChannel()).send(
194 buffer.buf(), remoteAddress);
195 }
196
197 @Override
198 protected void setInterestedInWrite(NioSession session, boolean interested)
199 throws Exception {
200 SelectionKey key = session.getSelectionKey();
201 if (key == null) {
202 return;
203 }
204
205 if (interested) {
206 key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
207 } else {
208 key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE);
209 }
210 }
211
212 @Override
213 protected void close(DatagramChannel handle) throws Exception {
214 SelectionKey key = handle.keyFor(selector);
215 if (key != null) {
216 key.cancel();
217 }
218 handle.disconnect();
219 handle.close();
220 }
221
222 @Override
223 protected void wakeup() {
224 selector.wakeup();
225 }
226
227 private static class DatagramChannelIterator implements Iterator<DatagramChannel> {
228
229 private final Iterator<SelectionKey> i;
230
231 private DatagramChannelIterator(Collection<SelectionKey> keys) {
232 this.i = keys.iterator();
233 }
234
235 public boolean hasNext() {
236 return i.hasNext();
237 }
238
239 public DatagramChannel next() {
240 return (DatagramChannel) i.next().channel();
241 }
242
243 public void remove() {
244 i.remove();
245 }
246
247 }
248 }