DnsPinger.java revision 79e43f679d6102066ee9eff862912806f53bb0e8
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;
25bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levyimport android.util.Slog;
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 {
54bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy    private static final boolean V = true;
55bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy
56d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    private static final int RECEIVE_POLL_INTERVAL_MS = 30;
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
73d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    private static final int BASE = Protocol.BASE_DNS_PINGER;
74d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy
75b1ef292b3d0c2b4b4c77bb7b442df8e73d1fbb5eIsaac Levy    /**
76d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy     * Async response packet for dns pings.
77d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy     * arg1 is the ID of the ping, also returned by {@link #pingDnsAsync(InetAddress, int, int)}
78d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy     * arg2 is the delay, or is negative on error.
79b1ef292b3d0c2b4b4c77bb7b442df8e73d1fbb5eIsaac Levy     */
80d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    public static final int DNS_PING_RESULT = BASE;
81d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    /** An error code for a {@link #DNS_PING_RESULT} packet */
82d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    public static final int TIMEOUT = -1;
83d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    /** An error code for a {@link #DNS_PING_RESULT} packet */
84d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    public static final int SOCKET_EXCEPTION = -2;
85d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy
86d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    /**
87d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy     * Send a new ping via a socket.  arg1 is ID, arg2 is timeout, obj is InetAddress to ping
88d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy     */
89d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    private static final int ACTION_PING_DNS = BASE + 1;
90d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    private static final int ACTION_LISTEN_FOR_RESPONSE = BASE + 2;
91d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    private static final int ACTION_CANCEL_ALL_PINGS = BASE + 3;
92d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy
93d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    private List<ActivePing> mActivePings = new ArrayList<ActivePing>();
94d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    private int mEventCounter;
95d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy
96d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    private class ActivePing {
97d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        DatagramSocket socket;
98d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        int internalId;
99d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        short packetId;
100d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        int timeout;
101d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        Integer result;
102d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        long start = SystemClock.elapsedRealtime();
103d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    }
104d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy
105d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    public DnsPinger(Context context, String TAG, Looper looper,
106d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy            Handler target, int connectionType) {
107d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        super(looper);
108d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        this.TAG = TAG;
109bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy        mContext = context;
110d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        mTarget = target;
111b1ef292b3d0c2b4b4c77bb7b442df8e73d1fbb5eIsaac Levy        mConnectionType = connectionType;
1123541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy        if (!ConnectivityManager.isNetworkTypeValid(connectionType)) {
113d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy            throw new IllegalArgumentException("Invalid connectionType in constructor: "
114d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    + connectionType);
1153541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy        }
11679e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy        mDefaultDns = new ArrayList<InetAddress>();
11779e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy        mDefaultDns.add(getDefaultDns());
118d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        mEventCounter = 0;
119d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    }
120d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy
121d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    @Override
122d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    public void handleMessage(Message msg) {
123d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        switch (msg.what) {
124d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy            case ACTION_PING_DNS:
125d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                try {
126d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    ActivePing newActivePing = new ActivePing();
127d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    InetAddress dnsAddress = (InetAddress) msg.obj;
128d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    newActivePing.internalId = msg.arg1;
129d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    newActivePing.timeout = msg.arg2;
130d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    newActivePing.socket = new DatagramSocket();
131d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    // Set some socket properties
132d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    newActivePing.socket.setSoTimeout(SOCKET_TIMEOUT_MS);
133d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy
134d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    // Try to bind but continue ping if bind fails
135d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    try {
136d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                        newActivePing.socket.setNetworkInterface(NetworkInterface.getByName(
137d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                                getCurrentLinkProperties().getInterfaceName()));
138d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    } catch (Exception e) {
139d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                        Slog.w(TAG,"sendDnsPing::Error binding to socket", e);
140d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    }
141d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy
142d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    newActivePing.packetId = (short) sRandom.nextInt();
143d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    byte[] buf = mDnsQuery.clone();
144d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    buf[0] = (byte) (newActivePing.packetId >> 8);
145d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    buf[1] = (byte) newActivePing.packetId;
146d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy
147d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    // Send the DNS query
148d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    DatagramPacket packet = new DatagramPacket(buf,
149d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                            buf.length, dnsAddress, DNS_PORT);
150d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    if (V) {
15126a8d71413f107603ad68f4fa80cf2bf3da9dab1Isaac Levy                        Slog.v(TAG, "Sending a ping " + newActivePing.internalId +
15226a8d71413f107603ad68f4fa80cf2bf3da9dab1Isaac Levy                                " to " + dnsAddress.getHostAddress()
15326a8d71413f107603ad68f4fa80cf2bf3da9dab1Isaac Levy                                + " with packetId " + newActivePing.packetId + ".");
154d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    }
155d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy
156d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    newActivePing.socket.send(packet);
157d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    mActivePings.add(newActivePing);
158d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    mEventCounter++;
159d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    sendMessageDelayed(obtainMessage(ACTION_LISTEN_FOR_RESPONSE, mEventCounter, 0),
160d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                            RECEIVE_POLL_INTERVAL_MS);
161d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                } catch (IOException e) {
16226a8d71413f107603ad68f4fa80cf2bf3da9dab1Isaac Levy                    sendResponse(msg.arg1, -9999, SOCKET_EXCEPTION);
163d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                }
164d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                break;
165d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy            case ACTION_LISTEN_FOR_RESPONSE:
166d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                if (msg.arg1 != mEventCounter) {
167d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    break;
168d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                }
169d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                for (ActivePing curPing : mActivePings) {
170d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    try {
171d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                        /** Each socket will block for {@link #SOCKET_TIMEOUT_MS} in receive() */
172d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                        byte[] responseBuf = new byte[2];
173d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                        DatagramPacket replyPacket = new DatagramPacket(responseBuf, 2);
174d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                        curPing.socket.receive(replyPacket);
175d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                        // Check that ID field matches (we're throwing out the rest of the packet)
176d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                        if (responseBuf[0] == (byte) (curPing.packetId >> 8) &&
177d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                                responseBuf[1] == (byte) curPing.packetId) {
178d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                            curPing.result =
179d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                                    (int) (SystemClock.elapsedRealtime() - curPing.start);
180d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                        } else {
181d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                            if (V) {
182d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                                Slog.v(TAG, "response ID didn't match, ignoring packet");
183d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                            }
184d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                        }
185d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    } catch (SocketTimeoutException e) {
186d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                        // A timeout here doesn't mean anything - squelsh this exception
187d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    } catch (Exception e) {
188d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                        if (V) {
189d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                            Slog.v(TAG, "DnsPinger.pingDns got socket exception: ", e);
190d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                        }
191d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                        curPing.result = SOCKET_EXCEPTION;
192d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    }
193d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                }
194d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                Iterator<ActivePing> iter = mActivePings.iterator();
195d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                while (iter.hasNext()) {
196d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                   ActivePing curPing = iter.next();
197d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                   if (curPing.result != null) {
19826a8d71413f107603ad68f4fa80cf2bf3da9dab1Isaac Levy                       sendResponse(curPing.internalId, curPing.packetId, curPing.result);
199d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                       curPing.socket.close();
200d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                       iter.remove();
201d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                   } else if (SystemClock.elapsedRealtime() >
202d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                                  curPing.start + curPing.timeout) {
20326a8d71413f107603ad68f4fa80cf2bf3da9dab1Isaac Levy                       sendResponse(curPing.internalId, curPing.packetId, TIMEOUT);
204d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                       curPing.socket.close();
205d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                       iter.remove();
206d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                   }
207d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                }
208d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                if (!mActivePings.isEmpty()) {
209d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    sendMessageDelayed(obtainMessage(ACTION_LISTEN_FOR_RESPONSE, mEventCounter, 0),
210d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                            RECEIVE_POLL_INTERVAL_MS);
211d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                }
212d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                break;
213d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy            case ACTION_CANCEL_ALL_PINGS:
214d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                for (ActivePing activePing : mActivePings)
215d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    activePing.socket.close();
216d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                mActivePings.clear();
217d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                break;
218d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        }
219bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy    }
220bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy
221bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy    /**
22279e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy     * Returns a list of DNS addresses, coming from either the link properties of the
22379e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy     * specified connection or the default system DNS if the link properties has no dnses.
22479e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy     * @return a non-empty non-null list
225bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy     */
22679e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy    public List<InetAddress> getDnsList() {
2273ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy        LinkProperties curLinkProps = getCurrentLinkProperties();
2283541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy        if (curLinkProps == null) {
2293541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy            Slog.e(TAG, "getCurLinkProperties:: LP for type" + mConnectionType + " is null!");
2303541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy            return mDefaultDns;
2313541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy        }
2323541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy
2333541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy        Collection<InetAddress> dnses = curLinkProps.getDnses();
2343541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy        if (dnses == null || dnses.size() == 0) {
2353541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy            Slog.v(TAG, "getDns::LinkProps has null dns - returning default");
2363541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy            return mDefaultDns;
2373541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy        }
238bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy
23979e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy        return new ArrayList<InetAddress>(dnses);
240bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy    }
241bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy
242d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    /**
243d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy     * Send a ping.  The response will come via a {@link #DNS_PING_RESULT} to the handler
244d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy     * specified at creation.
245d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy     * @param dns address of dns server to ping
246d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy     * @param timeout timeout for ping
247d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy     * @return an ID field, which will also be included in the {@link #DNS_PING_RESULT} message.
248d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy     */
249d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    public int pingDnsAsync(InetAddress dns, int timeout, int delay) {
250d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        int id = sCounter.incrementAndGet();
251d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        sendMessageDelayed(obtainMessage(ACTION_PING_DNS, id, timeout, dns), delay);
252d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        return id;
253d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    }
254d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy
255d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    public void cancelPings() {
256d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        obtainMessage(ACTION_CANCEL_ALL_PINGS).sendToTarget();
257d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    }
258d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy
25926a8d71413f107603ad68f4fa80cf2bf3da9dab1Isaac Levy    private void sendResponse(int internalId, int externalId, int responseVal) {
260d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        if(V) {
26126a8d71413f107603ad68f4fa80cf2bf3da9dab1Isaac Levy            Slog.d(TAG, "Responding to packet " + internalId +
26226a8d71413f107603ad68f4fa80cf2bf3da9dab1Isaac Levy                    " externalId " + externalId +
26326a8d71413f107603ad68f4fa80cf2bf3da9dab1Isaac Levy                    " and val " + responseVal);
264d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        }
265d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        mTarget.sendMessage(obtainMessage(DNS_PING_RESULT, internalId, responseVal));
266d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    }
267d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy
2683ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy    private LinkProperties getCurrentLinkProperties() {
2693ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy        if (mConnectivityManager == null) {
2703ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy            mConnectivityManager = (ConnectivityManager) mContext.getSystemService(
2713ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy                    Context.CONNECTIVITY_SERVICE);
2723ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy        }
2733ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy
2743ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy        return mConnectivityManager.getLinkProperties(mConnectionType);
2753ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy    }
2763ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy
2773541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy    private InetAddress getDefaultDns() {
2783541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy        String dns = Settings.Secure.getString(mContext.getContentResolver(),
2793541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy                Settings.Secure.DEFAULT_DNS_SERVER);
2803541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy        if (dns == null || dns.length() == 0) {
2813541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy            dns = mContext.getResources().getString(
2823541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy                    com.android.internal.R.string.config_default_dns_server);
2833541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy        }
2843541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy        try {
2853541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy            return NetworkUtils.numericToInetAddress(dns);
2863541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy        } catch (IllegalArgumentException e) {
2873541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy            Slog.w(TAG, "getDefaultDns::malformed default dns address");
2883541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy            return null;
289b1ef292b3d0c2b4b4c77bb7b442df8e73d1fbb5eIsaac Levy        }
290b1ef292b3d0c2b4b4c77bb7b442df8e73d1fbb5eIsaac Levy    }
291b1ef292b3d0c2b4b4c77bb7b442df8e73d1fbb5eIsaac Levy
292d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    private static final byte[] mDnsQuery = new byte[] {
293d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        0, 0, // [0-1] is for ID (will set each time)
29426a8d71413f107603ad68f4fa80cf2bf3da9dab1Isaac Levy        1, 0, // [2-3] are flags.  Set byte[2] = 1 for recursion desired (RD) on.  Currently on.
295d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        0, 1, // [4-5] bytes are for number of queries (QCOUNT)
296d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        0, 0, // [6-7] unused count field for dns response packets
297d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        0, 0, // [8-9] unused count field for dns response packets
298d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        0, 0, // [10-11] unused count field for dns response packets
299d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        3, 'w', 'w', 'w',
300d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        6, 'g', 'o', 'o', 'g', 'l', 'e',
301d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        3, 'c', 'o', 'm',
302d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        0,    // null terminator of address (also called empty TLD)
303d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        0, 1, // QTYPE, set to 1 = A (host address)
304d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        0, 1  // QCLASS, set to 1 = IN (internet)
305d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    };
306bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy}
307