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.buffer.ByteBufUtil;
21 import io.netty.buffer.Unpooled;
22 import io.netty.channel.AbstractChannel;
23 import io.netty.channel.Channel;
24 import io.netty.channel.ChannelConfig;
25 import io.netty.channel.ChannelException;
26 import io.netty.channel.ChannelFuture;
27 import io.netty.channel.ChannelFutureListener;
28 import io.netty.channel.ChannelMetadata;
29 import io.netty.channel.ChannelOutboundBuffer;
30 import io.netty.channel.ChannelPromise;
31 import io.netty.channel.ConnectTimeoutException;
32 import io.netty.channel.EventLoop;
33 import io.netty.channel.IoEvent;
34 import io.netty.channel.IoEventLoop;
35 import io.netty.channel.IoRegistration;
36 import io.netty.channel.RecvByteBufAllocator;
37 import io.netty.channel.socket.ChannelInputShutdownEvent;
38 import io.netty.channel.socket.ChannelInputShutdownReadComplete;
39 import io.netty.channel.socket.SocketChannelConfig;
40 import io.netty.channel.unix.FileDescriptor;
41 import io.netty.channel.unix.UnixChannel;
42 import io.netty.util.ReferenceCountUtil;
43 import io.netty.util.concurrent.Future;
44 import io.netty.util.internal.UnstableApi;
45
46 import java.io.IOException;
47 import java.net.ConnectException;
48 import java.net.InetSocketAddress;
49 import java.net.SocketAddress;
50 import java.nio.ByteBuffer;
51 import java.nio.channels.AlreadyConnectedException;
52 import java.nio.channels.ConnectionPendingException;
53 import java.nio.channels.NotYetConnectedException;
54 import java.nio.channels.UnresolvedAddressException;
55 import java.util.concurrent.TimeUnit;
56
57 import static io.netty.channel.internal.ChannelUtils.WRITE_STATUS_SNDBUF_FULL;
58 import static io.netty.channel.unix.UnixChannelUtil.computeRemoteAddr;
59 import static io.netty.util.internal.ObjectUtil.checkNotNull;
60
61 abstract class AbstractKQueueChannel extends AbstractChannel implements UnixChannel {
62
63 private static final ChannelMetadata METADATA = new ChannelMetadata(false);
64
65
66
67
68 private ChannelPromise connectPromise;
69 private Future<?> connectTimeoutFuture;
70 private SocketAddress requestedRemoteAddress;
71
72
73
74 private ChannelOutboundBuffer fastOpenOutboundBuffer;
75 private Object fastOpenData;
76 private long fastOpenBytes;
77
78 final BsdSocket socket;
79 private IoRegistration registration;
80 private boolean readFilterEnabled;
81 private boolean writeFilterEnabled;
82
83 boolean readReadyRunnablePending;
84 boolean inputClosedSeenErrorOnRead;
85 protected volatile boolean active;
86 private volatile SocketAddress local;
87 private volatile SocketAddress remote;
88
89 AbstractKQueueChannel(Channel parent, BsdSocket fd, boolean active) {
90 super(parent);
91 socket = checkNotNull(fd, "fd");
92 this.active = active;
93 if (active) {
94
95
96 local = fd.localAddress();
97 remote = fd.remoteAddress();
98 }
99 }
100
101 AbstractKQueueChannel(Channel parent, BsdSocket fd, SocketAddress remote) {
102 super(parent);
103 socket = checkNotNull(fd, "fd");
104 active = true;
105
106
107 this.remote = remote;
108 local = fd.localAddress();
109 }
110
111 @Override
112 protected boolean isCompatible(EventLoop loop) {
113 return loop instanceof IoEventLoop && ((IoEventLoop) loop).isCompatible(AbstractKQueueUnsafe.class);
114 }
115
116 static boolean isSoErrorZero(BsdSocket fd) {
117 try {
118 return fd.getSoError() == 0;
119 } catch (IOException e) {
120 throw new ChannelException(e);
121 }
122 }
123
124 protected final IoRegistration registration() {
125 assert registration != null;
126 return registration;
127 }
128
129 @Override
130 public final FileDescriptor fd() {
131 return socket;
132 }
133
134 @Override
135 public boolean isActive() {
136 return active;
137 }
138
139 @Override
140 public ChannelMetadata metadata() {
141 return METADATA;
142 }
143
144
145
146
147
148 final void fastOpenDataSent(ChannelOutboundBuffer in, Object data, long bytes) {
149 fastOpenOutboundBuffer = in;
150 fastOpenData = data;
151 fastOpenBytes = bytes;
152 }
153
154
155
156
157
158
159
160
161 final boolean removeFastOpenData() {
162 ChannelOutboundBuffer in = fastOpenOutboundBuffer;
163 if (in == null) {
164 return false;
165 }
166 Object data = fastOpenData;
167 long bytes = fastOpenBytes;
168 fastOpenOutboundBuffer = null;
169 fastOpenData = null;
170 fastOpenBytes = 0;
171 if (!isActive() || in.current() != data) {
172 return false;
173 }
174 in.removeBytes(bytes);
175 return true;
176 }
177
178 @Override
179 protected void doClose() throws Exception {
180
181
182 doDeregister();
183
184 active = false;
185
186
187 inputClosedSeenErrorOnRead = true;
188 socket.close();
189 }
190
191 @Override
192 protected void doDisconnect() throws Exception {
193 doClose();
194 }
195
196 void resetCachedAddresses() {
197 local = socket.localAddress();
198 remote = socket.remoteAddress();
199 }
200
201 @Override
202 public boolean isOpen() {
203 return socket.isOpen();
204 }
205
206 @Override
207 protected void doDeregister() throws Exception {
208 IoRegistration registration = this.registration;
209 if (registration != null) {
210
211
212
213 readFilter(false);
214 writeFilter(false);
215 clearRdHup0();
216
217 registration.cancel();
218 this.registration = null;
219 }
220 }
221
222 private void clearRdHup0() {
223 submit(KQueueIoOps.newOps(Native.EVFILT_SOCK, Native.EV_DELETE_DISABLE, Native.NOTE_RDHUP));
224 }
225
226 private void submit(KQueueIoOps ops) {
227 if (!isOpen()) {
228
229
230 return;
231 }
232 try {
233 registration.submit(ops);
234 } catch (Exception e) {
235 throw new ChannelException(e);
236 }
237 }
238
239 @Override
240 protected final void doBeginRead() throws Exception {
241
242 final AbstractKQueueUnsafe unsafe = (AbstractKQueueUnsafe) unsafe();
243 unsafe.readPending = true;
244
245
246
247
248 readFilter(true);
249 }
250
251 @Override
252 protected void doRegister(ChannelPromise promise) {
253 ((IoEventLoop) eventLoop()).register((AbstractKQueueUnsafe) unsafe()).addListener(f -> {
254 if (f.isSuccess()) {
255 this.registration = (IoRegistration) f.getNow();
256
257
258
259 readReadyRunnablePending = false;
260
261 submit(KQueueIoOps.newOps(Native.EVFILT_SOCK, Native.EV_ADD, Native.NOTE_RDHUP));
262
263
264 if (writeFilterEnabled) {
265 submit(Native.WRITE_ENABLED_OPS);
266 }
267 if (readFilterEnabled) {
268 submit(Native.READ_ENABLED_OPS);
269 }
270 promise.setSuccess();
271 } else {
272 promise.setFailure(f.cause());
273 }
274 });
275 }
276
277 @Override
278 protected abstract AbstractKQueueUnsafe newUnsafe();
279
280 @Override
281 public abstract KQueueChannelConfig config();
282
283
284
285
286 protected final ByteBuf newDirectBuffer(ByteBuf buf) {
287 return newDirectBuffer(buf, buf);
288 }
289
290
291
292
293
294
295 protected final ByteBuf newDirectBuffer(Object holder, ByteBuf buf) {
296 final int readableBytes = buf.readableBytes();
297 if (readableBytes == 0) {
298 ReferenceCountUtil.release(holder);
299 return Unpooled.EMPTY_BUFFER;
300 }
301
302 final ByteBufAllocator alloc = alloc();
303 if (alloc.isDirectBufferPooled()) {
304 return newDirectBuffer0(holder, buf, alloc, readableBytes);
305 }
306
307 final ByteBuf directBuf = ByteBufUtil.threadLocalDirectBuffer();
308 if (directBuf == null) {
309 return newDirectBuffer0(holder, buf, alloc, readableBytes);
310 }
311
312 directBuf.writeBytes(buf, buf.readerIndex(), readableBytes);
313 ReferenceCountUtil.safeRelease(holder);
314 return directBuf;
315 }
316
317 private static ByteBuf newDirectBuffer0(Object holder, ByteBuf buf, ByteBufAllocator alloc, int capacity) {
318 final ByteBuf directBuf = alloc.directBuffer(capacity);
319 directBuf.writeBytes(buf, buf.readerIndex(), capacity);
320 ReferenceCountUtil.safeRelease(holder);
321 return directBuf;
322 }
323
324 protected static void checkResolvable(InetSocketAddress addr) {
325 if (addr.isUnresolved()) {
326 throw new UnresolvedAddressException();
327 }
328 }
329
330
331
332
333 protected final int doReadBytes(ByteBuf byteBuf) throws Exception {
334 int writerIndex = byteBuf.writerIndex();
335 int localReadAmount;
336 unsafe().recvBufAllocHandle().attemptedBytesRead(byteBuf.writableBytes());
337 if (byteBuf.hasMemoryAddress()) {
338 localReadAmount = socket.readAddress(byteBuf.memoryAddress(), writerIndex, byteBuf.capacity());
339 } else {
340 ByteBuffer buf = byteBuf.internalNioBuffer(writerIndex, byteBuf.writableBytes());
341 localReadAmount = socket.read(buf, buf.position(), buf.limit());
342 }
343 if (localReadAmount > 0) {
344 byteBuf.writerIndex(writerIndex + localReadAmount);
345 }
346 return localReadAmount;
347 }
348
349 protected final int doWriteBytes(ChannelOutboundBuffer in, ByteBuf buf) throws Exception {
350 if (buf.hasMemoryAddress()) {
351 int localFlushedAmount = socket.writeAddress(buf.memoryAddress(), buf.readerIndex(), buf.writerIndex());
352 if (localFlushedAmount > 0) {
353 in.removeBytes(localFlushedAmount);
354 return 1;
355 }
356 } else {
357 final ByteBuffer nioBuf = buf.nioBufferCount() == 1?
358 buf.internalNioBuffer(buf.readerIndex(), buf.readableBytes()) : buf.nioBuffer();
359 int localFlushedAmount = socket.write(nioBuf, nioBuf.position(), nioBuf.limit());
360 if (localFlushedAmount > 0) {
361 nioBuf.position(nioBuf.position() + localFlushedAmount);
362 in.removeBytes(localFlushedAmount);
363 return 1;
364 }
365 }
366 return WRITE_STATUS_SNDBUF_FULL;
367 }
368
369 final boolean shouldBreakReadReady(ChannelConfig config) {
370 return socket.isInputShutdown() && (inputClosedSeenErrorOnRead || !isAllowHalfClosure(config));
371 }
372
373 private static boolean isAllowHalfClosure(ChannelConfig config) {
374 if (config instanceof KQueueDomainSocketChannelConfig) {
375 return ((KQueueDomainSocketChannelConfig) config).isAllowHalfClosure();
376 }
377
378 return config instanceof SocketChannelConfig &&
379 ((SocketChannelConfig) config).isAllowHalfClosure();
380 }
381
382 final void clearReadFilter() {
383
384 if (isRegistered()) {
385 final EventLoop loop = eventLoop();
386 final AbstractKQueueUnsafe unsafe = (AbstractKQueueUnsafe) unsafe();
387 if (loop.inEventLoop()) {
388 unsafe.clearReadFilter0();
389 } else {
390
391 loop.execute(new Runnable() {
392 @Override
393 public void run() {
394 if (!unsafe.readPending && !config().isAutoRead()) {
395
396 unsafe.clearReadFilter0();
397 }
398 }
399 });
400 }
401 } else {
402
403
404 readFilterEnabled = false;
405 }
406 }
407
408 void readFilter(boolean readFilterEnabled) throws IOException {
409 if (this.readFilterEnabled != readFilterEnabled) {
410 this.readFilterEnabled = readFilterEnabled;
411 submit(readFilterEnabled ? Native.READ_ENABLED_OPS : Native.READ_DISABLED_OPS);
412 }
413 }
414
415 void writeFilter(boolean writeFilterEnabled) throws IOException {
416 if (this.writeFilterEnabled != writeFilterEnabled) {
417 this.writeFilterEnabled = writeFilterEnabled;
418 submit(writeFilterEnabled ? Native.WRITE_ENABLED_OPS : Native.WRITE_DISABLED_OPS);
419 }
420 }
421
422 @UnstableApi
423 public abstract class AbstractKQueueUnsafe extends AbstractUnsafe implements KQueueIoHandle {
424 boolean readPending;
425 private KQueueRecvByteAllocatorHandle allocHandle;
426
427 Channel channel() {
428 return AbstractKQueueChannel.this;
429 }
430
431 @Override
432 public int ident() {
433 return fd().intValue();
434 }
435
436 @Override
437 public void close() {
438 close(voidPromise());
439 }
440
441 @Override
442 public void handle(IoRegistration registration, IoEvent event) {
443 KQueueIoEvent kqueueEvent = (KQueueIoEvent) event;
444 final short filter = kqueueEvent.filter();
445 final short flags = kqueueEvent.flags();
446 final int fflags = kqueueEvent.fflags();
447 final long data = kqueueEvent.data();
448
449
450
451 if (filter == Native.EVFILT_WRITE) {
452 writeReady();
453 } else if (filter == Native.EVFILT_READ) {
454
455 KQueueRecvByteAllocatorHandle allocHandle = recvBufAllocHandle();
456 readReady(allocHandle);
457 } else if (filter == Native.EVFILT_SOCK && (fflags & Native.NOTE_RDHUP) != 0) {
458 readEOF();
459 return;
460 }
461
462
463
464
465 if ((flags & Native.EV_EOF) != 0) {
466 readEOF();
467 }
468 }
469
470 abstract void readReady(KQueueRecvByteAllocatorHandle allocHandle);
471
472 final boolean shouldStopReading(ChannelConfig config) {
473
474
475
476
477
478
479 return !readPending && !config.isAutoRead();
480 }
481
482 final boolean failConnectPromise(Throwable cause) {
483 if (connectPromise != null) {
484
485
486
487 ChannelPromise connectPromise = AbstractKQueueChannel.this.connectPromise;
488 AbstractKQueueChannel.this.connectPromise = null;
489 if (connectPromise.tryFailure((cause instanceof ConnectException) ? cause
490 : new ConnectException("failed to connect").initCause(cause))) {
491 closeIfClosed();
492 return true;
493 }
494 }
495 return false;
496 }
497
498 private void writeReady() {
499 if (connectPromise != null) {
500
501 finishConnect();
502 } else if (!socket.isOutputShutdown()) {
503
504 super.flush0();
505 }
506 }
507
508
509
510
511 void shutdownInput(boolean readEOF) {
512
513
514
515
516
517 if (readEOF && connectPromise != null) {
518 finishConnect();
519 }
520 if (!socket.isInputShutdown()) {
521 if (isAllowHalfClosure(config())) {
522 try {
523 socket.shutdown(true, false);
524 } catch (IOException ignored) {
525
526
527 fireEventAndClose(ChannelInputShutdownEvent.INSTANCE);
528 return;
529 } catch (NotYetConnectedException ignore) {
530
531
532 }
533 if (shouldStopReading(config())) {
534 clearReadFilter0();
535 }
536 pipeline().fireUserEventTriggered(ChannelInputShutdownEvent.INSTANCE);
537 } else {
538 close(voidPromise());
539 return;
540 }
541 }
542 if (!readEOF && !inputClosedSeenErrorOnRead) {
543 inputClosedSeenErrorOnRead = true;
544 pipeline().fireUserEventTriggered(ChannelInputShutdownReadComplete.INSTANCE);
545 }
546 }
547
548 private void readEOF() {
549
550 final KQueueRecvByteAllocatorHandle allocHandle = recvBufAllocHandle();
551 allocHandle.readEOF();
552
553
554
555
556 if (connectPromise != null) {
557 finishConnect();
558 }
559
560 if (isActive()) {
561
562
563
564 readReady(allocHandle);
565 } else {
566
567 shutdownInput(true);
568 }
569
570
571 clearRdHup0();
572 }
573
574 @Override
575 public KQueueRecvByteAllocatorHandle recvBufAllocHandle() {
576 if (allocHandle == null) {
577 allocHandle = new KQueueRecvByteAllocatorHandle(
578 (RecvByteBufAllocator.ExtendedHandle) super.recvBufAllocHandle());
579 }
580 return allocHandle;
581 }
582
583 @Override
584 protected final void flush0() {
585
586
587
588 if (!writeFilterEnabled) {
589 super.flush0();
590 }
591 }
592
593 protected final void clearReadFilter0() {
594 assert eventLoop().inEventLoop();
595 try {
596 readPending = false;
597 readFilter(false);
598 } catch (IOException e) {
599
600
601 pipeline().fireExceptionCaught(e);
602 unsafe().close(unsafe().voidPromise());
603 }
604 }
605
606 private void fireEventAndClose(Object evt) {
607 pipeline().fireUserEventTriggered(evt);
608 close(voidPromise());
609 }
610
611 @Override
612 public void connect(
613 final SocketAddress remoteAddress, final SocketAddress localAddress, final ChannelPromise promise) {
614
615
616 if (promise.isDone() || !ensureOpen(promise)) {
617 return;
618 }
619
620 try {
621 if (connectPromise != null) {
622 throw new ConnectionPendingException();
623 }
624
625 boolean wasActive = isActive();
626 if (doConnect(remoteAddress, localAddress)) {
627 fulfillConnectPromise(promise, wasActive);
628 } else {
629 connectPromise = promise;
630 requestedRemoteAddress = remoteAddress;
631
632
633 final int connectTimeoutMillis = config().getConnectTimeoutMillis();
634 if (connectTimeoutMillis > 0) {
635 connectTimeoutFuture = eventLoop().schedule(new Runnable() {
636 @Override
637 public void run() {
638 ChannelPromise connectPromise = AbstractKQueueChannel.this.connectPromise;
639 if (connectPromise != null && !connectPromise.isDone()
640 && connectPromise.tryFailure(new ConnectTimeoutException(
641 "connection timed out after " + connectTimeoutMillis + " ms: " +
642 remoteAddress))) {
643 close(voidPromise());
644 }
645 }
646 }, connectTimeoutMillis, TimeUnit.MILLISECONDS);
647 }
648
649 promise.addListener(new ChannelFutureListener() {
650 @Override
651 public void operationComplete(ChannelFuture future) {
652
653
654 if (future.isCancelled()) {
655 if (connectTimeoutFuture != null) {
656 connectTimeoutFuture.cancel(false);
657 }
658 connectPromise = null;
659 close(voidPromise());
660 }
661 }
662 });
663 }
664 } catch (Throwable t) {
665 closeIfClosed();
666 promise.tryFailure(annotateConnectException(t, remoteAddress));
667 }
668 }
669
670 private void fulfillConnectPromise(ChannelPromise promise, boolean wasActive) {
671 if (promise == null) {
672
673 return;
674 }
675 active = true;
676
677
678
679 boolean active = isActive();
680
681
682 boolean promiseSet = promise.trySuccess();
683
684
685
686 if (!wasActive && active) {
687 pipeline().fireChannelActive();
688 }
689
690
691
692 if (removeFastOpenData()) {
693 flush0();
694 }
695
696
697 if (!promiseSet) {
698 close(voidPromise());
699 }
700 }
701
702 private void fulfillConnectPromise(ChannelPromise promise, Throwable cause) {
703
704
705 removeFastOpenData();
706 if (promise == null) {
707
708 return;
709 }
710
711
712 promise.tryFailure(cause);
713 closeIfClosed();
714 }
715
716 private void finishConnect() {
717
718
719
720 assert eventLoop().inEventLoop();
721
722 boolean connectStillInProgress = false;
723 try {
724 boolean wasActive = isActive();
725 if (!doFinishConnect()) {
726 connectStillInProgress = true;
727 return;
728 }
729 fulfillConnectPromise(connectPromise, wasActive);
730 } catch (Throwable t) {
731 fulfillConnectPromise(connectPromise, annotateConnectException(t, requestedRemoteAddress));
732 } finally {
733 if (!connectStillInProgress) {
734
735
736 if (connectTimeoutFuture != null) {
737 connectTimeoutFuture.cancel(false);
738 }
739 connectPromise = null;
740 }
741 }
742 }
743
744 private boolean doFinishConnect() throws Exception {
745 if (socket.finishConnect()) {
746 writeFilter(false);
747 if (requestedRemoteAddress instanceof InetSocketAddress) {
748 remote = computeRemoteAddr((InetSocketAddress) requestedRemoteAddress, socket.remoteAddress());
749 }
750 requestedRemoteAddress = null;
751 return true;
752 }
753 writeFilter(true);
754 return false;
755 }
756 }
757
758 @Override
759 protected void doBind(SocketAddress local) throws Exception {
760 if (local instanceof InetSocketAddress) {
761 checkResolvable((InetSocketAddress) local);
762 }
763 socket.bind(local);
764 this.local = socket.localAddress();
765 }
766
767
768
769
770 protected boolean doConnect(SocketAddress remoteAddress, SocketAddress localAddress) throws Exception {
771 if (localAddress instanceof InetSocketAddress) {
772 checkResolvable((InetSocketAddress) localAddress);
773 }
774
775 InetSocketAddress remoteSocketAddr = remoteAddress instanceof InetSocketAddress
776 ? (InetSocketAddress) remoteAddress : null;
777 if (remoteSocketAddr != null) {
778 checkResolvable(remoteSocketAddr);
779 }
780
781 if (remote != null) {
782
783
784
785 throw new AlreadyConnectedException();
786 }
787
788 if (localAddress != null) {
789 socket.bind(localAddress);
790 }
791
792 boolean connected = doConnect0(remoteAddress, localAddress);
793 if (connected) {
794 remote = remoteSocketAddr == null?
795 remoteAddress : computeRemoteAddr(remoteSocketAddr, socket.remoteAddress());
796 }
797
798
799
800 local = socket.localAddress();
801 return connected;
802 }
803
804 protected boolean doConnect0(SocketAddress remoteAddress, SocketAddress localAddress) throws Exception {
805 boolean success = false;
806 try {
807 boolean connected = socket.connect(remoteAddress);
808 if (!connected) {
809 writeFilter(true);
810 }
811 success = true;
812 return connected;
813 } finally {
814 if (!success) {
815 doClose();
816 }
817 }
818 }
819
820 @Override
821 protected SocketAddress localAddress0() {
822 return local;
823 }
824
825 @Override
826 protected SocketAddress remoteAddress0() {
827 return remote;
828 }
829 }