1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.channel.kqueue;
17
18 import io.netty.buffer.ByteBuf;
19 import io.netty.buffer.ByteBufAllocator;
20 import io.netty.channel.AddressedEnvelope;
21 import io.netty.channel.ChannelFuture;
22 import io.netty.channel.ChannelPipeline;
23 import io.netty.channel.ChannelPromise;
24 import io.netty.channel.DefaultAddressedEnvelope;
25 import io.netty.channel.socket.DatagramChannel;
26 import io.netty.channel.socket.DatagramChannelConfig;
27 import io.netty.channel.socket.DatagramPacket;
28 import io.netty.channel.socket.InternetProtocolFamily;
29 import io.netty.channel.socket.SocketProtocolFamily;
30 import io.netty.channel.unix.DatagramSocketAddress;
31 import io.netty.channel.unix.Errors;
32 import io.netty.channel.unix.IovArray;
33 import io.netty.channel.unix.UnixChannelUtil;
34 import io.netty.util.UncheckedBooleanSupplier;
35 import io.netty.util.internal.ObjectUtil;
36 import io.netty.util.internal.StringUtil;
37
38 import java.io.IOException;
39 import java.net.Inet4Address;
40 import java.net.InetAddress;
41 import java.net.InetSocketAddress;
42 import java.net.NetworkInterface;
43 import java.net.PortUnreachableException;
44 import java.net.SocketAddress;
45 import java.net.SocketException;
46 import java.nio.ByteBuffer;
47 import java.nio.channels.UnresolvedAddressException;
48
49 import static io.netty.channel.kqueue.BsdSocket.newSocketDgram;
50
51 public final class KQueueDatagramChannel extends AbstractKQueueDatagramChannel implements DatagramChannel {
52 private static final String EXPECTED_TYPES =
53 " (expected: " + StringUtil.simpleClassName(DatagramPacket.class) + ", " +
54 StringUtil.simpleClassName(AddressedEnvelope.class) + '<' +
55 StringUtil.simpleClassName(ByteBuf.class) + ", " +
56 StringUtil.simpleClassName(InetSocketAddress.class) + ">, " +
57 StringUtil.simpleClassName(ByteBuf.class) + ')';
58
59 private volatile boolean connected;
60 private final KQueueDatagramChannelConfig config;
61
62 public KQueueDatagramChannel() {
63 super(null, newSocketDgram(), false);
64 config = new KQueueDatagramChannelConfig(this);
65 }
66
67
68
69
70 @Deprecated
71 public KQueueDatagramChannel(InternetProtocolFamily protocol) {
72 super(null, newSocketDgram(protocol), false);
73 config = new KQueueDatagramChannelConfig(this);
74 }
75
76 public KQueueDatagramChannel(SocketProtocolFamily protocol) {
77 super(null, newSocketDgram(protocol), false);
78 config = new KQueueDatagramChannelConfig(this);
79 }
80
81 public KQueueDatagramChannel(int fd) {
82 this(new BsdSocket(fd), true);
83 }
84
85 KQueueDatagramChannel(BsdSocket socket, boolean active) {
86 super(null, socket, active);
87 config = new KQueueDatagramChannelConfig(this);
88 }
89
90 @Override
91 public InetSocketAddress remoteAddress() {
92 return (InetSocketAddress) super.remoteAddress();
93 }
94
95 @Override
96 public InetSocketAddress localAddress() {
97 return (InetSocketAddress) super.localAddress();
98 }
99
100 @Override
101 @SuppressWarnings("deprecation")
102 public boolean isActive() {
103 return socket.isOpen() && (config.getActiveOnOpen() && isRegistered() || active);
104 }
105
106 @Override
107 public boolean isConnected() {
108 return connected;
109 }
110
111 @Override
112 public ChannelFuture joinGroup(InetAddress multicastAddress) {
113 return joinGroup(multicastAddress, newPromise());
114 }
115
116 @Override
117 public ChannelFuture joinGroup(InetAddress multicastAddress, ChannelPromise promise) {
118 try {
119 return joinGroup(multicastAddress, defaultMulticastInterface(), null, promise);
120 } catch (SocketException e) {
121 promise.setFailure(e);
122 }
123 return promise;
124 }
125
126
127
128
129
130 private NetworkInterface defaultMulticastInterface() throws SocketException {
131 NetworkInterface iface = config().getNetworkInterface();
132 if (iface == null) {
133 iface = NetworkInterface.getByInetAddress(localAddress().getAddress());
134 }
135 return iface;
136 }
137
138 @Override
139 public ChannelFuture joinGroup(
140 InetSocketAddress multicastAddress, NetworkInterface networkInterface) {
141 return joinGroup(multicastAddress, networkInterface, newPromise());
142 }
143
144 @Override
145 public ChannelFuture joinGroup(
146 InetSocketAddress multicastAddress, NetworkInterface networkInterface,
147 ChannelPromise promise) {
148 return joinGroup(multicastAddress.getAddress(), networkInterface, null, promise);
149 }
150
151 @Override
152 public ChannelFuture joinGroup(
153 InetAddress multicastAddress, NetworkInterface networkInterface, InetAddress source) {
154 return joinGroup(multicastAddress, networkInterface, source, newPromise());
155 }
156
157 @Override
158 public ChannelFuture joinGroup(
159 final InetAddress multicastAddress, final NetworkInterface networkInterface,
160 final InetAddress source, final ChannelPromise promise) {
161
162 ObjectUtil.checkNotNull(multicastAddress, "multicastAddress");
163 ObjectUtil.checkNotNull(networkInterface, "networkInterface");
164
165 promise.setFailure(new UnsupportedOperationException("Multicast not supported"));
166 return promise;
167 }
168
169 @Override
170 public ChannelFuture leaveGroup(InetAddress multicastAddress) {
171 return leaveGroup(multicastAddress, newPromise());
172 }
173
174 @Override
175 public ChannelFuture leaveGroup(InetAddress multicastAddress, ChannelPromise promise) {
176 try {
177 return leaveGroup(multicastAddress, defaultMulticastInterface(), null, promise);
178 } catch (SocketException e) {
179 promise.setFailure(e);
180 }
181 return promise;
182 }
183
184 @Override
185 public ChannelFuture leaveGroup(
186 InetSocketAddress multicastAddress, NetworkInterface networkInterface) {
187 return leaveGroup(multicastAddress, networkInterface, newPromise());
188 }
189
190 @Override
191 public ChannelFuture leaveGroup(
192 InetSocketAddress multicastAddress,
193 NetworkInterface networkInterface, ChannelPromise promise) {
194 return leaveGroup(multicastAddress.getAddress(), networkInterface, null, promise);
195 }
196
197 @Override
198 public ChannelFuture leaveGroup(
199 InetAddress multicastAddress, NetworkInterface networkInterface, InetAddress source) {
200 return leaveGroup(multicastAddress, networkInterface, source, newPromise());
201 }
202
203 @Override
204 public ChannelFuture leaveGroup(
205 final InetAddress multicastAddress, final NetworkInterface networkInterface, final InetAddress source,
206 final ChannelPromise promise) {
207 ObjectUtil.checkNotNull(multicastAddress, "multicastAddress");
208 ObjectUtil.checkNotNull(networkInterface, "networkInterface");
209
210 promise.setFailure(new UnsupportedOperationException("Multicast not supported"));
211
212 return promise;
213 }
214
215 @Override
216 public ChannelFuture block(
217 InetAddress multicastAddress, NetworkInterface networkInterface,
218 InetAddress sourceToBlock) {
219 return block(multicastAddress, networkInterface, sourceToBlock, newPromise());
220 }
221
222 @Override
223 public ChannelFuture block(
224 final InetAddress multicastAddress, final NetworkInterface networkInterface,
225 final InetAddress sourceToBlock, final ChannelPromise promise) {
226 ObjectUtil.checkNotNull(multicastAddress, "multicastAddress");
227 ObjectUtil.checkNotNull(sourceToBlock, "sourceToBlock");
228 ObjectUtil.checkNotNull(networkInterface, "networkInterface");
229 promise.setFailure(new UnsupportedOperationException("Multicast not supported"));
230 return promise;
231 }
232
233 @Override
234 public ChannelFuture block(InetAddress multicastAddress, InetAddress sourceToBlock) {
235 return block(multicastAddress, sourceToBlock, newPromise());
236 }
237
238 @Override
239 public ChannelFuture block(
240 InetAddress multicastAddress, InetAddress sourceToBlock, ChannelPromise promise) {
241 try {
242 return block(multicastAddress, defaultMulticastInterface(), sourceToBlock, promise);
243 } catch (Throwable e) {
244 promise.setFailure(e);
245 }
246 return promise;
247 }
248
249 @Override
250 protected AbstractKQueueUnsafe newUnsafe() {
251 return new KQueueDatagramChannelUnsafe();
252 }
253
254 @Override
255 protected void doBind(SocketAddress localAddress) throws Exception {
256 if (localAddress instanceof InetSocketAddress) {
257 InetSocketAddress socketAddress = (InetSocketAddress) localAddress;
258 if (socketAddress.getAddress().isAnyLocalAddress() &&
259 socketAddress.getAddress() instanceof Inet4Address) {
260 if (socket.family() == SocketProtocolFamily.INET6) {
261 localAddress = new InetSocketAddress(Native.INET6_ANY, socketAddress.getPort());
262 }
263 }
264 }
265 super.doBind(localAddress);
266 active = true;
267 }
268
269 @Override
270 protected boolean doWriteMessage(Object msg) throws Exception {
271 final ByteBuf data;
272 InetSocketAddress remoteAddress;
273 if (msg instanceof AddressedEnvelope) {
274 @SuppressWarnings("unchecked")
275 AddressedEnvelope<ByteBuf, InetSocketAddress> envelope =
276 (AddressedEnvelope<ByteBuf, InetSocketAddress>) msg;
277 data = envelope.content();
278 remoteAddress = envelope.recipient();
279 } else {
280 data = (ByteBuf) msg;
281 remoteAddress = null;
282 }
283
284 final int dataLen = data.readableBytes();
285 final long writtenBytes;
286 if (data.hasMemoryAddress()) {
287 long memoryAddress = data.memoryAddress();
288 if (remoteAddress == null) {
289 try {
290 writtenBytes = socket.writeAddress(memoryAddress, data.readerIndex(), data.writerIndex());
291 } catch (Errors.NativeIoException e) {
292 throw translateForConnected(e);
293 }
294 } else {
295 writtenBytes = socket.sendToAddress(memoryAddress, data.readerIndex(), data.writerIndex(),
296 remoteAddress.getAddress(), remoteAddress.getPort());
297 }
298 } else if (data.nioBufferCount() > 1) {
299 IovArray array = ((NativeArrays) registration().attachment()).cleanIovArray();
300 array.add(data, data.readerIndex(), data.readableBytes());
301 int cnt = array.count();
302 assert cnt != 0;
303
304 if (remoteAddress == null) {
305 writtenBytes = socket.writevAddresses(array.memoryAddress(0), cnt);
306 } else {
307 writtenBytes = socket.sendToAddresses(array.memoryAddress(0), cnt,
308 remoteAddress.getAddress(), remoteAddress.getPort());
309 }
310 } else {
311 ByteBuffer nioData = data.internalNioBuffer(data.readerIndex(), data.readableBytes());
312 if (remoteAddress == null) {
313 writtenBytes = socket.write(nioData, nioData.position(), nioData.limit());
314 } else {
315 writtenBytes = socket.sendTo(nioData, nioData.position(), nioData.limit(),
316 remoteAddress.getAddress(), remoteAddress.getPort());
317 }
318 }
319
320
321 return writtenBytes > 0 || dataLen == 0;
322 }
323
324 private static IOException translateForConnected(Errors.NativeIoException e) {
325
326 if (e.expectedErr() == Errors.ERROR_ECONNREFUSED_NEGATIVE) {
327 PortUnreachableException error = new PortUnreachableException(e.getMessage());
328 error.initCause(e);
329 return error;
330 }
331 return e;
332 }
333
334 private static void checkUnresolved(AddressedEnvelope<?, ?> envelope) {
335 if (envelope.recipient() instanceof InetSocketAddress
336 && (((InetSocketAddress) envelope.recipient()).isUnresolved())) {
337 throw new UnresolvedAddressException();
338 }
339 }
340
341 @Override
342 protected Object filterOutboundMessage(Object msg) {
343 if (msg instanceof DatagramPacket) {
344 DatagramPacket packet = (DatagramPacket) msg;
345 checkUnresolved(packet);
346 ByteBuf content = packet.content();
347 return UnixChannelUtil.isBufferCopyNeededForWrite(content) ?
348 new DatagramPacket(newDirectBuffer(packet, content), packet.recipient()) : msg;
349 }
350
351 if (msg instanceof ByteBuf) {
352 ByteBuf buf = (ByteBuf) msg;
353 return UnixChannelUtil.isBufferCopyNeededForWrite(buf) ? newDirectBuffer(buf) : buf;
354 }
355
356 if (msg instanceof AddressedEnvelope) {
357 @SuppressWarnings("unchecked")
358 AddressedEnvelope<Object, SocketAddress> e = (AddressedEnvelope<Object, SocketAddress>) msg;
359 checkUnresolved(e);
360
361 if (e.content() instanceof ByteBuf &&
362 (e.recipient() == null || e.recipient() instanceof InetSocketAddress)) {
363
364 ByteBuf content = (ByteBuf) e.content();
365 return UnixChannelUtil.isBufferCopyNeededForWrite(content) ?
366 new DefaultAddressedEnvelope<ByteBuf, InetSocketAddress>(
367 newDirectBuffer(e, content), (InetSocketAddress) e.recipient()) : e;
368 }
369 }
370
371 throw new UnsupportedOperationException(
372 "unsupported message type: " + StringUtil.simpleClassName(msg) + EXPECTED_TYPES);
373 }
374
375 @Override
376 public KQueueDatagramChannelConfig config() {
377 return config;
378 }
379
380 @Override
381 protected void doDisconnect() throws Exception {
382 socket.disconnect();
383 connected = active = false;
384 resetCachedAddresses();
385 }
386
387 @Override
388 protected boolean doConnect(SocketAddress remoteAddress, SocketAddress localAddress) throws Exception {
389 if (super.doConnect(remoteAddress, localAddress)) {
390 connected = true;
391 return true;
392 }
393 return false;
394 }
395
396 @Override
397 protected void doClose() throws Exception {
398 super.doClose();
399 connected = false;
400 }
401
402 final class KQueueDatagramChannelUnsafe extends AbstractKQueueUnsafe {
403
404 @Override
405 void readReady(KQueueRecvByteAllocatorHandle allocHandle) {
406 assert eventLoop().inEventLoop();
407 final DatagramChannelConfig config = config();
408 if (shouldBreakReadReady(config)) {
409 clearReadFilter0();
410 return;
411 }
412 final ChannelPipeline pipeline = pipeline();
413 final ByteBufAllocator allocator = config.getAllocator();
414 allocHandle.reset(config);
415
416 Throwable exception = null;
417 try {
418 ByteBuf byteBuf = null;
419 try {
420 boolean connected = isConnected();
421 do {
422 byteBuf = allocHandle.allocate(allocator);
423 allocHandle.attemptedBytesRead(byteBuf.writableBytes());
424
425 final DatagramPacket packet;
426 if (connected) {
427 try {
428 allocHandle.lastBytesRead(doReadBytes(byteBuf));
429 } catch (Errors.NativeIoException e) {
430
431 if (e.expectedErr() == Errors.ERROR_ECONNREFUSED_NEGATIVE) {
432 PortUnreachableException error = new PortUnreachableException(e.getMessage());
433 error.initCause(e);
434 throw error;
435 }
436 throw e;
437 }
438 if (allocHandle.lastBytesRead() <= 0) {
439
440 byteBuf.release();
441 byteBuf = null;
442 break;
443 }
444 packet = new DatagramPacket(byteBuf,
445 (InetSocketAddress) localAddress(), (InetSocketAddress) remoteAddress());
446 } else {
447 final DatagramSocketAddress remoteAddress;
448 if (byteBuf.hasMemoryAddress()) {
449
450 remoteAddress = socket.recvFromAddress(byteBuf.memoryAddress(), byteBuf.writerIndex(),
451 byteBuf.capacity());
452 } else {
453 ByteBuffer nioData = byteBuf.internalNioBuffer(
454 byteBuf.writerIndex(), byteBuf.writableBytes());
455 remoteAddress = socket.recvFrom(nioData, nioData.position(), nioData.limit());
456 }
457
458 if (remoteAddress == null) {
459 allocHandle.lastBytesRead(-1);
460 byteBuf.release();
461 byteBuf = null;
462 break;
463 }
464 InetSocketAddress localAddress = remoteAddress.localAddress();
465 if (localAddress == null) {
466 localAddress = (InetSocketAddress) localAddress();
467 }
468 allocHandle.lastBytesRead(remoteAddress.receivedAmount());
469 byteBuf.writerIndex(byteBuf.writerIndex() + allocHandle.lastBytesRead());
470
471 packet = new DatagramPacket(byteBuf, localAddress, remoteAddress);
472 }
473
474 allocHandle.incMessagesRead(1);
475
476 readPending = false;
477 pipeline.fireChannelRead(packet);
478
479 byteBuf = null;
480
481
482
483 } while (allocHandle.continueReading(UncheckedBooleanSupplier.TRUE_SUPPLIER));
484 } catch (Throwable t) {
485 if (byteBuf != null) {
486 byteBuf.release();
487 }
488 exception = t;
489 }
490
491 allocHandle.readComplete();
492 pipeline.fireChannelReadComplete();
493
494 if (exception != null) {
495 pipeline.fireExceptionCaught(exception);
496 }
497 } finally {
498 if (shouldStopReading(config)) {
499 clearReadFilter0();
500 }
501 }
502 }
503 }
504 }