Repository: netty/netty
Issue: Expose requestedRemoteAddress in the Channel interface (improvement)

### Expected behavior

Most part of Channel abstract implementations contain `requestedRemoteAddress` object variable, which might be useful for debug purposes. When channel fails to connect in certain circumstances we lose information about what has been requested connect to.

### Actual behavior

`Channel` interface should expose `requestedRemoteAddress()` getter method

### Steps to reproduce

n/a

### Minimal yet complete reproducer code (or URL to code)

### Netty version

### JVM version (e.g. `java -version`)

### OS version (e.g. `uname -a`)


Issue comments:

Pull request review comments:

Patch that resolved the issue:
diff --git a/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2MultiplexCodec.java b/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2MultiplexCodec.java
index a7ca0bb8311..dabd0c1970a 100644
--- a/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2MultiplexCodec.java
+++ b/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2MultiplexCodec.java
@@ -460,6 +460,8 @@ private final class DefaultHttp2StreamChannel extends DefaultAttributeMap implem
         // We start with the writability of the channel when creating the StreamChannel.
         private volatile boolean writable;
 
+        private volatile SocketAddress requestedRemoteAddress;
+
         private boolean outboundClosed;
         /**
          * This variable represents if a read is in progress for the current channel. Note that depending upon the
@@ -567,6 +569,11 @@ public SocketAddress remoteAddress() {
             return parent().remoteAddress();
         }
 
+        @Override
+        public SocketAddress requestedRemoteAddress() {
+            return requestedRemoteAddress;
+        }
+
         @Override
         public ChannelFuture closeFuture() {
             return closePromise;
@@ -618,11 +625,13 @@ public ChannelFuture bind(SocketAddress localAddress) {
 
         @Override
         public ChannelFuture connect(SocketAddress remoteAddress) {
+            this.requestedRemoteAddress = remoteAddress;
             return pipeline().connect(remoteAddress);
         }
 
         @Override
         public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress) {
+            this.requestedRemoteAddress = remoteAddress;
             return pipeline().connect(remoteAddress, localAddress);
         }
 
diff --git a/transport-native-epoll/src/main/java/io/netty/channel/epoll/AbstractEpollChannel.java b/transport-native-epoll/src/main/java/io/netty/channel/epoll/AbstractEpollChannel.java
index 25ae95b2d4d..0e4ad67394d 100644
--- a/transport-native-epoll/src/main/java/io/netty/channel/epoll/AbstractEpollChannel.java
+++ b/transport-native-epoll/src/main/java/io/netty/channel/epoll/AbstractEpollChannel.java
@@ -67,7 +67,6 @@ abstract class AbstractEpollChannel extends AbstractChannel implements UnixChann
      */
     private ChannelPromise connectPromise;
     private ScheduledFuture<?> connectTimeoutFuture;
-    private SocketAddress requestedRemoteAddress;
 
     private volatile SocketAddress local;
     private volatile SocketAddress remote;
