Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Change how BoltServerAddress equality works #592

Merged
merged 2 commits into from
Apr 18, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,15 @@
import java.net.SocketAddress;
import java.net.URI;
import java.net.UnknownHostException;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.neo4j.driver.v1.net.ServerAddress;

import static java.util.Objects.requireNonNull;
import static java.util.stream.Collectors.toList;

/**
* Holds a host and port pair that denotes a Bolt server address.
Expand All @@ -37,11 +41,12 @@ public class BoltServerAddress implements ServerAddress
public static final int DEFAULT_PORT = 7687;
public static final BoltServerAddress LOCAL_DEFAULT = new BoltServerAddress( "localhost", DEFAULT_PORT );

private final String originalHost; // This keeps the original host name provided by the user.
private final String host; // This could either be the same as originalHost or it is an IP address resolved from the original host.
private final int port;
private final String stringValue;

private InetAddress resolved;

public BoltServerAddress( String address )
{
this( uriFrom( address ) );
Expand All @@ -54,15 +59,15 @@ public BoltServerAddress( URI uri )

public BoltServerAddress( String host, int port )
{
this( host, host, port );
this( host, null, port );
}

public BoltServerAddress( String originalHost, String host, int port )
private BoltServerAddress( String host, InetAddress resolved, int port )
{
this.originalHost = requireNonNull( originalHost, "original host" );
this.host = requireNonNull( host, "host" );
this.resolved = resolved;
this.port = requireValidPort( port );
this.stringValue = String.format( "%s:%d", host, port );
this.stringValue = resolved != null ? String.format( "%s(%s):%d", host, resolved.getHostAddress(), port ) : String.format( "%s:%d", host, port );
}

public static BoltServerAddress from( ServerAddress address )
Expand All @@ -84,13 +89,13 @@ public boolean equals( Object o )
return false;
}
BoltServerAddress that = (BoltServerAddress) o;
return port == that.port && originalHost.equals( that.originalHost ) && host.equals( that.host );
return port == that.port && host.equals( that.host );
}

@Override
public int hashCode()
{
return Objects.hash( originalHost, host, port );
return Objects.hash( host, port );
}

@Override
Expand All @@ -108,38 +113,39 @@ public String toString()
*/
public SocketAddress toSocketAddress()
{
return new InetSocketAddress( host, port );
return resolved == null ? new InetSocketAddress( host, port ) : new InetSocketAddress( resolved, port );
}

/**
* Resolve the host name down to an IP address, if not already resolved.
* Resolve the host name down to an IP address
*
* @return this instance if already resolved, otherwise a new address instance
* @return a new address instance
* @throws UnknownHostException if no IP address for the host could be found
* @see InetAddress#getByName(String)
*/
public BoltServerAddress resolve() throws UnknownHostException
{
String ipAddress = InetAddress.getByName( host ).getHostAddress();
if ( ipAddress.equals( host ) )
{
return this;
}
else
{
return new BoltServerAddress( host, ipAddress, port );
}
return new BoltServerAddress( host, InetAddress.getByName( host ), port );
}

@Override
public String host()
/**
* Resolve the host name down to all IP addresses that can be resolved to
*
* @return an array of new address instances that holds resolved addresses
* @throws UnknownHostException if no IP address for the host could be found
* @see InetAddress#getAllByName(String)
*/
public List<BoltServerAddress> resolveAll() throws UnknownHostException
{
return host;
return Stream.of( InetAddress.getAllByName( host ) )
.map( address -> new BoltServerAddress( host, address, port ) )
.collect( toList() );
}

