Merge "Delete unused DnsPinger" into nyc-dev
This commit is contained in:
@@ -1,334 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.SystemClock;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.util.Protocol;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.DatagramPacket;
|
||||
import java.net.DatagramSocket;
|
||||
import java.net.InetAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* Performs a simple DNS "ping" by sending a "server status" query packet to the
|
||||
* DNS server. As long as the server replies, we consider it a success.
|
||||
* <p>
|
||||
* We do not use a simple hostname lookup because that could be cached and the
|
||||
* API may not differentiate between a time out and a failure lookup (which we
|
||||
* really care about).
|
||||
* <p>
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public final class DnsPinger extends Handler {
|
||||
private static final boolean DBG = false;
|
||||
|
||||
private static final int RECEIVE_POLL_INTERVAL_MS = 200;
|
||||
private static final int DNS_PORT = 53;
|
||||
|
||||
/** Short socket timeout so we don't block one any 'receive' call */
|
||||
private static final int SOCKET_TIMEOUT_MS = 1;
|
||||
|
||||
/** Used to generate IDs */
|
||||
private static final Random sRandom = new Random();
|
||||
private static final AtomicInteger sCounter = new AtomicInteger();
|
||||
|
||||
private ConnectivityManager mConnectivityManager = null;
|
||||
private final Context mContext;
|
||||
private final int mConnectionType;
|
||||
private final Handler mTarget;
|
||||
private final ArrayList<InetAddress> mDefaultDns;
|
||||
private String TAG;
|
||||
|
||||
//Invalidates old dns requests upon a cancel
|
||||
private AtomicInteger mCurrentToken = new AtomicInteger();
|
||||
|
||||
private static final int BASE = Protocol.BASE_DNS_PINGER;
|
||||
|
||||
/**
|
||||
* Async response packet for dns pings.
|
||||
* arg1 is the ID of the ping, also returned by {@link #pingDnsAsync(InetAddress, int, int)}
|
||||
* arg2 is the delay, or is negative on error.
|
||||
*/
|
||||
public static final int DNS_PING_RESULT = BASE;
|
||||
/** An error code for a {@link #DNS_PING_RESULT} packet */
|
||||
public static final int TIMEOUT = -1;
|
||||
/** An error code for a {@link #DNS_PING_RESULT} packet */
|
||||
public static final int SOCKET_EXCEPTION = -2;
|
||||
|
||||
/**
|
||||
* Send a new ping via a socket. arg1 is ID, arg2 is timeout, obj is InetAddress to ping
|
||||
*/
|
||||
private static final int ACTION_PING_DNS = BASE + 1;
|
||||
private static final int ACTION_LISTEN_FOR_RESPONSE = BASE + 2;
|
||||
private static final int ACTION_CANCEL_ALL_PINGS = BASE + 3;
|
||||
|
||||
private List<ActivePing> mActivePings = new ArrayList<ActivePing>();
|
||||
private int mEventCounter;
|
||||
|
||||
private class ActivePing {
|
||||
DatagramSocket socket;
|
||||
int internalId;
|
||||
short packetId;
|
||||
int timeout;
|
||||
Integer result;
|
||||
long start = SystemClock.elapsedRealtime();
|
||||
}
|
||||
|
||||
/* Message argument for ACTION_PING_DNS */
|
||||
private class DnsArg {
|
||||
InetAddress dns;
|
||||
int seq;
|
||||
|
||||
DnsArg(InetAddress d, int s) {
|
||||
dns = d;
|
||||
seq = s;
|
||||
}
|
||||
}
|
||||
|
||||
public DnsPinger(Context context, String TAG, Looper looper,
|
||||
Handler target, int connectionType) {
|
||||
super(looper);
|
||||
this.TAG = TAG;
|
||||
mContext = context;
|
||||
mTarget = target;
|
||||
mConnectionType = connectionType;
|
||||
if (!ConnectivityManager.isNetworkTypeValid(connectionType)) {
|
||||
throw new IllegalArgumentException("Invalid connectionType in constructor: "
|
||||
+ connectionType);
|
||||
}
|
||||
mDefaultDns = new ArrayList<InetAddress>();
|
||||
mDefaultDns.add(getDefaultDns());
|
||||
mEventCounter = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case ACTION_PING_DNS:
|
||||
DnsArg dnsArg = (DnsArg) msg.obj;
|
||||
if (dnsArg.seq != mCurrentToken.get()) {
|
||||
break;
|
||||
}
|
||||
try {
|
||||
ActivePing newActivePing = new ActivePing();
|
||||
InetAddress dnsAddress = dnsArg.dns;
|
||||
newActivePing.internalId = msg.arg1;
|
||||
newActivePing.timeout = msg.arg2;
|
||||
newActivePing.socket = new DatagramSocket();
|
||||
// Set some socket properties
|
||||
newActivePing.socket.setSoTimeout(SOCKET_TIMEOUT_MS);
|
||||
|
||||
// Try to bind but continue ping if bind fails
|
||||
try {
|
||||
newActivePing.socket.setNetworkInterface(NetworkInterface.getByName(
|
||||
getCurrentLinkProperties().getInterfaceName()));
|
||||
} catch (Exception e) {
|
||||
loge("sendDnsPing::Error binding to socket " + e);
|
||||
}
|
||||
|
||||
newActivePing.packetId = (short) sRandom.nextInt();
|
||||
byte[] buf = mDnsQuery.clone();
|
||||
buf[0] = (byte) (newActivePing.packetId >> 8);
|
||||
buf[1] = (byte) newActivePing.packetId;
|
||||
|
||||
// Send the DNS query
|
||||
DatagramPacket packet = new DatagramPacket(buf,
|
||||
buf.length, dnsAddress, DNS_PORT);
|
||||
if (DBG) {
|
||||
log("Sending a ping " + newActivePing.internalId +
|
||||
" to " + dnsAddress.getHostAddress()
|
||||
+ " with packetId " + newActivePing.packetId + ".");
|
||||
}
|
||||
|
||||
newActivePing.socket.send(packet);
|
||||
mActivePings.add(newActivePing);
|
||||
mEventCounter++;
|
||||
sendMessageDelayed(obtainMessage(ACTION_LISTEN_FOR_RESPONSE, mEventCounter, 0),
|
||||
RECEIVE_POLL_INTERVAL_MS);
|
||||
} catch (IOException e) {
|
||||
sendResponse(msg.arg1, -9999, SOCKET_EXCEPTION);
|
||||
}
|
||||
break;
|
||||
case ACTION_LISTEN_FOR_RESPONSE:
|
||||
if (msg.arg1 != mEventCounter) {
|
||||
break;
|
||||
}
|
||||
for (ActivePing curPing : mActivePings) {
|
||||
try {
|
||||
/** Each socket will block for {@link #SOCKET_TIMEOUT_MS} in receive() */
|
||||
byte[] responseBuf = new byte[2];
|
||||
DatagramPacket replyPacket = new DatagramPacket(responseBuf, 2);
|
||||
curPing.socket.receive(replyPacket);
|
||||
// Check that ID field matches (we're throwing out the rest of the packet)
|
||||
if (responseBuf[0] == (byte) (curPing.packetId >> 8) &&
|
||||
responseBuf[1] == (byte) curPing.packetId) {
|
||||
curPing.result =
|
||||
(int) (SystemClock.elapsedRealtime() - curPing.start);
|
||||
} else {
|
||||
if (DBG) {
|
||||
log("response ID didn't match, ignoring packet");
|
||||
}
|
||||
}
|
||||
} catch (SocketTimeoutException e) {
|
||||
// A timeout here doesn't mean anything - squelsh this exception
|
||||
} catch (Exception e) {
|
||||
if (DBG) {
|
||||
log("DnsPinger.pingDns got socket exception: " + e);
|
||||
}
|
||||
curPing.result = SOCKET_EXCEPTION;
|
||||
}
|
||||
}
|
||||
Iterator<ActivePing> iter = mActivePings.iterator();
|
||||
while (iter.hasNext()) {
|
||||
ActivePing curPing = iter.next();
|
||||
if (curPing.result != null) {
|
||||
sendResponse(curPing.internalId, curPing.packetId, curPing.result);
|
||||
curPing.socket.close();
|
||||
iter.remove();
|
||||
} else if (SystemClock.elapsedRealtime() >
|
||||
curPing.start + curPing.timeout) {
|
||||
sendResponse(curPing.internalId, curPing.packetId, TIMEOUT);
|
||||
curPing.socket.close();
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
if (!mActivePings.isEmpty()) {
|
||||
sendMessageDelayed(obtainMessage(ACTION_LISTEN_FOR_RESPONSE, mEventCounter, 0),
|
||||
RECEIVE_POLL_INTERVAL_MS);
|
||||
}
|
||||
break;
|
||||
case ACTION_CANCEL_ALL_PINGS:
|
||||
for (ActivePing activePing : mActivePings)
|
||||
activePing.socket.close();
|
||||
mActivePings.clear();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of DNS addresses, coming from either the link properties of the
|
||||
* specified connection or the default system DNS if the link properties has no dnses.
|
||||
* @return a non-empty non-null list
|
||||
*/
|
||||
public List<InetAddress> getDnsList() {
|
||||
LinkProperties curLinkProps = getCurrentLinkProperties();
|
||||
if (curLinkProps == null) {
|
||||
loge("getCurLinkProperties:: LP for type" + mConnectionType + " is null!");
|
||||
return mDefaultDns;
|
||||
}
|
||||
|
||||
Collection<InetAddress> dnses = curLinkProps.getDnsServers();
|
||||
if (dnses == null || dnses.size() == 0) {
|
||||
loge("getDns::LinkProps has null dns - returning default");
|
||||
return mDefaultDns;
|
||||
}
|
||||
|
||||
return new ArrayList<InetAddress>(dnses);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a ping. The response will come via a {@link #DNS_PING_RESULT} to the handler
|
||||
* specified at creation.
|
||||
* @param dns address of dns server to ping
|
||||
* @param timeout timeout for ping
|
||||
* @return an ID field, which will also be included in the {@link #DNS_PING_RESULT} message.
|
||||
*/
|
||||
public int pingDnsAsync(InetAddress dns, int timeout, int delay) {
|
||||
int id = sCounter.incrementAndGet();
|
||||
sendMessageDelayed(obtainMessage(ACTION_PING_DNS, id, timeout,
|
||||
new DnsArg(dns, mCurrentToken.get())), delay);
|
||||
return id;
|
||||
}
|
||||
|
||||
public void cancelPings() {
|
||||
mCurrentToken.incrementAndGet();
|
||||
obtainMessage(ACTION_CANCEL_ALL_PINGS).sendToTarget();
|
||||
}
|
||||
|
||||
private void sendResponse(int internalId, int externalId, int responseVal) {
|
||||
if(DBG) {
|
||||
log("Responding to packet " + internalId +
|
||||
" externalId " + externalId +
|
||||
" and val " + responseVal);
|
||||
}
|
||||
mTarget.sendMessage(obtainMessage(DNS_PING_RESULT, internalId, responseVal));
|
||||
}
|
||||
|
||||
private LinkProperties getCurrentLinkProperties() {
|
||||
if (mConnectivityManager == null) {
|
||||
mConnectivityManager = (ConnectivityManager) mContext.getSystemService(
|
||||
Context.CONNECTIVITY_SERVICE);
|
||||
}
|
||||
|
||||
return mConnectivityManager.getLinkProperties(mConnectionType);
|
||||
}
|
||||
|
||||
private InetAddress getDefaultDns() {
|
||||
String dns = Settings.Global.getString(mContext.getContentResolver(),
|
||||
Settings.Global.DEFAULT_DNS_SERVER);
|
||||
if (dns == null || dns.length() == 0) {
|
||||
dns = mContext.getResources().getString(
|
||||
com.android.internal.R.string.config_default_dns_server);
|
||||
}
|
||||
try {
|
||||
return NetworkUtils.numericToInetAddress(dns);
|
||||
} catch (IllegalArgumentException e) {
|
||||
loge("getDefaultDns::malformed default dns address");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static final byte[] mDnsQuery = new byte[] {
|
||||
0, 0, // [0-1] is for ID (will set each time)
|
||||
1, 0, // [2-3] are flags. Set byte[2] = 1 for recursion desired (RD) on. Currently on.
|
||||
0, 1, // [4-5] bytes are for number of queries (QCOUNT)
|
||||
0, 0, // [6-7] unused count field for dns response packets
|
||||
0, 0, // [8-9] unused count field for dns response packets
|
||||
0, 0, // [10-11] unused count field for dns response packets
|
||||
3, 'w', 'w', 'w',
|
||||
6, 'g', 'o', 'o', 'g', 'l', 'e',
|
||||
3, 'c', 'o', 'm',
|
||||
0, // null terminator of address (also called empty TLD)
|
||||
0, 1, // QTYPE, set to 1 = A (host address)
|
||||
0, 1 // QCLASS, set to 1 = IN (internet)
|
||||
};
|
||||
|
||||
private void log(String s) {
|
||||
Log.d(TAG, s);
|
||||
}
|
||||
|
||||
private void loge(String s) {
|
||||
Log.e(TAG, s);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user