From f118f6410ba9b8d37608d12fd70d633f05bf3730 Mon Sep 17 00:00:00 2001 From: moparisthebest Date: Wed, 13 Mar 2019 00:01:48 -0400 Subject: [PATCH] Re-factor Listeners and Resolvers to use ServiceLoader protocol discovery --- .../dns/listen/DefaultServices.java | 19 ++++++++++++ .../moparisthebest/dns/listen/Listener.java | 29 ++++++----------- .../moparisthebest/dns/listen/Services.java | 10 ++++++ .../com/moparisthebest/dns/net/ParsedUrl.java | 10 ++++-- .../AbstractQueueProcessingResolver.java | 11 ------- .../dns/resolve/DefaultServices.java | 19 ++++++++++++ .../DelegatingQueueProcessingResolver.java | 25 +++++++++++++++ .../dns/resolve/HttpResolver.java | 5 ++- .../dns/resolve/QueueProcessingResolver.java | 16 +--------- .../moparisthebest/dns/resolve/Resolver.java | 31 ++++++++++++++----- .../moparisthebest/dns/resolve/Services.java | 7 +++++ .../dns/resolve/SocketResolver.java | 5 ++- .../com.moparisthebest.dns.listen.Services | 1 + .../com.moparisthebest.dns.resolve.Services | 1 + 14 files changed, 128 insertions(+), 61 deletions(-) create mode 100644 jDnsProxy/src/main/java/com/moparisthebest/dns/listen/DefaultServices.java create mode 100644 jDnsProxy/src/main/java/com/moparisthebest/dns/listen/Services.java create mode 100644 jDnsProxy/src/main/java/com/moparisthebest/dns/resolve/DefaultServices.java create mode 100644 jDnsProxy/src/main/java/com/moparisthebest/dns/resolve/DelegatingQueueProcessingResolver.java create mode 100644 jDnsProxy/src/main/java/com/moparisthebest/dns/resolve/Services.java create mode 100644 jDnsProxy/src/main/resources/META-INF/services/com.moparisthebest.dns.listen.Services create mode 100644 jDnsProxy/src/main/resources/META-INF/services/com.moparisthebest.dns.resolve.Services diff --git a/jDnsProxy/src/main/java/com/moparisthebest/dns/listen/DefaultServices.java b/jDnsProxy/src/main/java/com/moparisthebest/dns/listen/DefaultServices.java new file mode 100644 index 0000000..aa60921 --- /dev/null +++ b/jDnsProxy/src/main/java/com/moparisthebest/dns/listen/DefaultServices.java @@ -0,0 +1,19 @@ +package com.moparisthebest.dns.listen; + +import com.moparisthebest.dns.net.ParsedUrl; +import com.moparisthebest.dns.resolve.Resolver; + +import java.util.concurrent.ExecutorService; + +public class DefaultServices implements Services { + @Override + public Listener getListener(ParsedUrl parsedUrl, final Resolver resolver, final ExecutorService executor) { + switch(parsedUrl.getProtocol()) { + case "tcp": + return new TcpAsync(parsedUrl.getAddr(), resolver, executor); + case "udp": + return new UdpSync(parsedUrl.getAddr(), resolver, executor); + } + return null; + } +} diff --git a/jDnsProxy/src/main/java/com/moparisthebest/dns/listen/Listener.java b/jDnsProxy/src/main/java/com/moparisthebest/dns/listen/Listener.java index df6cf96..ad392a4 100644 --- a/jDnsProxy/src/main/java/com/moparisthebest/dns/listen/Listener.java +++ b/jDnsProxy/src/main/java/com/moparisthebest/dns/listen/Listener.java @@ -6,30 +6,21 @@ import com.moparisthebest.dns.resolve.Resolver; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.util.Arrays; +import java.util.ServiceLoader; import java.util.concurrent.ExecutorService; public interface Listener extends Runnable, AutoCloseable { - public static Listener of(final String listener, final Resolver resolver, final ExecutorService executor) { - /* - listener = listener.trim().toLowerCase(); - final String[] hostPort = listener.substring(6).split(":"); - //System.out.println("hostPort: " + Arrays.toString(hostPort)); - final SocketAddress socketAddress = new InetSocketAddress(hostPort[0], Integer.parseInt(hostPort[1])); - //System.out.println("socketAddress: " + socketAddress); - if(listener.startsWith("tcp://")) { - return new TcpAsync(socketAddress, resolver, executor); - } else if(listener.startsWith("udp://")) { - return new UdpSync(socketAddress, resolver, executor); - } - */ + + ServiceLoader services = ServiceLoader.load(Services.class); + + static Listener of(final String listener, final Resolver resolver, final ExecutorService executor) { final ParsedUrl parsedUrl = ParsedUrl.of(listener); - switch(parsedUrl.getProtocol()) { - case "tcp": - return new TcpAsync(parsedUrl.getAddr(), resolver, executor); - case "udp": - return new UdpSync(parsedUrl.getAddr(), resolver, executor); + for (final Services s : services) { + final Listener ret = s.getListener(parsedUrl, resolver, executor); + if (ret != null) + return ret; } - throw new IllegalArgumentException("invalid listener format"); + throw new IllegalArgumentException("unhandled listener format: " + listener); } public static Listener ofAndStart(final String listener, final Resolver resolver, final ExecutorService executor) { diff --git a/jDnsProxy/src/main/java/com/moparisthebest/dns/listen/Services.java b/jDnsProxy/src/main/java/com/moparisthebest/dns/listen/Services.java new file mode 100644 index 0000000..d6cd2af --- /dev/null +++ b/jDnsProxy/src/main/java/com/moparisthebest/dns/listen/Services.java @@ -0,0 +1,10 @@ +package com.moparisthebest.dns.listen; + +import com.moparisthebest.dns.net.ParsedUrl; +import com.moparisthebest.dns.resolve.Resolver; + +import java.util.concurrent.ExecutorService; + +public interface Services { + Listener getListener(ParsedUrl parsedUrl, Resolver resolver, ExecutorService executor); +} diff --git a/jDnsProxy/src/main/java/com/moparisthebest/dns/net/ParsedUrl.java b/jDnsProxy/src/main/java/com/moparisthebest/dns/net/ParsedUrl.java index b09bb4f..fe90a6e 100644 --- a/jDnsProxy/src/main/java/com/moparisthebest/dns/net/ParsedUrl.java +++ b/jDnsProxy/src/main/java/com/moparisthebest/dns/net/ParsedUrl.java @@ -11,13 +11,15 @@ import java.util.*; public class ParsedUrl { + private final String urlStr; private final SocketAddress addr; private final URI uri; // minus # private final Map props; // after #, split by ; private final Proxy proxy; private final SSLSocketFactory sslSocketFactory; - public ParsedUrl(final SocketAddress addr, final URI uri, final Map props, final Proxy proxy, final SSLSocketFactory sslSocketFactory) { + public ParsedUrl(final String urlStr, final SocketAddress addr, final URI uri, final Map props, final Proxy proxy, final SSLSocketFactory sslSocketFactory) { + this.urlStr = urlStr; this.addr = addr; this.uri = uri; this.props = props; @@ -70,7 +72,7 @@ public class ParsedUrl { } if(sslSocketFactory == null && url.getScheme().equals("tls")) sslSocketFactory = (SSLSocketFactory) SSLSocketFactory.getDefault(); - return new ParsedUrl(addr, url, props, proxy, sslSocketFactory); + return new ParsedUrl(urlStr, addr, url, props, proxy, sslSocketFactory); } catch (Exception e) { if (e instanceof RuntimeException) throw (RuntimeException) e; @@ -104,6 +106,10 @@ public class ParsedUrl { return toUrlRemoveRef(uri); } + public String getUrlStr() { + return urlStr; + } + public SocketAddress getAddr() { return addr; } diff --git a/jDnsProxy/src/main/java/com/moparisthebest/dns/resolve/AbstractQueueProcessingResolver.java b/jDnsProxy/src/main/java/com/moparisthebest/dns/resolve/AbstractQueueProcessingResolver.java index ecaf7f3..97a65a3 100644 --- a/jDnsProxy/src/main/java/com/moparisthebest/dns/resolve/AbstractQueueProcessingResolver.java +++ b/jDnsProxy/src/main/java/com/moparisthebest/dns/resolve/AbstractQueueProcessingResolver.java @@ -29,17 +29,6 @@ public abstract class AbstractQueueProcessingResolver implements QueueProcessing executor.execute(this); } - @Override - public CompletableFuture resolveAsync(final E requestResponse) { - return null; - /* - return CompletableFuture.supplyAsync(() -> { - requestResponse.setResponse(resolve(requestResponse.getRequest())); - return requestResponse; - }, executor); - */ - } - @Override public void run() { thisThread = Thread.currentThread(); diff --git a/jDnsProxy/src/main/java/com/moparisthebest/dns/resolve/DefaultServices.java b/jDnsProxy/src/main/java/com/moparisthebest/dns/resolve/DefaultServices.java new file mode 100644 index 0000000..df69bf9 --- /dev/null +++ b/jDnsProxy/src/main/java/com/moparisthebest/dns/resolve/DefaultServices.java @@ -0,0 +1,19 @@ +package com.moparisthebest.dns.resolve; + +import com.moparisthebest.dns.net.ParsedUrl; + +public class DefaultServices implements Services { + @Override + public Resolver getResolver(ParsedUrl parsedUrl) { + final int connectTimeout = Integer.parseInt(parsedUrl.getProps().getOrDefault("connectTimeout", "500")); + switch(parsedUrl.getProtocol()) { + case "tcp": + case "tls": + return new SocketResolver(parsedUrl.getAddr(), connectTimeout, parsedUrl.getProxy(), parsedUrl.getSslSocketFactory()); + case "http": + case "https": + return new HttpResolver(parsedUrl.getUrlWithoutFragment(), connectTimeout, parsedUrl.getProxy(), parsedUrl.getSslSocketFactory()); + } + return null; + } +} diff --git a/jDnsProxy/src/main/java/com/moparisthebest/dns/resolve/DelegatingQueueProcessingResolver.java b/jDnsProxy/src/main/java/com/moparisthebest/dns/resolve/DelegatingQueueProcessingResolver.java new file mode 100644 index 0000000..fd03ec1 --- /dev/null +++ b/jDnsProxy/src/main/java/com/moparisthebest/dns/resolve/DelegatingQueueProcessingResolver.java @@ -0,0 +1,25 @@ +package com.moparisthebest.dns.resolve; + +import com.moparisthebest.dns.dto.Packet; + +import java.util.concurrent.CompletableFuture; + +public class DelegatingQueueProcessingResolver extends AbstractQueueProcessingResolver { + + private final Resolver delegate; + + public DelegatingQueueProcessingResolver(final int maxRetries, final String name, final Resolver delegate) { + super(maxRetries, name); + this.delegate = delegate; + } + + @Override + public CompletableFuture resolveAsync(final E requestResponse) { + return delegate.resolveAsync(requestResponse); + } + + @Override + public Packet resolve(final Packet request) throws Exception { + return delegate.resolve(request); + } +} diff --git a/jDnsProxy/src/main/java/com/moparisthebest/dns/resolve/HttpResolver.java b/jDnsProxy/src/main/java/com/moparisthebest/dns/resolve/HttpResolver.java index 15b0a30..40176b7 100644 --- a/jDnsProxy/src/main/java/com/moparisthebest/dns/resolve/HttpResolver.java +++ b/jDnsProxy/src/main/java/com/moparisthebest/dns/resolve/HttpResolver.java @@ -9,7 +9,7 @@ import java.net.*; import static com.moparisthebest.dns.Util.readPacket; -public class HttpResolver extends AbstractQueueProcessingResolver { +public class HttpResolver implements Resolver { private final OpenConnection openConnection; private final int connectTimeout; private final int readTimeout = 4000; @@ -18,8 +18,7 @@ public class HttpResolver extends AbstractQueueProcessingResolver { HttpURLConnection open() throws Exception; } - public HttpResolver(final int maxRetries, final String name, final URL url, final int connectTimeout, final Proxy proxy, final SSLSocketFactory sslSocketFactory) { - super(maxRetries, name); + public HttpResolver(final URL url, final int connectTimeout, final Proxy proxy, final SSLSocketFactory sslSocketFactory) { this.connectTimeout = connectTimeout; if(proxy == null && sslSocketFactory == null) { openConnection = () -> (HttpURLConnection) url.openConnection(); diff --git a/jDnsProxy/src/main/java/com/moparisthebest/dns/resolve/QueueProcessingResolver.java b/jDnsProxy/src/main/java/com/moparisthebest/dns/resolve/QueueProcessingResolver.java index e3c4338..459e065 100644 --- a/jDnsProxy/src/main/java/com/moparisthebest/dns/resolve/QueueProcessingResolver.java +++ b/jDnsProxy/src/main/java/com/moparisthebest/dns/resolve/QueueProcessingResolver.java @@ -1,14 +1,9 @@ package com.moparisthebest.dns.resolve; -import com.moparisthebest.dns.dto.Packet; import com.moparisthebest.dns.net.ParsedUrl; -import javax.net.SocketFactory; -import java.net.InetSocketAddress; -import java.net.SocketAddress; import java.util.Map; import java.util.concurrent.BlockingQueue; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; public interface QueueProcessingResolver extends Resolver, Runnable, AutoCloseable { @@ -27,15 +22,6 @@ public interface QueueProcessingResolver extends Resolver, Runnable, AutoCloseab String name = parsedUrl.getProps().get("name"); if(name == null) name = parsedUrl.getUri().toString(); - final int connectTimeout = Integer.parseInt(parsedUrl.getProps().getOrDefault("connectTimeout", "500")); - switch(parsedUrl.getProtocol()) { - case "tcp": - case "tls": - return new SocketResolver(maxRetries, name, parsedUrl.getAddr(), connectTimeout, parsedUrl.getProxy(), parsedUrl.getSslSocketFactory()); - case "http": - case "https": - return new HttpResolver(maxRetries, name, parsedUrl.getUrlWithoutFragment(), connectTimeout, parsedUrl.getProxy(), parsedUrl.getSslSocketFactory()); - } - throw new IllegalArgumentException("invalid listener format"); + return new DelegatingQueueProcessingResolver(maxRetries, name, Resolver.of(parsedUrl)); } } diff --git a/jDnsProxy/src/main/java/com/moparisthebest/dns/resolve/Resolver.java b/jDnsProxy/src/main/java/com/moparisthebest/dns/resolve/Resolver.java index bf393f8..187db9b 100644 --- a/jDnsProxy/src/main/java/com/moparisthebest/dns/resolve/Resolver.java +++ b/jDnsProxy/src/main/java/com/moparisthebest/dns/resolve/Resolver.java @@ -1,17 +1,32 @@ package com.moparisthebest.dns.resolve; import com.moparisthebest.dns.dto.Packet; -import com.moparisthebest.dns.listen.Listener; -import com.moparisthebest.dns.listen.TcpAsync; -import com.moparisthebest.dns.listen.UdpSync; +import com.moparisthebest.dns.net.ParsedUrl; -import javax.net.SocketFactory; -import java.net.InetSocketAddress; -import java.net.SocketAddress; +import java.util.ServiceLoader; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutorService; public interface Resolver { - CompletableFuture resolveAsync(E requestResponse); + default CompletableFuture resolveAsync(E requestResponse) { + return null; + /* + return CompletableFuture.supplyAsync(() -> { + requestResponse.setResponse(resolve(requestResponse.getRequest())); + return requestResponse; + }, executor); + */ + } + Packet resolve(Packet request) throws Exception; + + ServiceLoader services = ServiceLoader.load(Services.class); + + static Resolver of(final ParsedUrl parsedUrl) { + for (final Services s : services) { + final Resolver ret = s.getResolver(parsedUrl); + if (ret != null) + return ret; + } + throw new IllegalArgumentException("unhandled resolver format: " + parsedUrl.getUrlStr()); + } } diff --git a/jDnsProxy/src/main/java/com/moparisthebest/dns/resolve/Services.java b/jDnsProxy/src/main/java/com/moparisthebest/dns/resolve/Services.java new file mode 100644 index 0000000..8340951 --- /dev/null +++ b/jDnsProxy/src/main/java/com/moparisthebest/dns/resolve/Services.java @@ -0,0 +1,7 @@ +package com.moparisthebest.dns.resolve; + +import com.moparisthebest.dns.net.ParsedUrl; + +public interface Services { + Resolver getResolver(ParsedUrl parsedUrl); +} diff --git a/jDnsProxy/src/main/java/com/moparisthebest/dns/resolve/SocketResolver.java b/jDnsProxy/src/main/java/com/moparisthebest/dns/resolve/SocketResolver.java index 4db1e1b..0b58772 100644 --- a/jDnsProxy/src/main/java/com/moparisthebest/dns/resolve/SocketResolver.java +++ b/jDnsProxy/src/main/java/com/moparisthebest/dns/resolve/SocketResolver.java @@ -14,7 +14,7 @@ import static com.moparisthebest.dns.Util.readTcpPacket; import static com.moparisthebest.dns.Util.tryClose; import static com.moparisthebest.dns.Util.writeTcpPacket; -public class SocketResolver extends AbstractQueueProcessingResolver { +public class SocketResolver implements Resolver { private final OpenSocket openConnection; private final int readTimeout = 4000; @@ -22,8 +22,7 @@ public class SocketResolver extends AbstractQueueProcessingResolver { Socket open() throws Exception; } - public SocketResolver(final int maxRetries, final String name, final SocketAddress endpoint, final int connectTimeout, final Proxy proxy, final SSLSocketFactory sslSocketFactory) { - super(maxRetries, name); + public SocketResolver(final SocketAddress endpoint, final int connectTimeout, final Proxy proxy, final SSLSocketFactory sslSocketFactory) { if(proxy == null && sslSocketFactory == null) { openConnection = () -> { Socket s = null; diff --git a/jDnsProxy/src/main/resources/META-INF/services/com.moparisthebest.dns.listen.Services b/jDnsProxy/src/main/resources/META-INF/services/com.moparisthebest.dns.listen.Services new file mode 100644 index 0000000..ce83039 --- /dev/null +++ b/jDnsProxy/src/main/resources/META-INF/services/com.moparisthebest.dns.listen.Services @@ -0,0 +1 @@ +com.moparisthebest.dns.listen.DefaultServices \ No newline at end of file diff --git a/jDnsProxy/src/main/resources/META-INF/services/com.moparisthebest.dns.resolve.Services b/jDnsProxy/src/main/resources/META-INF/services/com.moparisthebest.dns.resolve.Services new file mode 100644 index 0000000..3e3e3c1 --- /dev/null +++ b/jDnsProxy/src/main/resources/META-INF/services/com.moparisthebest.dns.resolve.Services @@ -0,0 +1 @@ +com.moparisthebest.dns.resolve.DefaultServices \ No newline at end of file