@@ -556,7 +555,6 @@ public void connect(
                     fulfillConnectPromise(promise, wasActive);
                 } else {
                     connectPromise = promise;
-                    requestedRemoteAddress = remoteAddress;
 
                     // Schedule connect timeout.
                     int connectTimeoutMillis = config().getConnectTimeoutMillis();
@@ -645,7 +643,7 @@ private void finishConnect() {
                 }
                 fulfillConnectPromise(connectPromise, wasActive);
             } catch (Throwable t) {
-                fulfillConnectPromise(connectPromise, annotateConnectException(t, requestedRemoteAddress));
+                fulfillConnectPromise(connectPromise, annotateConnectException(t, requestedRemoteAddress()));
             } finally {
                 if (!connectStillInProgress) {
                     // Check for null as the connectTimeoutFuture is only created if a connectTimeoutMillis > 0 is used
@@ -664,10 +662,11 @@ private void finishConnect() {
         private boolean doFinishConnect() throws Exception {
             if (socket.finishConnect()) {
                 clearFlag(Native.EPOLLOUT);
+                SocketAddress requestedRemoteAddress = requestedRemoteAddress();
                 if (requestedRemoteAddress instanceof InetSocketAddress) {
                     remote = computeRemoteAddr((InetSocketAddress) requestedRemoteAddress, socket.remoteAddress());
                 }
-                requestedRemoteAddress = null;
+                invalidateRequestedRemoteAddress();
 
                 return true;
             }
diff --git a/transport-native-kqueue/src/main/java/io/netty/channel/kqueue/AbstractKQueueChannel.java b/transport-native-kqueue/src/main/java/io/netty/channel/kqueue/AbstractKQueueChannel.java
index 6073fa9ca12..87c48142c0e 100644
--- a/transport-native-kqueue/src/main/java/io/netty/channel/kqueue/AbstractKQueueChannel.java
+++ b/transport-native-kqueue/src/main/java/io/netty/channel/kqueue/AbstractKQueueChannel.java
@@ -62,7 +62,6 @@ abstract class AbstractKQueueChannel extends AbstractChannel implements UnixChan
      */
     private ChannelPromise connectPromise;
     private ScheduledFuture<?> connectTimeoutFuture;
-    private SocketAddress requestedRemoteAddress;
 
     final BsdSocket socket;
     private boolean readFilterEnabled;
@@ -562,7 +561,6 @@ public void connect(
                     fulfillConnectPromise(promise, wasActive);
                 } else {
                     connectPromise = promise;
-                    requestedRemoteAddress = remoteAddress;
 
                     // Schedule connect timeout.
                     int connectTimeoutMillis = config().getConnectTimeoutMillis();
@@ -651,7 +649,7 @@ private void finishConnect() {
                 }
                 fulfillConnectPromise(connectPromise, wasActive);
             } catch (Throwable t) {
-                fulfillConnectPromise(connectPromise, annotateConnectException(t, requestedRemoteAddress));
+                fulfillConnectPromise(connectPromise, annotateConnectException(t, requestedRemoteAddress()));
             } finally {
                 if (!connectStillInProgress) {
                     // Check for null as the connectTimeoutFuture is only created if a connectTimeoutMillis > 0 is used
@@ -667,10 +665,11 @@ private void finishConnect() {
         private boolean doFinishConnect() throws Exception {
             if (socket.finishConnect()) {
                 writeFilter(false);
+                SocketAddress requestedRemoteAddress = requestedRemoteAddress();
                 if (requestedRemoteAddress instanceof InetSocketAddress) {
                     remote = computeRemoteAddr((InetSocketAddress) requestedRemoteAddress, socket.remoteAddress());
                 }
-                requestedRemoteAddress = null;
+                invalidateRequestedRemoteAddress();
                 return true;
             }
             writeFilter(true);
diff --git a/transport/src/main/java/io/netty/channel/AbstractChannel.java b/transport/src/main/java/io/netty/channel/AbstractChannel.java
index ad671423df9..3b16f8335e8 100644
--- a/transport/src/main/java/io/netty/channel/AbstractChannel.java
+++ b/transport/src/main/java/io/netty/channel/AbstractChannel.java
@@ -64,6 +64,7 @@ public abstract class AbstractChannel extends DefaultAttributeMap implements Cha
 
     private volatile SocketAddress localAddress;
     private volatile SocketAddress remoteAddress;
+    private volatile SocketAddress requestedRemoteAddress;
     private volatile EventLoop eventLoop;
     private volatile boolean registered;
     private boolean closeInitiated;
@@ -220,11 +221,13 @@ public ChannelFuture bind(SocketAddress localAddress) {
 
     @Override
     public ChannelFuture connect(SocketAddress remoteAddress) {
+        this.requestedRemoteAddress = remoteAddress;
         return pipeline.connect(remoteAddress);
     }
 
     @Override
     public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress) {
+        this.requestedRemoteAddress = remoteAddress;
         return pipeline.connect(remoteAddress, localAddress);
     }
 
@@ -1196,4 +1199,14 @@ public Throwable fillInStackTrace() {
             return this;
         }
     }
+
+    protected void invalidateRequestedRemoteAddress() {
+        requestedRemoteAddress = null;
+    }
+
+    @Override
+    public SocketAddress requestedRemoteAddress() {
+        return requestedRemoteAddress;
+    }
+
 }
diff --git a/transport/src/main/java/io/netty/channel/Channel.java b/transport/src/main/java/io/netty/channel/Channel.java
index 6acb59d3b31..4890087cd83 100644
--- a/transport/src/main/java/io/netty/channel/Channel.java
+++ b/transport/src/main/java/io/netty/channel/Channel.java
@@ -146,6 +146,17 @@ public interface Channel extends AttributeMap, ChannelOutboundInvoker, Comparabl
      */
     SocketAddress remoteAddress();
 
+    /**
+     * Returns the remote address where this channel has been requested connected to. The
+     * returned {@link SocketAddress} is supposed to be down-cast into more
+     * concrete type such as {@link InetSocketAddress} to retrieve the detailed
+     * information.
+     *
+     * @return the requested remote address of this channel.
+     *         {@code null} if this channel has not been requested to connect yet.
+     */
+    SocketAddress requestedRemoteAddress();
+
     /**
      * Returns the {@link ChannelFuture} which will be notified when this
      * channel is closed.  This method always returns the same future instance.
diff --git a/transport/src/main/java/io/netty/channel/nio/AbstractNioChannel.java b/transport/src/main/java/io/netty/channel/nio/AbstractNioChannel.java
index 01467b98361..71185d9ed42 100644
--- a/transport/src/main/java/io/netty/channel/nio/AbstractNioChannel.java
+++ b/transport/src/main/java/io/netty/channel/nio/AbstractNioChannel.java
@@ -71,7 +71,6 @@ public void run() {
      */
     private ChannelPromise connectPromise;
     private ScheduledFuture<?> connectTimeoutFuture;
-    private SocketAddress requestedRemoteAddress;
 
     /**
      * Create a new instance
@@ -255,7 +254,6 @@ public final void connect(
                     fulfillConnectPromise(promise, wasActive);
                 } else {
                     connectPromise = promise;
-                    requestedRemoteAddress = remoteAddress;
 
                     // Schedule connect timeout.
                     int connectTimeoutMillis = config().getConnectTimeoutMillis();
@@ -340,7 +338,7 @@ public final void finishConnect() {
                 doFinishConnect();
                 fulfillConnectPromise(connectPromise, wasActive);
             } catch (Throwable t) {
-                fulfillConnectPromise(connectPromise, annotateConnectException(t, requestedRemoteAddress));
+                fulfillConnectPromise(connectPromise, annotateConnectException(t, requestedRemoteAddress()));
             } finally {
                 // Check for null as the connectTimeoutFuture is only created if a connectTimeoutMillis > 0 is used
                 // See https://github.com/netty/netty/issues/1770


Test patch: