diff --git a/core/src/main/java/io/grpc/DnsNameResolver.java b/core/src/main/java/io/grpc/DnsNameResolver.java new file mode 100644 index 0000000000..2960a2a4ff --- /dev/null +++ b/core/src/main/java/io/grpc/DnsNameResolver.java @@ -0,0 +1,122 @@ +/* + * Copyright 2015, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.grpc; + +import com.google.common.base.Preconditions; + +import io.grpc.internal.GrpcUtil; +import io.grpc.internal.SharedResourceHolder; + +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.URI; +import java.util.ArrayList; +import java.util.concurrent.ExecutorService; + +import javax.annotation.Nullable; + +/** + * A DNS-based {@link NameResolver}. + * + * @see DnsNameResolverFactory + */ +final class DnsNameResolver extends NameResolver { + private final String authority; + private final String host; + private final int port; + private ExecutorService executor; + + DnsNameResolver(@Nullable String nsAuthority, String name, Attributes params) { + // TODO: if a DNS server is provided as nsAuthority, use it. + // https://www.captechconsulting.com/blogs/accessing-the-dusty-corners-of-dns-with-java + + // Must prepend a "//" to the name when constructing a URI, otherwise it will be treated as an + // opaque URI, thus the authority and host of the resulted URI would be null. + URI nameUri = URI.create("//" + name); + authority = Preconditions.checkNotNull(nameUri.getAuthority(), + "nameUri (%s) doesn't have an authority", nameUri); + host = Preconditions.checkNotNull(nameUri.getHost(), "host"); + if (nameUri.getPort() == -1) { + Integer defaultPort = params.get(NameResolver.Factory.PARAMS_DEFAULT_PORT); + if (defaultPort != null) { + port = defaultPort; + } else { + throw new IllegalArgumentException( + "name '" + name + "' doesn't contain a port, and default port is not set in params"); + } + } else { + port = nameUri.getPort(); + } + } + + @Override + public String getServiceAuthority() { + return authority; + } + + @Override + public synchronized void start(final Listener listener) { + Preconditions.checkState(executor == null, "already started"); + executor = SharedResourceHolder.get(GrpcUtil.SHARED_CHANNEL_EXECUTOR); + executor.execute(new Runnable() { + @Override + public void run() { + InetAddress[] inetAddrs; + try { + inetAddrs = InetAddress.getAllByName(host); + } catch (Exception e) { + listener.onError(Status.UNAVAILABLE.withCause(e)); + return; + } + ArrayList servers + = new ArrayList(inetAddrs.length); + for (int i = 0; i < inetAddrs.length; i++) { + InetAddress inetAddr = inetAddrs[i]; + servers.add( + new ResolvedServerInfo(new InetSocketAddress(inetAddr, port), Attributes.EMPTY)); + } + listener.onUpdate(servers, Attributes.EMPTY); + } + }); + } + + @Override + public synchronized void shutdown() { + if (executor != null) { + executor = SharedResourceHolder.release(GrpcUtil.SHARED_CHANNEL_EXECUTOR, executor); + } + } + + int getPort() { + return port; + } +} diff --git a/core/src/main/java/io/grpc/DnsNameResolverFactory.java b/core/src/main/java/io/grpc/DnsNameResolverFactory.java index 0c3e2f6f80..5af73f828f 100644 --- a/core/src/main/java/io/grpc/DnsNameResolverFactory.java +++ b/core/src/main/java/io/grpc/DnsNameResolverFactory.java @@ -33,19 +33,10 @@ package io.grpc; import com.google.common.base.Preconditions; -import io.grpc.internal.GrpcUtil; -import io.grpc.internal.SharedResourceHolder; - -import java.net.InetAddress; -import java.net.InetSocketAddress; import java.net.URI; -import java.util.ArrayList; -import java.util.concurrent.ExecutorService; - -import javax.annotation.Nullable; /** - * A factory for DNS-based {@link NameResolver}s. + * A factory for {@link DnsNameResolver}. * *

It resolves a target URI whose scheme is {@code "dns"}. The (optional) authority of the target * URI is reserved for the address of alternative DNS server (not implemented yet). The path of the @@ -83,72 +74,4 @@ public final class DnsNameResolverFactory extends NameResolver.Factory { public static DnsNameResolverFactory getInstance() { return instance; } - - private static class DnsNameResolver extends NameResolver { - private final String authority; - private final String host; - private final int port; - private ExecutorService executor; - - DnsNameResolver(@Nullable String nsAuthority, String name, Attributes params) { - // TODO: if a DNS server is provided as nsAuthority, use it. - // https://www.captechconsulting.com/blogs/accessing-the-dusty-corners-of-dns-with-java - - // Must prepend a "//" to the name when constructing a URI, otherwise - // the authority and host of the resulted URI would be null. - URI nameUri = URI.create("//" + name); - authority = Preconditions.checkNotNull(nameUri.getAuthority(), - "nameUri (%s) doesn't have an authority", nameUri); - host = Preconditions.checkNotNull(nameUri.getHost(), "host"); - if (nameUri.getPort() == -1) { - Integer defaultPort = params.get(NameResolver.Factory.PARAMS_DEFAULT_PORT); - if (defaultPort != null) { - port = defaultPort; - } else { - throw new IllegalArgumentException( - "name '" + name + "' doesn't contain a port, and default port is not set in params"); - } - } else { - port = nameUri.getPort(); - } - } - - @Override - public String getServiceAuthority() { - return authority; - } - - @Override - public synchronized void start(final Listener listener) { - Preconditions.checkState(executor == null, "already started"); - executor = SharedResourceHolder.get(GrpcUtil.SHARED_CHANNEL_EXECUTOR); - executor.execute(new Runnable() { - @Override - public void run() { - InetAddress[] inetAddrs; - try { - inetAddrs = InetAddress.getAllByName(host); - } catch (Exception e) { - listener.onError(Status.UNAVAILABLE.withCause(e)); - return; - } - ArrayList servers - = new ArrayList(inetAddrs.length); - for (int i = 0; i < inetAddrs.length; i++) { - InetAddress inetAddr = inetAddrs[i]; - servers.add( - new ResolvedServerInfo(new InetSocketAddress(inetAddr, port), Attributes.EMPTY)); - } - listener.onUpdate(servers, Attributes.EMPTY); - } - }); - } - - @Override - public synchronized void shutdown() { - if (executor != null) { - executor = SharedResourceHolder.release(GrpcUtil.SHARED_CHANNEL_EXECUTOR, executor); - } - } - } } diff --git a/core/src/main/java/io/grpc/ManagedChannelBuilder.java b/core/src/main/java/io/grpc/ManagedChannelBuilder.java index 7e2cd5c582..5d8ca36518 100644 --- a/core/src/main/java/io/grpc/ManagedChannelBuilder.java +++ b/core/src/main/java/io/grpc/ManagedChannelBuilder.java @@ -46,19 +46,22 @@ public abstract class ManagedChannelBuilder> /** * Creates a channel with a target string, which can be either a valid {@link - * NameResolver}-compliant URI, or a HOST:PORT string. + * NameResolver}-compliant URI, or an authority string. * - *

Example {@code NameResolver}-compliant URIs: + *

A {@code NameResolver}-compliant URI is an aboslute hierarchical URI as defined by {@link + * java.net.URI}. Example URIs: *

* - *

Example HOST:PORT strings, which will be converted to {@code NameResolver}-compliant URIs by - * prepending {@code "dns:///"}. + *

An authority string will be converted to a {@code NameResolver}-compliant URI, which has + * {@code "dns"} as the scheme, no authority, and the original authority string as its path after + * properly escaped. Example authority strings: *