View Javadoc
1   /*
2    * Copyright 2014 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package io.netty.channel.epoll;
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.IovArray;
42  import io.netty.channel.unix.Socket;
43  import io.netty.channel.unix.UnixChannel;
44  import io.netty.util.ReferenceCountUtil;
45  import io.netty.util.concurrent.Future;
46  
47  import java.io.IOException;
48  import java.io.UncheckedIOException;
49  import java.net.InetSocketAddress;
50  import java.net.SocketAddress;
51  import java.nio.ByteBuffer;
52  import java.nio.channels.AlreadyConnectedException;
53  import java.nio.channels.ClosedChannelException;
54  import java.nio.channels.ConnectionPendingException;
55  import java.nio.channels.NotYetConnectedException;
56  import java.nio.channels.UnresolvedAddressException;
57  import java.util.concurrent.TimeUnit;
58  
59  import static io.netty.channel.epoll.EpollIoOps.EPOLL_ERR_IN_MASK;
60  import static io.netty.channel.epoll.EpollIoOps.EPOLL_ERR_OUT_MASK;
61  import static io.netty.channel.epoll.EpollIoOps.EPOLL_RDHUP_MASK;
62  import static io.netty.channel.internal.ChannelUtils.WRITE_STATUS_SNDBUF_FULL;
63  import static io.netty.channel.unix.UnixChannelUtil.computeRemoteAddr;
64  import static io.netty.util.internal.ObjectUtil.checkNotNull;
65  
66  abstract class AbstractEpollChannel extends AbstractChannel implements UnixChannel {
67      private static final ChannelMetadata METADATA = new ChannelMetadata(false);
68      protected final LinuxSocket socket;
69      private final EpollIoOps initial;
70  
71      /**
72       * The future of the current connection attempt.  If not null, subsequent
73       * connection attempts will fail.
74       */
75      private ChannelPromise connectPromise;
76      private Future<?> connectTimeoutFuture;
77      private SocketAddress requestedRemoteAddress;
78      private volatile SocketAddress local;
79      private volatile SocketAddress remote;
80  
81      // The initial data that was sent by a TCP_FASTOPEN_CONNECT. Its bytes are only removed from the
82      // ChannelOutboundBuffer once the connect is complete, so listeners of the initial write see an active channel.
83      private ChannelOutboundBuffer fastOpenOutboundBuffer;
84      private Object fastOpenData;
85      private long fastOpenBytes;
86  
87      private IoRegistration registration;
88      boolean inputClosedSeenErrorOnRead;
89      private EpollIoOps ops;
90  
91      protected volatile boolean active;
92  
93      AbstractEpollChannel(Channel parent, LinuxSocket fd, boolean active, EpollIoOps initialOps) {
94          super(parent);
95          this.socket = checkNotNull(fd, "fd");
96          this.active = active;
97          if (active) {
98              // Directly cache the remote and local addresses
99              // See https://github.com/netty/netty/issues/2359
100             this.local = fd.localAddress();
101             this.remote = fd.remoteAddress();
102         }
103         this.initial = initialOps;
104         this.ops = initialOps;
105     }
106 
107     AbstractEpollChannel(Channel parent, LinuxSocket fd, SocketAddress remote, EpollIoOps initialOps) {
108         super(parent);
109         this.socket = checkNotNull(fd, "fd");
110         this.active = true;
111         // Directly cache the remote and local addresses
112         // See https://github.com/netty/netty/issues/2359
113         this.remote = remote;
114         this.local = fd.localAddress();
115         this.initial = initialOps;
116         this.ops = initialOps;
117     }
118 
119     static boolean isSoErrorZero(Socket fd) {
120         try {
121             return fd.getSoError() == 0;
122         } catch (IOException e) {
123             throw new ChannelException(e);
124         }
125     }
126 
127     protected void setFlag(int flag) throws IOException {
128         if (ops.contains(flag)) {
129             // we can save a syscall if the ops did not change
130             return;
131         }
132         ops = ops.with(EpollIoOps.valueOf(flag));
133         if (isRegistered()) {
134             IoRegistration registration = registration();
135             registration.submit(ops);
136         } else {
137             ops = ops.with(EpollIoOps.valueOf(flag));
138         }
139     }
140 
141     void clearFlag(int flag) throws IOException {
142         IoRegistration registration = registration();
143         if (!ops.contains(flag)) {
144             // we can save a syscall if the ops did not change
145             return;
146         }
147         ops = ops.without(EpollIoOps.valueOf(flag));
148         registration.submit(ops);
149     }
150 
151     protected final IoRegistration registration() {
152         assert registration != null;
153         return registration;
154     }
155 
156     boolean isFlagSet(int flag) {
157         return (ops.value & flag) != 0;
158     }
159 
160     @Override
161     public final FileDescriptor fd() {
162         return socket;
163     }
164 
165     @Override
166     public abstract EpollChannelConfig config();
167 
168     @Override
169     public boolean isActive() {
170         return active;
171     }
172 
173     @Override
174     public ChannelMetadata metadata() {
175         return METADATA;
176     }
177 
178     /**
179      * Remember that {@code bytes} of {@code data}, the current message of {@code in}, were sent by a
180      * TCP_FASTOPEN_CONNECT.
181      */
182     final void fastOpenDataSent(ChannelOutboundBuffer in, Object data, long bytes) {
183         fastOpenOutboundBuffer = in;
184         fastOpenData = data;
185         fastOpenBytes = bytes;
186     }
187 
188     /**
189      * Removes the bytes that were sent by a TCP_FASTOPEN_CONNECT from the {@link ChannelOutboundBuffer} if the
190      * channel was connected, and forgets about them otherwise. Must be called before the
191      * {@link ChannelOutboundBuffer} is written or its messages are failed.
192      *
193      * @return {@code true} if bytes were removed.
194      */
195     final boolean removeFastOpenData() {
196         ChannelOutboundBuffer in = fastOpenOutboundBuffer;
197         if (in == null) {
198             return false;
199         }
200         Object data = fastOpenData;
201         long bytes = fastOpenBytes;
202         fastOpenOutboundBuffer = null;
203         fastOpenData = null;
204         fastOpenBytes = 0;
205         if (!isActive() || in.current() != data) {
206             return false;
207         }
208         in.removeBytes(bytes);
209         return true;
210     }
211 
212     @Override
213     protected void doClose() throws Exception {
214         active = false;
215         // Even if we allow half closed sockets we should give up on reading. Otherwise we may allow a read attempt on a
216         // socket which has not even been connected yet. This has been observed to block during unit tests.
217         inputClosedSeenErrorOnRead = true;
218         try {
219             ChannelPromise promise = connectPromise;
220             if (promise != null) {
221                 // Use tryFailure() instead of setFailure() to avoid the race against cancel().
222                 promise.tryFailure(new ClosedChannelException());
223                 connectPromise = null;
224             }
225 
226             Future<?> future = connectTimeoutFuture;
227             if (future != null) {
228                 future.cancel(false);
229                 connectTimeoutFuture = null;
230             }
231 
232             if (isRegistered()) {
233                 // Need to check if we are on the EventLoop as doClose() may be triggered by the GlobalEventExecutor
234                 // if SO_LINGER is used.
235                 //
236                 // See https://github.com/netty/netty/issues/7159
237                 EventLoop loop = eventLoop();
238                 if (loop.inEventLoop()) {
239                     doDeregister();
240                 } else {
241                     loop.execute(new Runnable() {
242                         @Override
243                         public void run() {
244                             try {
245                                 doDeregister();
246                             } catch (Throwable cause) {
247                                 pipeline().fireExceptionCaught(cause);
248                             }
249                         }
250                     });
251                 }
252             }
253         } finally {
254             socket.close();
255         }
256     }
257 
258     void resetCachedAddresses() {
259         local = socket.localAddress();
260         remote = socket.remoteAddress();
261     }
262 
263     @Override
264     protected void doDisconnect() throws Exception {
265         doClose();
266     }
267 
268     @Override
269     public boolean isOpen() {
270         return socket.isOpen();
271     }
272 
273     @Override
274     protected void doDeregister() throws Exception {
275         IoRegistration registration = this.registration;
276         if (registration != null) {
277             ops = initial;
278             registration.cancel();
279         }
280     }
281 
282     @Override
283     protected boolean isCompatible(EventLoop loop) {
284         return loop instanceof IoEventLoop && ((IoEventLoop) loop).isCompatible(AbstractEpollUnsafe.class);
285     }
286 
287     @Override
288     protected void doBeginRead() throws Exception {
289         // Channel.read() or ChannelHandlerContext.read() was called
290         final AbstractEpollUnsafe unsafe = (AbstractEpollUnsafe) unsafe();
291         unsafe.readPending = true;
292 
293         // We must set the read flag here as it is possible the user didn't read in the last read loop, the
294         // executeEpollInReadyRunnable could read nothing, and if the user doesn't explicitly call read they will
295         // never get data after this.
296         setFlag(Native.EPOLLIN);
297     }
298 
299     final boolean shouldBreakEpollInReady(ChannelConfig config) {
300         return socket.isInputShutdown() && (inputClosedSeenErrorOnRead || !isAllowHalfClosure(config));
301     }
302 
303     private static boolean isAllowHalfClosure(ChannelConfig config) {
304         if (config instanceof EpollDomainSocketChannelConfig) {
305             return ((EpollDomainSocketChannelConfig) config).isAllowHalfClosure();
306         }
307         return config instanceof SocketChannelConfig &&
308                 ((SocketChannelConfig) config).isAllowHalfClosure();
309     }
310 
311     final void clearEpollIn() {
312         // Only clear if registered with an EventLoop as otherwise
313         if (isRegistered()) {
314             final EventLoop loop = eventLoop();
315             final AbstractEpollUnsafe unsafe = (AbstractEpollUnsafe) unsafe();
316             if (loop.inEventLoop()) {
317                 unsafe.clearEpollIn0();
318             } else {
319                 // schedule a task to clear the EPOLLIN as it is not safe to modify it directly
320                 loop.execute(new Runnable() {
321                     @Override
322                     public void run() {
323                         if (!unsafe.readPending && !config().isAutoRead()) {
324                             // Still no read triggered so clear it now
325                             unsafe.clearEpollIn0();
326                         }
327                     }
328                 });
329             }
330         } else  {
331             // The EventLoop is not registered atm so just update the flags so the correct value
332             // will be used once the channel is registered
333             ops = ops.without(EpollIoOps.EPOLLIN);
334         }
335     }
336 
337     @Override
338     protected void doRegister(ChannelPromise promise) {
339         ((IoEventLoop) eventLoop()).register((AbstractEpollUnsafe) unsafe()).addListener(f -> {
340             if (f.isSuccess()) {
341                 registration = (IoRegistration) f.getNow();
342                 if (isActive()) {
343                     // The channel is active, register with current ops now as we are ready to start receiving events.
344                     submitCurrentOps();
345                 }
346                 promise.setSuccess();
347             } else {
348                 promise.setFailure(f.cause());
349             }
350         });
351     }
352 
353     @Override
354     protected abstract AbstractEpollUnsafe newUnsafe();
355 
356     /**
357      * Returns an off-heap copy of the specified {@link ByteBuf}, and releases the original one.
358      */
359     protected final ByteBuf newDirectBuffer(ByteBuf buf) {
360         return newDirectBuffer(buf, buf);
361     }
362 
363     /**
364      * Returns an off-heap copy of the specified {@link ByteBuf}, and releases the specified holder.
365      * The caller must ensure that the holder releases the original {@link ByteBuf} when the holder is released by
366      * this method.
367      */
368     protected final ByteBuf newDirectBuffer(Object holder, ByteBuf buf) {
369         final int readableBytes = buf.readableBytes();
370         if (readableBytes == 0) {
371             ReferenceCountUtil.release(holder);
372             return Unpooled.EMPTY_BUFFER;
373         }
374 
375         final ByteBufAllocator alloc = alloc();
376         if (alloc.isDirectBufferPooled()) {
377             return newDirectBuffer0(holder, buf, alloc, readableBytes);
378         }
379 
380         final ByteBuf directBuf = ByteBufUtil.threadLocalDirectBuffer();
381         if (directBuf == null) {
382             return newDirectBuffer0(holder, buf, alloc, readableBytes);
383         }
384 
385         directBuf.writeBytes(buf, buf.readerIndex(), readableBytes);
386         ReferenceCountUtil.safeRelease(holder);
387         return directBuf;
388     }
389 
390     private static ByteBuf newDirectBuffer0(Object holder, ByteBuf buf, ByteBufAllocator alloc, int capacity) {
391         final ByteBuf directBuf = alloc.directBuffer(capacity);
392         directBuf.writeBytes(buf, buf.readerIndex(), capacity);
393         ReferenceCountUtil.safeRelease(holder);
394         return directBuf;
395     }
396 
397     protected static void checkResolvable(InetSocketAddress addr) {
398         if (addr.isUnresolved()) {
399             throw new UnresolvedAddressException();
400         }
401     }
402 
403     /**
404      * Read bytes into the given {@link ByteBuf} and return the amount.
405      */
406     protected final int doReadBytes(ByteBuf byteBuf) throws Exception {
407         int writerIndex = byteBuf.writerIndex();
408         int localReadAmount;
409         unsafe().recvBufAllocHandle().attemptedBytesRead(byteBuf.writableBytes());
410         if (byteBuf.hasMemoryAddress()) {
411             localReadAmount = socket.recvAddress(byteBuf.memoryAddress(), writerIndex, byteBuf.capacity());
412         } else {
413             ByteBuffer buf = byteBuf.internalNioBuffer(writerIndex, byteBuf.writableBytes());
414             localReadAmount = socket.recv(buf, buf.position(), buf.limit());
415         }
416         if (localReadAmount > 0) {
417             byteBuf.writerIndex(writerIndex + localReadAmount);
418         }
419         return localReadAmount;
420     }
421 
422     protected final int doWriteBytes(ChannelOutboundBuffer in, ByteBuf buf) throws Exception {
423         if (buf.hasMemoryAddress()) {
424             int localFlushedAmount = socket.sendAddress(buf.memoryAddress(), buf.readerIndex(), buf.writerIndex());
425             if (localFlushedAmount > 0) {
426                 in.removeBytes(localFlushedAmount);
427                 return 1;
428             }
429         } else {
430             final ByteBuffer nioBuf = buf.nioBufferCount() == 1 ?
431                     buf.internalNioBuffer(buf.readerIndex(), buf.readableBytes()) : buf.nioBuffer();
432             int localFlushedAmount = socket.send(nioBuf, nioBuf.position(), nioBuf.limit());
433             if (localFlushedAmount > 0) {
434                 nioBuf.position(nioBuf.position() + localFlushedAmount);
435                 in.removeBytes(localFlushedAmount);
436                 return 1;
437             }
438         }
439         return WRITE_STATUS_SNDBUF_FULL;
440     }
441 
442     /**
443      * Write bytes to the socket, with or without a remote address.
444      * Used for datagram and TCP client fast open writes.
445      */
446     final long doWriteOrSendBytes(ByteBuf data, InetSocketAddress remoteAddress, boolean fastOpen)
447             throws IOException {
448         assert !(fastOpen && remoteAddress == null) : "fastOpen requires a remote address";
449         if (data.hasMemoryAddress()) {
450             long memoryAddress = data.memoryAddress();
451             if (remoteAddress == null) {
452                 return socket.sendAddress(memoryAddress, data.readerIndex(), data.writerIndex());
453             }
454             return socket.sendToAddress(memoryAddress, data.readerIndex(), data.writerIndex(),
455                     remoteAddress.getAddress(), remoteAddress.getPort(), fastOpen);
456         }
457 
458         if (data.nioBufferCount() > 1) {
459             IovArray array = ((NativeArrays) registration.attachment()).cleanIovArray();
460             array.add(data, data.readerIndex(), data.readableBytes());
461             int cnt = array.count();
462             assert cnt != 0;
463 
464             if (remoteAddress == null) {
465                 return socket.writevAddresses(array.memoryAddress(0), cnt);
466             }
467             return socket.sendToAddresses(array.memoryAddress(0), cnt,
468                     remoteAddress.getAddress(), remoteAddress.getPort(), fastOpen);
469         }
470 
471         ByteBuffer nioData = data.internalNioBuffer(data.readerIndex(), data.readableBytes());
472         if (remoteAddress == null) {
473             return socket.send(nioData, nioData.position(), nioData.limit());
474         }
475         return socket.sendTo(nioData, nioData.position(), nioData.limit(),
476                 remoteAddress.getAddress(), remoteAddress.getPort(), fastOpen);
477     }
478 
479     protected abstract class AbstractEpollUnsafe extends AbstractUnsafe implements EpollIoHandle {
480         boolean readPending;
481         private EpollRecvByteAllocatorHandle allocHandle;
482 
483         Channel channel() {
484             return AbstractEpollChannel.this;
485         }
486 
487         @Override
488         public FileDescriptor fd() {
489             return AbstractEpollChannel.this.fd();
490         }
491 
492         @Override
493         public void close() {
494             close(voidPromise());
495         }
496 
497         @Override
498         public void handle(IoRegistration registration, IoEvent event) {
499             EpollIoEvent epollEvent = (EpollIoEvent) event;
500             int ops = epollEvent.ops().value;
501 
502             // Don't change the ordering of processing EPOLLOUT | EPOLLRDHUP / EPOLLIN if you're not 100%
503             // sure about it!
504             // Re-ordering can easily introduce bugs and bad side-effects, as we found out painfully in the
505             // past.
506 
507             // First check for EPOLLOUT as we may need to fail the connect ChannelPromise before try
508             // to read from the file descriptor.
509             // See https://github.com/netty/netty/issues/3785
510             //
511             // It is possible for an EPOLLOUT or EPOLLERR to be generated when a connection is refused.
512             // In either case epollOutReady() will do the correct thing (finish connecting, or fail
513             // the connection).
514             // See https://github.com/netty/netty/issues/3848
515             if ((ops & EPOLL_ERR_OUT_MASK) != 0) {
516                 // Force flush of data as the epoll is writable again
517                 epollOutReady();
518             }
519 
520             // Check EPOLLIN before EPOLLRDHUP to ensure all data is read before shutting down the input.
521             // See https://github.com/netty/netty/issues/4317.
522             //
523             // If EPOLLIN or EPOLLERR was received and the channel is still open call epollInReady(). This will
524             // try to read from the underlying file descriptor and so notify the user about the error.
525             if ((ops & EPOLL_ERR_IN_MASK) != 0) {
526                 // The Channel is still open and there is something to read. Do it now.
527                 epollInReady();
528             }
529 
530             // Check if EPOLLRDHUP was set, this will notify us for connection-reset in which case
531             // we may close the channel directly or try to read more data depending on the state of the
532             // Channel and als depending on the AbstractEpollChannel subtype.
533             if ((ops & EPOLL_RDHUP_MASK) != 0) {
534                 epollRdHupReady();
535             }
536         }
537 
538         /**
539          * Called once EPOLLIN event is ready to be processed
540          */
541         abstract void epollInReady();
542 
543         final boolean shouldStopReading(ChannelConfig config) {
544             // Check if there is a readPending which was not processed yet.
545             // This could be for two reasons:
546             // * The user called Channel.read() or ChannelHandlerContext.read() in channelRead(...) method
547             // * The user called Channel.read() or ChannelHandlerContext.read() in channelReadComplete(...) method
548             //
549             // See https://github.com/netty/netty/issues/2254
550             return !readPending && !config.isAutoRead();
551         }
552 
553         /**
554          * Called once EPOLLRDHUP event is ready to be processed
555          */
556         final void epollRdHupReady() {
557             // This must happen before we attempt to read. This will ensure reading continues until an error occurs.
558             recvBufAllocHandle().receivedRdHup();
559 
560             if (isActive()) {
561                 // If it is still active, we need to call epollInReady as otherwise we may miss to
562                 // read pending data from the underlying file descriptor.
563                 // See https://github.com/netty/netty/issues/3709
564                 epollInReady();
565             } else {
566                 // Just to be safe make sure the input marked as closed.
567                 shutdownInput(false);
568             }
569 
570             // Clear the EPOLLRDHUP flag to prevent continuously getting woken up on this event.
571             clearEpollRdHup();
572         }
573 
574         /**
575          * Clear the {@link Native#EPOLLRDHUP} flag from EPOLL, and close on failure.
576          */
577         private void clearEpollRdHup() {
578             try {
579                 clearFlag(Native.EPOLLRDHUP);
580             } catch (IOException e) {
581                 pipeline().fireExceptionCaught(e);
582                 close(voidPromise());
583             }
584         }
585 
586         /**
587          * Shutdown the input side of the channel.
588          */
589         void shutdownInput(boolean allDataRead) {
590             if (!socket.isInputShutdown()) {
591                 if (isAllowHalfClosure(config())) {
592                     try {
593                         socket.shutdown(true, false);
594                     } catch (IOException ignored) {
595                         // We attempted to shutdown and failed, which means the input has already effectively been
596                         // shutdown.
597                         fireEventAndClose(ChannelInputShutdownEvent.INSTANCE);
598                         return;
599                     } catch (NotYetConnectedException ignore) {
600                         // We attempted to shutdown and failed, which means the input has already effectively been
601                         // shutdown.
602                     }
603                     if (shouldStopReading(config())) {
604                         clearEpollIn0();
605                     }
606                     pipeline().fireUserEventTriggered(ChannelInputShutdownEvent.INSTANCE);
607                 } else {
608                     close(voidPromise());
609                     return;
610                 }
611             }
612 
613             if (allDataRead && !inputClosedSeenErrorOnRead) {
614                 inputClosedSeenErrorOnRead = true;
615                 pipeline().fireUserEventTriggered(ChannelInputShutdownReadComplete.INSTANCE);
616             }
617         }
618 
619         private void fireEventAndClose(Object evt) {
620             pipeline().fireUserEventTriggered(evt);
621             close(voidPromise());
622         }
623 
624         @Override
625         public EpollRecvByteAllocatorHandle recvBufAllocHandle() {
626             if (allocHandle == null) {
627                 allocHandle = newEpollHandle((RecvByteBufAllocator.ExtendedHandle) super.recvBufAllocHandle());
628             }
629             return allocHandle;
630         }
631 
632         /**
633          * Create a new {@link EpollRecvByteAllocatorHandle} instance.
634          * @param handle The handle to wrap with EPOLL specific logic.
635          */
636         EpollRecvByteAllocatorHandle newEpollHandle(RecvByteBufAllocator.ExtendedHandle handle) {
637             return new EpollRecvByteAllocatorHandle(handle);
638         }
639 
640         @Override
641         protected final void flush0() {
642             // Flush immediately only when there's no pending flush.
643             // If there's a pending flush operation, event loop will call forceFlush() later,
644             // and thus there's no need to call it now.
645             if (!isFlagSet(Native.EPOLLOUT)) {
646                 super.flush0();
647             }
648         }
649 
650         /**
651          * Called once a EPOLLOUT event is ready to be processed
652          */
653         final void epollOutReady() {
654             if (connectPromise != null) {
655                 // pending connect which is now complete so handle it.
656                 finishConnect();
657             } else if (!socket.isOutputShutdown()) {
658                 // directly call super.flush0() to force a flush now
659                 super.flush0();
660             }
661         }
662 
663         protected final void clearEpollIn0() {
664             assert eventLoop().inEventLoop();
665             try {
666                 readPending = false;
667                 if (!ops.contains(EpollIoOps.EPOLLIN)) {
668                     return;
669                 }
670                 ops = ops.without(EpollIoOps.EPOLLIN);
671                 IoRegistration registration = registration();
672                 registration.submit(ops);
673             } catch (UncheckedIOException e) {
674                 // When this happens there is something completely wrong with either the filedescriptor or epoll,
675                 // so fire the exception through the pipeline and close the Channel.
676                 pipeline().fireExceptionCaught(e);
677                 unsafe().close(unsafe().voidPromise());
678             }
679         }
680 
681         @Override
682         public void connect(
683                 final SocketAddress remoteAddress, final SocketAddress localAddress, final ChannelPromise promise) {
684             // Don't mark the connect promise as uncancellable as in fact we can cancel it as it is using
685             // non-blocking io.
686             if (promise.isDone() || !ensureOpen(promise)) {
687                 return;
688             }
689 
690             try {
691                 if (connectPromise != null) {
692                     throw new ConnectionPendingException();
693                 }
694 
695                 boolean wasActive = isActive();
696                 if (doConnect(remoteAddress, localAddress)) {
697                     fulfillConnectPromise(promise, wasActive);
698                 } else {
699                     connectPromise = promise;
700                     requestedRemoteAddress = remoteAddress;
701 
702                     // Schedule connect timeout.
703                     final int connectTimeoutMillis = config().getConnectTimeoutMillis();
704                     if (connectTimeoutMillis > 0) {
705                         connectTimeoutFuture = eventLoop().schedule(new Runnable() {
706                             @Override
707                             public void run() {
708                                 ChannelPromise connectPromise = AbstractEpollChannel.this.connectPromise;
709                                 if (connectPromise != null && !connectPromise.isDone()
710                                         && connectPromise.tryFailure(new ConnectTimeoutException(
711                                                 "connection timed out after " + connectTimeoutMillis + " ms: " +
712                                                         remoteAddress))) {
713                                     close(voidPromise());
714                                 }
715                             }
716                         }, connectTimeoutMillis, TimeUnit.MILLISECONDS);
717                     }
718 
719                     promise.addListener(new ChannelFutureListener() {
720                         @Override
721                         public void operationComplete(ChannelFuture future) {
722                             // If the connect future is cancelled we also cancel the timeout and close the
723                             // underlying socket.
724                             if (future.isCancelled()) {
725                                 if (connectTimeoutFuture != null) {
726                                     connectTimeoutFuture.cancel(false);
727                                 }
728                                 connectPromise = null;
729                                 close(voidPromise());
730                             }
731                         }
732                     });
733                 }
734             } catch (Throwable t) {
735                 closeIfClosed();
736                 promise.tryFailure(annotateConnectException(t, remoteAddress));
737             }
738         }
739 
740         private void fulfillConnectPromise(ChannelPromise promise, boolean wasActive) {
741             if (promise == null) {
742                 // Closed via cancellation and the promise has been notified already.
743                 return;
744             }
745             active = true;
746 
747             // The channel is active, register with current ops now as we are ready to start receiving events.
748             submitCurrentOps();
749 
750             // Get the state as trySuccess() may trigger an ChannelFutureListener that will close the Channel.
751             // We still need to ensure we call fireChannelActive() in this case.
752             boolean active = isActive();
753 
754             // trySuccess() will return false if a user cancelled the connection attempt.
755             boolean promiseSet = promise.trySuccess();
756 
757             // Regardless if the connection attempt was cancelled, channelActive() event should be triggered,
758             // because what happened is what happened.
759             if (!wasActive && active) {
760                 pipeline().fireChannelActive();
761             }
762 
763             // The connect is complete, so remove the initial data that was sent by TCP_FASTOPEN_CONNECT now and
764             // write what is left of it.
765             if (removeFastOpenData()) {
766                 flush0();
767             }
768 
769             // If a user cancelled the connection attempt, close the channel, which is followed by channelInactive().
770             if (!promiseSet) {
771                 close(voidPromise());
772             }
773         }
774 
775         private void fulfillConnectPromise(ChannelPromise promise, Throwable cause) {
776             // The connect failed, so we don't know if the initial data that was sent by TCP_FASTOPEN_CONNECT
777             // was received.
778             removeFastOpenData();
779             if (promise == null) {
780                 // Closed via cancellation and the promise has been notified already.
781                 return;
782             }
783 
784             // Use tryFailure() instead of setFailure() to avoid the race against cancel().
785             promise.tryFailure(cause);
786             closeIfClosed();
787         }
788 
789         private void finishConnect() {
790             // Note this method is invoked by the event loop only if the connection attempt was
791             // neither cancelled nor timed out.
792 
793             assert eventLoop().inEventLoop();
794 
795             boolean connectStillInProgress = false;
796             try {
797                 boolean wasActive = isActive();
798                 if (!doFinishConnect()) {
799                     connectStillInProgress = true;
800                     return;
801                 }
802                 fulfillConnectPromise(connectPromise, wasActive);
803             } catch (Throwable t) {
804                 fulfillConnectPromise(connectPromise, annotateConnectException(t, requestedRemoteAddress));
805             } finally {
806                 if (!connectStillInProgress) {
807                     // Check for null as the connectTimeoutFuture is only created if a connectTimeoutMillis > 0 is used
808                     // See https://github.com/netty/netty/issues/1770
809                     if (connectTimeoutFuture != null) {
810                         connectTimeoutFuture.cancel(false);
811                     }
812                     connectPromise = null;
813                 }
814             }
815         }
816 
817         /**
818          * Finish the connect
819          */
820         private boolean doFinishConnect() throws Exception {
821             if (socket.finishConnect()) {
822                 clearFlag(Native.EPOLLOUT);
823                 if (requestedRemoteAddress instanceof InetSocketAddress) {
824                     remote = computeRemoteAddr((InetSocketAddress) requestedRemoteAddress, socket.remoteAddress());
825                 }
826                 requestedRemoteAddress = null;
827 
828                 return true;
829             }
830             setFlag(Native.EPOLLOUT);
831             return false;
832         }
833     }
834 
835     @Override
836     protected void doBind(SocketAddress local) throws Exception {
837         if (local instanceof InetSocketAddress) {
838             checkResolvable((InetSocketAddress) local);
839         }
840         socket.bind(local);
841         this.local = socket.localAddress();
842     }
843 
844     /**
845      * Connect to the remote peer
846      */
847     protected boolean doConnect(SocketAddress remoteAddress, SocketAddress localAddress) throws Exception {
848         if (localAddress instanceof InetSocketAddress) {
849             checkResolvable((InetSocketAddress) localAddress);
850         }
851 
852         InetSocketAddress remoteSocketAddr = remoteAddress instanceof InetSocketAddress
853                 ? (InetSocketAddress) remoteAddress : null;
854         if (remoteSocketAddr != null) {
855             checkResolvable(remoteSocketAddr);
856         }
857 
858         if (remote != null) {
859             // Check if already connected before trying to connect. This is needed as connect(...) will not return -1
860             // and set errno to EISCONN if a previous connect(...) attempt was setting errno to EINPROGRESS and finished
861             // later.
862             throw new AlreadyConnectedException();
863         }
864 
865         if (localAddress != null) {
866             socket.bind(localAddress);
867         }
868 
869         boolean connected = doConnect0(remoteAddress);
870         if (connected) {
871             remote = remoteSocketAddr == null ?
872                     remoteAddress : computeRemoteAddr(remoteSocketAddr, socket.remoteAddress());
873         }
874         // We always need to set the localAddress even if not connected yet as the bind already took place.
875         //
876         // See https://github.com/netty/netty/issues/3463
877         local = socket.localAddress();
878         return connected;
879     }
880 
881     boolean doConnect0(SocketAddress remote) throws Exception {
882         boolean success = false;
883         try {
884             boolean connected = socket.connect(remote);
885             if (!connected) {
886                 setFlag(Native.EPOLLOUT);
887             }
888             success = true;
889             return connected;
890         } finally {
891             if (!success) {
892                 doClose();
893             }
894         }
895     }
896 
897     final void submitCurrentOps() {
898         IoRegistration registration = registration();
899         registration.submit(ops);
900     }
901 
902     @Override
903     protected SocketAddress localAddress0() {
904         return local;
905     }
906 
907     @Override
908     protected SocketAddress remoteAddress0() {
909         return remote;
910     }
911 }