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