blob: 5f83b6a989c87e60f554484eeaa96cd5cb445069 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF 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 org.apache.cassandra.net;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import io.netty.channel.WriteBufferWaterMark;
import org.apache.cassandra.auth.IInternodeAuthenticator;
import org.apache.cassandra.config.Config;
import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.config.EncryptionOptions;
import org.apache.cassandra.config.EncryptionOptions.ServerEncryptionOptions;
import org.apache.cassandra.db.SystemKeyspace;
import org.apache.cassandra.locator.IEndpointSnitch;
import org.apache.cassandra.locator.InetAddressAndPort;
import org.apache.cassandra.utils.FBUtilities;
import static org.apache.cassandra.config.DatabaseDescriptor.getEndpointSnitch;
import static org.apache.cassandra.net.MessagingService.VERSION_40;
import static org.apache.cassandra.net.MessagingService.instance;
import static org.apache.cassandra.net.SocketFactory.encryptionLogStatement;
import static org.apache.cassandra.utils.FBUtilities.getBroadcastAddressAndPort;
/**
* A collection of settings to be passed around for outbound connections.
*/
@SuppressWarnings({ "WeakerAccess", "unused" })
public class OutboundConnectionSettings
{
private static final String INTRADC_TCP_NODELAY_PROPERTY = Config.PROPERTY_PREFIX + "otc_intradc_tcp_nodelay";
/**
* Enabled/disable TCP_NODELAY for intradc connections. Defaults to enabled.
*/
private static final boolean INTRADC_TCP_NODELAY = Boolean.parseBoolean(System.getProperty(INTRADC_TCP_NODELAY_PROPERTY, "true"));
public enum Framing
{
// for < VERSION_40, implies no framing
// for >= VERSION_40, uses simple unprotected frames with header crc but no payload protection
UNPROTECTED(0),
// for < VERSION_40, uses the jpountz framing format
// for >= VERSION_40, uses our framing format with header crc24
LZ4(1),
// for < VERSION_40, implies UNPROTECTED
// for >= VERSION_40, uses simple frames with separate header and payload crc
CRC(2);
public static Framing forId(int id)
{
switch (id)
{
case 0: return UNPROTECTED;
case 1: return LZ4;
case 2: return CRC;
}
throw new IllegalStateException();
}
final int id;
Framing(int id)
{
this.id = id;
}
}
public final IInternodeAuthenticator authenticator;
public final InetAddressAndPort to;
public final InetAddressAndPort connectTo; // may be represented by a different IP address on this node's local network
public final EncryptionOptions encryption;
public final Framing framing;
public final Integer socketSendBufferSizeInBytes;
public final Integer applicationSendQueueCapacityInBytes;
public final Integer applicationSendQueueReserveEndpointCapacityInBytes;
public final ResourceLimits.Limit applicationSendQueueReserveGlobalCapacityInBytes;
public final Boolean tcpNoDelay;
public final int flushLowWaterMark, flushHighWaterMark;
public final Integer tcpConnectTimeoutInMS;
public final Integer tcpUserTimeoutInMS;
public final AcceptVersions acceptVersions;
public final InetAddressAndPort from;
public final SocketFactory socketFactory;
public final OutboundMessageCallbacks callbacks;
public final OutboundDebugCallbacks debug;
public final EndpointMessagingVersions endpointToVersion;
public OutboundConnectionSettings(InetAddressAndPort to)
{
this(to, null);
}
public OutboundConnectionSettings(InetAddressAndPort to, InetAddressAndPort preferred)
{
this(null, to, preferred, null, null, null, null, null, null, null, 1 << 15, 1 << 16, null, null, null, null, null, null, null, null);
}
private OutboundConnectionSettings(IInternodeAuthenticator authenticator,
InetAddressAndPort to,
InetAddressAndPort connectTo,
EncryptionOptions encryption,
Framing framing,
Integer socketSendBufferSizeInBytes,
Integer applicationSendQueueCapacityInBytes,
Integer applicationSendQueueReserveEndpointCapacityInBytes,
ResourceLimits.Limit applicationSendQueueReserveGlobalCapacityInBytes,
Boolean tcpNoDelay,
int flushLowWaterMark,
int flushHighWaterMark,
Integer tcpConnectTimeoutInMS,
Integer tcpUserTimeoutInMS,
AcceptVersions acceptVersions,
InetAddressAndPort from,
SocketFactory socketFactory,
OutboundMessageCallbacks callbacks,
OutboundDebugCallbacks debug,
EndpointMessagingVersions endpointToVersion)
{
Preconditions.checkArgument(socketSendBufferSizeInBytes == null || socketSendBufferSizeInBytes == 0 || socketSendBufferSizeInBytes >= 1 << 10, "illegal socket send buffer size: " + socketSendBufferSizeInBytes);
Preconditions.checkArgument(applicationSendQueueCapacityInBytes == null || applicationSendQueueCapacityInBytes >= 1 << 10, "illegal application send queue capacity: " + applicationSendQueueCapacityInBytes);
Preconditions.checkArgument(tcpUserTimeoutInMS == null || tcpUserTimeoutInMS >= 0, "tcp user timeout must be non negative: " + tcpUserTimeoutInMS);
Preconditions.checkArgument(tcpConnectTimeoutInMS == null || tcpConnectTimeoutInMS > 0, "tcp connect timeout must be positive: " + tcpConnectTimeoutInMS);
this.authenticator = authenticator;
this.to = to;
this.connectTo = connectTo;
this.encryption = encryption;
this.framing = framing;
this.socketSendBufferSizeInBytes = socketSendBufferSizeInBytes;
this.applicationSendQueueCapacityInBytes = applicationSendQueueCapacityInBytes;
this.applicationSendQueueReserveEndpointCapacityInBytes = applicationSendQueueReserveEndpointCapacityInBytes;
this.applicationSendQueueReserveGlobalCapacityInBytes = applicationSendQueueReserveGlobalCapacityInBytes;
this.tcpNoDelay = tcpNoDelay;
this.flushLowWaterMark = flushLowWaterMark;
this.flushHighWaterMark = flushHighWaterMark;
this.tcpConnectTimeoutInMS = tcpConnectTimeoutInMS;
this.tcpUserTimeoutInMS = tcpUserTimeoutInMS;
this.acceptVersions = acceptVersions;
this.from = from;
this.socketFactory = socketFactory;
this.callbacks = callbacks;
this.debug = debug;
this.endpointToVersion = endpointToVersion;
}
public boolean authenticate()
{
return authenticator.authenticate(to.address, to.port);
}
public boolean withEncryption()
{
return encryption != null;
}
public String toString()
{
return String.format("peer: (%s, %s), framing: %s, encryption: %s",
to, connectTo, framing, encryptionLogStatement(encryption));
}
public OutboundConnectionSettings withAuthenticator(IInternodeAuthenticator authenticator)
{
return new OutboundConnectionSettings(authenticator, to, connectTo, encryption, framing,
socketSendBufferSizeInBytes, applicationSendQueueCapacityInBytes,
applicationSendQueueReserveEndpointCapacityInBytes, applicationSendQueueReserveGlobalCapacityInBytes,
tcpNoDelay, flushLowWaterMark, flushHighWaterMark, tcpConnectTimeoutInMS,
tcpUserTimeoutInMS, acceptVersions, from, socketFactory, callbacks, debug, endpointToVersion);
}
@SuppressWarnings("unused")
public OutboundConnectionSettings toEndpoint(InetAddressAndPort endpoint)
{
return new OutboundConnectionSettings(authenticator, endpoint, connectTo, encryption, framing,
socketSendBufferSizeInBytes, applicationSendQueueCapacityInBytes,
applicationSendQueueReserveEndpointCapacityInBytes, applicationSendQueueReserveGlobalCapacityInBytes,
tcpNoDelay, flushLowWaterMark, flushHighWaterMark, tcpConnectTimeoutInMS,
tcpUserTimeoutInMS, acceptVersions, from, socketFactory, callbacks, debug, endpointToVersion);
}
public OutboundConnectionSettings withConnectTo(InetAddressAndPort connectTo)
{
return new OutboundConnectionSettings(authenticator, to, connectTo, encryption, framing,
socketSendBufferSizeInBytes, applicationSendQueueCapacityInBytes,
applicationSendQueueReserveEndpointCapacityInBytes, applicationSendQueueReserveGlobalCapacityInBytes,
tcpNoDelay, flushLowWaterMark, flushHighWaterMark, tcpConnectTimeoutInMS,
tcpUserTimeoutInMS, acceptVersions, from, socketFactory, callbacks, debug, endpointToVersion);
}
public OutboundConnectionSettings withEncryption(ServerEncryptionOptions encryption)
{
return new OutboundConnectionSettings(authenticator, to, connectTo, encryption, framing,
socketSendBufferSizeInBytes, applicationSendQueueCapacityInBytes,
applicationSendQueueReserveEndpointCapacityInBytes, applicationSendQueueReserveGlobalCapacityInBytes,
tcpNoDelay, flushLowWaterMark, flushHighWaterMark, tcpConnectTimeoutInMS,
tcpUserTimeoutInMS, acceptVersions, from, socketFactory, callbacks, debug, endpointToVersion);
}
@SuppressWarnings("unused")
public OutboundConnectionSettings withFraming(Framing framing)
{
return new OutboundConnectionSettings(authenticator, to, connectTo, encryption, framing, socketSendBufferSizeInBytes, applicationSendQueueCapacityInBytes,
applicationSendQueueReserveEndpointCapacityInBytes, applicationSendQueueReserveGlobalCapacityInBytes,
tcpNoDelay, flushLowWaterMark, flushHighWaterMark, tcpConnectTimeoutInMS,
tcpUserTimeoutInMS, acceptVersions, from, socketFactory, callbacks, debug, endpointToVersion);
}
public OutboundConnectionSettings withSocketSendBufferSizeInBytes(int socketSendBufferSizeInBytes)
{
return new OutboundConnectionSettings(authenticator, to, connectTo, encryption, framing,
socketSendBufferSizeInBytes, applicationSendQueueCapacityInBytes,
applicationSendQueueReserveEndpointCapacityInBytes, applicationSendQueueReserveGlobalCapacityInBytes,
tcpNoDelay, flushLowWaterMark, flushHighWaterMark, tcpConnectTimeoutInMS,
tcpUserTimeoutInMS, acceptVersions, from, socketFactory, callbacks, debug, endpointToVersion);
}
@SuppressWarnings("unused")
public OutboundConnectionSettings withApplicationSendQueueCapacityInBytes(int applicationSendQueueCapacityInBytes)
{
return new OutboundConnectionSettings(authenticator, to, connectTo, encryption, framing,
socketSendBufferSizeInBytes, applicationSendQueueCapacityInBytes,
applicationSendQueueReserveEndpointCapacityInBytes, applicationSendQueueReserveGlobalCapacityInBytes,
tcpNoDelay, flushLowWaterMark, flushHighWaterMark, tcpConnectTimeoutInMS,
tcpUserTimeoutInMS, acceptVersions, from, socketFactory, callbacks, debug, endpointToVersion);
}
public OutboundConnectionSettings withApplicationReserveSendQueueCapacityInBytes(Integer applicationReserveSendQueueEndpointCapacityInBytes, ResourceLimits.Limit applicationReserveSendQueueGlobalCapacityInBytes)
{
return new OutboundConnectionSettings(authenticator, to, connectTo, encryption, framing,
socketSendBufferSizeInBytes, applicationSendQueueCapacityInBytes,
applicationReserveSendQueueEndpointCapacityInBytes, applicationReserveSendQueueGlobalCapacityInBytes,
tcpNoDelay, flushLowWaterMark, flushHighWaterMark, tcpConnectTimeoutInMS,
tcpUserTimeoutInMS, acceptVersions, from, socketFactory, callbacks, debug, endpointToVersion);
}
@SuppressWarnings("unused")
public OutboundConnectionSettings withTcpNoDelay(boolean tcpNoDelay)
{
return new OutboundConnectionSettings(authenticator, to, connectTo, encryption, framing,
socketSendBufferSizeInBytes, applicationSendQueueCapacityInBytes,
applicationSendQueueReserveEndpointCapacityInBytes, applicationSendQueueReserveGlobalCapacityInBytes,
tcpNoDelay, flushLowWaterMark, flushHighWaterMark, tcpConnectTimeoutInMS,
tcpUserTimeoutInMS, acceptVersions, from, socketFactory, callbacks, debug, endpointToVersion);
}
@SuppressWarnings("unused")
public OutboundConnectionSettings withNettyBufferBounds(WriteBufferWaterMark nettyBufferBounds)
{
return new OutboundConnectionSettings(authenticator, to, connectTo, encryption, framing,
socketSendBufferSizeInBytes, applicationSendQueueCapacityInBytes,
applicationSendQueueReserveEndpointCapacityInBytes, applicationSendQueueReserveGlobalCapacityInBytes,
tcpNoDelay, flushLowWaterMark, flushHighWaterMark, tcpConnectTimeoutInMS,
tcpUserTimeoutInMS, acceptVersions, from, socketFactory, callbacks, debug, endpointToVersion);
}
public OutboundConnectionSettings withTcpConnectTimeoutInMS(int tcpConnectTimeoutInMS)
{
return new OutboundConnectionSettings(authenticator, to, connectTo, encryption, framing,
socketSendBufferSizeInBytes, applicationSendQueueCapacityInBytes,
applicationSendQueueReserveEndpointCapacityInBytes, applicationSendQueueReserveGlobalCapacityInBytes,
tcpNoDelay, flushLowWaterMark, flushHighWaterMark, tcpConnectTimeoutInMS,
tcpUserTimeoutInMS, acceptVersions, from, socketFactory, callbacks, debug, endpointToVersion);
}
public OutboundConnectionSettings withTcpUserTimeoutInMS(int tcpUserTimeoutInMS)
{
return new OutboundConnectionSettings(authenticator, to, connectTo, encryption, framing,
socketSendBufferSizeInBytes, applicationSendQueueCapacityInBytes,
applicationSendQueueReserveEndpointCapacityInBytes, applicationSendQueueReserveGlobalCapacityInBytes,
tcpNoDelay, flushLowWaterMark, flushHighWaterMark, tcpConnectTimeoutInMS,
tcpUserTimeoutInMS, acceptVersions, from, socketFactory, callbacks, debug, endpointToVersion);
}
public OutboundConnectionSettings withAcceptVersions(AcceptVersions acceptVersions)
{
return new OutboundConnectionSettings(authenticator, to, connectTo, encryption, framing,
socketSendBufferSizeInBytes, applicationSendQueueCapacityInBytes,
applicationSendQueueReserveEndpointCapacityInBytes, applicationSendQueueReserveGlobalCapacityInBytes,
tcpNoDelay, flushLowWaterMark, flushHighWaterMark, tcpConnectTimeoutInMS,
tcpUserTimeoutInMS, acceptVersions, from, socketFactory, callbacks, debug, endpointToVersion);
}
public OutboundConnectionSettings withFrom(InetAddressAndPort from)
{
return new OutboundConnectionSettings(authenticator, to, connectTo, encryption, framing,
socketSendBufferSizeInBytes, applicationSendQueueCapacityInBytes,
applicationSendQueueReserveEndpointCapacityInBytes, applicationSendQueueReserveGlobalCapacityInBytes,
tcpNoDelay, flushLowWaterMark, flushHighWaterMark, tcpConnectTimeoutInMS,
tcpUserTimeoutInMS, acceptVersions, from, socketFactory, callbacks, debug, endpointToVersion);
}
public OutboundConnectionSettings withSocketFactory(SocketFactory socketFactory)
{
return new OutboundConnectionSettings(authenticator, to, connectTo, encryption, framing,
socketSendBufferSizeInBytes, applicationSendQueueCapacityInBytes,
applicationSendQueueReserveEndpointCapacityInBytes, applicationSendQueueReserveGlobalCapacityInBytes,
tcpNoDelay, flushLowWaterMark, flushHighWaterMark, tcpConnectTimeoutInMS,
tcpUserTimeoutInMS, acceptVersions, from, socketFactory, callbacks, debug, endpointToVersion);
}
public OutboundConnectionSettings withCallbacks(OutboundMessageCallbacks callbacks)
{
return new OutboundConnectionSettings(authenticator, to, connectTo, encryption, framing,
socketSendBufferSizeInBytes, applicationSendQueueCapacityInBytes,
applicationSendQueueReserveEndpointCapacityInBytes, applicationSendQueueReserveGlobalCapacityInBytes,
tcpNoDelay, flushLowWaterMark, flushHighWaterMark, tcpConnectTimeoutInMS,
tcpUserTimeoutInMS, acceptVersions, from, socketFactory, callbacks, debug, endpointToVersion);
}
public OutboundConnectionSettings withDebugCallbacks(OutboundDebugCallbacks debug)
{
return new OutboundConnectionSettings(authenticator, to, connectTo, encryption, framing,
socketSendBufferSizeInBytes, applicationSendQueueCapacityInBytes,
applicationSendQueueReserveEndpointCapacityInBytes, applicationSendQueueReserveGlobalCapacityInBytes,
tcpNoDelay, flushLowWaterMark, flushHighWaterMark, tcpConnectTimeoutInMS,
tcpUserTimeoutInMS, acceptVersions, from, socketFactory, callbacks, debug, endpointToVersion);
}
public OutboundConnectionSettings withDefaultReserveLimits()
{
Integer applicationReserveSendQueueEndpointCapacityInBytes = this.applicationSendQueueReserveEndpointCapacityInBytes;
ResourceLimits.Limit applicationReserveSendQueueGlobalCapacityInBytes = this.applicationSendQueueReserveGlobalCapacityInBytes;
if (applicationReserveSendQueueEndpointCapacityInBytes == null)
applicationReserveSendQueueEndpointCapacityInBytes = DatabaseDescriptor.getInternodeApplicationSendQueueReserveEndpointCapacityInBytes();
if (applicationReserveSendQueueGlobalCapacityInBytes == null)
applicationReserveSendQueueGlobalCapacityInBytes = MessagingService.instance().outboundGlobalReserveLimit;
return withApplicationReserveSendQueueCapacityInBytes(applicationReserveSendQueueEndpointCapacityInBytes, applicationReserveSendQueueGlobalCapacityInBytes);
}
public IInternodeAuthenticator authenticator()
{
return authenticator != null ? authenticator : DatabaseDescriptor.getInternodeAuthenticator();
}
public EndpointMessagingVersions endpointToVersion()
{
if (endpointToVersion == null)
return instance().versions;
return endpointToVersion;
}
public InetAddressAndPort from()
{
return from != null ? from : FBUtilities.getBroadcastAddressAndPort();
}
public OutboundDebugCallbacks debug()
{
return debug != null ? debug : OutboundDebugCallbacks.NONE;
}
public EncryptionOptions encryption()
{
return encryption != null ? encryption : defaultEncryptionOptions(to);
}
public SocketFactory socketFactory()
{
return socketFactory != null ? socketFactory : instance().socketFactory;
}
public OutboundMessageCallbacks callbacks()
{
return callbacks != null ? callbacks : instance().callbacks;
}
public int socketSendBufferSizeInBytes()
{
return socketSendBufferSizeInBytes != null ? socketSendBufferSizeInBytes
: DatabaseDescriptor.getInternodeSocketSendBufferSizeInBytes();
}
public int applicationSendQueueCapacityInBytes()
{
return applicationSendQueueCapacityInBytes != null ? applicationSendQueueCapacityInBytes
: DatabaseDescriptor.getInternodeApplicationSendQueueCapacityInBytes();
}
public ResourceLimits.Limit applicationSendQueueReserveGlobalCapacityInBytes()
{
return applicationSendQueueReserveGlobalCapacityInBytes != null ? applicationSendQueueReserveGlobalCapacityInBytes
: instance().outboundGlobalReserveLimit;
}
public int applicationSendQueueReserveEndpointCapacityInBytes()
{
return applicationSendQueueReserveEndpointCapacityInBytes != null ? applicationSendQueueReserveEndpointCapacityInBytes
: DatabaseDescriptor.getInternodeApplicationReceiveQueueReserveEndpointCapacityInBytes();
}
public int tcpConnectTimeoutInMS()
{
return tcpConnectTimeoutInMS != null ? tcpConnectTimeoutInMS
: DatabaseDescriptor.getInternodeTcpConnectTimeoutInMS();
}
public int tcpUserTimeoutInMS()
{
return tcpUserTimeoutInMS != null ? tcpUserTimeoutInMS
: DatabaseDescriptor.getInternodeTcpUserTimeoutInMS();
}
public boolean tcpNoDelay()
{
if (tcpNoDelay != null)
return tcpNoDelay;
if (isInLocalDC(getEndpointSnitch(), getBroadcastAddressAndPort(), to))
return INTRADC_TCP_NODELAY;
return DatabaseDescriptor.getInterDCTcpNoDelay();
}
public AcceptVersions acceptVersions(ConnectionCategory category)
{
return acceptVersions != null ? acceptVersions
: category.isStreaming()
? MessagingService.accept_streaming
: MessagingService.accept_messaging;
}
public OutboundConnectionSettings withLegacyPortIfNecessary(int messagingVersion)
{
return withConnectTo(maybeWithSecurePort(connectTo(), messagingVersion, withEncryption()));
}
public InetAddressAndPort connectTo()
{
InetAddressAndPort connectTo = this.connectTo;
if (connectTo == null)
connectTo = SystemKeyspace.getPreferredIP(to);
return connectTo;
}
public String connectToId()
{
return !to.equals(connectTo())
? to.toString()
: to.toString() + '(' + connectTo().toString() + ')';
}
public Framing framing(ConnectionCategory category)
{
if (framing != null)
return framing;
if (category.isStreaming())
return Framing.UNPROTECTED;
return shouldCompressConnection(getEndpointSnitch(), getBroadcastAddressAndPort(), to)
? Framing.LZ4 : Framing.CRC;
}
// note that connectTo is updated even if specified, in the case of pre40 messaging and using encryption (to update port)
public OutboundConnectionSettings withDefaults(ConnectionCategory category)
{
if (to == null)
throw new IllegalArgumentException();
return new OutboundConnectionSettings(authenticator(), to, connectTo(),
encryption(), framing(category),
socketSendBufferSizeInBytes(), applicationSendQueueCapacityInBytes(),
applicationSendQueueReserveEndpointCapacityInBytes(),
applicationSendQueueReserveGlobalCapacityInBytes(),
tcpNoDelay(), flushLowWaterMark, flushHighWaterMark,
tcpConnectTimeoutInMS(), tcpUserTimeoutInMS(), acceptVersions(category),
from(), socketFactory(), callbacks(), debug(), endpointToVersion());
}
private static boolean isInLocalDC(IEndpointSnitch snitch, InetAddressAndPort localHost, InetAddressAndPort remoteHost)
{
String remoteDC = snitch.getDatacenter(remoteHost);
String localDC = snitch.getDatacenter(localHost);
return remoteDC != null && remoteDC.equals(localDC);
}
@VisibleForTesting
static EncryptionOptions defaultEncryptionOptions(InetAddressAndPort endpoint)
{
ServerEncryptionOptions options = DatabaseDescriptor.getInternodeMessagingEncyptionOptions();
return options.shouldEncrypt(endpoint) ? options : null;
}
@VisibleForTesting
static boolean shouldCompressConnection(IEndpointSnitch snitch, InetAddressAndPort localHost, InetAddressAndPort remoteHost)
{
return (DatabaseDescriptor.internodeCompression() == Config.InternodeCompression.all)
|| ((DatabaseDescriptor.internodeCompression() == Config.InternodeCompression.dc) && !isInLocalDC(snitch, localHost, remoteHost));
}
private static InetAddressAndPort maybeWithSecurePort(InetAddressAndPort address, int messagingVersion, boolean isEncrypted)
{
if (!isEncrypted || messagingVersion >= VERSION_40)
return address;
// if we don't know the version of the peer, assume it is 4.0 (or higher) as the only time is would be lower
// (as in a 3.x version) is during a cluster upgrade (from 3.x to 4.0). In that case the outbound connection will
// unfortunately fail - however the peer should connect to this node (at some point), and once we learn it's version, it'll be
// in versions map. thus, when we attempt to reconnect to that node, we'll have the version and we can get the correct port.
// we will be able to remove this logic at 5.0.
// Also as of 4.0 we will propagate the "regular" port (which will support both SSL and non-SSL) via gossip so
// for SSL and version 4.0 always connect to the gossiped port because if SSL is enabled it should ALWAYS
// listen for SSL on the "regular" port.
return address.withPort(DatabaseDescriptor.getSSLStoragePort());
}
}