You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by jo...@apache.org on 2022/03/19 14:09:22 UTC

[cassandra] branch cassandra-3.0 updated: ConnectionLimitHandler may leaks connection count if remote connection drops

This is an automated email from the ASF dual-hosted git repository.

jonmeredith pushed a commit to branch cassandra-3.0
in repository https://gitbox.apache.org/repos/asf/cassandra.git


The following commit(s) were added to refs/heads/cassandra-3.0 by this push:
     new 647ec92  ConnectionLimitHandler may leaks connection count if remote connection drops
647ec92 is described below

commit 647ec92db17e1b1a3677e7880849a29c0c30adde
Author: Jon Meredith <jo...@apache.org>
AuthorDate: Fri Mar 18 17:17:17 2022 -0600

    ConnectionLimitHandler may leaks connection count if remote connection drops
    
    patch by Jon Meredith; reviewed by Caleb Rackliffe for CASSANDRA-17252
---
 CHANGES.txt                                        |  1 +
 .../transport/ConnectionLimitHandler.java          | 44 ++++++++++++++++++++--
 2 files changed, 41 insertions(+), 4 deletions(-)

diff --git a/CHANGES.txt b/CHANGES.txt
index 36d6064..28fe6ec 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
 3.0.27
+ * ConnectionLimitHandler may leaks connection count if remote connection drops (CASSANDRA-17252)
  * Require ant >= 1.10 (CASSANDRA-17428)
  * Disallow CONTAINS for UPDATE and DELETE (CASSANDRA-15266)
  * filter out NULL_VERSION entries from peers table in ConfiguredLimit (CASSANDRA-16518)
diff --git a/src/java/org/apache/cassandra/transport/ConnectionLimitHandler.java b/src/java/org/apache/cassandra/transport/ConnectionLimitHandler.java
index 7bcf280..271004d 100644
--- a/src/java/org/apache/cassandra/transport/ConnectionLimitHandler.java
+++ b/src/java/org/apache/cassandra/transport/ConnectionLimitHandler.java
@@ -18,15 +18,19 @@
 package org.apache.cassandra.transport;
 
 
+import io.netty.channel.Channel;
 import io.netty.channel.ChannelHandler;
 import io.netty.channel.ChannelHandlerContext;
 import io.netty.channel.ChannelInboundHandlerAdapter;
+import io.netty.util.Attribute;
+import io.netty.util.AttributeKey;
 import org.apache.cassandra.config.DatabaseDescriptor;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
+import java.net.SocketAddress;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.atomic.AtomicLong;
@@ -40,9 +44,37 @@ import java.util.concurrent.atomic.AtomicLong;
 final class ConnectionLimitHandler extends ChannelInboundHandlerAdapter
 {
     private static final Logger logger = LoggerFactory.getLogger(ConnectionLimitHandler.class);
+    private static final AttributeKey<InetAddress> addressAttributeKey = AttributeKey.valueOf("address");
     private final ConcurrentMap<InetAddress, AtomicLong> connectionsPerClient = new ConcurrentHashMap<>();
     private final AtomicLong counter = new AtomicLong(0);
 
+    // Keep the remote address as a channel attribute.  The channel inactive callback needs
+    // to know the entry into the connetionsPerClient map and depending on the state of the remote
+    // an exception may be thrown trying to retrieve the address. Make sure the same address used
+    // to increment is used for decrement.
+    private static InetAddress setRemoteAddressAttribute(Channel channel)
+    {
+        Attribute<InetAddress> addressAttribute = channel.attr(addressAttributeKey);
+        SocketAddress remoteAddress = channel.remoteAddress();
+        if (remoteAddress instanceof InetSocketAddress)
+        {
+            addressAttribute.setIfAbsent(((InetSocketAddress) remoteAddress).getAddress());
+        }
+        else
+        {
+            logger.warn("Remote address of unknown type: {}, skipping per-IP connection limits",
+                              remoteAddress.getClass());
+        }
+        return addressAttribute.get();
+    }
+
+    private static InetAddress getRemoteAddressAttribute(Channel channel)
+    {
+        Attribute<InetAddress> addressAttribute = channel.attr(addressAttributeKey);
+        return addressAttribute.get();
+    }
+
+
     @Override
     public void channelActive(ChannelHandlerContext ctx) throws Exception
     {
@@ -64,8 +96,12 @@ final class ConnectionLimitHandler extends ChannelInboundHandlerAdapter
             long perIpLimit = DatabaseDescriptor.getNativeTransportMaxConcurrentConnectionsPerIp();
             if (perIpLimit > 0)
             {
-                InetAddress address = ((InetSocketAddress) ctx.channel().remoteAddress()).getAddress();
-
+                InetAddress address = setRemoteAddressAttribute(ctx.channel());
+                if (address == null)
+                {
+                    ctx.close();
+                    return;
+                }
                 AtomicLong perIpCount = connectionsPerClient.get(address);
                 if (perIpCount == null)
                 {
@@ -93,9 +129,9 @@ final class ConnectionLimitHandler extends ChannelInboundHandlerAdapter
     public void channelInactive(ChannelHandlerContext ctx) throws Exception
     {
         counter.decrementAndGet();
-        InetAddress address = ((InetSocketAddress) ctx.channel().remoteAddress()).getAddress();
+        InetAddress address = getRemoteAddressAttribute(ctx.channel());
 
-        AtomicLong count = connectionsPerClient.get(address);
+        AtomicLong count = address == null ? null : connectionsPerClient.get(address);
         if (count != null)
         {
             if (count.decrementAndGet() <= 0)

---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cassandra.apache.org
For additional commands, e-mail: commits-help@cassandra.apache.org