1d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
2d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
3d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpackage org.xbill.DNS;
4d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
5d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.util.*;
6d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.io.*;
7d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.net.*;
8d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
9d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
10d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * An implementation of Resolver that can send queries to multiple servers,
11d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * sending the queries multiple times if necessary.
12d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @see Resolver
13d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *
14d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @author Brian Wellington
15d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
16d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
17d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic class ExtendedResolver implements Resolver {
18d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
19d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenprivate static class Resolution implements ResolverListener {
20d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	Resolver [] resolvers;
21d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	int [] sent;
22d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	Object [] inprogress;
23d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	int retries;
24d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	int outstanding;
25d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	boolean done;
26d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	Message query;
27d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	Message response;
28d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	Throwable thrown;
29d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	ResolverListener listener;
30d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
31d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	public
32d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	Resolution(ExtendedResolver eres, Message query) {
33d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		List l = eres.resolvers;
34d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		resolvers = (Resolver []) l.toArray (new Resolver[l.size()]);
35d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		if (eres.loadBalance) {
36d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			int nresolvers = resolvers.length;
37d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			/*
38d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			 * Note: this is not synchronized, since the
39d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			 * worst thing that can happen is a random
40d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			 * ordering, which is ok.
41d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			 */
42d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			int start = eres.lbStart++ % nresolvers;
43d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			if (eres.lbStart > nresolvers)
44d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				eres.lbStart %= nresolvers;
45d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			if (start > 0) {
46d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				Resolver [] shuffle = new Resolver[nresolvers];
47d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				for (int i = 0; i < nresolvers; i++) {
48d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen					int pos = (i + start) % nresolvers;
49d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen					shuffle[i] = resolvers[pos];
50d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				}
51d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				resolvers = shuffle;
52d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			}
53d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		}
54d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		sent = new int[resolvers.length];
55d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		inprogress = new Object[resolvers.length];
56d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		retries = eres.retries;
57d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		this.query = query;
58d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
59d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
60d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	/* Asynchronously sends a message. */
61d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	public void
62d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	send(int n) {
63d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		sent[n]++;
64d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		outstanding++;
65d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		try {
66d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			inprogress[n] = resolvers[n].sendAsync(query, this);
67d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		}
68d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		catch (Throwable t) {
69d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			synchronized (this) {
70d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				thrown = t;
71d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				done = true;
72d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				if (listener == null) {
73d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen					notifyAll();
74d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen					return;
75d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				}
76d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			}
77d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		}
78d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
79d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
80d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	/* Start a synchronous resolution */
81d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	public Message
82d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	start() throws IOException {
83d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		try {
84d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			/*
85d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			 * First, try sending synchronously.  If this works,
86d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			 * we're done.  Otherwise, we'll get an exception
87d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			 * and continue.  It would be easier to call send(0),
88d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			 * but this avoids a thread creation.  If and when
89d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			 * SimpleResolver.sendAsync() can be made to not
90d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			 * create a thread, this could be changed.
91d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			 */
92d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			sent[0]++;
93d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			outstanding++;
94d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			inprogress[0] = new Object();
95d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			return resolvers[0].send(query);
96d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		}
97d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		catch (Exception e) {
98d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			/*
99d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			 * This will either cause more queries to be sent
100d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			 * asynchronously or will set the 'done' flag.
101d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			 */
102d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			handleException(inprogress[0], e);
103d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		}
104d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		/*
105d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		 * Wait for a successful response or for each
106d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		 * subresolver to fail.
107d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		 */
108d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		synchronized (this) {
109d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			while (!done) {
110d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				try {
111d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen					wait();
112d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				}
113d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				catch (InterruptedException e) {
114d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				}
115d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			}
116d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		}
117d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		/* Return the response or throw an exception */
118d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		if (response != null)
119d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			return response;
120d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		else if (thrown instanceof IOException)
121d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			throw (IOException) thrown;
122d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		else if (thrown instanceof RuntimeException)
123d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			throw (RuntimeException) thrown;
124d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		else if (thrown instanceof Error)
125d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			throw (Error) thrown;
126d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		else
127d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			throw new IllegalStateException
128d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				("ExtendedResolver failure");
129d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
130d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
131d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	/* Start an asynchronous resolution */
132d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	public void
133d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	startAsync(ResolverListener listener) {
134d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		this.listener = listener;
135d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		send(0);
136d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
137d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
138d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	/*
139d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * Receive a response.  If the resolution hasn't been completed,
140d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * either wake up the blocking thread or call the callback.
141d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 */
142d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	public void
143d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	receiveMessage(Object id, Message m) {
144d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		if (Options.check("verbose"))
145d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			System.err.println("ExtendedResolver: " +
146d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen					   "received message");
147d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		synchronized (this) {
148d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			if (done)
149d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				return;
150d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			response = m;
151d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			done = true;
152d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			if (listener == null) {
153d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				notifyAll();
154d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				return;
155d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			}
156d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		}
157d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		listener.receiveMessage(this, response);
158d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
159d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
160d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	/*
161d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * Receive an exception.  If the resolution has been completed,
162d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * do nothing.  Otherwise make progress.
163d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 */
164d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	public void
165d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	handleException(Object id, Exception e) {
166d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		if (Options.check("verbose"))
167d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			System.err.println("ExtendedResolver: got " + e);
168d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		synchronized (this) {
169d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			outstanding--;
170d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			if (done)
171d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				return;
172d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			int n;
173d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			for (n = 0; n < inprogress.length; n++)
174d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				if (inprogress[n] == id)
175d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen					break;
176d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			/* If we don't know what this is, do nothing. */
177d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			if (n == inprogress.length)
178d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				return;
179d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			boolean startnext = false;
180d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			/*
181d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			 * If this is the first response from server n,
182d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			 * we should start sending queries to server n + 1.
183d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			 */
184d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			if (sent[n] == 1 && n < resolvers.length - 1)
185d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				startnext = true;
186d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			if (e instanceof InterruptedIOException) {
187d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				/* Got a timeout; resend */
188d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				if (sent[n] < retries)
189d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen					send(n);
190d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				if (thrown == null)
191d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen					thrown = e;
192d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			} else if (e instanceof SocketException) {
193d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				/*
194d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				 * Problem with the socket; don't resend
195d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				 * on it
196d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				 */
197d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				if (thrown == null ||
198d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				    thrown instanceof InterruptedIOException)
199d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen					thrown = e;
200d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			} else {
201d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				/*
202d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				 * Problem with the response; don't resend
203d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				 * on the same socket.
204d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				 */
205d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				thrown = e;
206d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			}
207d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			if (done)
208d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				return;
209d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			if (startnext)
210d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				send(n + 1);
211d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			if (done)
212d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				return;
213d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			if (outstanding == 0) {
214d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				/*
215d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				 * If we're done and this is synchronous,
216d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				 * wake up the blocking thread.
217d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				 */
218d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				done = true;
219d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				if (listener == null) {
220d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen					notifyAll();
221d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen					return;
222d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				}
223d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			}
224d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			if (!done)
225d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				return;
226d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		}
227d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		/* If we're done and this is asynchronous, call the callback. */
228d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		if (!(thrown instanceof Exception))
229d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			thrown = new RuntimeException(thrown.getMessage());
230d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		listener.handleException(this, (Exception) thrown);
231d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
232d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
233d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
234d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenprivate static final int quantum = 5;
235d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
236d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenprivate List resolvers;
237d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenprivate boolean loadBalance = false;
238d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenprivate int lbStart = 0;
239d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenprivate int retries = 3;
240d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
241d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenprivate void
242d7955ce24d294fb2014c59d11fca184471056f44Shuyi Cheninit() {
243d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	resolvers = new ArrayList();
244d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
245d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
246d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
247d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Creates a new Extended Resolver.  The default ResolverConfig is used to
248d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * determine the servers for which SimpleResolver contexts should be
249d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * initialized.
250d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @see SimpleResolver
251d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @see ResolverConfig
252d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @exception UnknownHostException Failure occured initializing SimpleResolvers
253d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
254d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic
255d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChenExtendedResolver() throws UnknownHostException {
256d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	init();
257d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	String [] servers = ResolverConfig.getCurrentConfig().servers();
258d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	if (servers != null) {
259d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		for (int i = 0; i < servers.length; i++) {
260d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			Resolver r = new SimpleResolver(servers[i]);
261d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			r.setTimeout(quantum);
262d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			resolvers.add(r);
263d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		}
264d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
265d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	else
266d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		resolvers.add(new SimpleResolver());
267d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
268d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
269d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
270d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Creates a new Extended Resolver
271d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param servers An array of server names for which SimpleResolver
272d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * contexts should be initialized.
273d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @see SimpleResolver
274d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @exception UnknownHostException Failure occured initializing SimpleResolvers
275d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
276d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic
277d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChenExtendedResolver(String [] servers) throws UnknownHostException {
278d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	init();
279d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	for (int i = 0; i < servers.length; i++) {
280d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		Resolver r = new SimpleResolver(servers[i]);
281d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		r.setTimeout(quantum);
282d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		resolvers.add(r);
283d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
284d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
285d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
286d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
287d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Creates a new Extended Resolver
288d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param res An array of pre-initialized Resolvers is provided.
289d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @see SimpleResolver
290d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @exception UnknownHostException Failure occured initializing SimpleResolvers
291d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
292d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic
293d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChenExtendedResolver(Resolver [] res) throws UnknownHostException {
294d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	init();
295d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	for (int i = 0; i < res.length; i++)
296d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		resolvers.add(res[i]);
297d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
298d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
299d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic void
300d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChensetPort(int port) {
301d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	for (int i = 0; i < resolvers.size(); i++)
302d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		((Resolver)resolvers.get(i)).setPort(port);
303d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
304d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
305d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic void
306d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChensetTCP(boolean flag) {
307d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	for (int i = 0; i < resolvers.size(); i++)
308d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		((Resolver)resolvers.get(i)).setTCP(flag);
309d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
310d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
311d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic void
312d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChensetIgnoreTruncation(boolean flag) {
313d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	for (int i = 0; i < resolvers.size(); i++)
314d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		((Resolver)resolvers.get(i)).setIgnoreTruncation(flag);
315d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
316d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
317d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic void
318d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChensetEDNS(int level) {
319d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	for (int i = 0; i < resolvers.size(); i++)
320d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		((Resolver)resolvers.get(i)).setEDNS(level);
321d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
322d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
323d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic void
324d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChensetEDNS(int level, int payloadSize, int flags, List options) {
325d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	for (int i = 0; i < resolvers.size(); i++)
326d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		((Resolver)resolvers.get(i)).setEDNS(level, payloadSize,
327d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen						     flags, options);
328d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
329d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
330d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic void
331d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChensetTSIGKey(TSIG key) {
332d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	for (int i = 0; i < resolvers.size(); i++)
333d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		((Resolver)resolvers.get(i)).setTSIGKey(key);
334d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
335d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
336d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic void
337d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChensetTimeout(int secs, int msecs) {
338d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	for (int i = 0; i < resolvers.size(); i++)
339d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		((Resolver)resolvers.get(i)).setTimeout(secs, msecs);
340d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
341d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
342d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic void
343d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChensetTimeout(int secs) {
344d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	setTimeout(secs, 0);
345d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
346d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
347d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
348d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Sends a message and waits for a response.  Multiple servers are queried,
349d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * and queries are sent multiple times until either a successful response
350d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * is received, or it is clear that there is no successful response.
351d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param query The query to send.
352d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return The response.
353d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws IOException An error occurred while sending or receiving.
354d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
355d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic Message
356d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chensend(Message query) throws IOException {
357d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	Resolution res = new Resolution(this, query);
358d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	return res.start();
359d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
360d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
361d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
362d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Asynchronously sends a message to multiple servers, potentially multiple
363d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * times, registering a listener to receive a callback on success or exception.
364d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Multiple asynchronous lookups can be performed in parallel.  Since the
365d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * callback may be invoked before the function returns, external
366d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * synchronization is necessary.
367d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param query The query to send
368d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param listener The object containing the callbacks.
369d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return An identifier, which is also a parameter in the callback
370d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
371d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic Object
372d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChensendAsync(final Message query, final ResolverListener listener) {
373d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	Resolution res = new Resolution(this, query);
374d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	res.startAsync(listener);
375d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	return res;
376d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
377d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
378d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/** Returns the nth resolver used by this ExtendedResolver */
379d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic Resolver
380d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChengetResolver(int n) {
381d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	if (n < resolvers.size())
382d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		return (Resolver)resolvers.get(n);
383d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	return null;
384d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
385d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
386d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/** Returns all resolvers used by this ExtendedResolver */
387d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic Resolver []
388d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChengetResolvers() {
389d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	return (Resolver []) resolvers.toArray(new Resolver[resolvers.size()]);
390d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
391d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
392d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/** Adds a new resolver to be used by this ExtendedResolver */
393d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic void
394d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChenaddResolver(Resolver r) {
395d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	resolvers.add(r);
396d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
397d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
398d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/** Deletes a resolver used by this ExtendedResolver */
399d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic void
400d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChendeleteResolver(Resolver r) {
401d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	resolvers.remove(r);
402d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
403d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
404d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/** Sets whether the servers should be load balanced.
405d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param flag If true, servers will be tried in round-robin order.  If false,
406d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * servers will always be queried in the same order.
407d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
408d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic void
409d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChensetLoadBalance(boolean flag) {
410d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	loadBalance = flag;
411d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
412d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
413d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/** Sets the number of retries sent to each server per query */
414d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic void
415d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChensetRetries(int retries) {
416d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	this.retries = retries;
417d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
418d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
419d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
420