public String originalHost()
@Override
public String host()
{
return originalHost;
return host;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
import org.neo4j.driver.internal.async.ChannelConnectorImpl;
import org.neo4j.driver.internal.async.pool.ConnectionPoolImpl;
import org.neo4j.driver.internal.async.pool.PoolSettings;
import org.neo4j.driver.internal.cluster.DnsResolver;
import org.neo4j.driver.internal.cluster.IdentityResolver;
import org.neo4j.driver.internal.cluster.RoutingContext;
import org.neo4j.driver.internal.cluster.RoutingSettings;
import org.neo4j.driver.internal.cluster.loadbalancing.LeastConnectedLoadBalancingStrategy;
Expand Down Expand Up @@ -62,6 +62,7 @@
import org.neo4j.driver.v1.net.ServerAddressResolver;

import static java.lang.String.format;
import static org.neo4j.driver.internal.cluster.IdentityResolver.IDENTITY_RESOLVER;
import static org.neo4j.driver.internal.metrics.InternalAbstractMetrics.DEV_NULL_METRICS;
import static org.neo4j.driver.internal.metrics.spi.Metrics.isMetricsEnabled;
import static org.neo4j.driver.internal.security.SecurityPlan.insecure;
Expand Down Expand Up @@ -109,7 +110,7 @@ protected ConnectionPool createConnectionPool( AuthToken authToken, SecurityPlan

protected static InternalAbstractMetrics createDriverMetrics( Config config )
{
if( isMetricsEnabled() )
if ( isMetricsEnabled() )
{
return new InternalMetrics( config );
}
Expand Down Expand Up @@ -160,7 +161,7 @@ protected InternalDriver createDirectDriver( SecurityPlan securityPlan, BoltServ
{
ConnectionProvider connectionProvider = new DirectConnectionProvider( address, connectionPool );
SessionFactory sessionFactory = createSessionFactory( connectionProvider, retryLogic, config );
InternalDriver driver = createDriver(securityPlan, sessionFactory, metrics, config);
InternalDriver driver = createDriver( securityPlan, sessionFactory, metrics, config );
Logger log = config.logging().getLog( Driver.class.getSimpleName() );
log.info( "Direct driver instance %s created for server address %s", driver.hashCode(), address );
return driver;
Expand All @@ -181,7 +182,7 @@ protected InternalDriver createRoutingDriver( SecurityPlan securityPlan, BoltSer
ConnectionProvider connectionProvider = createLoadBalancer( address, connectionPool, eventExecutorGroup,
config, routingSettings );
SessionFactory sessionFactory = createSessionFactory( connectionProvider, retryLogic, config );
InternalDriver driver = createDriver(securityPlan, sessionFactory, metrics, config);
InternalDriver driver = createDriver( securityPlan, sessionFactory, metrics, config );
Logger log = config.logging().getLog( Driver.class.getSimpleName() );
log.info( "Routing driver instance %s created for server address %s", driver.hashCode(), address );
return driver;
Expand Down Expand Up @@ -228,7 +229,7 @@ private static LoadBalancingStrategy createLoadBalancingStrategy( Config config,
private static ServerAddressResolver createResolver( Config config )
{
ServerAddressResolver configuredResolver = config.resolver();
return configuredResolver != null ? configuredResolver : new DnsResolver( config.logging() );
return configuredResolver != null ? configuredResolver : IDENTITY_RESOLVER;
}

/**
Expand Down Expand Up @@ -303,12 +304,12 @@ private static SecurityPlan createSecurityPlanImpl( BoltServerAddress address, C
case TRUST_ON_FIRST_USE:
logger.warn(
"Option `TRUST_ON_FIRST_USE` has been deprecated and will be removed in a future " +
"version of the driver. Please switch to use `TRUST_ALL_CERTIFICATES` instead." );
"version of the driver. Please switch to use `TRUST_ALL_CERTIFICATES` instead." );
return SecurityPlan.forTrustOnFirstUse( trustStrategy.certFile(), hostnameVerificationEnabled, address, logger );
case TRUST_SIGNED_CERTIFICATES:
logger.warn(
"Option `TRUST_SIGNED_CERTIFICATE` has been deprecated and will be removed in a future " +
"version of the driver. Please switch to use `TRUST_CUSTOM_CA_SIGNED_CERTIFICATES` instead." );
"version of the driver. Please switch to use `TRUST_CUSTOM_CA_SIGNED_CERTIFICATES` instead." );
// intentional fallthrough

case TRUST_CUSTOM_CA_SIGNED_CERTIFICATES:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ private SslHandler createSslHandler()
private SSLEngine createSslEngine()
{
SSLContext sslContext = securityPlan.sslContext();
SSLEngine sslEngine = sslContext.createSSLEngine( address.originalHost(), address.port() );
SSLEngine sslEngine = sslContext.createSSLEngine( address.host(), address.port() );
sslEngine.setUseClientMode( true );
if ( securityPlan.requiresHostnameVerification() )
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,42 +18,25 @@
*/
package org.neo4j.driver.internal.cluster;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Set;
import java.util.stream.Stream;

import org.neo4j.driver.internal.BoltServerAddress;
import org.neo4j.driver.v1.Logger;
import org.neo4j.driver.v1.Logging;
import org.neo4j.driver.v1.net.ServerAddress;
import org.neo4j.driver.v1.net.ServerAddressResolver;

import static java.util.Collections.singleton;
import static java.util.stream.Collectors.toSet;

public class DnsResolver implements ServerAddressResolver
public class IdentityResolver implements ServerAddressResolver
{
private final Logger logger;
public static final IdentityResolver IDENTITY_RESOLVER = new IdentityResolver();

public DnsResolver( Logging logging )
private IdentityResolver()
{
this.logger = logging.getLog( DnsResolver.class.getSimpleName() );

}

@Override
public Set<ServerAddress> resolve( ServerAddress initialRouter )
{
try
{
return Stream.of( InetAddress.getAllByName( initialRouter.host() ) )
.map( address -> new BoltServerAddress( initialRouter.host(), address.getHostAddress(), initialRouter.port() ) )
.collect( toSet() );
}
catch ( UnknownHostException e )
{
logger.error( "Failed to resolve address `" + initialRouter + "` to IPs due to error: " + e.getMessage(), e );
return singleton( initialRouter );
}
return singleton( initialRouter );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,16 @@

import io.netty.util.concurrent.EventExecutorGroup;

import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;

import org.neo4j.driver.internal.BoltServerAddress;
import org.neo4j.driver.internal.spi.Connection;
Expand All @@ -35,10 +38,12 @@
import org.neo4j.driver.v1.Logger;
import org.neo4j.driver.v1.exceptions.SecurityException;
import org.neo4j.driver.v1.exceptions.ServiceUnavailableException;
import org.neo4j.driver.v1.net.ServerAddress;
import org.neo4j.driver.v1.net.ServerAddressResolver;

import static java.lang.String.format;
import static java.util.Collections.emptySet;
import static java.util.Collections.singleton;
import static java.util.concurrent.CompletableFuture.completedFuture;
import static java.util.stream.Collectors.toList;
import static org.neo4j.driver.internal.util.Futures.completedWithNull;
Expand Down Expand Up @@ -270,7 +275,20 @@ private List<BoltServerAddress> resolve( BoltServerAddress address )
{
return resolver.resolve( address )
.stream()
.map( BoltServerAddress::from )
.flatMap( resolved -> resolveAll( BoltServerAddress.from( resolved ) ) )
.collect( toList() ); // collect to list to preserve the order
}

private Stream<BoltServerAddress> resolveAll( BoltServerAddress address )
{
try
{
return address.resolveAll().stream();
}
catch ( UnknownHostException e )
{
logger.error( "Failed to resolve address `" + address + "` to IPs due to error: " + e.getMessage(), e );
return Stream.of( address );
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ public String toString()

static String serverAddressToUniqueName( BoltServerAddress serverAddress )
{
return serverAddress.toString();
return String.format( "%s:%d", serverAddress.host(), serverAddress.port() );
}

private ConnectionPoolMetricsListener poolMetrics( BoltServerAddress serverAddress )
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,6 @@ public interface ServerAddress
*/
static ServerAddress of( String host, int port )
{
return new BoltServerAddress( host, host, port );
return new BoltServerAddress( host, port );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ void shouldUpdateChannelAttributes()
@Test
void shouldIncludeSniHostName() throws Exception
{
BoltServerAddress address = new BoltServerAddress( "database.neo4j.com", "10.0.0.18", 8989 );
BoltServerAddress address = new BoltServerAddress( "database.neo4j.com", 8989 );
NettyChannelInitializer initializer = new NettyChannelInitializer( address, trustAllCertificates(), 10000, Clock.SYSTEM, DEV_NULL_LOGGING );

initializer.initChannel( channel );
Expand All @@ -125,7 +125,7 @@ void shouldIncludeSniHostName() throws Exception
List<SNIServerName> sniServerNames = sslParameters.getServerNames();
assertThat( sniServerNames, hasSize( 1 ) );
assertThat( sniServerNames.get( 0 ), instanceOf( SNIHostName.class ) );
assertThat( ((SNIHostName) sniServerNames.get( 0 )).getAsciiName(), equalTo( address.originalHost() ) );
assertThat( ((SNIHostName) sniServerNames.get( 0 )).getAsciiName(), equalTo( address.host() ) );
}

@Test
Expand Down
Loading