NsdService.java revision ef12884da7c8844f8dd27cbc9c9980f685b73a2c
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2010 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
569a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes * you may not use this file except in compliance with the License.
669a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes * You may obtain a copy of the License at
769a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
969a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
1169a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes * distributed under the License is distributed on an "AS IS" BASIS,
1269a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1369a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes * See the License for the specific language governing permissions and
1469a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage com.android.server;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ContentResolver;
210795272aa226f4e965968a03daddc53ce30b7cdaMathias Agopianimport android.content.Intent;
220795272aa226f4e965968a03daddc53ce30b7cdaMathias Agopianimport android.content.pm.PackageManager;
23a23fcd7be8e40078a913b1a99222cdd89229e67bNarayan Kamathimport android.database.ContentObserver;
24f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kastenimport android.net.nsd.NsdServiceInfo;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.nsd.DnsSdTxtRecord;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.nsd.INsdManager;
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.nsd.NsdManager;
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Binder;
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Message;
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Messenger;
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.UserHandle;
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.Settings;
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Slog;
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.SparseArray;
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
36c6a410164e1fd728cf7873493baacca7bc29548dMark Salyzynimport java.io.FileDescriptor;
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.PrintWriter;
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.UnsupportedEncodingException;
39c6a410164e1fd728cf7873493baacca7bc29548dMark Salyzynimport java.net.InetAddress;
40c6a410164e1fd728cf7873493baacca7bc29548dMark Salyzynimport java.util.HashMap;
41c6a410164e1fd728cf7873493baacca7bc29548dMark Salyzynimport java.util.List;
42c6a410164e1fd728cf7873493baacca7bc29548dMark Salyzynimport java.util.Locale;
436af763bec7c3f4d50fee8dd0046409bb8a7fe8f6Glenn Kastenimport java.util.Map;
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.concurrent.CountDownLatch;
45957e58670baad8c5995f1368e3b5280f0dbd891fSan Mehat
46160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tateimport com.android.internal.util.AsyncChannel;
47a5109a878eeff22e32ee5ce1b1cd15e8daad5234San Mehatimport com.android.internal.util.Protocol;
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.internal.util.State;
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.internal.util.StateMachine;
50160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tateimport com.android.server.NativeDaemonConnector.Command;
51160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate
52160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate/**
53160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate * Network Service Discovery Service handles remote service discovery operation requests by
54160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate * implementing the INsdManager interface.
55f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten *
56f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten * @hide
576793ac943afeb16642f477c43ddfd27e498db37bGlenn Kasten */
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class NsdService extends INsdManager.Stub {
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String TAG = "NsdService";
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String MDNS_TAG = "mDnsConnector";
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final boolean DBG = true;
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Context mContext;
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private ContentResolver mContentResolver;
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private NsdStateMachine mNsdStateMachine;
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Clients receiving asynchronous messages
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private HashMap<Messenger, ClientInfo> mClients = new HashMap<Messenger, ClientInfo>();
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* A map from unique id to client info */
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private SparseArray<ClientInfo> mIdToClientInfoMap= new SparseArray<ClientInfo>();
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private AsyncChannel mReplyChannel = new AsyncChannel();
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
786793ac943afeb16642f477c43ddfd27e498db37bGlenn Kasten    private int INVALID_ID = 0;
79e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat    private int mUniqueId = 1;
80e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat
81e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat    private static final int BASE = Protocol.BASE_NSD_MANAGER;
82e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat    private static final int CMD_TO_STRING_COUNT = NsdManager.RESOLVE_SERVICE - BASE + 1;
83e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat    private static String[] sCmdToString = new String[CMD_TO_STRING_COUNT];
84e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat
85e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat    static {
86e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat        sCmdToString[NsdManager.DISCOVER_SERVICES - BASE] = "DISCOVER";
87e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat        sCmdToString[NsdManager.STOP_DISCOVERY - BASE] = "STOP-DISCOVER";
88e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat        sCmdToString[NsdManager.REGISTER_SERVICE - BASE] = "REGISTER";
89e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat        sCmdToString[NsdManager.UNREGISTER_SERVICE - BASE] = "UNREGISTER";
90e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat        sCmdToString[NsdManager.RESOLVE_SERVICE - BASE] = "RESOLVE";
91e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat    }
92e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat
93e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat    private static String cmdToString(int cmd) {
94e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat        cmd -= BASE;
95e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat        if ((cmd >= 0) && (cmd < sCmdToString.length)) {
96e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat            return sCmdToString[cmd];
97e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat        } else {
98e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat            return null;
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10269a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes    private class NsdStateMachine extends StateMachine {
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final DefaultState mDefaultState = new DefaultState();
10569a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes        private final DisabledState mDisabledState = new DisabledState();
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final EnabledState mEnabledState = new EnabledState();
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        protected String getWhatToString(int what) {
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return cmdToString(what);
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Observes the NSD on/off setting, and takes action when changed.
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private void registerForNsdSetting() {
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ContentObserver contentObserver = new ContentObserver(this.getHandler()) {
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                @Override
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    public void onChange(boolean selfChange) {
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (isNsdEnabled()) {
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            mNsdStateMachine.sendMessage(NsdManager.ENABLE);
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        } else {
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            mNsdStateMachine.sendMessage(NsdManager.DISABLE);
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            };
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mContext.getContentResolver().registerContentObserver(
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Settings.Global.getUriFor(Settings.Global.NSD_ON),
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    false, contentObserver);
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13369a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes        NsdStateMachine(String name) {
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super(name);
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            addState(mDefaultState);
13669a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes                addState(mDisabledState, mDefaultState);
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                addState(mEnabledState, mDefaultState);
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (isNsdEnabled()) {
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                setInitialState(mEnabledState);
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                setInitialState(mDisabledState);
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setLogRecSize(25);
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            registerForNsdSetting();
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        class DefaultState extends State {
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            @Override
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            public boolean processMessage(Message msg) {
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ClientInfo cInfo = null;
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                switch (msg.what) {
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            AsyncChannel c = (AsyncChannel) msg.obj;
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            if (DBG) Slog.d(TAG, "New client listening to asynchronous messages");
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            c.sendMessage(AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED);
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            cInfo = new ClientInfo(c, msg.replyTo);
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            mClients.put(msg.replyTo, cInfo);
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        } else {
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            Slog.e(TAG, "Client connection failure, error=" + msg.arg1);
161f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten                        }
162e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat                        break;
163c6a410164e1fd728cf7873493baacca7bc29548dMark Salyzyn                    case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
164f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten                        switch (msg.arg1) {
165f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten                            case AsyncChannel.STATUS_SEND_UNSUCCESSFUL:
166887f355f99ff83d568ef2885a4fdcaae475583dfDianne Hackborn                                Slog.e(TAG, "Send failed, client connection lost");
167f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten                                break;
168e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat                            case AsyncChannel.STATUS_REMOTE_DISCONNECTION:
169e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat                                if (DBG) Slog.d(TAG, "Client disconnected");
170e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat                                break;
17169a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes                            default:
1723e458241d9930465a20a861ecb42744355d48e48San Mehat                                if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1);
173c6a410164e1fd728cf7873493baacca7bc29548dMark Salyzyn                                break;
1743e458241d9930465a20a861ecb42744355d48e48San Mehat                        }
1753e458241d9930465a20a861ecb42744355d48e48San Mehat                        cInfo = mClients.get(msg.replyTo);
1763e458241d9930465a20a861ecb42744355d48e48San Mehat                        if (cInfo != null) {
1773e458241d9930465a20a861ecb42744355d48e48San Mehat                            cInfo.expungeAllRequests();
1783e458241d9930465a20a861ecb42744355d48e48San Mehat                            mClients.remove(msg.replyTo);
179f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten                        }
1806793ac943afeb16642f477c43ddfd27e498db37bGlenn Kasten                        //Last client
1813e458241d9930465a20a861ecb42744355d48e48San Mehat                        if (mClients.size() == 0) {
1823e458241d9930465a20a861ecb42744355d48e48San Mehat                            stopMDnsDaemon();
1833e458241d9930465a20a861ecb42744355d48e48San Mehat                        }
184f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten                        break;
185f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten                    case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION:
186f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten                        AsyncChannel ac = new AsyncChannel();
187f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten                        ac.connect(mContext, getHandler(), msg.replyTo);
188f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten                        break;
189f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten                    case NsdManager.DISCOVER_SERVICES:
190f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten                        replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED,
191a5109a878eeff22e32ee5ce1b1cd15e8daad5234San Mehat                                NsdManager.FAILURE_INTERNAL_ERROR);
192a5109a878eeff22e32ee5ce1b1cd15e8daad5234San Mehat                       break;
193a5109a878eeff22e32ee5ce1b1cd15e8daad5234San Mehat                    case NsdManager.STOP_DISCOVERY:
194a5109a878eeff22e32ee5ce1b1cd15e8daad5234San Mehat                       replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED,
195a5109a878eeff22e32ee5ce1b1cd15e8daad5234San Mehat                               NsdManager.FAILURE_INTERNAL_ERROR);
196a5109a878eeff22e32ee5ce1b1cd15e8daad5234San Mehat                        break;
197a5109a878eeff22e32ee5ce1b1cd15e8daad5234San Mehat                    case NsdManager.REGISTER_SERVICE:
198a5109a878eeff22e32ee5ce1b1cd15e8daad5234San Mehat                        replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED,
199a5109a878eeff22e32ee5ce1b1cd15e8daad5234San Mehat                                NsdManager.FAILURE_INTERNAL_ERROR);
200a5109a878eeff22e32ee5ce1b1cd15e8daad5234San Mehat                        break;
201a5109a878eeff22e32ee5ce1b1cd15e8daad5234San Mehat                    case NsdManager.UNREGISTER_SERVICE:
202a5109a878eeff22e32ee5ce1b1cd15e8daad5234San Mehat                        replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED,
203a5109a878eeff22e32ee5ce1b1cd15e8daad5234San Mehat                                NsdManager.FAILURE_INTERNAL_ERROR);
20469a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes                        break;
205f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten                    case NsdManager.RESOLVE_SERVICE:
2065baa3a62a97544669fba6d65a11c07f252e654ddSteve Block                        replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED,
207a5109a878eeff22e32ee5ce1b1cd15e8daad5234San Mehat                                NsdManager.FAILURE_INTERNAL_ERROR);
2085baa3a62a97544669fba6d65a11c07f252e654ddSteve Block                        break;
209a5109a878eeff22e32ee5ce1b1cd15e8daad5234San Mehat                    case NsdManager.NATIVE_DAEMON_EVENT:
210a5109a878eeff22e32ee5ce1b1cd15e8daad5234San Mehat                    default:
2113e458241d9930465a20a861ecb42744355d48e48San Mehat                        Slog.e(TAG, "Unhandled " + msg);
2123e458241d9930465a20a861ecb42744355d48e48San Mehat                        return NOT_HANDLED;
2131fd0ec738b0a2b97cc28701aa37b1a9869afc684San Mehat                }
2141fd0ec738b0a2b97cc28701aa37b1a9869afc684San Mehat                return HANDLED;
2156793ac943afeb16642f477c43ddfd27e498db37bGlenn Kasten            }
2163e458241d9930465a20a861ecb42744355d48e48San Mehat        }
2173e458241d9930465a20a861ecb42744355d48e48San Mehat
2183e458241d9930465a20a861ecb42744355d48e48San Mehat        class DisabledState extends State {
2193e458241d9930465a20a861ecb42744355d48e48San Mehat            @Override
2207e63789a0e0689d940609b1daceebc1bc08dcbefSan Mehat            public void enter() {
2217e63789a0e0689d940609b1daceebc1bc08dcbefSan Mehat                sendNsdStateChangeBroadcast(false);
2227e63789a0e0689d940609b1daceebc1bc08dcbefSan Mehat            }
2233e458241d9930465a20a861ecb42744355d48e48San Mehat
2243e458241d9930465a20a861ecb42744355d48e48San Mehat            @Override
2257e63789a0e0689d940609b1daceebc1bc08dcbefSan Mehat            public boolean processMessage(Message msg) {
2267e63789a0e0689d940609b1daceebc1bc08dcbefSan Mehat                switch (msg.what) {
2277e63789a0e0689d940609b1daceebc1bc08dcbefSan Mehat                    case NsdManager.ENABLE:
2283762c311729fe9f3af085c14c5c1fb471d994c03Steve Block                        transitionTo(mEnabledState);
2297e63789a0e0689d940609b1daceebc1bc08dcbefSan Mehat                        break;
2307e63789a0e0689d940609b1daceebc1bc08dcbefSan Mehat                    default:
2311fd0ec738b0a2b97cc28701aa37b1a9869afc684San Mehat                        return NOT_HANDLED;
23207b0465095bd9ab3412caefa4fcacbdc3825c64bGlenn Kasten                }
23307b0465095bd9ab3412caefa4fcacbdc3825c64bGlenn Kasten                return HANDLED;
23407b0465095bd9ab3412caefa4fcacbdc3825c64bGlenn Kasten            }
23507b0465095bd9ab3412caefa4fcacbdc3825c64bGlenn Kasten        }
23607b0465095bd9ab3412caefa4fcacbdc3825c64bGlenn Kasten
23707b0465095bd9ab3412caefa4fcacbdc3825c64bGlenn Kasten        class EnabledState extends State {
23807b0465095bd9ab3412caefa4fcacbdc3825c64bGlenn Kasten            @Override
23907b0465095bd9ab3412caefa4fcacbdc3825c64bGlenn Kasten            public void enter() {
24007b0465095bd9ab3412caefa4fcacbdc3825c64bGlenn Kasten                sendNsdStateChangeBroadcast(true);
2417e63789a0e0689d940609b1daceebc1bc08dcbefSan Mehat                if (mClients.size() > 0) {
24207b0465095bd9ab3412caefa4fcacbdc3825c64bGlenn Kasten                    startMDnsDaemon();
243f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten                }
244f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten            }
245f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten
246f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten            @Override
2477e63789a0e0689d940609b1daceebc1bc08dcbefSan Mehat            public void exit() {
24869a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes                if (mClients.size() > 0) {
249f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten                    stopMDnsDaemon();
250f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten                }
251f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten            }
2520a42b811aea490a9a605b75f0320101f6eafd283San Mehat
253242d65bf9faf1d2bc3468490e510551140e23462San Mehat            private boolean requestLimitReached(ClientInfo clientInfo) {
2543e458241d9930465a20a861ecb42744355d48e48San Mehat                if (clientInfo.mClientIds.size() >= ClientInfo.MAX_LIMIT) {
2553e458241d9930465a20a861ecb42744355d48e48San Mehat                    if (DBG) Slog.d(TAG, "Exceeded max outstanding requests " + clientInfo);
2563e458241d9930465a20a861ecb42744355d48e48San Mehat                    return true;
2573e458241d9930465a20a861ecb42744355d48e48San Mehat                }
2589e57c414f39e1a31349bc215635fdcfaf1902ceeJeff Sharkey                return false;
2599e57c414f39e1a31349bc215635fdcfaf1902ceeJeff Sharkey            }
2609e57c414f39e1a31349bc215635fdcfaf1902ceeJeff Sharkey
2619e57c414f39e1a31349bc215635fdcfaf1902ceeJeff Sharkey            private void storeRequestMap(int clientId, int globalId, ClientInfo clientInfo, int what) {
2629e57c414f39e1a31349bc215635fdcfaf1902ceeJeff Sharkey                clientInfo.mClientIds.put(clientId, globalId);
2639e57c414f39e1a31349bc215635fdcfaf1902ceeJeff Sharkey                clientInfo.mClientRequests.put(clientId, what);
2649e57c414f39e1a31349bc215635fdcfaf1902ceeJeff Sharkey                mIdToClientInfoMap.put(globalId, clientInfo);
2659e57c414f39e1a31349bc215635fdcfaf1902ceeJeff Sharkey            }
2669e57c414f39e1a31349bc215635fdcfaf1902ceeJeff Sharkey
267160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate            private void removeRequestMap(int clientId, int globalId, ClientInfo clientInfo) {
268160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate                clientInfo.mClientIds.remove(clientId);
269160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate                clientInfo.mClientRequests.remove(clientId);
270160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate                mIdToClientInfoMap.remove(globalId);
27171f2cf116aab893e224056c38ab146bd1538dd3eSteve Block            }
272160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate
273160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate            @Override
274160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate            public boolean processMessage(Message msg) {
275160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate                ClientInfo clientInfo;
276160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate                NsdServiceInfo servInfo;
277160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate                boolean result = HANDLED;
278160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate                int id;
279160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate                switch (msg.what) {
280160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate                  case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
281160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate                        //First client
282160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate                        if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL &&
283160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate                                mClients.size() == 0) {
2846793ac943afeb16642f477c43ddfd27e498db37bGlenn Kasten                            startMDnsDaemon();
2856793ac943afeb16642f477c43ddfd27e498db37bGlenn Kasten                        }
2866793ac943afeb16642f477c43ddfd27e498db37bGlenn Kasten                        result = NOT_HANDLED;
287cc767191cfb675f744e0165608b0a4196aba2b37Glenn Kasten                        break;
2886793ac943afeb16642f477c43ddfd27e498db37bGlenn Kasten                    case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
2896793ac943afeb16642f477c43ddfd27e498db37bGlenn Kasten                        result = NOT_HANDLED;
2906793ac943afeb16642f477c43ddfd27e498db37bGlenn Kasten                        break;
2916793ac943afeb16642f477c43ddfd27e498db37bGlenn Kasten                    case NsdManager.DISABLE:
2926793ac943afeb16642f477c43ddfd27e498db37bGlenn Kasten                        //TODO: cleanup clients
2936793ac943afeb16642f477c43ddfd27e498db37bGlenn Kasten                        transitionTo(mDisabledState);
294cc767191cfb675f744e0165608b0a4196aba2b37Glenn Kasten                        break;
295cc767191cfb675f744e0165608b0a4196aba2b37Glenn Kasten                    case NsdManager.DISCOVER_SERVICES:
296cc767191cfb675f744e0165608b0a4196aba2b37Glenn Kasten                        if (DBG) Slog.d(TAG, "Discover services");
2976793ac943afeb16642f477c43ddfd27e498db37bGlenn Kasten                        servInfo = (NsdServiceInfo) msg.obj;
2986793ac943afeb16642f477c43ddfd27e498db37bGlenn Kasten                        clientInfo = mClients.get(msg.replyTo);
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (requestLimitReached(clientInfo)) {
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED,
302160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate                                    NsdManager.FAILURE_MAX_LIMIT);
303160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate                            break;
304160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate                        }
305160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate
306160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate                        id = getUniqueId();
307160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate                        if (discoverServices(id, servInfo.getServiceType())) {
308160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate                            if (DBG) {
3093762c311729fe9f3af085c14c5c1fb471d994c03Steve Block                                Slog.d(TAG, "Discover " + msg.arg2 + " " + id +
310160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate                                        servInfo.getServiceType());
311160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate                            }
312160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate                            storeRequestMap(msg.arg2, id, clientInfo, msg.what);
313160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate                            replyToMessage(msg, NsdManager.DISCOVER_SERVICES_STARTED, servInfo);
314160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate                        } else {
315160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate                            stopServiceDiscovery(id);
316160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate                            replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED,
317887f355f99ff83d568ef2885a4fdcaae475583dfDianne Hackborn                                    NsdManager.FAILURE_INTERNAL_ERROR);
318887f355f99ff83d568ef2885a4fdcaae475583dfDianne Hackborn                        }
319887f355f99ff83d568ef2885a4fdcaae475583dfDianne Hackborn                        break;
3206793ac943afeb16642f477c43ddfd27e498db37bGlenn Kasten                    case NsdManager.STOP_DISCOVERY:
321887f355f99ff83d568ef2885a4fdcaae475583dfDianne Hackborn                        if (DBG) Slog.d(TAG, "Stop service discovery");
3226793ac943afeb16642f477c43ddfd27e498db37bGlenn Kasten                        clientInfo = mClients.get(msg.replyTo);
323887f355f99ff83d568ef2885a4fdcaae475583dfDianne Hackborn
3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        try {
32569a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes                            id = clientInfo.mClientIds.get(msg.arg2).intValue();
326c6a410164e1fd728cf7873493baacca7bc29548dMark Salyzyn                        } catch (NullPointerException e) {
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED,
3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    NsdManager.FAILURE_INTERNAL_ERROR);
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            break;
3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        removeRequestMap(msg.arg2, id, clientInfo);
3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (stopServiceDiscovery(id)) {
3336d4b1e24aef5b74b40de4d8f6e63c21874ce8e3aElliott Hughes                            replyToMessage(msg, NsdManager.STOP_DISCOVERY_SUCCEEDED);
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        } else {
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED,
3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    NsdManager.FAILURE_INTERNAL_ERROR);
3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        break;
3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    case NsdManager.REGISTER_SERVICE:
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (DBG) Slog.d(TAG, "Register service");
3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        clientInfo = mClients.get(msg.replyTo);
3426793ac943afeb16642f477c43ddfd27e498db37bGlenn Kasten                        if (requestLimitReached(clientInfo)) {
3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED,
344c6a410164e1fd728cf7873493baacca7bc29548dMark Salyzyn                                    NsdManager.FAILURE_MAX_LIMIT);
3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            break;
3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        id = getUniqueId();
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (registerService(id, (NsdServiceInfo) msg.obj)) {
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            if (DBG) Slog.d(TAG, "Register " + msg.arg2 + " " + id);
3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            storeRequestMap(msg.arg2, id, clientInfo, msg.what);
35210e89712863f5b91a2982dc1783fbdfe39c1485dJeff Brown                            // Return success after mDns reports success
35310e89712863f5b91a2982dc1783fbdfe39c1485dJeff Brown                        } else {
35410e89712863f5b91a2982dc1783fbdfe39c1485dJeff Brown                            unregisterService(id);
35510e89712863f5b91a2982dc1783fbdfe39c1485dJeff Brown                            replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED,
35610e89712863f5b91a2982dc1783fbdfe39c1485dJeff Brown                                    NsdManager.FAILURE_INTERNAL_ERROR);
35710e89712863f5b91a2982dc1783fbdfe39c1485dJeff Brown                        }
35810e89712863f5b91a2982dc1783fbdfe39c1485dJeff Brown                        break;
3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    case NsdManager.UNREGISTER_SERVICE:
36010e89712863f5b91a2982dc1783fbdfe39c1485dJeff Brown                        if (DBG) Slog.d(TAG, "unregister service");
3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        clientInfo = mClients.get(msg.replyTo);
3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        try {
3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            id = clientInfo.mClientIds.get(msg.arg2).intValue();
3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        } catch (NullPointerException e) {
3655534ba91ac0a0c9af822af62bcf92e2c5a8d6ec8Rom Lemarchand                            replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED,
3665534ba91ac0a0c9af822af62bcf92e2c5a8d6ec8Rom Lemarchand                                    NsdManager.FAILURE_INTERNAL_ERROR);
3675534ba91ac0a0c9af822af62bcf92e2c5a8d6ec8Rom Lemarchand                            break;
3685534ba91ac0a0c9af822af62bcf92e2c5a8d6ec8Rom Lemarchand                        }
3695534ba91ac0a0c9af822af62bcf92e2c5a8d6ec8Rom Lemarchand                        removeRequestMap(msg.arg2, id, clientInfo);
3705534ba91ac0a0c9af822af62bcf92e2c5a8d6ec8Rom Lemarchand                        if (unregisterService(id)) {
3715534ba91ac0a0c9af822af62bcf92e2c5a8d6ec8Rom Lemarchand                            replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_SUCCEEDED);
3725534ba91ac0a0c9af822af62bcf92e2c5a8d6ec8Rom Lemarchand                        } else {
3735534ba91ac0a0c9af822af62bcf92e2c5a8d6ec8Rom Lemarchand                            replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED,
3745534ba91ac0a0c9af822af62bcf92e2c5a8d6ec8Rom Lemarchand                                    NsdManager.FAILURE_INTERNAL_ERROR);
3755534ba91ac0a0c9af822af62bcf92e2c5a8d6ec8Rom Lemarchand                        }
3765534ba91ac0a0c9af822af62bcf92e2c5a8d6ec8Rom Lemarchand                        break;
3775534ba91ac0a0c9af822af62bcf92e2c5a8d6ec8Rom Lemarchand                    case NsdManager.RESOLVE_SERVICE:
3785534ba91ac0a0c9af822af62bcf92e2c5a8d6ec8Rom Lemarchand                        if (DBG) Slog.d(TAG, "Resolve service");
3795534ba91ac0a0c9af822af62bcf92e2c5a8d6ec8Rom Lemarchand                        servInfo = (NsdServiceInfo) msg.obj;
3805534ba91ac0a0c9af822af62bcf92e2c5a8d6ec8Rom Lemarchand                        clientInfo = mClients.get(msg.replyTo);
3815534ba91ac0a0c9af822af62bcf92e2c5a8d6ec8Rom Lemarchand
3825534ba91ac0a0c9af822af62bcf92e2c5a8d6ec8Rom Lemarchand
383c6a410164e1fd728cf7873493baacca7bc29548dMark Salyzyn                        if (clientInfo.mResolvedService != null) {
3845534ba91ac0a0c9af822af62bcf92e2c5a8d6ec8Rom Lemarchand                            replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED,
3855534ba91ac0a0c9af822af62bcf92e2c5a8d6ec8Rom Lemarchand                                    NsdManager.FAILURE_ALREADY_ACTIVE);
3865534ba91ac0a0c9af822af62bcf92e2c5a8d6ec8Rom Lemarchand                            break;
3875534ba91ac0a0c9af822af62bcf92e2c5a8d6ec8Rom Lemarchand                        }
3885534ba91ac0a0c9af822af62bcf92e2c5a8d6ec8Rom Lemarchand
3895534ba91ac0a0c9af822af62bcf92e2c5a8d6ec8Rom Lemarchand                        id = getUniqueId();
3905534ba91ac0a0c9af822af62bcf92e2c5a8d6ec8Rom Lemarchand                        if (resolveService(id, servInfo)) {
3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            clientInfo.mResolvedService = new NsdServiceInfo();
3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            storeRequestMap(msg.arg2, id, clientInfo, msg.what);
3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        } else {
39469a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes                            replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED,
3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    NsdManager.FAILURE_INTERNAL_ERROR);
3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
39769a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes                        break;
3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    case NsdManager.NATIVE_DAEMON_EVENT:
3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        NativeEvent event = (NativeEvent) msg.obj;
4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (!handleNativeEvent(event.code, event.raw, event.cooked)) {
4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            result = NOT_HANDLED;
4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        break;
4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    default:
4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        result = NOT_HANDLED;
406a23fcd7be8e40078a913b1a99222cdd89229e67bNarayan Kamath                        break;
407a23fcd7be8e40078a913b1a99222cdd89229e67bNarayan Kamath                }
408a23fcd7be8e40078a913b1a99222cdd89229e67bNarayan Kamath                return result;
4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            private boolean handleNativeEvent(int code, String raw, String[] cooked) {
4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                boolean handled = true;
4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                NsdServiceInfo servInfo;
4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int id = Integer.parseInt(cooked[1]);
4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ClientInfo clientInfo = mIdToClientInfoMap.get(id);
4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (clientInfo == null) {
4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Slog.e(TAG, "Unique id with no client mapping: " + id);
4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    handled = false;
4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return handled;
4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                /* This goes in response as msg.arg2 */
4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int clientId = clientInfo.getClientId(id);
424c6a410164e1fd728cf7873493baacca7bc29548dMark Salyzyn                if (clientId < 0) {
4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // This can happen because of race conditions. For example,
4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // SERVICE_FOUND may race with STOP_SERVICE_DISCOVERY,
4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // and we may get in this situation.
428c367d48c55e5a3fa0df14fd62889e4bb6b63cb01Elliott Hughes                    Slog.d(TAG, "Notification for a listener that is no longer active: " + id);
4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    handled = false;
4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return handled;
43169a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes                }
4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4338564c8da817a845353d213acd8636b76f567b234Steve Block                switch (code) {
4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    case NativeResponseCode.SERVICE_FOUND:
4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        /* NNN uniqueId serviceName regType domain */
43669a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes                        if (DBG) Slog.d(TAG, "SERVICE_FOUND Raw: " + raw);
4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        servInfo = new NsdServiceInfo(cooked[2], cooked[3]);
4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        clientInfo.mChannel.sendMessage(NsdManager.SERVICE_FOUND, 0,
4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                clientId, servInfo);
44069a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes                        break;
4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    case NativeResponseCode.SERVICE_LOST:
4428564c8da817a845353d213acd8636b76f567b234Steve Block                        /* NNN uniqueId serviceName regType domain */
4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (DBG) Slog.d(TAG, "SERVICE_LOST Raw: " + raw);
4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        servInfo = new NsdServiceInfo(cooked[2], cooked[3]);
4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        clientInfo.mChannel.sendMessage(NsdManager.SERVICE_LOST, 0,
4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                clientId, servInfo);
447c367d48c55e5a3fa0df14fd62889e4bb6b63cb01Elliott Hughes                        break;
4480bca96bcbfe559f9330a01f723c5c9cba51ec05aMarco Nelissen                    case NativeResponseCode.SERVICE_DISCOVERY_FAILED:
44969a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes                        /* NNN uniqueId errorCode */
4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (DBG) Slog.d(TAG, "SERVICE_DISC_FAILED Raw: " + raw);
45159325eb31f25704bb88c348160bb69e7c1aa3b48Dianne Hackborn                        clientInfo.mChannel.sendMessage(NsdManager.DISCOVER_SERVICES_FAILED,
4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                NsdManager.FAILURE_INTERNAL_ERROR, clientId);
4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        break;
4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    case NativeResponseCode.SERVICE_REGISTERED:
4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        /* NNN regId serviceName regType */
4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (DBG) Slog.d(TAG, "SERVICE_REGISTERED Raw: " + raw);
4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        servInfo = new NsdServiceInfo(cooked[2], null);
4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        clientInfo.mChannel.sendMessage(NsdManager.REGISTER_SERVICE_SUCCEEDED,
4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                id, clientId, servInfo);
4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        break;
4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    case NativeResponseCode.SERVICE_REGISTRATION_FAILED:
4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        /* NNN regId errorCode */
4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (DBG) Slog.d(TAG, "SERVICE_REGISTER_FAILED Raw: " + raw);
4640bca96bcbfe559f9330a01f723c5c9cba51ec05aMarco Nelissen                        clientInfo.mChannel.sendMessage(NsdManager.REGISTER_SERVICE_FAILED,
4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                               NsdManager.FAILURE_INTERNAL_ERROR, clientId);
4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        break;
4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    case NativeResponseCode.SERVICE_UPDATED:
4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        /* NNN regId */
4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        break;
4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    case NativeResponseCode.SERVICE_UPDATE_FAILED:
4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        /* NNN regId errorCode */
47269a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes                        break;
4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    case NativeResponseCode.SERVICE_RESOLVED:
4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        /* NNN resolveId fullName hostName port txtlen txtdata */
4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (DBG) Slog.d(TAG, "SERVICE_RESOLVED Raw: " + raw);
47659325eb31f25704bb88c348160bb69e7c1aa3b48Dianne Hackborn                        int index = 0;
47759325eb31f25704bb88c348160bb69e7c1aa3b48Dianne Hackborn                        while (index < cooked[2].length() && cooked[2].charAt(index) != '.') {
47859325eb31f25704bb88c348160bb69e7c1aa3b48Dianne Hackborn                            if (cooked[2].charAt(index) == '\\') {
479c367d48c55e5a3fa0df14fd62889e4bb6b63cb01Elliott Hughes                                ++index;
48059325eb31f25704bb88c348160bb69e7c1aa3b48Dianne Hackborn                            }
48159325eb31f25704bb88c348160bb69e7c1aa3b48Dianne Hackborn                            ++index;
48259325eb31f25704bb88c348160bb69e7c1aa3b48Dianne Hackborn                        }
48359325eb31f25704bb88c348160bb69e7c1aa3b48Dianne Hackborn                        if (index >= cooked[2].length()) {
48459325eb31f25704bb88c348160bb69e7c1aa3b48Dianne Hackborn                            Slog.e(TAG, "Invalid service found " + raw);
48559325eb31f25704bb88c348160bb69e7c1aa3b48Dianne Hackborn                            break;
486c367d48c55e5a3fa0df14fd62889e4bb6b63cb01Elliott Hughes                        }
48759325eb31f25704bb88c348160bb69e7c1aa3b48Dianne Hackborn                        String name = cooked[2].substring(0, index);
48859325eb31f25704bb88c348160bb69e7c1aa3b48Dianne Hackborn                        String rest = cooked[2].substring(index);
48959325eb31f25704bb88c348160bb69e7c1aa3b48Dianne Hackborn                        String type = rest.replace(".local.", "");
4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        name = unescape(name);
4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4936215d3ff4b5dfa52a5d8b9a42e343051f31066a5Steve Block                        clientInfo.mResolvedService.setServiceName(name);
49469a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes                        clientInfo.mResolvedService.setServiceType(type);
4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        clientInfo.mResolvedService.setPort(Integer.parseInt(cooked[4]));
49669a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes
4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        stopResolveService(id);
4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        removeRequestMap(clientId, id, clientInfo);
49969a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes
5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        int id2 = getUniqueId();
5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (getAddrInfo(id2, cooked[3])) {
5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            storeRequestMap(clientId, id2, clientInfo, NsdManager.RESOLVE_SERVICE);
5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        } else {
5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    NsdManager.FAILURE_INTERNAL_ERROR, clientId);
50669a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes                            clientInfo.mResolvedService = null;
5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        break;
5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    case NativeResponseCode.SERVICE_RESOLUTION_FAILED:
5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        /* NNN resolveId errorCode */
5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (DBG) Slog.d(TAG, "SERVICE_RESOLVE_FAILED Raw: " + raw);
51269a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes                        stopResolveService(id);
5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        removeRequestMap(clientId, id, clientInfo);
5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        clientInfo.mResolvedService = null;
51569a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes                        clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                NsdManager.FAILURE_INTERNAL_ERROR, clientId);
5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        break;
5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    case NativeResponseCode.SERVICE_GET_ADDR_FAILED:
5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        /* NNN resolveId errorCode */
5206215d3ff4b5dfa52a5d8b9a42e343051f31066a5Steve Block                        stopGetAddrInfo(id);
5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        removeRequestMap(clientId, id, clientInfo);
52269a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes                        clientInfo.mResolvedService = null;
5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (DBG) Slog.d(TAG, "SERVICE_RESOLVE_FAILED Raw: " + raw);
5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                NsdManager.FAILURE_INTERNAL_ERROR, clientId);
5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        break;
5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    case NativeResponseCode.SERVICE_GET_ADDR_SUCCESS:
52869a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes                        /* NNN resolveId hostname ttl addr */
5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (DBG) Slog.d(TAG, "SERVICE_GET_ADDR_SUCCESS Raw: " + raw);
5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        try {
5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            clientInfo.mResolvedService.setHost(InetAddress.getByName(cooked[4]));
53269a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes                            clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_SUCCEEDED,
5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                   0, clientId, clientInfo.mResolvedService);
5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        } catch (java.net.UnknownHostException e) {
5359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    NsdManager.FAILURE_INTERNAL_ERROR, clientId);
53769a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes                        }
538c6a410164e1fd728cf7873493baacca7bc29548dMark Salyzyn                        stopGetAddrInfo(id);
5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        removeRequestMap(clientId, id, clientInfo);
5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        clientInfo.mResolvedService = null;
5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        break;
54269a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes                    default:
5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        handled = false;
54469a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes                        break;
5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return handled;
5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project       }
5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
55069a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes
5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private String unescape(String s) {
5528564c8da817a845353d213acd8636b76f567b234Steve Block        StringBuilder sb = new StringBuilder(s.length());
5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < s.length(); ++i) {
5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            char c = s.charAt(i);
5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (c == '\\') {
55669a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes                if (++i >= s.length()) {
5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Slog.e(TAG, "Unexpected end of escape sequence in: " + s);
55869a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes                    break;
5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                c = s.charAt(i);
5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (c != '.' && c != '\\') {
5626215d3ff4b5dfa52a5d8b9a42e343051f31066a5Steve Block                    if (i + 2 >= s.length()) {
5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        Slog.e(TAG, "Unexpected end of escape sequence in: " + s);
5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        break;
5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    c = (char) ((c-'0') * 100 + (s.charAt(i+1)-'0') * 10 + (s.charAt(i+2)-'0'));
567add868cebaf62cffe96e79764ea0b7f2320a03ebAmith Yamasani                    i += 2;
5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sb.append(c);
5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return sb.toString();
5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private NativeDaemonConnector mNativeConnector;
5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final CountDownLatch mNativeDaemonConnected = new CountDownLatch(1);
577c6a410164e1fd728cf7873493baacca7bc29548dMark Salyzyn
5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private NsdService(Context context) {
5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext = context;
5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContentResolver = context.getContentResolver();
5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mNativeConnector = new NativeDaemonConnector(new NativeCallbackReceiver(), "mdns", 10,
5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                MDNS_TAG, 25, null);
5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mNsdStateMachine = new NsdStateMachine(TAG);
5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mNsdStateMachine.start();
5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Thread th = new Thread(mNativeConnector, MDNS_TAG);
5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        th.start();
5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
59169a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes
5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static NsdService create(Context context) throws InterruptedException {
5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        NsdService service = new NsdService(context);
5948564c8da817a845353d213acd8636b76f567b234Steve Block        service.mNativeDaemonConnected.await();
5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return service;
59669a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes    }
5976215d3ff4b5dfa52a5d8b9a42e343051f31066a5Steve Block
5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Messenger getMessenger() {
5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INTERNET,
6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            "NsdService");
6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return new Messenger(mNsdStateMachine.getHandler());
6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setEnabled(boolean enable) {
60569a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL,
6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                "NsdService");
6079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Settings.Global.putInt(mContentResolver, Settings.Global.NSD_ON, enable ? 1 : 0);
60869a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes        if (enable) {
6099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mNsdStateMachine.sendMessage(NsdManager.ENABLE);
6109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
6119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mNsdStateMachine.sendMessage(NsdManager.DISABLE);
6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
61469a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes
6159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void sendNsdStateChangeBroadcast(boolean enabled) {
61669a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes        final Intent intent = new Intent(NsdManager.ACTION_NSD_STATE_CHANGED);
6179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
61869a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes        if (enabled) {
6199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            intent.putExtra(NsdManager.EXTRA_NSD_STATE, NsdManager.NSD_STATE_ENABLED);
6209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            intent.putExtra(NsdManager.EXTRA_NSD_STATE, NsdManager.NSD_STATE_DISABLED);
62269a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes        }
6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean isNsdEnabled() {
6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean ret = Settings.Global.getInt(mContentResolver, Settings.Global.NSD_ON, 1) == 1;
6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (DBG) Slog.d(TAG, "Network service discovery enabled " + ret);
62969a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes        return ret;
6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
63169a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes
6329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int getUniqueId() {
6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (++mUniqueId == INVALID_ID) return ++mUniqueId;
6349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mUniqueId;
6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* These should be in sync with system/netd/server/ResponseCode.h */
6389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    class NativeResponseCode {
6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public static final int SERVICE_DISCOVERY_FAILED    =   602;
64069a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes        public static final int SERVICE_FOUND               =   603;
6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public static final int SERVICE_LOST                =   604;
6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6436215d3ff4b5dfa52a5d8b9a42e343051f31066a5Steve Block        public static final int SERVICE_REGISTRATION_FAILED =   605;
6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public static final int SERVICE_REGISTERED          =   606;
6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public static final int SERVICE_RESOLUTION_FAILED   =   607;
6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public static final int SERVICE_RESOLVED            =   608;
6489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public static final int SERVICE_UPDATED             =   609;
6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public static final int SERVICE_UPDATE_FAILED       =   610;
6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public static final int SERVICE_GET_ADDR_FAILED     =   611;
6539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public static final int SERVICE_GET_ADDR_SUCCESS    =   612;
6549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private class NativeEvent {
6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int code;
6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final String raw;
6599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final String[] cooked;
6609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
66169a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes        NativeEvent(int code, String raw, String[] cooked) {
6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            this.code = code;
6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            this.raw = raw;
6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            this.cooked = cooked;
66569a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes        }
6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
66769a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes
6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    class NativeCallbackReceiver implements INativeDaemonConnectorCallbacks {
6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onDaemonConnected() {
6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mNativeDaemonConnected.countDown();
67169a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes        }
6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public boolean onCheckHoldWakeLock(int code) {
6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
67669a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes
6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public boolean onEvent(int code, String raw, String[] cooked) {
6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // TODO: NDC translates a message to a callback, we could enhance NDC to
6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // directly interact with a state machine through messages
68069a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes            NativeEvent event = new NativeEvent(code, raw, cooked);
6819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mNsdStateMachine.sendMessage(NsdManager.NATIVE_DAEMON_EVENT, event);
6829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean startMDnsDaemon() {
6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (DBG) Slog.d(TAG, "startMDnsDaemon");
6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mNativeConnector.execute("mdnssd", "start-service");
69013ac041b9f21043bc7c848a743be618bfd7a67e9Dianne Hackborn        } catch(NativeDaemonConnectorException e) {
6919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Slog.e(TAG, "Failed to start daemon" + e);
6929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
6959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
696c64edde69d18498fb2954f71a546357b07ab996aEvan Millar
69769a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes    private boolean stopMDnsDaemon() {
698c64edde69d18498fb2954f71a546357b07ab996aEvan Millar        if (DBG) Slog.d(TAG, "stopMDnsDaemon");
6999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
70069a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes            mNativeConnector.execute("mdnssd", "stop-service");
7019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch(NativeDaemonConnectorException e) {
7029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Slog.e(TAG, "Failed to start daemon" + e);
7039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
7049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
70569a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes        return true;
7069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean registerService(int regId, NsdServiceInfo service) {
7099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (DBG) Slog.d(TAG, "registerService: " + regId + " " + service);
7109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Command cmd = new Command("mdnssd", "register", regId, service.getServiceName(),
7129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    service.getServiceType(), service.getPort());
7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Add TXT records as additional arguments.
7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Map<String, byte[]> txtRecords = service.getAttributes();
7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (String key : txtRecords.keySet()) {
7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
7189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // TODO: Send encoded TXT record as bytes once NDC/netd supports binary data.
7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    cmd.appendArg(String.format(Locale.US, "%s=%s", key,
7209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            new String(txtRecords.get(key), "UTF_8")));
7219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (UnsupportedEncodingException e) {
7229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Slog.e(TAG, "Failed to encode txtRecord " + e);
7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
726c64edde69d18498fb2954f71a546357b07ab996aEvan Millar            mNativeConnector.execute(cmd);
7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch(NativeDaemonConnectorException e) {
72869a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes            Slog.e(TAG, "Failed to execute registerService " + e);
7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
73069a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes        }
7319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
73213ac041b9f21043bc7c848a743be618bfd7a67e9Dianne Hackborn    }
7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean unregisterService(int regId) {
73513ac041b9f21043bc7c848a743be618bfd7a67e9Dianne Hackborn        if (DBG) Slog.d(TAG, "unregisterService: " + regId);
73613ac041b9f21043bc7c848a743be618bfd7a67e9Dianne Hackborn        try {
73713ac041b9f21043bc7c848a743be618bfd7a67e9Dianne Hackborn            mNativeConnector.execute("mdnssd", "stop-register", regId);
73813ac041b9f21043bc7c848a743be618bfd7a67e9Dianne Hackborn        } catch(NativeDaemonConnectorException e) {
73913ac041b9f21043bc7c848a743be618bfd7a67e9Dianne Hackborn            Slog.e(TAG, "Failed to execute unregisterService " + e);
74013ac041b9f21043bc7c848a743be618bfd7a67e9Dianne Hackborn            return false;
7419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
7439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
744c64edde69d18498fb2954f71a546357b07ab996aEvan Millar
7459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean updateService(int regId, DnsSdTxtRecord t) {
7469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (DBG) Slog.d(TAG, "updateService: " + regId + " " + t);
7479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
74869a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes            if (t == null) return false;
7499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mNativeConnector.execute("mdnssd", "update", regId, t.size(), t.getRawData());
7509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch(NativeDaemonConnectorException e) {
751c367d48c55e5a3fa0df14fd62889e4bb6b63cb01Elliott Hughes            Slog.e(TAG, "Failed to updateServices " + e);
7529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
75613ac041b9f21043bc7c848a743be618bfd7a67e9Dianne Hackborn
75713ac041b9f21043bc7c848a743be618bfd7a67e9Dianne Hackborn    private boolean discoverServices(int discoveryId, String serviceType) {
75813ac041b9f21043bc7c848a743be618bfd7a67e9Dianne Hackborn        if (DBG) Slog.d(TAG, "discoverServices: " + discoveryId + " " + serviceType);
75913ac041b9f21043bc7c848a743be618bfd7a67e9Dianne Hackborn        try {
76013ac041b9f21043bc7c848a743be618bfd7a67e9Dianne Hackborn            mNativeConnector.execute("mdnssd", "discover", discoveryId, serviceType);
76113ac041b9f21043bc7c848a743be618bfd7a67e9Dianne Hackborn        } catch(NativeDaemonConnectorException e) {
7629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Slog.e(TAG, "Failed to discoverServices " + e);
763c367d48c55e5a3fa0df14fd62889e4bb6b63cb01Elliott Hughes            return false;
7649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
7669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean stopServiceDiscovery(int discoveryId) {
76969a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes        if (DBG) Slog.d(TAG, "stopServiceDiscovery: " + discoveryId);
770c64edde69d18498fb2954f71a546357b07ab996aEvan Millar        try {
7719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mNativeConnector.execute("mdnssd", "stop-discover", discoveryId);
7729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch(NativeDaemonConnectorException e) {
773c367d48c55e5a3fa0df14fd62889e4bb6b63cb01Elliott Hughes            Slog.e(TAG, "Failed to stopServiceDiscovery " + e);
7749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
7759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
7779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
77869a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes
779c6a410164e1fd728cf7873493baacca7bc29548dMark Salyzyn    private boolean resolveService(int resolveId, NsdServiceInfo service) {
78069a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes        if (DBG) Slog.d(TAG, "resolveService: " + resolveId + " " + service);
7819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
7829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mNativeConnector.execute("mdnssd", "resolve", resolveId, service.getServiceName(),
7839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    service.getServiceType(), "local.");
7849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch(NativeDaemonConnectorException e) {
7859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Slog.e(TAG, "Failed to resolveService " + e);
7869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
7879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
7899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean stopResolveService(int resolveId) {
7929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (DBG) Slog.d(TAG, "stopResolveService: " + resolveId);
7939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
7949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mNativeConnector.execute("mdnssd", "stop-resolve", resolveId);
7959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch(NativeDaemonConnectorException e) {
7969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Slog.e(TAG, "Failed to stop resolve " + e);
7979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
7989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
80069a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes    }
8019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean getAddrInfo(int resolveId, String hostname) {
8039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (DBG) Slog.d(TAG, "getAdddrInfo: " + resolveId);
8049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
8059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mNativeConnector.execute("mdnssd", "getaddrinfo", resolveId, hostname);
8069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch(NativeDaemonConnectorException e) {
8079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Slog.e(TAG, "Failed to getAddrInfo " + e);
80869a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes            return false;
8099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
8119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
812c64edde69d18498fb2954f71a546357b07ab996aEvan Millar
81369a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes    private boolean stopGetAddrInfo(int resolveId) {
814c64edde69d18498fb2954f71a546357b07ab996aEvan Millar        if (DBG) Slog.d(TAG, "stopGetAdddrInfo: " + resolveId);
815c64edde69d18498fb2954f71a546357b07ab996aEvan Millar        try {
816c64edde69d18498fb2954f71a546357b07ab996aEvan Millar            mNativeConnector.execute("mdnssd", "stop-getaddrinfo", resolveId);
817c64edde69d18498fb2954f71a546357b07ab996aEvan Millar        } catch(NativeDaemonConnectorException e) {
81869a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes            Slog.e(TAG, "Failed to stopGetAddrInfo " + e);
81969a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes            return false;
820c64edde69d18498fb2954f71a546357b07ab996aEvan Millar        }
82169a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes        return true;
822c64edde69d18498fb2954f71a546357b07ab996aEvan Millar    }
82369a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes
824c64edde69d18498fb2954f71a546357b07ab996aEvan Millar    @Override
825c64edde69d18498fb2954f71a546357b07ab996aEvan Millar    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
826c64edde69d18498fb2954f71a546357b07ab996aEvan Millar        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
827c64edde69d18498fb2954f71a546357b07ab996aEvan Millar                != PackageManager.PERMISSION_GRANTED) {
828c64edde69d18498fb2954f71a546357b07ab996aEvan Millar            pw.println("Permission Denial: can't dump ServiceDiscoverService from from pid="
829c64edde69d18498fb2954f71a546357b07ab996aEvan Millar                    + Binder.getCallingPid()
830c64edde69d18498fb2954f71a546357b07ab996aEvan Millar                    + ", uid=" + Binder.getCallingUid());
831c64edde69d18498fb2954f71a546357b07ab996aEvan Millar            return;
83269a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes        }
833c64edde69d18498fb2954f71a546357b07ab996aEvan Millar
834c64edde69d18498fb2954f71a546357b07ab996aEvan Millar        for (ClientInfo client : mClients.values()) {
835c64edde69d18498fb2954f71a546357b07ab996aEvan Millar            pw.println("Client Info");
836c64edde69d18498fb2954f71a546357b07ab996aEvan Millar            pw.println(client);
837c64edde69d18498fb2954f71a546357b07ab996aEvan Millar        }
838c64edde69d18498fb2954f71a546357b07ab996aEvan Millar
839c64edde69d18498fb2954f71a546357b07ab996aEvan Millar        mNsdStateMachine.dump(fd, pw, args);
840c64edde69d18498fb2954f71a546357b07ab996aEvan Millar    }
841c64edde69d18498fb2954f71a546357b07ab996aEvan Millar
842c64edde69d18498fb2954f71a546357b07ab996aEvan Millar    /* arg2 on the source message has an id that needs to be retained in replies
84369a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes     * see NsdManager for details */
844c64edde69d18498fb2954f71a546357b07ab996aEvan Millar    private Message obtainMessage(Message srcMsg) {
8458564c8da817a845353d213acd8636b76f567b234Steve Block        Message msg = Message.obtain();
846c64edde69d18498fb2954f71a546357b07ab996aEvan Millar        msg.arg2 = srcMsg.arg2;
847c64edde69d18498fb2954f71a546357b07ab996aEvan Millar        return msg;
84869a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes    }
849c64edde69d18498fb2954f71a546357b07ab996aEvan Millar
850c64edde69d18498fb2954f71a546357b07ab996aEvan Millar    private void replyToMessage(Message msg, int what) {
851c64edde69d18498fb2954f71a546357b07ab996aEvan Millar        if (msg.replyTo == null) return;
85269a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes        Message dstMsg = obtainMessage(msg);
853c64edde69d18498fb2954f71a546357b07ab996aEvan Millar        dstMsg.what = what;
8548564c8da817a845353d213acd8636b76f567b234Steve Block        mReplyChannel.replyToMessage(msg, dstMsg);
855c64edde69d18498fb2954f71a546357b07ab996aEvan Millar    }
856c64edde69d18498fb2954f71a546357b07ab996aEvan Millar
857c64edde69d18498fb2954f71a546357b07ab996aEvan Millar    private void replyToMessage(Message msg, int what, int arg1) {
85869a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes        if (msg.replyTo == null) return;
85969a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes        Message dstMsg = obtainMessage(msg);
860c64edde69d18498fb2954f71a546357b07ab996aEvan Millar        dstMsg.what = what;
86169a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes        dstMsg.arg1 = arg1;
862c64edde69d18498fb2954f71a546357b07ab996aEvan Millar        mReplyChannel.replyToMessage(msg, dstMsg);
863c64edde69d18498fb2954f71a546357b07ab996aEvan Millar    }
8649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void replyToMessage(Message msg, int what, Object obj) {
8669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (msg.replyTo == null) return;
8679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Message dstMsg = obtainMessage(msg);
86869a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes        dstMsg.what = what;
8699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        dstMsg.obj = obj;
8709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mReplyChannel.replyToMessage(msg, dstMsg);
8719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* Information tracked per client */
8749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private class ClientInfo {
8759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private static final int MAX_LIMIT = 10;
8779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final AsyncChannel mChannel;
878c6a410164e1fd728cf7873493baacca7bc29548dMark Salyzyn        private final Messenger mMessenger;
8799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /* Remembers a resolved service until getaddrinfo completes */
8809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private NsdServiceInfo mResolvedService;
8819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /* A map from client id to unique id sent to mDns */
883906497c574d45d8dfd295b16dece0d0bc32c0895Dianne Hackborn        private SparseArray<Integer> mClientIds = new SparseArray<Integer>();
884906497c574d45d8dfd295b16dece0d0bc32c0895Dianne Hackborn
885906497c574d45d8dfd295b16dece0d0bc32c0895Dianne Hackborn        /* A map from client id to the type of the request we had received */
886906497c574d45d8dfd295b16dece0d0bc32c0895Dianne Hackborn        private SparseArray<Integer> mClientRequests = new SparseArray<Integer>();
887906497c574d45d8dfd295b16dece0d0bc32c0895Dianne Hackborn
888906497c574d45d8dfd295b16dece0d0bc32c0895Dianne Hackborn        private ClientInfo(AsyncChannel c, Messenger m) {
889906497c574d45d8dfd295b16dece0d0bc32c0895Dianne Hackborn            mChannel = c;
8909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mMessenger = m;
8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (DBG) Slog.d(TAG, "New client, channel: " + c + " messenger: " + m);
8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
89569a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes        public String toString() {
8969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            StringBuffer sb = new StringBuffer();
8979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sb.append("mChannel ").append(mChannel).append("\n");
89869a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes            sb.append("mMessenger ").append(mMessenger).append("\n");
89969a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes            sb.append("mResolvedService ").append(mResolvedService).append("\n");
9009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for(int i = 0; i< mClientIds.size(); i++) {
9019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int clientID = mClientIds.keyAt(i);
9029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sb.append("clientId ").append(clientID).
9039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    append(" mDnsId ").append(mClientIds.valueAt(i)).
9049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    append(" type ").append(mClientRequests.get(clientID)).append("\n");
9059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return sb.toString();
9079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
908c6a410164e1fd728cf7873493baacca7bc29548dMark Salyzyn
9099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Remove any pending requests from the global map when we get rid of a client,
9109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // and send cancellations to the daemon.
9119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private void expungeAllRequests() {
9129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int globalId, clientId, i;
9139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (i = 0; i < mClientIds.size(); i++) {
9149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                clientId = mClientIds.keyAt(i);
9159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                globalId = mClientIds.valueAt(i);
9169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mIdToClientInfoMap.remove(globalId);
9179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (DBG) Slog.d(TAG, "Terminating client-ID " + clientId +
9189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        " global-ID " + globalId + " type " + mClientRequests.get(clientId));
9199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                switch (mClientRequests.get(clientId)) {
920c6a410164e1fd728cf7873493baacca7bc29548dMark Salyzyn                    case NsdManager.DISCOVER_SERVICES:
9219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        stopServiceDiscovery(globalId);
9229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        break;
9239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    case NsdManager.RESOLVE_SERVICE:
9249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        stopResolveService(globalId);
9259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        break;
9269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    case NsdManager.REGISTER_SERVICE:
9279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        unregisterService(globalId);
9289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        break;
9299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    default:
9309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        break;
931f72467ad9843bf5d4b75fb308386e77ebb5c3447Dianne Hackborn                }
932f72467ad9843bf5d4b75fb308386e77ebb5c3447Dianne Hackborn            }
933f72467ad9843bf5d4b75fb308386e77ebb5c3447Dianne Hackborn            mClientIds.clear();
934f72467ad9843bf5d4b75fb308386e77ebb5c3447Dianne Hackborn            mClientRequests.clear();
935f72467ad9843bf5d4b75fb308386e77ebb5c3447Dianne Hackborn        }
936f72467ad9843bf5d4b75fb308386e77ebb5c3447Dianne Hackborn
937f72467ad9843bf5d4b75fb308386e77ebb5c3447Dianne Hackborn        // mClientIds is a sparse array of listener id -> mDnsClient id.  For a given mDnsClient id,
938f72467ad9843bf5d4b75fb308386e77ebb5c3447Dianne Hackborn        // return the corresponding listener id.  mDnsClient id is also called a global id.
939f72467ad9843bf5d4b75fb308386e77ebb5c3447Dianne Hackborn        private int getClientId(final int globalId) {
940f72467ad9843bf5d4b75fb308386e77ebb5c3447Dianne Hackborn            // This doesn't use mClientIds.indexOfValue because indexOfValue uses == (not .equals)
941f72467ad9843bf5d4b75fb308386e77ebb5c3447Dianne Hackborn            // while also coercing the int primitives to Integer objects.
942f72467ad9843bf5d4b75fb308386e77ebb5c3447Dianne Hackborn            for (int i = 0, nSize = mClientIds.size(); i < nSize; i++) {
943f72467ad9843bf5d4b75fb308386e77ebb5c3447Dianne Hackborn                int mDnsId = mClientIds.valueAt(i);
944f72467ad9843bf5d4b75fb308386e77ebb5c3447Dianne Hackborn                if (globalId == mDnsId) {
945f72467ad9843bf5d4b75fb308386e77ebb5c3447Dianne Hackborn                    return mClientIds.keyAt(i);
946f72467ad9843bf5d4b75fb308386e77ebb5c3447Dianne Hackborn                }
947f72467ad9843bf5d4b75fb308386e77ebb5c3447Dianne Hackborn            }
948f72467ad9843bf5d4b75fb308386e77ebb5c3447Dianne Hackborn            return -1;
949f72467ad9843bf5d4b75fb308386e77ebb5c3447Dianne Hackborn        }
950f72467ad9843bf5d4b75fb308386e77ebb5c3447Dianne Hackborn    }
951f72467ad9843bf5d4b75fb308386e77ebb5c3447Dianne Hackborn}
952f72467ad9843bf5d4b75fb308386e77ebb5c3447Dianne Hackborn