diff --git a/common/src/main/java/io/netty/util/internal/SocketUtil.java b/common/src/main/java/io/netty/util/internal/SocketUtil.java new file mode 100644 index 0000000000..53c0094781 --- /dev/null +++ b/common/src/main/java/io/netty/util/internal/SocketUtil.java @@ -0,0 +1,78 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.util.internal; + +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.UnknownHostException; + +public final class SocketUtil { + + + private static final String ZONE_ID_SEPARATOR = "%"; + + + /** + * Takes care of stripping the zone id from the {@link InetAddress} if its an {@link Inet6Address} and the java + * version is < 7. After that a new {@link InetSocketAddress} is created based on the old one. This is needed because of a bug that exists in java + * versions < 7. + * + * See https://github.com/netty/netty/issues/267 + * + */ + public static InetSocketAddress stripZoneId(InetSocketAddress socketAddress) throws UnknownHostException { + return new InetSocketAddress(socketAddress.getAddress(), socketAddress.getPort()); + } + + /** + * Takes care of stripping the zone id from the {@link InetAddress} if its an {@link Inet6Address} and the java + * version is < 7. This is needed because of a bug that exists in java versions < 7. + * + * See https://github.com/netty/netty/issues/267 + * + */ + public static InetAddress stripZoneId(InetAddress address) throws UnknownHostException { + // If we have a java version which is >= 7 we can just return the given + // InetSocketAddress as this bug only seems + // to exist in java 6 (and maybe also versions before) + if (DetectionUtil.javaVersion() >= 7) { + return address; + } + + if (address instanceof Inet6Address) { + Inet6Address inet6Address = (Inet6Address) address; + + // Check if its a LinkLocalAddress as this is the only one which is + // affected + if (inet6Address.isLinkLocalAddress()) { + String hostaddress = inet6Address.getHostAddress(); + + int separator = hostaddress.indexOf(ZONE_ID_SEPARATOR); + + // strip of the zoneId + String withoutZonedId = inet6Address.getHostAddress().substring(0, separator); + return InetAddress.getByName(withoutZonedId); + } + } + return address; + + } + + private SocketUtil() { + + } +} diff --git a/transport/src/main/java/io/netty/channel/socket/nio/NioClientSocketPipelineSink.java b/transport/src/main/java/io/netty/channel/socket/nio/NioClientSocketPipelineSink.java index 495dd371fb..6b4008a520 100644 --- a/transport/src/main/java/io/netty/channel/socket/nio/NioClientSocketPipelineSink.java +++ b/transport/src/main/java/io/netty/channel/socket/nio/NioClientSocketPipelineSink.java @@ -27,7 +27,9 @@ import io.netty.channel.ChannelStateEvent; import io.netty.channel.MessageEvent; import io.netty.logging.InternalLogger; import io.netty.logging.InternalLoggerFactory; +import io.netty.util.internal.SocketUtil; +import java.net.InetSocketAddress; import java.net.SocketAddress; import java.nio.channels.ClosedChannelException; @@ -99,6 +101,7 @@ class NioClientSocketPipelineSink extends AbstractNioChannelSink { final NioClientSocketChannel channel, final ChannelFuture cf, SocketAddress remoteAddress) { try { + remoteAddress = SocketUtil.stripZoneId((InetSocketAddress) remoteAddress); channel.getJdkChannel().connect(remoteAddress); channel.getCloseFuture().addListener(new ChannelFutureListener() { @Override diff --git a/transport/src/main/java/io/netty/channel/socket/oio/OioClientSocketPipelineSink.java b/transport/src/main/java/io/netty/channel/socket/oio/OioClientSocketPipelineSink.java index e607d3282e..ea5148b76b 100644 --- a/transport/src/main/java/io/netty/channel/socket/oio/OioClientSocketPipelineSink.java +++ b/transport/src/main/java/io/netty/channel/socket/oio/OioClientSocketPipelineSink.java @@ -18,6 +18,7 @@ package io.netty.channel.socket.oio; import static io.netty.channel.Channels.*; import java.io.PushbackInputStream; +import java.net.InetSocketAddress; import java.net.SocketAddress; import java.util.concurrent.Executor; @@ -29,6 +30,7 @@ import io.netty.channel.ChannelState; import io.netty.channel.ChannelStateEvent; import io.netty.channel.MessageEvent; import io.netty.util.internal.DeadLockProofWorker; +import io.netty.util.internal.SocketUtil; class OioClientSocketPipelineSink extends AbstractOioChannelSink { @@ -102,6 +104,8 @@ class OioClientSocketPipelineSink extends AbstractOioChannelSink { future.addListener(ChannelFutureListener.CLOSE_ON_FAILURE); try { + remoteAddress = SocketUtil.stripZoneId((InetSocketAddress) remoteAddress); + channel.socket.connect( remoteAddress, channel.getConfig().getConnectTimeoutMillis()); connected = true;