17d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff/*
27d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * Copyright (C) 2010 The Android Open Source Project
37d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff *
47d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * Licensed under the Apache License, Version 2.0 (the "License");
57d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * you may not use this file except in compliance with the License.
67d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * You may obtain a copy of the License at
77d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff *
87d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff *      http://www.apache.org/licenses/LICENSE-2.0
97d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff *
107d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * Unless required by applicable law or agreed to in writing, software
117d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * distributed under the License is distributed on an "AS IS" BASIS,
127d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * See the License for the specific language governing permissions and
147d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * limitations under the License.
157d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff */
167d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
177d024d372431effc87168afdc7cbe387680c4935Irfan Sheriffpackage com.android.server;
187d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
197d024d372431effc87168afdc7cbe387680c4935Irfan Sheriffimport android.content.Context;
203ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriffimport android.content.ContentResolver;
213ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriffimport android.content.Intent;
227d024d372431effc87168afdc7cbe387680c4935Irfan Sheriffimport android.content.pm.PackageManager;
23919aca5663be997eb238a9635e742858d29b8592Irfan Sheriffimport android.database.ContentObserver;
2422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriffimport android.net.nsd.NsdServiceInfo;
257d024d372431effc87168afdc7cbe387680c4935Irfan Sheriffimport android.net.nsd.DnsSdTxtRecord;
267d024d372431effc87168afdc7cbe387680c4935Irfan Sheriffimport android.net.nsd.INsdManager;
277d024d372431effc87168afdc7cbe387680c4935Irfan Sheriffimport android.net.nsd.NsdManager;
287d024d372431effc87168afdc7cbe387680c4935Irfan Sheriffimport android.os.Binder;
297d024d372431effc87168afdc7cbe387680c4935Irfan Sheriffimport android.os.Message;
307d024d372431effc87168afdc7cbe387680c4935Irfan Sheriffimport android.os.Messenger;
315ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackbornimport android.os.UserHandle;
323ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriffimport android.provider.Settings;
337d024d372431effc87168afdc7cbe387680c4935Irfan Sheriffimport android.util.Slog;
3422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriffimport android.util.SparseArray;
357d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
367d024d372431effc87168afdc7cbe387680c4935Irfan Sheriffimport java.io.FileDescriptor;
377d024d372431effc87168afdc7cbe387680c4935Irfan Sheriffimport java.io.PrintWriter;
38b72d8b4091ab31948c91b0382a9b46afdc7ef7daChristopher Laneimport java.io.UnsupportedEncodingException;
39817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriffimport java.net.InetAddress;
40817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriffimport java.util.HashMap;
417d024d372431effc87168afdc7cbe387680c4935Irfan Sheriffimport java.util.List;
42b72d8b4091ab31948c91b0382a9b46afdc7ef7daChristopher Laneimport java.util.Locale;
43b72d8b4091ab31948c91b0382a9b46afdc7ef7daChristopher Laneimport java.util.Map;
44817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriffimport java.util.concurrent.CountDownLatch;
457d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
467d024d372431effc87168afdc7cbe387680c4935Irfan Sheriffimport com.android.internal.util.AsyncChannel;
473ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriffimport com.android.internal.util.Protocol;
483ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriffimport com.android.internal.util.State;
493ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriffimport com.android.internal.util.StateMachine;
50771cd657acc37b50bafe18bf5f649d3c1d85b3d8Christopher Laneimport com.android.server.NativeDaemonConnector.Command;
517d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
527d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff/**
537d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * Network Service Discovery Service handles remote service discovery operation requests by
547d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * implementing the INsdManager interface.
557d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff *
567d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * @hide
577d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff */
587d024d372431effc87168afdc7cbe387680c4935Irfan Sheriffpublic class NsdService extends INsdManager.Stub {
597d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    private static final String TAG = "NsdService";
607d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    private static final String MDNS_TAG = "mDnsConnector";
617d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
627d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    private static final boolean DBG = true;
637d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
647d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    private Context mContext;
653ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff    private ContentResolver mContentResolver;
663ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff    private NsdStateMachine mNsdStateMachine;
677d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
687d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    /**
697d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff     * Clients receiving asynchronous messages
707d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff     */
71817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff    private HashMap<Messenger, ClientInfo> mClients = new HashMap<Messenger, ClientInfo>();
727d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
7322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff    /* A map from unique id to client info */
7422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff    private SparseArray<ClientInfo> mIdToClientInfoMap= new SparseArray<ClientInfo>();
7522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff
767d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    private AsyncChannel mReplyChannel = new AsyncChannel();
777d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
78817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff    private int INVALID_ID = 0;
79817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff    private int mUniqueId = 1;
80817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff
813ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff    private static final int BASE = Protocol.BASE_NSD_MANAGER;
8222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff    private static final int CMD_TO_STRING_COUNT = NsdManager.RESOLVE_SERVICE - BASE + 1;
833ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff    private static String[] sCmdToString = new String[CMD_TO_STRING_COUNT];
843ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff
853ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff    static {
863ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff        sCmdToString[NsdManager.DISCOVER_SERVICES - BASE] = "DISCOVER";
873ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff        sCmdToString[NsdManager.STOP_DISCOVERY - BASE] = "STOP-DISCOVER";
883ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff        sCmdToString[NsdManager.REGISTER_SERVICE - BASE] = "REGISTER";
893ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff        sCmdToString[NsdManager.UNREGISTER_SERVICE - BASE] = "UNREGISTER";
903ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff        sCmdToString[NsdManager.RESOLVE_SERVICE - BASE] = "RESOLVE";
913ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff    }
927d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
933ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff    private static String cmdToString(int cmd) {
943ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff        cmd -= BASE;
953ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff        if ((cmd >= 0) && (cmd < sCmdToString.length)) {
963ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff            return sCmdToString[cmd];
973ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff        } else {
983ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff            return null;
997d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff        }
1003ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff    }
1013ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff
1023ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff    private class NsdStateMachine extends StateMachine {
1033ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff
10422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        private final DefaultState mDefaultState = new DefaultState();
10522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        private final DisabledState mDisabledState = new DisabledState();
10622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        private final EnabledState mEnabledState = new EnabledState();
1077d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
1087d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff        @Override
109bbf30dfd767f823f5f40d14b498e2a593454c5c9Wink Saville        protected String getWhatToString(int what) {
110bbf30dfd767f823f5f40d14b498e2a593454c5c9Wink Saville            return cmdToString(what);
1113ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff        }
1123ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff
113919aca5663be997eb238a9635e742858d29b8592Irfan Sheriff        /**
114919aca5663be997eb238a9635e742858d29b8592Irfan Sheriff         * Observes the NSD on/off setting, and takes action when changed.
115919aca5663be997eb238a9635e742858d29b8592Irfan Sheriff         */
116919aca5663be997eb238a9635e742858d29b8592Irfan Sheriff        private void registerForNsdSetting() {
117919aca5663be997eb238a9635e742858d29b8592Irfan Sheriff            ContentObserver contentObserver = new ContentObserver(this.getHandler()) {
118919aca5663be997eb238a9635e742858d29b8592Irfan Sheriff                @Override
119919aca5663be997eb238a9635e742858d29b8592Irfan Sheriff                    public void onChange(boolean selfChange) {
120919aca5663be997eb238a9635e742858d29b8592Irfan Sheriff                        if (isNsdEnabled()) {
121919aca5663be997eb238a9635e742858d29b8592Irfan Sheriff                            mNsdStateMachine.sendMessage(NsdManager.ENABLE);
122919aca5663be997eb238a9635e742858d29b8592Irfan Sheriff                        } else {
123919aca5663be997eb238a9635e742858d29b8592Irfan Sheriff                            mNsdStateMachine.sendMessage(NsdManager.DISABLE);
124919aca5663be997eb238a9635e742858d29b8592Irfan Sheriff                        }
125919aca5663be997eb238a9635e742858d29b8592Irfan Sheriff                    }
126919aca5663be997eb238a9635e742858d29b8592Irfan Sheriff            };
127919aca5663be997eb238a9635e742858d29b8592Irfan Sheriff
128919aca5663be997eb238a9635e742858d29b8592Irfan Sheriff            mContext.getContentResolver().registerContentObserver(
129625239a05401bbf18b04d9874cea3f82da7c29a1Jeff Sharkey                    Settings.Global.getUriFor(Settings.Global.NSD_ON),
130919aca5663be997eb238a9635e742858d29b8592Irfan Sheriff                    false, contentObserver);
131919aca5663be997eb238a9635e742858d29b8592Irfan Sheriff        }
132919aca5663be997eb238a9635e742858d29b8592Irfan Sheriff
1333ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff        NsdStateMachine(String name) {
1343ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff            super(name);
1353ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff            addState(mDefaultState);
1363ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                addState(mDisabledState, mDefaultState);
1373ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                addState(mEnabledState, mDefaultState);
1383ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff            if (isNsdEnabled()) {
1393ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                setInitialState(mEnabledState);
1403ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff            } else {
1413ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                setInitialState(mDisabledState);
1423ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff            }
143bbf30dfd767f823f5f40d14b498e2a593454c5c9Wink Saville            setLogRecSize(25);
144919aca5663be997eb238a9635e742858d29b8592Irfan Sheriff            registerForNsdSetting();
1453ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff        }
1463ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff
1473ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff        class DefaultState extends State {
1483ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff            @Override
1493ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff            public boolean processMessage(Message msg) {
150f31760c63401be72748487c9d4fce3fecdedede4Dave Platt                ClientInfo cInfo = null;
1513ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                switch (msg.what) {
1523ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                    case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
1533ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
1543ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                            AsyncChannel c = (AsyncChannel) msg.obj;
1553ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                            if (DBG) Slog.d(TAG, "New client listening to asynchronous messages");
1563ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                            c.sendMessage(AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED);
157f31760c63401be72748487c9d4fce3fecdedede4Dave Platt                            cInfo = new ClientInfo(c, msg.replyTo);
1583ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                            mClients.put(msg.replyTo, cInfo);
1593ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        } else {
1603ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                            Slog.e(TAG, "Client connection failure, error=" + msg.arg1);
161817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff                        }
162817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff                        break;
1633ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                    case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
164f31760c63401be72748487c9d4fce3fecdedede4Dave Platt                        switch (msg.arg1) {
165f31760c63401be72748487c9d4fce3fecdedede4Dave Platt                            case AsyncChannel.STATUS_SEND_UNSUCCESSFUL:
166f31760c63401be72748487c9d4fce3fecdedede4Dave Platt                                Slog.e(TAG, "Send failed, client connection lost");
167f31760c63401be72748487c9d4fce3fecdedede4Dave Platt                                break;
168f31760c63401be72748487c9d4fce3fecdedede4Dave Platt                            case AsyncChannel.STATUS_REMOTE_DISCONNECTION:
169f31760c63401be72748487c9d4fce3fecdedede4Dave Platt                                if (DBG) Slog.d(TAG, "Client disconnected");
170f31760c63401be72748487c9d4fce3fecdedede4Dave Platt                                break;
171f31760c63401be72748487c9d4fce3fecdedede4Dave Platt                            default:
172f31760c63401be72748487c9d4fce3fecdedede4Dave Platt                                if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1);
173f31760c63401be72748487c9d4fce3fecdedede4Dave Platt                                break;
174f31760c63401be72748487c9d4fce3fecdedede4Dave Platt                        }
175f31760c63401be72748487c9d4fce3fecdedede4Dave Platt                        cInfo = mClients.get(msg.replyTo);
176f31760c63401be72748487c9d4fce3fecdedede4Dave Platt                        if (cInfo != null) {
177f31760c63401be72748487c9d4fce3fecdedede4Dave Platt                            cInfo.expungeAllRequests();
178f31760c63401be72748487c9d4fce3fecdedede4Dave Platt                            mClients.remove(msg.replyTo);
179f31760c63401be72748487c9d4fce3fecdedede4Dave Platt                        }
180f31760c63401be72748487c9d4fce3fecdedede4Dave Platt                        //Last client
181f31760c63401be72748487c9d4fce3fecdedede4Dave Platt                        if (mClients.size() == 0) {
182f31760c63401be72748487c9d4fce3fecdedede4Dave Platt                            stopMDnsDaemon();
1833ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        }
1843ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        break;
1853ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                    case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION:
1863ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        AsyncChannel ac = new AsyncChannel();
1873ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        ac.connect(mContext, getHandler(), msg.replyTo);
1883ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        break;
1893ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                    case NsdManager.DISCOVER_SERVICES:
19022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                        replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED,
19122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                                NsdManager.FAILURE_INTERNAL_ERROR);
1923ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                       break;
1933ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                    case NsdManager.STOP_DISCOVERY:
19422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                       replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED,
19522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                               NsdManager.FAILURE_INTERNAL_ERROR);
196817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff                        break;
1973ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                    case NsdManager.REGISTER_SERVICE:
19822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                        replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED,
19922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                                NsdManager.FAILURE_INTERNAL_ERROR);
2003ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        break;
2013ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                    case NsdManager.UNREGISTER_SERVICE:
20222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                        replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED,
20322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                                NsdManager.FAILURE_INTERNAL_ERROR);
2043ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        break;
2053ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                    case NsdManager.RESOLVE_SERVICE:
20622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                        replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED,
20722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                                NsdManager.FAILURE_INTERNAL_ERROR);
2083ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        break;
20922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                    case NsdManager.NATIVE_DAEMON_EVENT:
2103ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                    default:
2113ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        Slog.e(TAG, "Unhandled " + msg);
2123ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        return NOT_HANDLED;
2133ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                }
2143ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                return HANDLED;
2157d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff            }
2167d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff        }
2173ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff
2183ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff        class DisabledState extends State {
2193ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff            @Override
2203ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff            public void enter() {
2213ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                sendNsdStateChangeBroadcast(false);
2223ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff            }
2233ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff
2243ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff            @Override
2253ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff            public boolean processMessage(Message msg) {
2263ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                switch (msg.what) {
2273ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                    case NsdManager.ENABLE:
2283ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        transitionTo(mEnabledState);
2293ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        break;
2303ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                    default:
2313ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        return NOT_HANDLED;
2323ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                }
2333ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                return HANDLED;
2343ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff            }
2353ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff        }
2363ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff
2373ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff        class EnabledState extends State {
2383ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff            @Override
2393ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff            public void enter() {
2403ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                sendNsdStateChangeBroadcast(true);
2413ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                if (mClients.size() > 0) {
2423ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                    startMDnsDaemon();
2433ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                }
2443ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff            }
2453ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff
2463ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff            @Override
2473ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff            public void exit() {
2483ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                if (mClients.size() > 0) {
2493ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                    stopMDnsDaemon();
2503ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                }
2513ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff            }
2523ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff
25322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff            private boolean requestLimitReached(ClientInfo clientInfo) {
25422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                if (clientInfo.mClientIds.size() >= ClientInfo.MAX_LIMIT) {
25522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                    if (DBG) Slog.d(TAG, "Exceeded max outstanding requests " + clientInfo);
25622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                    return true;
25722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                }
25822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                return false;
25922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff            }
26022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff
261f31760c63401be72748487c9d4fce3fecdedede4Dave Platt            private void storeRequestMap(int clientId, int globalId, ClientInfo clientInfo, int what) {
26222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                clientInfo.mClientIds.put(clientId, globalId);
263f31760c63401be72748487c9d4fce3fecdedede4Dave Platt                clientInfo.mClientRequests.put(clientId, what);
26422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                mIdToClientInfoMap.put(globalId, clientInfo);
26522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff            }
26622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff
26722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff            private void removeRequestMap(int clientId, int globalId, ClientInfo clientInfo) {
26822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                clientInfo.mClientIds.remove(clientId);
269f31760c63401be72748487c9d4fce3fecdedede4Dave Platt                clientInfo.mClientRequests.remove(clientId);
27022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                mIdToClientInfoMap.remove(globalId);
27122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff            }
27222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff
2733ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff            @Override
2743ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff            public boolean processMessage(Message msg) {
2753ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                ClientInfo clientInfo;
27622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                NsdServiceInfo servInfo;
2773ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                boolean result = HANDLED;
27822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                int id;
2793ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                switch (msg.what) {
2803ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                  case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
2813ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        //First client
2823ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL &&
2833ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                                mClients.size() == 0) {
2843ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                            startMDnsDaemon();
2853ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        }
2863ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        result = NOT_HANDLED;
2873ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        break;
2883ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                    case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
2893ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        result = NOT_HANDLED;
2903ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        break;
2913ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                    case NsdManager.DISABLE:
2923ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        //TODO: cleanup clients
2933ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        transitionTo(mDisabledState);
2943ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        break;
2953ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                    case NsdManager.DISCOVER_SERVICES:
2963ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        if (DBG) Slog.d(TAG, "Discover services");
29722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                        servInfo = (NsdServiceInfo) msg.obj;
2983ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        clientInfo = mClients.get(msg.replyTo);
29922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff
30022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                        if (requestLimitReached(clientInfo)) {
30122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                            replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED,
30222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                                    NsdManager.FAILURE_MAX_LIMIT);
3033ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                            break;
3043ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        }
30522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff
30622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                        id = getUniqueId();
30722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                        if (discoverServices(id, servInfo.getServiceType())) {
30822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                            if (DBG) {
30922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                                Slog.d(TAG, "Discover " + msg.arg2 + " " + id +
31022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                                        servInfo.getServiceType());
31122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                            }
312f31760c63401be72748487c9d4fce3fecdedede4Dave Platt                            storeRequestMap(msg.arg2, id, clientInfo, msg.what);
31322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                            replyToMessage(msg, NsdManager.DISCOVER_SERVICES_STARTED, servInfo);
3143ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        } else {
31522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                            stopServiceDiscovery(id);
31622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                            replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED,
31722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                                    NsdManager.FAILURE_INTERNAL_ERROR);
3183ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        }
3193ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        break;
3203ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                    case NsdManager.STOP_DISCOVERY:
3213ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        if (DBG) Slog.d(TAG, "Stop service discovery");
3223ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        clientInfo = mClients.get(msg.replyTo);
32322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff
32422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                        try {
32522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                            id = clientInfo.mClientIds.get(msg.arg2).intValue();
32622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                        } catch (NullPointerException e) {
32722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                            replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED,
32822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                                    NsdManager.FAILURE_INTERNAL_ERROR);
3293ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                            break;
3303ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        }
33122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                        removeRequestMap(msg.arg2, id, clientInfo);
33222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                        if (stopServiceDiscovery(id)) {
33322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                            replyToMessage(msg, NsdManager.STOP_DISCOVERY_SUCCEEDED);
3343ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        } else {
33522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                            replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED,
33622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                                    NsdManager.FAILURE_INTERNAL_ERROR);
3373ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        }
3383ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        break;
3393ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                    case NsdManager.REGISTER_SERVICE:
3403ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        if (DBG) Slog.d(TAG, "Register service");
3413ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        clientInfo = mClients.get(msg.replyTo);
34222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                        if (requestLimitReached(clientInfo)) {
34322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                            replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED,
34422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                                    NsdManager.FAILURE_MAX_LIMIT);
34522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                            break;
3463ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        }
3473ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff
34822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                        id = getUniqueId();
34922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                        if (registerService(id, (NsdServiceInfo) msg.obj)) {
35022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                            if (DBG) Slog.d(TAG, "Register " + msg.arg2 + " " + id);
351f31760c63401be72748487c9d4fce3fecdedede4Dave Platt                            storeRequestMap(msg.arg2, id, clientInfo, msg.what);
35222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                            // Return success after mDns reports success
3533ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        } else {
35422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                            unregisterService(id);
35522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                            replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED,
35622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                                    NsdManager.FAILURE_INTERNAL_ERROR);
3573ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        }
3583ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        break;
3593ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                    case NsdManager.UNREGISTER_SERVICE:
3603ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        if (DBG) Slog.d(TAG, "unregister service");
3613ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        clientInfo = mClients.get(msg.replyTo);
36222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                        try {
36322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                            id = clientInfo.mClientIds.get(msg.arg2).intValue();
36422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                        } catch (NullPointerException e) {
36522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                            replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED,
36622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                                    NsdManager.FAILURE_INTERNAL_ERROR);
36722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                            break;
36822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                        }
36922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                        removeRequestMap(msg.arg2, id, clientInfo);
37022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                        if (unregisterService(id)) {
37122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                            replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_SUCCEEDED);
3723ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        } else {
37322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                            replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED,
37422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                                    NsdManager.FAILURE_INTERNAL_ERROR);
3753ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        }
3763ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        break;
3773ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                    case NsdManager.RESOLVE_SERVICE:
3783ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        if (DBG) Slog.d(TAG, "Resolve service");
37922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                        servInfo = (NsdServiceInfo) msg.obj;
3803ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        clientInfo = mClients.get(msg.replyTo);
3813ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff
38222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff
38322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                        if (clientInfo.mResolvedService != null) {
38422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                            replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED,
38522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                                    NsdManager.FAILURE_ALREADY_ACTIVE);
3863ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                            break;
3873ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        }
38822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff
38922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                        id = getUniqueId();
39022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                        if (resolveService(id, servInfo)) {
39122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                            clientInfo.mResolvedService = new NsdServiceInfo();
392f31760c63401be72748487c9d4fce3fecdedede4Dave Platt                            storeRequestMap(msg.arg2, id, clientInfo, msg.what);
3933ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        } else {
39422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                            replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED,
39522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                                    NsdManager.FAILURE_INTERNAL_ERROR);
3963ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        }
3973ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        break;
39822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                    case NsdManager.NATIVE_DAEMON_EVENT:
39922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                        NativeEvent event = (NativeEvent) msg.obj;
400ef12884da7c8844f8dd27cbc9c9980f685b73a2cSreeram Ramachandran                        if (!handleNativeEvent(event.code, event.raw, event.cooked)) {
4016727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                            result = NOT_HANDLED;
4026727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        }
40322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                        break;
4043ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                    default:
4053ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        result = NOT_HANDLED;
4063ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                        break;
4073ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                }
4083ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                return result;
4093ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff            }
4106727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan
4116727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan            private boolean handleNativeEvent(int code, String raw, String[] cooked) {
4126727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                boolean handled = true;
4136727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                NsdServiceInfo servInfo;
4146727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                int id = Integer.parseInt(cooked[1]);
4156727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                ClientInfo clientInfo = mIdToClientInfoMap.get(id);
4166727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                if (clientInfo == null) {
4176727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                    Slog.e(TAG, "Unique id with no client mapping: " + id);
4186727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                    handled = false;
4196727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                    return handled;
4206727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                }
4216727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan
4226727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                /* This goes in response as msg.arg2 */
4235a577903d366ff07b3c4ec6359e4757154f49790Christopher Lane                int clientId = clientInfo.getClientId(id);
4245a577903d366ff07b3c4ec6359e4757154f49790Christopher Lane                if (clientId < 0) {
4258ed09e893f6a4b6a4f6503186515b8f6978baa14Vinit Deshapnde                    // This can happen because of race conditions. For example,
4268ed09e893f6a4b6a4f6503186515b8f6978baa14Vinit Deshapnde                    // SERVICE_FOUND may race with STOP_SERVICE_DISCOVERY,
4278ed09e893f6a4b6a4f6503186515b8f6978baa14Vinit Deshapnde                    // and we may get in this situation.
4288ed09e893f6a4b6a4f6503186515b8f6978baa14Vinit Deshapnde                    Slog.d(TAG, "Notification for a listener that is no longer active: " + id);
4298ed09e893f6a4b6a4f6503186515b8f6978baa14Vinit Deshapnde                    handled = false;
4308ed09e893f6a4b6a4f6503186515b8f6978baa14Vinit Deshapnde                    return handled;
4316727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                }
4328ed09e893f6a4b6a4f6503186515b8f6978baa14Vinit Deshapnde
4336727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                switch (code) {
4346727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                    case NativeResponseCode.SERVICE_FOUND:
4356727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        /* NNN uniqueId serviceName regType domain */
4366727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        if (DBG) Slog.d(TAG, "SERVICE_FOUND Raw: " + raw);
437b72d8b4091ab31948c91b0382a9b46afdc7ef7daChristopher Lane                        servInfo = new NsdServiceInfo(cooked[2], cooked[3]);
4386727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        clientInfo.mChannel.sendMessage(NsdManager.SERVICE_FOUND, 0,
4396727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                                clientId, servInfo);
4406727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        break;
4416727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                    case NativeResponseCode.SERVICE_LOST:
4426727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        /* NNN uniqueId serviceName regType domain */
4436727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        if (DBG) Slog.d(TAG, "SERVICE_LOST Raw: " + raw);
444b72d8b4091ab31948c91b0382a9b46afdc7ef7daChristopher Lane                        servInfo = new NsdServiceInfo(cooked[2], cooked[3]);
4456727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        clientInfo.mChannel.sendMessage(NsdManager.SERVICE_LOST, 0,
4466727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                                clientId, servInfo);
4476727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        break;
4486727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                    case NativeResponseCode.SERVICE_DISCOVERY_FAILED:
4496727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        /* NNN uniqueId errorCode */
4506727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        if (DBG) Slog.d(TAG, "SERVICE_DISC_FAILED Raw: " + raw);
4516727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        clientInfo.mChannel.sendMessage(NsdManager.DISCOVER_SERVICES_FAILED,
4526727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                                NsdManager.FAILURE_INTERNAL_ERROR, clientId);
4536727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        break;
4546727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                    case NativeResponseCode.SERVICE_REGISTERED:
4556727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        /* NNN regId serviceName regType */
4566727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        if (DBG) Slog.d(TAG, "SERVICE_REGISTERED Raw: " + raw);
457b72d8b4091ab31948c91b0382a9b46afdc7ef7daChristopher Lane                        servInfo = new NsdServiceInfo(cooked[2], null);
4586727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        clientInfo.mChannel.sendMessage(NsdManager.REGISTER_SERVICE_SUCCEEDED,
4596727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                                id, clientId, servInfo);
4606727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        break;
4616727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                    case NativeResponseCode.SERVICE_REGISTRATION_FAILED:
4626727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        /* NNN regId errorCode */
4636727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        if (DBG) Slog.d(TAG, "SERVICE_REGISTER_FAILED Raw: " + raw);
4646727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        clientInfo.mChannel.sendMessage(NsdManager.REGISTER_SERVICE_FAILED,
4656727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                               NsdManager.FAILURE_INTERNAL_ERROR, clientId);
4666727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        break;
4676727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                    case NativeResponseCode.SERVICE_UPDATED:
4686727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        /* NNN regId */
4696727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        break;
4706727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                    case NativeResponseCode.SERVICE_UPDATE_FAILED:
4716727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        /* NNN regId errorCode */
4726727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        break;
4736727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                    case NativeResponseCode.SERVICE_RESOLVED:
4746727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        /* NNN resolveId fullName hostName port txtlen txtdata */
4756727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        if (DBG) Slog.d(TAG, "SERVICE_RESOLVED Raw: " + raw);
476ef12884da7c8844f8dd27cbc9c9980f685b73a2cSreeram Ramachandran                        int index = 0;
477ef12884da7c8844f8dd27cbc9c9980f685b73a2cSreeram Ramachandran                        while (index < cooked[2].length() && cooked[2].charAt(index) != '.') {
478ef12884da7c8844f8dd27cbc9c9980f685b73a2cSreeram Ramachandran                            if (cooked[2].charAt(index) == '\\') {
479ef12884da7c8844f8dd27cbc9c9980f685b73a2cSreeram Ramachandran                                ++index;
480ef12884da7c8844f8dd27cbc9c9980f685b73a2cSreeram Ramachandran                            }
481ef12884da7c8844f8dd27cbc9c9980f685b73a2cSreeram Ramachandran                            ++index;
482ef12884da7c8844f8dd27cbc9c9980f685b73a2cSreeram Ramachandran                        }
483ef12884da7c8844f8dd27cbc9c9980f685b73a2cSreeram Ramachandran                        if (index >= cooked[2].length()) {
4846727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                            Slog.e(TAG, "Invalid service found " + raw);
4856727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                            break;
4866727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        }
4876727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        String name = cooked[2].substring(0, index);
4886727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        String rest = cooked[2].substring(index);
4896727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        String type = rest.replace(".local.", "");
4906727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan
491ef12884da7c8844f8dd27cbc9c9980f685b73a2cSreeram Ramachandran                        name = unescape(name);
492ef12884da7c8844f8dd27cbc9c9980f685b73a2cSreeram Ramachandran
4936727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        clientInfo.mResolvedService.setServiceName(name);
4946727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        clientInfo.mResolvedService.setServiceType(type);
4956727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        clientInfo.mResolvedService.setPort(Integer.parseInt(cooked[4]));
4966727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan
4976727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        stopResolveService(id);
4984038724a536c990859866489195add7ed537006bVinit Deshapnde                        removeRequestMap(clientId, id, clientInfo);
4994038724a536c990859866489195add7ed537006bVinit Deshapnde
5004038724a536c990859866489195add7ed537006bVinit Deshapnde                        int id2 = getUniqueId();
5014038724a536c990859866489195add7ed537006bVinit Deshapnde                        if (getAddrInfo(id2, cooked[3])) {
502f31760c63401be72748487c9d4fce3fecdedede4Dave Platt                            storeRequestMap(clientId, id2, clientInfo, NsdManager.RESOLVE_SERVICE);
5034038724a536c990859866489195add7ed537006bVinit Deshapnde                        } else {
5046727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                            clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
5056727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                                    NsdManager.FAILURE_INTERNAL_ERROR, clientId);
5066727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                            clientInfo.mResolvedService = null;
5076727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        }
5086727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        break;
5096727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                    case NativeResponseCode.SERVICE_RESOLUTION_FAILED:
5106727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        /* NNN resolveId errorCode */
5116727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        if (DBG) Slog.d(TAG, "SERVICE_RESOLVE_FAILED Raw: " + raw);
5126727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        stopResolveService(id);
5136727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        removeRequestMap(clientId, id, clientInfo);
5146727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        clientInfo.mResolvedService = null;
5156727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
5166727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                                NsdManager.FAILURE_INTERNAL_ERROR, clientId);
5176727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        break;
5186727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                    case NativeResponseCode.SERVICE_GET_ADDR_FAILED:
5196727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        /* NNN resolveId errorCode */
5206727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        stopGetAddrInfo(id);
5216727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        removeRequestMap(clientId, id, clientInfo);
5226727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        clientInfo.mResolvedService = null;
5236727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        if (DBG) Slog.d(TAG, "SERVICE_RESOLVE_FAILED Raw: " + raw);
5246727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
5256727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                                NsdManager.FAILURE_INTERNAL_ERROR, clientId);
5266727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        break;
5276727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                    case NativeResponseCode.SERVICE_GET_ADDR_SUCCESS:
5286727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        /* NNN resolveId hostname ttl addr */
5296727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        if (DBG) Slog.d(TAG, "SERVICE_GET_ADDR_SUCCESS Raw: " + raw);
5306727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        try {
5316727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                            clientInfo.mResolvedService.setHost(InetAddress.getByName(cooked[4]));
5326727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                            clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_SUCCEEDED,
5336727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                                   0, clientId, clientInfo.mResolvedService);
5346727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        } catch (java.net.UnknownHostException e) {
5356727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                            clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
5366727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                                    NsdManager.FAILURE_INTERNAL_ERROR, clientId);
5376727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        }
5386727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        stopGetAddrInfo(id);
5396727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        removeRequestMap(clientId, id, clientInfo);
5406727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        clientInfo.mResolvedService = null;
5416727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        break;
5426727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                    default:
5436727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        handled = false;
5446727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                        break;
5456727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                }
5466727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan                return handled;
5476727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan            }
5483ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff       }
5497d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    }
5507d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
551ef12884da7c8844f8dd27cbc9c9980f685b73a2cSreeram Ramachandran    private String unescape(String s) {
552ef12884da7c8844f8dd27cbc9c9980f685b73a2cSreeram Ramachandran        StringBuilder sb = new StringBuilder(s.length());
553ef12884da7c8844f8dd27cbc9c9980f685b73a2cSreeram Ramachandran        for (int i = 0; i < s.length(); ++i) {
554ef12884da7c8844f8dd27cbc9c9980f685b73a2cSreeram Ramachandran            char c = s.charAt(i);
555ef12884da7c8844f8dd27cbc9c9980f685b73a2cSreeram Ramachandran            if (c == '\\') {
556ef12884da7c8844f8dd27cbc9c9980f685b73a2cSreeram Ramachandran                if (++i >= s.length()) {
557ef12884da7c8844f8dd27cbc9c9980f685b73a2cSreeram Ramachandran                    Slog.e(TAG, "Unexpected end of escape sequence in: " + s);
558ef12884da7c8844f8dd27cbc9c9980f685b73a2cSreeram Ramachandran                    break;
559ef12884da7c8844f8dd27cbc9c9980f685b73a2cSreeram Ramachandran                }
560ef12884da7c8844f8dd27cbc9c9980f685b73a2cSreeram Ramachandran                c = s.charAt(i);
561ef12884da7c8844f8dd27cbc9c9980f685b73a2cSreeram Ramachandran                if (c != '.' && c != '\\') {
562ef12884da7c8844f8dd27cbc9c9980f685b73a2cSreeram Ramachandran                    if (i + 2 >= s.length()) {
563ef12884da7c8844f8dd27cbc9c9980f685b73a2cSreeram Ramachandran                        Slog.e(TAG, "Unexpected end of escape sequence in: " + s);
564ef12884da7c8844f8dd27cbc9c9980f685b73a2cSreeram Ramachandran                        break;
565ef12884da7c8844f8dd27cbc9c9980f685b73a2cSreeram Ramachandran                    }
566ef12884da7c8844f8dd27cbc9c9980f685b73a2cSreeram Ramachandran                    c = (char) ((c-'0') * 100 + (s.charAt(i+1)-'0') * 10 + (s.charAt(i+2)-'0'));
567ef12884da7c8844f8dd27cbc9c9980f685b73a2cSreeram Ramachandran                    i += 2;
568ef12884da7c8844f8dd27cbc9c9980f685b73a2cSreeram Ramachandran                }
569ef12884da7c8844f8dd27cbc9c9980f685b73a2cSreeram Ramachandran            }
570ef12884da7c8844f8dd27cbc9c9980f685b73a2cSreeram Ramachandran            sb.append(c);
571ef12884da7c8844f8dd27cbc9c9980f685b73a2cSreeram Ramachandran        }
572ef12884da7c8844f8dd27cbc9c9980f685b73a2cSreeram Ramachandran        return sb.toString();
573ef12884da7c8844f8dd27cbc9c9980f685b73a2cSreeram Ramachandran    }
574ef12884da7c8844f8dd27cbc9c9980f685b73a2cSreeram Ramachandran
5757d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    private NativeDaemonConnector mNativeConnector;
5767d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    private final CountDownLatch mNativeDaemonConnected = new CountDownLatch(1);
5777d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
5787d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    private NsdService(Context context) {
5797d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff        mContext = context;
5803ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff        mContentResolver = context.getContentResolver();
5817d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
5827d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff        mNativeConnector = new NativeDaemonConnector(new NativeCallbackReceiver(), "mdns", 10,
58377b987f1a1bb6028a871de01065b94c4cfff0b5cDianne Hackborn                MDNS_TAG, 25, null);
5843ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff
5853ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff        mNsdStateMachine = new NsdStateMachine(TAG);
5863ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff        mNsdStateMachine.start();
5873ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff
5887d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff        Thread th = new Thread(mNativeConnector, MDNS_TAG);
5897d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff        th.start();
5907d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    }
5917d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
5927d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    public static NsdService create(Context context) throws InterruptedException {
5937d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff        NsdService service = new NsdService(context);
5943ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff        service.mNativeDaemonConnected.await();
5957d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff        return service;
5967d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    }
5977d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
5987d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    public Messenger getMessenger() {
59992784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INTERNET,
60092784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff            "NsdService");
6013ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff        return new Messenger(mNsdStateMachine.getHandler());
6023ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff    }
6033ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff
6043ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff    public void setEnabled(boolean enable) {
6053ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL,
6063ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff                "NsdService");
607625239a05401bbf18b04d9874cea3f82da7c29a1Jeff Sharkey        Settings.Global.putInt(mContentResolver, Settings.Global.NSD_ON, enable ? 1 : 0);
6083ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff        if (enable) {
6093ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff            mNsdStateMachine.sendMessage(NsdManager.ENABLE);
6103ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff        } else {
6113ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff            mNsdStateMachine.sendMessage(NsdManager.DISABLE);
6123ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff        }
6133ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff    }
6143ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff
6153ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff    private void sendNsdStateChangeBroadcast(boolean enabled) {
61654ac7a510245e5f00c16ff5595b6ae8d002c1c3bIrfan Sheriff        final Intent intent = new Intent(NsdManager.ACTION_NSD_STATE_CHANGED);
6173ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
6183ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff        if (enabled) {
6193ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff            intent.putExtra(NsdManager.EXTRA_NSD_STATE, NsdManager.NSD_STATE_ENABLED);
6203ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff        } else {
6213ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff            intent.putExtra(NsdManager.EXTRA_NSD_STATE, NsdManager.NSD_STATE_DISABLED);
6223ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff        }
6235ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
6243ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff    }
6253ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff
6263ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff    private boolean isNsdEnabled() {
627625239a05401bbf18b04d9874cea3f82da7c29a1Jeff Sharkey        boolean ret = Settings.Global.getInt(mContentResolver, Settings.Global.NSD_ON, 1) == 1;
6283ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff        if (DBG) Slog.d(TAG, "Network service discovery enabled " + ret);
6293ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff        return ret;
6307d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    }
6317d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
632817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff    private int getUniqueId() {
633817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        if (++mUniqueId == INVALID_ID) return ++mUniqueId;
634817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        return mUniqueId;
635817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff    }
636817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff
63703666c705ddabe0e7c5869ab69c2ca8b964164e9Sreeram Ramachandran    /* These should be in sync with system/netd/server/ResponseCode.h */
6387d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    class NativeResponseCode {
639817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        public static final int SERVICE_DISCOVERY_FAILED    =   602;
640817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        public static final int SERVICE_FOUND               =   603;
641817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        public static final int SERVICE_LOST                =   604;
6427d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
643817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        public static final int SERVICE_REGISTRATION_FAILED =   605;
644817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        public static final int SERVICE_REGISTERED          =   606;
6457d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
646817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        public static final int SERVICE_RESOLUTION_FAILED   =   607;
647817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        public static final int SERVICE_RESOLVED            =   608;
6487d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
649817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        public static final int SERVICE_UPDATED             =   609;
650817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        public static final int SERVICE_UPDATE_FAILED       =   610;
6517d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
652817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        public static final int SERVICE_GET_ADDR_FAILED     =   611;
653817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        public static final int SERVICE_GET_ADDR_SUCCESS    =   612;
654817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff    }
6557d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
65622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff    private class NativeEvent {
6576727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan        final int code;
6586727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan        final String raw;
659ef12884da7c8844f8dd27cbc9c9980f685b73a2cSreeram Ramachandran        final String[] cooked;
66022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff
661ef12884da7c8844f8dd27cbc9c9980f685b73a2cSreeram Ramachandran        NativeEvent(int code, String raw, String[] cooked) {
66222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff            this.code = code;
66322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff            this.raw = raw;
664ef12884da7c8844f8dd27cbc9c9980f685b73a2cSreeram Ramachandran            this.cooked = cooked;
66522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        }
66622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff    }
66722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff
6687d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    class NativeCallbackReceiver implements INativeDaemonConnectorCallbacks {
6697d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff        public void onDaemonConnected() {
6707d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff            mNativeDaemonConnected.countDown();
6717d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff        }
6727d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
67377b987f1a1bb6028a871de01065b94c4cfff0b5cDianne Hackborn        public boolean onCheckHoldWakeLock(int code) {
67477b987f1a1bb6028a871de01065b94c4cfff0b5cDianne Hackborn            return false;
67577b987f1a1bb6028a871de01065b94c4cfff0b5cDianne Hackborn        }
67677b987f1a1bb6028a871de01065b94c4cfff0b5cDianne Hackborn
6777d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff        public boolean onEvent(int code, String raw, String[] cooked) {
67822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff            // TODO: NDC translates a message to a callback, we could enhance NDC to
67922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff            // directly interact with a state machine through messages
680ef12884da7c8844f8dd27cbc9c9980f685b73a2cSreeram Ramachandran            NativeEvent event = new NativeEvent(code, raw, cooked);
68122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff            mNsdStateMachine.sendMessage(NsdManager.NATIVE_DAEMON_EVENT, event);
68222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff            return true;
68322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        }
68422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff    }
685817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff
686817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff    private boolean startMDnsDaemon() {
687817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        if (DBG) Slog.d(TAG, "startMDnsDaemon");
688817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        try {
689817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff            mNativeConnector.execute("mdnssd", "start-service");
690817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        } catch(NativeDaemonConnectorException e) {
691817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff            Slog.e(TAG, "Failed to start daemon" + e);
692817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff            return false;
693817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        }
694817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        return true;
695817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff    }
696817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff
697817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff    private boolean stopMDnsDaemon() {
698817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        if (DBG) Slog.d(TAG, "stopMDnsDaemon");
699817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        try {
700817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff            mNativeConnector.execute("mdnssd", "stop-service");
701817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        } catch(NativeDaemonConnectorException e) {
702817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff            Slog.e(TAG, "Failed to start daemon" + e);
703817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff            return false;
704817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        }
705817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        return true;
706817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff    }
707817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff
70822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff    private boolean registerService(int regId, NsdServiceInfo service) {
709817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        if (DBG) Slog.d(TAG, "registerService: " + regId + " " + service);
7107d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff        try {
711b72d8b4091ab31948c91b0382a9b46afdc7ef7daChristopher Lane            Command cmd = new Command("mdnssd", "register", regId, service.getServiceName(),
7127d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff                    service.getServiceType(), service.getPort());
713b72d8b4091ab31948c91b0382a9b46afdc7ef7daChristopher Lane
714b72d8b4091ab31948c91b0382a9b46afdc7ef7daChristopher Lane            // Add TXT records as additional arguments.
715b72d8b4091ab31948c91b0382a9b46afdc7ef7daChristopher Lane            Map<String, byte[]> txtRecords = service.getAttributes();
716b72d8b4091ab31948c91b0382a9b46afdc7ef7daChristopher Lane            for (String key : txtRecords.keySet()) {
717b72d8b4091ab31948c91b0382a9b46afdc7ef7daChristopher Lane                try {
718b72d8b4091ab31948c91b0382a9b46afdc7ef7daChristopher Lane                    // TODO: Send encoded TXT record as bytes once NDC/netd supports binary data.
7190f35cdd862fba23e9bcc5344403426ae74fec55cChristopher Lane                    byte[] recordValue = txtRecords.get(key);
720b72d8b4091ab31948c91b0382a9b46afdc7ef7daChristopher Lane                    cmd.appendArg(String.format(Locale.US, "%s=%s", key,
7210f35cdd862fba23e9bcc5344403426ae74fec55cChristopher Lane                            recordValue != null ? new String(recordValue, "UTF_8") : ""));
722b72d8b4091ab31948c91b0382a9b46afdc7ef7daChristopher Lane                } catch (UnsupportedEncodingException e) {
723b72d8b4091ab31948c91b0382a9b46afdc7ef7daChristopher Lane                    Slog.e(TAG, "Failed to encode txtRecord " + e);
724b72d8b4091ab31948c91b0382a9b46afdc7ef7daChristopher Lane                }
725b72d8b4091ab31948c91b0382a9b46afdc7ef7daChristopher Lane            }
726b72d8b4091ab31948c91b0382a9b46afdc7ef7daChristopher Lane
727b72d8b4091ab31948c91b0382a9b46afdc7ef7daChristopher Lane            mNativeConnector.execute(cmd);
7287d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff        } catch(NativeDaemonConnectorException e) {
729817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff            Slog.e(TAG, "Failed to execute registerService " + e);
730817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff            return false;
731817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        }
732817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        return true;
733817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff    }
734817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff
735817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff    private boolean unregisterService(int regId) {
736817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        if (DBG) Slog.d(TAG, "unregisterService: " + regId);
737817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        try {
738817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff            mNativeConnector.execute("mdnssd", "stop-register", regId);
739817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        } catch(NativeDaemonConnectorException e) {
740817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff            Slog.e(TAG, "Failed to execute unregisterService " + e);
741817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff            return false;
7427d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff        }
743817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        return true;
7447d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    }
7457d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
746817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff    private boolean updateService(int regId, DnsSdTxtRecord t) {
747817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        if (DBG) Slog.d(TAG, "updateService: " + regId + " " + t);
7487d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff        try {
749817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff            if (t == null) return false;
7507d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff            mNativeConnector.execute("mdnssd", "update", regId, t.size(), t.getRawData());
7517d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff        } catch(NativeDaemonConnectorException e) {
752817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff            Slog.e(TAG, "Failed to updateServices " + e);
753817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff            return false;
7547d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff        }
755817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        return true;
7567d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    }
7577d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
758817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff    private boolean discoverServices(int discoveryId, String serviceType) {
759817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        if (DBG) Slog.d(TAG, "discoverServices: " + discoveryId + " " + serviceType);
7607d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff        try {
7617d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff            mNativeConnector.execute("mdnssd", "discover", discoveryId, serviceType);
7627d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff        } catch(NativeDaemonConnectorException e) {
763817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff            Slog.e(TAG, "Failed to discoverServices " + e);
764817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff            return false;
765817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        }
766817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        return true;
767817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff    }
768817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff
769817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff    private boolean stopServiceDiscovery(int discoveryId) {
770817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        if (DBG) Slog.d(TAG, "stopServiceDiscovery: " + discoveryId);
771817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        try {
772817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff            mNativeConnector.execute("mdnssd", "stop-discover", discoveryId);
773817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        } catch(NativeDaemonConnectorException e) {
774817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff            Slog.e(TAG, "Failed to stopServiceDiscovery " + e);
775817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff            return false;
776817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        }
777817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        return true;
778817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff    }
779817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff
78022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff    private boolean resolveService(int resolveId, NsdServiceInfo service) {
781817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        if (DBG) Slog.d(TAG, "resolveService: " + resolveId + " " + service);
782817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        try {
783817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff            mNativeConnector.execute("mdnssd", "resolve", resolveId, service.getServiceName(),
784817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff                    service.getServiceType(), "local.");
785817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        } catch(NativeDaemonConnectorException e) {
786817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff            Slog.e(TAG, "Failed to resolveService " + e);
787817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff            return false;
788817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        }
789817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        return true;
790817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff    }
791817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff
792817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff    private boolean stopResolveService(int resolveId) {
793817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        if (DBG) Slog.d(TAG, "stopResolveService: " + resolveId);
794817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        try {
795817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff            mNativeConnector.execute("mdnssd", "stop-resolve", resolveId);
796817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        } catch(NativeDaemonConnectorException e) {
797817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff            Slog.e(TAG, "Failed to stop resolve " + e);
798817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff            return false;
7997d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff        }
800817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        return true;
8017d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    }
8027d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
803817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff    private boolean getAddrInfo(int resolveId, String hostname) {
804817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        if (DBG) Slog.d(TAG, "getAdddrInfo: " + resolveId);
8057d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff        try {
806817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff            mNativeConnector.execute("mdnssd", "getaddrinfo", resolveId, hostname);
8077d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff        } catch(NativeDaemonConnectorException e) {
808817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff            Slog.e(TAG, "Failed to getAddrInfo " + e);
809817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff            return false;
8107d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff        }
811817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        return true;
8127d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    }
8137d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
814817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff    private boolean stopGetAddrInfo(int resolveId) {
815817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        if (DBG) Slog.d(TAG, "stopGetAdddrInfo: " + resolveId);
8167d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff        try {
817817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff            mNativeConnector.execute("mdnssd", "stop-getaddrinfo", resolveId);
8187d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff        } catch(NativeDaemonConnectorException e) {
819817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff            Slog.e(TAG, "Failed to stopGetAddrInfo " + e);
820817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff            return false;
8217d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff        }
822817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        return true;
8237d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    }
8247d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
8257d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    @Override
8263ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
8277d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
8287d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff                != PackageManager.PERMISSION_GRANTED) {
8297d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff            pw.println("Permission Denial: can't dump ServiceDiscoverService from from pid="
8307d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff                    + Binder.getCallingPid()
8317d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff                    + ", uid=" + Binder.getCallingUid());
8327d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff            return;
8337d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff        }
8347d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
8353ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff        for (ClientInfo client : mClients.values()) {
8363ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff            pw.println("Client Info");
8373ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff            pw.println(client);
8383ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff        }
8393ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff
8403ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff        mNsdStateMachine.dump(fd, pw, args);
8417d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    }
842817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff
84322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff    /* arg2 on the source message has an id that needs to be retained in replies
84422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff     * see NsdManager for details */
84522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff    private Message obtainMessage(Message srcMsg) {
84622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        Message msg = Message.obtain();
84722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        msg.arg2 = srcMsg.arg2;
84822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        return msg;
849817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff    }
850817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff
85122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff    private void replyToMessage(Message msg, int what) {
85222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        if (msg.replyTo == null) return;
85322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        Message dstMsg = obtainMessage(msg);
85422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        dstMsg.what = what;
85522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        mReplyChannel.replyToMessage(msg, dstMsg);
856817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff    }
857817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff
85822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff    private void replyToMessage(Message msg, int what, int arg1) {
85922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        if (msg.replyTo == null) return;
86022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        Message dstMsg = obtainMessage(msg);
86122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        dstMsg.what = what;
86222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        dstMsg.arg1 = arg1;
86322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        mReplyChannel.replyToMessage(msg, dstMsg);
86422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff    }
86522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff
86622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff    private void replyToMessage(Message msg, int what, Object obj) {
86722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        if (msg.replyTo == null) return;
86822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        Message dstMsg = obtainMessage(msg);
86922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        dstMsg.what = what;
87022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        dstMsg.obj = obj;
87122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        mReplyChannel.replyToMessage(msg, dstMsg);
872817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff    }
873817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff
874817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff    /* Information tracked per client */
875817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff    private class ClientInfo {
876817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff
87722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        private static final int MAX_LIMIT = 10;
8786727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan        private final AsyncChannel mChannel;
8796727e7351e2a95d64017340c51c35239210f1381Vairavan Srinivasan        private final Messenger mMessenger;
880817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        /* Remembers a resolved service until getaddrinfo completes */
88122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        private NsdServiceInfo mResolvedService;
88222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff
88322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        /* A map from client id to unique id sent to mDns */
88422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        private SparseArray<Integer> mClientIds = new SparseArray<Integer>();
885817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff
886f31760c63401be72748487c9d4fce3fecdedede4Dave Platt        /* A map from client id to the type of the request we had received */
887f31760c63401be72748487c9d4fce3fecdedede4Dave Platt        private SparseArray<Integer> mClientRequests = new SparseArray<Integer>();
888f31760c63401be72748487c9d4fce3fecdedede4Dave Platt
889817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        private ClientInfo(AsyncChannel c, Messenger m) {
890817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff            mChannel = c;
891817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff            mMessenger = m;
892817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff            if (DBG) Slog.d(TAG, "New client, channel: " + c + " messenger: " + m);
893817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff        }
8943ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff
8953ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff        @Override
8963ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff        public String toString() {
8973ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff            StringBuffer sb = new StringBuffer();
8983ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff            sb.append("mChannel ").append(mChannel).append("\n");
8993ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff            sb.append("mMessenger ").append(mMessenger).append("\n");
9003ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff            sb.append("mResolvedService ").append(mResolvedService).append("\n");
90122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff            for(int i = 0; i< mClientIds.size(); i++) {
902f31760c63401be72748487c9d4fce3fecdedede4Dave Platt                int clientID = mClientIds.keyAt(i);
903f31760c63401be72748487c9d4fce3fecdedede4Dave Platt                sb.append("clientId ").append(clientID).
904f31760c63401be72748487c9d4fce3fecdedede4Dave Platt                    append(" mDnsId ").append(mClientIds.valueAt(i)).
905f31760c63401be72748487c9d4fce3fecdedede4Dave Platt                    append(" type ").append(mClientRequests.get(clientID)).append("\n");
9063ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff            }
9073ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff            return sb.toString();
9083ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff        }
909f31760c63401be72748487c9d4fce3fecdedede4Dave Platt
910f31760c63401be72748487c9d4fce3fecdedede4Dave Platt        // Remove any pending requests from the global map when we get rid of a client,
911f31760c63401be72748487c9d4fce3fecdedede4Dave Platt        // and send cancellations to the daemon.
912f31760c63401be72748487c9d4fce3fecdedede4Dave Platt        private void expungeAllRequests() {
913f31760c63401be72748487c9d4fce3fecdedede4Dave Platt            int globalId, clientId, i;
914f31760c63401be72748487c9d4fce3fecdedede4Dave Platt            for (i = 0; i < mClientIds.size(); i++) {
915f31760c63401be72748487c9d4fce3fecdedede4Dave Platt                clientId = mClientIds.keyAt(i);
916f31760c63401be72748487c9d4fce3fecdedede4Dave Platt                globalId = mClientIds.valueAt(i);
917f31760c63401be72748487c9d4fce3fecdedede4Dave Platt                mIdToClientInfoMap.remove(globalId);
918f31760c63401be72748487c9d4fce3fecdedede4Dave Platt                if (DBG) Slog.d(TAG, "Terminating client-ID " + clientId +
919f31760c63401be72748487c9d4fce3fecdedede4Dave Platt                        " global-ID " + globalId + " type " + mClientRequests.get(clientId));
920f31760c63401be72748487c9d4fce3fecdedede4Dave Platt                switch (mClientRequests.get(clientId)) {
921f31760c63401be72748487c9d4fce3fecdedede4Dave Platt                    case NsdManager.DISCOVER_SERVICES:
922f31760c63401be72748487c9d4fce3fecdedede4Dave Platt                        stopServiceDiscovery(globalId);
923f31760c63401be72748487c9d4fce3fecdedede4Dave Platt                        break;
924f31760c63401be72748487c9d4fce3fecdedede4Dave Platt                    case NsdManager.RESOLVE_SERVICE:
925f31760c63401be72748487c9d4fce3fecdedede4Dave Platt                        stopResolveService(globalId);
926f31760c63401be72748487c9d4fce3fecdedede4Dave Platt                        break;
927f31760c63401be72748487c9d4fce3fecdedede4Dave Platt                    case NsdManager.REGISTER_SERVICE:
928f31760c63401be72748487c9d4fce3fecdedede4Dave Platt                        unregisterService(globalId);
929f31760c63401be72748487c9d4fce3fecdedede4Dave Platt                        break;
930f31760c63401be72748487c9d4fce3fecdedede4Dave Platt                    default:
931f31760c63401be72748487c9d4fce3fecdedede4Dave Platt                        break;
932f31760c63401be72748487c9d4fce3fecdedede4Dave Platt                }
933f31760c63401be72748487c9d4fce3fecdedede4Dave Platt            }
934f31760c63401be72748487c9d4fce3fecdedede4Dave Platt            mClientIds.clear();
935f31760c63401be72748487c9d4fce3fecdedede4Dave Platt            mClientRequests.clear();
936f31760c63401be72748487c9d4fce3fecdedede4Dave Platt        }
937f31760c63401be72748487c9d4fce3fecdedede4Dave Platt
9385a577903d366ff07b3c4ec6359e4757154f49790Christopher Lane        // mClientIds is a sparse array of listener id -> mDnsClient id.  For a given mDnsClient id,
9395a577903d366ff07b3c4ec6359e4757154f49790Christopher Lane        // return the corresponding listener id.  mDnsClient id is also called a global id.
9405a577903d366ff07b3c4ec6359e4757154f49790Christopher Lane        private int getClientId(final int globalId) {
9415a577903d366ff07b3c4ec6359e4757154f49790Christopher Lane            // This doesn't use mClientIds.indexOfValue because indexOfValue uses == (not .equals)
9425a577903d366ff07b3c4ec6359e4757154f49790Christopher Lane            // while also coercing the int primitives to Integer objects.
9435a577903d366ff07b3c4ec6359e4757154f49790Christopher Lane            for (int i = 0, nSize = mClientIds.size(); i < nSize; i++) {
9445a577903d366ff07b3c4ec6359e4757154f49790Christopher Lane                int mDnsId = mClientIds.valueAt(i);
9455a577903d366ff07b3c4ec6359e4757154f49790Christopher Lane                if (globalId == mDnsId) {
9465a577903d366ff07b3c4ec6359e4757154f49790Christopher Lane                    return mClientIds.keyAt(i);
9475a577903d366ff07b3c4ec6359e4757154f49790Christopher Lane                }
9485a577903d366ff07b3c4ec6359e4757154f49790Christopher Lane            }
9495a577903d366ff07b3c4ec6359e4757154f49790Christopher Lane            return -1;
9505a577903d366ff07b3c4ec6359e4757154f49790Christopher Lane        }
951817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff    }
9527d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff}
953