1bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy/*
2bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * Copyright (C) 2011 The Android Open Source Project
3bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy *
4bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * Licensed under the Apache License, Version 2.0 (the "License");
5bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * you may not use this file except in compliance with the License.
6bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * You may obtain a copy of the License at
7bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy *
8bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy *      http://www.apache.org/licenses/LICENSE-2.0
9bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy *
10bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * Unless required by applicable law or agreed to in writing, software
11bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * distributed under the License is distributed on an "AS IS" BASIS,
12bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * See the License for the specific language governing permissions and
14bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * limitations under the License.
15bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy */
16bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy
17a7bc1135c270fd4a84ab7ad45b7194e9b580300eIsaac Levypackage android.net;
18bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy
19bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levyimport android.content.Context;
20d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levyimport android.os.Handler;
21d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levyimport android.os.Looper;
22d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levyimport android.os.Message;
23bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levyimport android.os.SystemClock;
243541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levyimport android.provider.Settings;
257f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriffimport android.util.Log;
26bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy
27d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levyimport com.android.internal.util.Protocol;
28d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy
29d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levyimport java.io.IOException;
30bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levyimport java.net.DatagramPacket;
31bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levyimport java.net.DatagramSocket;
32bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levyimport java.net.InetAddress;
333ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levyimport java.net.NetworkInterface;
34bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levyimport java.net.SocketTimeoutException;
35d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levyimport java.util.ArrayList;
36bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levyimport java.util.Collection;
37d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levyimport java.util.Iterator;
38d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levyimport java.util.List;
39bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levyimport java.util.Random;
40d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levyimport java.util.concurrent.atomic.AtomicInteger;
41bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy
42bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy/**
43bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * Performs a simple DNS "ping" by sending a "server status" query packet to the
44bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * DNS server. As long as the server replies, we consider it a success.
45bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * <p>
46bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * We do not use a simple hostname lookup because that could be cached and the
47bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * API may not differentiate between a time out and a failure lookup (which we
48bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * really care about).
49bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * <p>
50bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy *
51bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * @hide
52bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy */
53d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levypublic final class DnsPinger extends Handler {
547f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff    private static final boolean DBG = false;
55bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy
5632f04e9009046f72242932bf4e820802148e423aIrfan Sheriff    private static final int RECEIVE_POLL_INTERVAL_MS = 200;
57bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy    private static final int DNS_PORT = 53;
58bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy
59d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    /** Short socket timeout so we don't block one any 'receive' call */
60d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    private static final int SOCKET_TIMEOUT_MS = 1;
61d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy
62bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy    /** Used to generate IDs */
63d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    private static final Random sRandom = new Random();
64d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    private static final AtomicInteger sCounter = new AtomicInteger();
65bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy
66bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy    private ConnectivityManager mConnectivityManager = null;
67d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    private final Context mContext;
68d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    private final int mConnectionType;
69d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    private final Handler mTarget;
7079e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy    private final ArrayList<InetAddress> mDefaultDns;
71bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy    private String TAG;
72bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy
7332f04e9009046f72242932bf4e820802148e423aIrfan Sheriff    //Invalidates old dns requests upon a cancel
7432f04e9009046f72242932bf4e820802148e423aIrfan Sheriff    private AtomicInteger mCurrentToken = new AtomicInteger();
7532f04e9009046f72242932bf4e820802148e423aIrfan Sheriff
76d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    private static final int BASE = Protocol.BASE_DNS_PINGER;
77d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy
78b1ef292b3d0c2b4b4c77bb7b442df8e73d1fbb5eIsaac Levy    /**
79d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy     * Async response packet for dns pings.
80d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy     * arg1 is the ID of the ping, also returned by {@link #pingDnsAsync(InetAddress, int, int)}
81d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy     * arg2 is the delay, or is negative on error.
82b1ef292b3d0c2b4b4c77bb7b442df8e73d1fbb5eIsaac Levy     */
83d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    public static final int DNS_PING_RESULT = BASE;
84d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    /** An error code for a {@link #DNS_PING_RESULT} packet */
85d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    public static final int TIMEOUT = -1;
86d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    /** An error code for a {@link #DNS_PING_RESULT} packet */
87d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    public static final int SOCKET_EXCEPTION = -2;
88d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy
89d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    /**
90d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy     * Send a new ping via a socket.  arg1 is ID, arg2 is timeout, obj is InetAddress to ping
91d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy     */
92d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    private static final int ACTION_PING_DNS = BASE + 1;
93d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    private static final int ACTION_LISTEN_FOR_RESPONSE = BASE + 2;
94d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    private static final int ACTION_CANCEL_ALL_PINGS = BASE + 3;
95d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy
96d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    private List<ActivePing> mActivePings = new ArrayList<ActivePing>();
97d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    private int mEventCounter;
98d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy
99d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    private class ActivePing {
100d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        DatagramSocket socket;
101d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        int internalId;
102d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        short packetId;
103d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        int timeout;
104d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        Integer result;
105d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        long start = SystemClock.elapsedRealtime();
106d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    }
107d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy
10832f04e9009046f72242932bf4e820802148e423aIrfan Sheriff    /* Message argument for ACTION_PING_DNS */
10932f04e9009046f72242932bf4e820802148e423aIrfan Sheriff    private class DnsArg {
11032f04e9009046f72242932bf4e820802148e423aIrfan Sheriff        InetAddress dns;
11132f04e9009046f72242932bf4e820802148e423aIrfan Sheriff        int seq;
11232f04e9009046f72242932bf4e820802148e423aIrfan Sheriff
11332f04e9009046f72242932bf4e820802148e423aIrfan Sheriff        DnsArg(InetAddress d, int s) {
11432f04e9009046f72242932bf4e820802148e423aIrfan Sheriff            dns = d;
11532f04e9009046f72242932bf4e820802148e423aIrfan Sheriff            seq = s;
11632f04e9009046f72242932bf4e820802148e423aIrfan Sheriff        }
11732f04e9009046f72242932bf4e820802148e423aIrfan Sheriff    }
11832f04e9009046f72242932bf4e820802148e423aIrfan Sheriff
119d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    public DnsPinger(Context context, String TAG, Looper looper,
120d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy            Handler target, int connectionType) {
121d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        super(looper);
122d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        this.TAG = TAG;
123bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy        mContext = context;
124d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        mTarget = target;
125b1ef292b3d0c2b4b4c77bb7b442df8e73d1fbb5eIsaac Levy        mConnectionType = connectionType;
1263541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy        if (!ConnectivityManager.isNetworkTypeValid(connectionType)) {
127d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy            throw new IllegalArgumentException("Invalid connectionType in constructor: "
128d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    + connectionType);
1293541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy        }
13079e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy        mDefaultDns = new ArrayList<InetAddress>();
13179e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy        mDefaultDns.add(getDefaultDns());
132d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        mEventCounter = 0;
133d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    }
134d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy
135d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    @Override
136d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    public void handleMessage(Message msg) {
137d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        switch (msg.what) {
138d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy            case ACTION_PING_DNS:
13932f04e9009046f72242932bf4e820802148e423aIrfan Sheriff                DnsArg dnsArg = (DnsArg) msg.obj;
14032f04e9009046f72242932bf4e820802148e423aIrfan Sheriff                if (dnsArg.seq != mCurrentToken.get()) {
14132f04e9009046f72242932bf4e820802148e423aIrfan Sheriff                    break;
14232f04e9009046f72242932bf4e820802148e423aIrfan Sheriff                }
143d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                try {
144d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    ActivePing newActivePing = new ActivePing();
14532f04e9009046f72242932bf4e820802148e423aIrfan Sheriff                    InetAddress dnsAddress = dnsArg.dns;
146d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    newActivePing.internalId = msg.arg1;
147d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    newActivePing.timeout = msg.arg2;
148d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    newActivePing.socket = new DatagramSocket();
149d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    // Set some socket properties
150d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    newActivePing.socket.setSoTimeout(SOCKET_TIMEOUT_MS);
151d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy
152d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    // Try to bind but continue ping if bind fails
153d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    try {
154d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                        newActivePing.socket.setNetworkInterface(NetworkInterface.getByName(
155d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                                getCurrentLinkProperties().getInterfaceName()));
156d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    } catch (Exception e) {
1577f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                        loge("sendDnsPing::Error binding to socket " + e);
158d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    }
159d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy
160d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    newActivePing.packetId = (short) sRandom.nextInt();
161d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    byte[] buf = mDnsQuery.clone();
162d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    buf[0] = (byte) (newActivePing.packetId >> 8);
163d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    buf[1] = (byte) newActivePing.packetId;
164d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy
165d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    // Send the DNS query
166d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    DatagramPacket packet = new DatagramPacket(buf,
167d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                            buf.length, dnsAddress, DNS_PORT);
1687f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                    if (DBG) {
1697f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                        log("Sending a ping " + newActivePing.internalId +
17026a8d71413f107603ad68f4fa80cf2bf3da9dab1Isaac Levy                                " to " + dnsAddress.getHostAddress()
17126a8d71413f107603ad68f4fa80cf2bf3da9dab1Isaac Levy                                + " with packetId " + newActivePing.packetId + ".");
172d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    }
173d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy
174d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    newActivePing.socket.send(packet);
175d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    mActivePings.add(newActivePing);
176d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    mEventCounter++;
177d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    sendMessageDelayed(obtainMessage(ACTION_LISTEN_FOR_RESPONSE, mEventCounter, 0),
178d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                            RECEIVE_POLL_INTERVAL_MS);
179d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                } catch (IOException e) {
18026a8d71413f107603ad68f4fa80cf2bf3da9dab1Isaac Levy                    sendResponse(msg.arg1, -9999, SOCKET_EXCEPTION);
181d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                }
182d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                break;
183d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy            case ACTION_LISTEN_FOR_RESPONSE:
184d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                if (msg.arg1 != mEventCounter) {
185d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    break;
186d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                }
187d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                for (ActivePing curPing : mActivePings) {
188d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    try {
189d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                        /** Each socket will block for {@link #SOCKET_TIMEOUT_MS} in receive() */
190d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                        byte[] responseBuf = new byte[2];
191d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                        DatagramPacket replyPacket = new DatagramPacket(responseBuf, 2);
192d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                        curPing.socket.receive(replyPacket);
193d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                        // Check that ID field matches (we're throwing out the rest of the packet)
194d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                        if (responseBuf[0] == (byte) (curPing.packetId >> 8) &&
195d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                                responseBuf[1] == (byte) curPing.packetId) {
196d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                            curPing.result =
197d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                                    (int) (SystemClock.elapsedRealtime() - curPing.start);
198d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                        } else {
1997f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                            if (DBG) {
2007f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                                log("response ID didn't match, ignoring packet");
201d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                            }
202d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                        }
203d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    } catch (SocketTimeoutException e) {
204d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                        // A timeout here doesn't mean anything - squelsh this exception
205d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    } catch (Exception e) {
2067f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                        if (DBG) {
2077f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                            log("DnsPinger.pingDns got socket exception: " + e);
208d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                        }
209d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                        curPing.result = SOCKET_EXCEPTION;
210d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    }
211d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                }
212d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                Iterator<ActivePing> iter = mActivePings.iterator();
213d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                while (iter.hasNext()) {
214d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                   ActivePing curPing = iter.next();
215d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                   if (curPing.result != null) {
21626a8d71413f107603ad68f4fa80cf2bf3da9dab1Isaac Levy                       sendResponse(curPing.internalId, curPing.packetId, curPing.result);
217d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                       curPing.socket.close();
218d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                       iter.remove();
219d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                   } else if (SystemClock.elapsedRealtime() >
220d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                                  curPing.start + curPing.timeout) {
22126a8d71413f107603ad68f4fa80cf2bf3da9dab1Isaac Levy                       sendResponse(curPing.internalId, curPing.packetId, TIMEOUT);
222d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                       curPing.socket.close();
223d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                       iter.remove();
224d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                   }
225d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                }
226d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                if (!mActivePings.isEmpty()) {
227d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    sendMessageDelayed(obtainMessage(ACTION_LISTEN_FOR_RESPONSE, mEventCounter, 0),
228d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                            RECEIVE_POLL_INTERVAL_MS);
229d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                }
230d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                break;
231d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy            case ACTION_CANCEL_ALL_PINGS:
232d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                for (ActivePing activePing : mActivePings)
233d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    activePing.socket.close();
234d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                mActivePings.clear();
235d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                break;
236d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        }
237bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy    }
238bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy
239bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy    /**
24079e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy     * Returns a list of DNS addresses, coming from either the link properties of the
24179e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy     * specified connection or the default system DNS if the link properties has no dnses.
24279e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy     * @return a non-empty non-null list
243bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy     */
24479e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy    public List<InetAddress> getDnsList() {
2453ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy        LinkProperties curLinkProps = getCurrentLinkProperties();
2463541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy        if (curLinkProps == null) {
2477f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff            loge("getCurLinkProperties:: LP for type" + mConnectionType + " is null!");
2483541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy            return mDefaultDns;
2493541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy        }
2503541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy
2513541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy        Collection<InetAddress> dnses = curLinkProps.getDnses();
2523541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy        if (dnses == null || dnses.size() == 0) {
2537f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff            loge("getDns::LinkProps has null dns - returning default");
2543541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy            return mDefaultDns;
2553541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy        }
256bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy
25779e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy        return new ArrayList<InetAddress>(dnses);
258bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy    }
259bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy
260d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    /**
261d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy     * Send a ping.  The response will come via a {@link #DNS_PING_RESULT} to the handler
262d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy     * specified at creation.
263d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy     * @param dns address of dns server to ping
264d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy     * @param timeout timeout for ping
265d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy     * @return an ID field, which will also be included in the {@link #DNS_PING_RESULT} message.
266d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy     */
267d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    public int pingDnsAsync(InetAddress dns, int timeout, int delay) {
268d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        int id = sCounter.incrementAndGet();
26932f04e9009046f72242932bf4e820802148e423aIrfan Sheriff        sendMessageDelayed(obtainMessage(ACTION_PING_DNS, id, timeout,
27032f04e9009046f72242932bf4e820802148e423aIrfan Sheriff                new DnsArg(dns, mCurrentToken.get())), delay);
271d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        return id;
272d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    }
273d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy
274d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    public void cancelPings() {
27532f04e9009046f72242932bf4e820802148e423aIrfan Sheriff        mCurrentToken.incrementAndGet();
276d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        obtainMessage(ACTION_CANCEL_ALL_PINGS).sendToTarget();
277d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    }
278d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy
27926a8d71413f107603ad68f4fa80cf2bf3da9dab1Isaac Levy    private void sendResponse(int internalId, int externalId, int responseVal) {
2807f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff        if(DBG) {
2817f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff            log("Responding to packet " + internalId +
28226a8d71413f107603ad68f4fa80cf2bf3da9dab1Isaac Levy                    " externalId " + externalId +
28326a8d71413f107603ad68f4fa80cf2bf3da9dab1Isaac Levy                    " and val " + responseVal);
284d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        }
285d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        mTarget.sendMessage(obtainMessage(DNS_PING_RESULT, internalId, responseVal));
286d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    }
287d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy
2883ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy    private LinkProperties getCurrentLinkProperties() {
2893ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy        if (mConnectivityManager == null) {
2903ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy            mConnectivityManager = (ConnectivityManager) mContext.getSystemService(
2913ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy                    Context.CONNECTIVITY_SERVICE);
2923ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy        }
2933ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy
2943ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy        return mConnectivityManager.getLinkProperties(mConnectionType);
2953ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy    }
2963ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy
2973541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy    private InetAddress getDefaultDns() {
298625239a05401bbf18b04d9874cea3f82da7c29a1Jeff Sharkey        String dns = Settings.Global.getString(mContext.getContentResolver(),
299625239a05401bbf18b04d9874cea3f82da7c29a1Jeff Sharkey                Settings.Global.DEFAULT_DNS_SERVER);
3003541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy        if (dns == null || dns.length() == 0) {
3013541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy            dns = mContext.getResources().getString(
3023541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy                    com.android.internal.R.string.config_default_dns_server);
3033541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy        }
3043541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy        try {
3053541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy            return NetworkUtils.numericToInetAddress(dns);
3063541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy        } catch (IllegalArgumentException e) {
3077f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff            loge("getDefaultDns::malformed default dns address");
3083541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy            return null;
309b1ef292b3d0c2b4b4c77bb7b442df8e73d1fbb5eIsaac Levy        }
310b1ef292b3d0c2b4b4c77bb7b442df8e73d1fbb5eIsaac Levy    }
311b1ef292b3d0c2b4b4c77bb7b442df8e73d1fbb5eIsaac Levy
312d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    private static final byte[] mDnsQuery = new byte[] {
313d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        0, 0, // [0-1] is for ID (will set each time)
31426a8d71413f107603ad68f4fa80cf2bf3da9dab1Isaac Levy        1, 0, // [2-3] are flags.  Set byte[2] = 1 for recursion desired (RD) on.  Currently on.
315d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        0, 1, // [4-5] bytes are for number of queries (QCOUNT)
316d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        0, 0, // [6-7] unused count field for dns response packets
317d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        0, 0, // [8-9] unused count field for dns response packets
318d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        0, 0, // [10-11] unused count field for dns response packets
319d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        3, 'w', 'w', 'w',
320d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        6, 'g', 'o', 'o', 'g', 'l', 'e',
321d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        3, 'c', 'o', 'm',
322d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        0,    // null terminator of address (also called empty TLD)
323d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        0, 1, // QTYPE, set to 1 = A (host address)
324d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        0, 1  // QCLASS, set to 1 = IN (internet)
325d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    };
3267f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff
3277f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff    private void log(String s) {
3287f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff        Log.d(TAG, s);
3297f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff    }
3307f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff
3317f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff    private void loge(String s) {
3327f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff        Log.e(TAG, s);
3337f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff    }
334bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy}
335