]> WPIA git - gigi.git/blob - lib/jetty/org/eclipse/jetty/util/SocketAddressResolver.java
Merge "Update notes about password security"
[gigi.git] / lib / jetty / org / eclipse / jetty / util / SocketAddressResolver.java
1 //
2 //  ========================================================================
3 //  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
4 //  ------------------------------------------------------------------------
5 //  All rights reserved. This program and the accompanying materials
6 //  are made available under the terms of the Eclipse Public License v1.0
7 //  and Apache License v2.0 which accompanies this distribution.
8 //
9 //      The Eclipse Public License is available at
10 //      http://www.eclipse.org/legal/epl-v10.html
11 //
12 //      The Apache License v2.0 is available at
13 //      http://www.opensource.org/licenses/apache2.0.php
14 //
15 //  You may elect to redistribute this code under either of these licenses.
16 //  ========================================================================
17 //
18
19 package org.eclipse.jetty.util;
20
21 import java.net.InetSocketAddress;
22 import java.net.SocketAddress;
23 import java.nio.channels.UnresolvedAddressException;
24 import java.util.concurrent.Executor;
25 import java.util.concurrent.TimeUnit;
26 import java.util.concurrent.TimeoutException;
27 import java.util.concurrent.atomic.AtomicBoolean;
28
29 import org.eclipse.jetty.util.log.Log;
30 import org.eclipse.jetty.util.log.Logger;
31 import org.eclipse.jetty.util.thread.Scheduler;
32
33 /**
34  * <p>Creates {@link SocketAddress} instances, returning them through a {@link Promise}.</p>
35  */
36 public interface SocketAddressResolver
37 {
38     /**
39      * Resolves the given host and port, returning a {@link SocketAddress} through the given {@link Promise}
40      * with the default timeout.
41      *
42      * @param host the host to resolve
43      * @param port the port of the resulting socket address
44      * @param promise the callback invoked when the resolution succeeds or fails
45      */
46     public void resolve(String host, int port, Promise<SocketAddress> promise);
47
48     /**
49      * <p>Creates {@link SocketAddress} instances synchronously in the caller thread.</p>
50      */
51     public static class Sync implements SocketAddressResolver
52     {
53         @Override
54         public void resolve(String host, int port, Promise<SocketAddress> promise)
55         {
56             try
57             {
58                 InetSocketAddress result = new InetSocketAddress(host, port);
59                 if (result.isUnresolved())
60                     promise.failed(new UnresolvedAddressException());
61                 else
62                     promise.succeeded(result);
63             }
64             catch (Throwable x)
65             {
66                 promise.failed(x);
67             }
68         }
69     }
70
71     /**
72      * <p>Creates {@link SocketAddress} instances asynchronously in a different thread.</p>
73      * <p>{@link InetSocketAddress#InetSocketAddress(String, int)} attempts to perform a DNS
74      * resolution of the host name, and this may block for several seconds.
75      * This class creates the {@link InetSocketAddress} in a separate thread and provides the result
76      * through a {@link Promise}, with the possibility to specify a timeout for the operation.</p>
77      * <p>Example usage:</p>
78      * <pre>
79      * SocketAddressResolver resolver = new SocketAddressResolver.Async(executor, scheduler, timeout);
80      * resolver.resolve("www.google.com", 80, new Promise&lt;SocketAddress&gt;()
81      * {
82      *     public void succeeded(SocketAddress result)
83      *     {
84      *         // The address was resolved
85      *     }
86      *
87      *     public void failed(Throwable failure)
88      *     {
89      *         // The address resolution failed
90      *     }
91      * });
92      * </pre>
93      */
94     public static class Async implements SocketAddressResolver
95     {
96         private static final Logger LOG = Log.getLogger(SocketAddressResolver.class);
97
98         private final Executor executor;
99         private final Scheduler scheduler;
100         private final long timeout;
101
102         /**
103          * Creates a new instance with the given executor (to perform DNS resolution in a separate thread),
104          * the given scheduler (to cancel the operation if it takes too long) and the given timeout, in milliseconds.
105          *
106          * @param executor  the thread pool to use to perform DNS resolution in pooled threads
107          * @param scheduler the scheduler to schedule tasks to cancel DNS resolution if it takes too long
108          * @param timeout   the timeout, in milliseconds, for the DNS resolution to complete
109          */
110         public Async(Executor executor, Scheduler scheduler, long timeout)
111         {
112             this.executor = executor;
113             this.scheduler = scheduler;
114             this.timeout = timeout;
115         }
116
117         public Executor getExecutor()
118         {
119             return executor;
120         }
121
122         public Scheduler getScheduler()
123         {
124             return scheduler;
125         }
126
127         public long getTimeout()
128         {
129             return timeout;
130         }
131
132         @Override
133         public void resolve(final String host, final int port, final Promise<SocketAddress> promise)
134         {
135             executor.execute(new Runnable()
136             {
137                 @Override
138                 public void run()
139                 {
140                     Scheduler.Task task = null;
141                     final AtomicBoolean complete = new AtomicBoolean();
142                     if (timeout > 0)
143                     {
144                         final Thread thread = Thread.currentThread();
145                         task = scheduler.schedule(new Runnable()
146                         {
147                             @Override
148                             public void run()
149                             {
150                                 if (complete.compareAndSet(false, true))
151                                 {
152                                     promise.failed(new TimeoutException());
153                                     thread.interrupt();
154                                 }
155                             }
156                         }, timeout, TimeUnit.MILLISECONDS);
157                     }
158
159                     try
160                     {
161                         long start = System.nanoTime();
162                         InetSocketAddress result = new InetSocketAddress(host, port);
163                         long elapsed = System.nanoTime() - start;
164                         if (LOG.isDebugEnabled())
165                             LOG.debug("Resolved {} in {} ms", host, TimeUnit.NANOSECONDS.toMillis(elapsed));
166                         if (complete.compareAndSet(false, true))
167                         {
168                             if (result.isUnresolved())
169                                 promise.failed(new UnresolvedAddressException());
170                             else
171                                 promise.succeeded(result);
172                         }
173                     }
174                     catch (Throwable x)
175                     {
176                         if (complete.compareAndSet(false, true))
177                             promise.failed(x);
178                     }
179                     finally
180                     {
181                         if (task != null)
182                             task.cancel();
183                         // Reset the interrupted status before releasing the thread to the pool
184                         Thread.interrupted();
185                     }
186                 }
187             });
188         }
189     }
190 }