blob: cf7e65c0e38d083d78753d984f2edfdfeac86432 [file] [log] [blame]
Irfan Sheriff7d024d32012-03-22 17:01:39 -07001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
19import android.content.Context;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070020import android.content.ContentResolver;
21import android.content.Intent;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070022import android.content.pm.PackageManager;
Irfan Sheriff919aca52012-06-01 16:44:13 -070023import android.database.ContentObserver;
Irfan Sheriff22af38c2012-05-03 16:44:27 -070024import android.net.nsd.NsdServiceInfo;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070025import android.net.nsd.DnsSdTxtRecord;
26import android.net.nsd.INsdManager;
27import android.net.nsd.NsdManager;
28import android.os.Binder;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070029import android.os.Message;
30import android.os.Messenger;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070031import android.os.UserHandle;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070032import android.provider.Settings;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070033import android.util.Slog;
Irfan Sheriff22af38c2012-05-03 16:44:27 -070034import android.util.SparseArray;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070035
36import java.io.FileDescriptor;
37import java.io.PrintWriter;
Christopher Laneb72d8b42014-03-17 16:35:45 -070038import java.io.UnsupportedEncodingException;
Irfan Sheriff817388e2012-04-11 14:52:19 -070039import java.net.InetAddress;
Irfan Sheriff817388e2012-04-11 14:52:19 -070040import java.util.HashMap;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070041import java.util.List;
Christopher Laneb72d8b42014-03-17 16:35:45 -070042import java.util.Locale;
43import java.util.Map;
Irfan Sheriff817388e2012-04-11 14:52:19 -070044import java.util.concurrent.CountDownLatch;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070045
Irfan Sheriff7d024d32012-03-22 17:01:39 -070046import com.android.internal.util.AsyncChannel;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070047import com.android.internal.util.Protocol;
48import com.android.internal.util.State;
49import com.android.internal.util.StateMachine;
Christopher Lane771cd652014-04-14 16:31:27 -070050import com.android.server.NativeDaemonConnector.Command;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070051
52/**
53 * Network Service Discovery Service handles remote service discovery operation requests by
54 * implementing the INsdManager interface.
55 *
56 * @hide
57 */
58public class NsdService extends INsdManager.Stub {
59 private static final String TAG = "NsdService";
60 private static final String MDNS_TAG = "mDnsConnector";
61
62 private static final boolean DBG = true;
63
64 private Context mContext;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070065 private ContentResolver mContentResolver;
66 private NsdStateMachine mNsdStateMachine;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070067
68 /**
69 * Clients receiving asynchronous messages
70 */
Irfan Sheriff817388e2012-04-11 14:52:19 -070071 private HashMap<Messenger, ClientInfo> mClients = new HashMap<Messenger, ClientInfo>();
Irfan Sheriff7d024d32012-03-22 17:01:39 -070072
Irfan Sheriff22af38c2012-05-03 16:44:27 -070073 /* A map from unique id to client info */
74 private SparseArray<ClientInfo> mIdToClientInfoMap= new SparseArray<ClientInfo>();
75
Irfan Sheriff7d024d32012-03-22 17:01:39 -070076 private AsyncChannel mReplyChannel = new AsyncChannel();
77
Irfan Sheriff817388e2012-04-11 14:52:19 -070078 private int INVALID_ID = 0;
79 private int mUniqueId = 1;
80
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070081 private static final int BASE = Protocol.BASE_NSD_MANAGER;
Irfan Sheriff22af38c2012-05-03 16:44:27 -070082 private static final int CMD_TO_STRING_COUNT = NsdManager.RESOLVE_SERVICE - BASE + 1;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070083 private static String[] sCmdToString = new String[CMD_TO_STRING_COUNT];
Irfan Sheriff7d024d32012-03-22 17:01:39 -070084
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070085 static {
86 sCmdToString[NsdManager.DISCOVER_SERVICES - BASE] = "DISCOVER";
87 sCmdToString[NsdManager.STOP_DISCOVERY - BASE] = "STOP-DISCOVER";
88 sCmdToString[NsdManager.REGISTER_SERVICE - BASE] = "REGISTER";
89 sCmdToString[NsdManager.UNREGISTER_SERVICE - BASE] = "UNREGISTER";
90 sCmdToString[NsdManager.RESOLVE_SERVICE - BASE] = "RESOLVE";
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070091 }
Irfan Sheriff7d024d32012-03-22 17:01:39 -070092
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070093 private static String cmdToString(int cmd) {
94 cmd -= BASE;
95 if ((cmd >= 0) && (cmd < sCmdToString.length)) {
96 return sCmdToString[cmd];
97 } else {
98 return null;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070099 }
100 }
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700101
102 private class NsdStateMachine extends StateMachine {
103
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700104 private final DefaultState mDefaultState = new DefaultState();
105 private final DisabledState mDisabledState = new DisabledState();
106 private final EnabledState mEnabledState = new EnabledState();
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700107
108 @Override
Wink Savillebbf30dfd2012-05-29 12:40:46 -0700109 protected String getWhatToString(int what) {
110 return cmdToString(what);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700111 }
112
Irfan Sheriff919aca52012-06-01 16:44:13 -0700113 /**
114 * Observes the NSD on/off setting, and takes action when changed.
115 */
116 private void registerForNsdSetting() {
117 ContentObserver contentObserver = new ContentObserver(this.getHandler()) {
118 @Override
119 public void onChange(boolean selfChange) {
120 if (isNsdEnabled()) {
121 mNsdStateMachine.sendMessage(NsdManager.ENABLE);
122 } else {
123 mNsdStateMachine.sendMessage(NsdManager.DISABLE);
124 }
125 }
126 };
127
128 mContext.getContentResolver().registerContentObserver(
Jeff Sharkey625239a2012-09-26 22:03:49 -0700129 Settings.Global.getUriFor(Settings.Global.NSD_ON),
Irfan Sheriff919aca52012-06-01 16:44:13 -0700130 false, contentObserver);
131 }
132
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700133 NsdStateMachine(String name) {
134 super(name);
135 addState(mDefaultState);
136 addState(mDisabledState, mDefaultState);
137 addState(mEnabledState, mDefaultState);
138 if (isNsdEnabled()) {
139 setInitialState(mEnabledState);
140 } else {
141 setInitialState(mDisabledState);
142 }
Wink Savillebbf30dfd2012-05-29 12:40:46 -0700143 setLogRecSize(25);
Irfan Sheriff919aca52012-06-01 16:44:13 -0700144 registerForNsdSetting();
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700145 }
146
147 class DefaultState extends State {
148 @Override
149 public boolean processMessage(Message msg) {
Dave Plattf31760c2014-03-07 14:48:22 -0800150 ClientInfo cInfo = null;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700151 switch (msg.what) {
152 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
153 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
154 AsyncChannel c = (AsyncChannel) msg.obj;
155 if (DBG) Slog.d(TAG, "New client listening to asynchronous messages");
156 c.sendMessage(AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED);
Dave Plattf31760c2014-03-07 14:48:22 -0800157 cInfo = new ClientInfo(c, msg.replyTo);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700158 mClients.put(msg.replyTo, cInfo);
159 } else {
160 Slog.e(TAG, "Client connection failure, error=" + msg.arg1);
161 }
162 break;
163 case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
Dave Plattf31760c2014-03-07 14:48:22 -0800164 switch (msg.arg1) {
165 case AsyncChannel.STATUS_SEND_UNSUCCESSFUL:
166 Slog.e(TAG, "Send failed, client connection lost");
167 break;
168 case AsyncChannel.STATUS_REMOTE_DISCONNECTION:
169 if (DBG) Slog.d(TAG, "Client disconnected");
170 break;
171 default:
172 if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1);
173 break;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700174 }
Dave Plattf31760c2014-03-07 14:48:22 -0800175 cInfo = mClients.get(msg.replyTo);
176 if (cInfo != null) {
177 cInfo.expungeAllRequests();
178 mClients.remove(msg.replyTo);
179 }
180 //Last client
181 if (mClients.size() == 0) {
182 stopMDnsDaemon();
183 }
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700184 break;
185 case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION:
186 AsyncChannel ac = new AsyncChannel();
187 ac.connect(mContext, getHandler(), msg.replyTo);
188 break;
189 case NsdManager.DISCOVER_SERVICES:
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700190 replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED,
191 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700192 break;
193 case NsdManager.STOP_DISCOVERY:
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700194 replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED,
195 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700196 break;
197 case NsdManager.REGISTER_SERVICE:
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700198 replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED,
199 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700200 break;
201 case NsdManager.UNREGISTER_SERVICE:
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700202 replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED,
203 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700204 break;
205 case NsdManager.RESOLVE_SERVICE:
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700206 replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED,
207 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700208 break;
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700209 case NsdManager.NATIVE_DAEMON_EVENT:
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700210 default:
211 Slog.e(TAG, "Unhandled " + msg);
212 return NOT_HANDLED;
213 }
214 return HANDLED;
215 }
216 }
217
218 class DisabledState extends State {
219 @Override
220 public void enter() {
221 sendNsdStateChangeBroadcast(false);
222 }
223
224 @Override
225 public boolean processMessage(Message msg) {
226 switch (msg.what) {
227 case NsdManager.ENABLE:
228 transitionTo(mEnabledState);
229 break;
230 default:
231 return NOT_HANDLED;
232 }
233 return HANDLED;
234 }
235 }
236
237 class EnabledState extends State {
238 @Override
239 public void enter() {
240 sendNsdStateChangeBroadcast(true);
241 if (mClients.size() > 0) {
242 startMDnsDaemon();
243 }
244 }
245
246 @Override
247 public void exit() {
248 if (mClients.size() > 0) {
249 stopMDnsDaemon();
250 }
251 }
252
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700253 private boolean requestLimitReached(ClientInfo clientInfo) {
254 if (clientInfo.mClientIds.size() >= ClientInfo.MAX_LIMIT) {
255 if (DBG) Slog.d(TAG, "Exceeded max outstanding requests " + clientInfo);
256 return true;
257 }
258 return false;
259 }
260
Dave Plattf31760c2014-03-07 14:48:22 -0800261 private void storeRequestMap(int clientId, int globalId, ClientInfo clientInfo, int what) {
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700262 clientInfo.mClientIds.put(clientId, globalId);
Dave Plattf31760c2014-03-07 14:48:22 -0800263 clientInfo.mClientRequests.put(clientId, what);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700264 mIdToClientInfoMap.put(globalId, clientInfo);
265 }
266
267 private void removeRequestMap(int clientId, int globalId, ClientInfo clientInfo) {
268 clientInfo.mClientIds.remove(clientId);
Dave Plattf31760c2014-03-07 14:48:22 -0800269 clientInfo.mClientRequests.remove(clientId);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700270 mIdToClientInfoMap.remove(globalId);
271 }
272
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700273 @Override
274 public boolean processMessage(Message msg) {
275 ClientInfo clientInfo;
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700276 NsdServiceInfo servInfo;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700277 boolean result = HANDLED;
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700278 int id;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700279 switch (msg.what) {
280 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
281 //First client
282 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL &&
283 mClients.size() == 0) {
284 startMDnsDaemon();
285 }
286 result = NOT_HANDLED;
287 break;
288 case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700289 result = NOT_HANDLED;
290 break;
291 case NsdManager.DISABLE:
292 //TODO: cleanup clients
293 transitionTo(mDisabledState);
294 break;
295 case NsdManager.DISCOVER_SERVICES:
296 if (DBG) Slog.d(TAG, "Discover services");
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700297 servInfo = (NsdServiceInfo) msg.obj;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700298 clientInfo = mClients.get(msg.replyTo);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700299
300 if (requestLimitReached(clientInfo)) {
301 replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED,
302 NsdManager.FAILURE_MAX_LIMIT);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700303 break;
304 }
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700305
306 id = getUniqueId();
307 if (discoverServices(id, servInfo.getServiceType())) {
308 if (DBG) {
309 Slog.d(TAG, "Discover " + msg.arg2 + " " + id +
310 servInfo.getServiceType());
311 }
Dave Plattf31760c2014-03-07 14:48:22 -0800312 storeRequestMap(msg.arg2, id, clientInfo, msg.what);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700313 replyToMessage(msg, NsdManager.DISCOVER_SERVICES_STARTED, servInfo);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700314 } else {
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700315 stopServiceDiscovery(id);
316 replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED,
317 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700318 }
319 break;
320 case NsdManager.STOP_DISCOVERY:
321 if (DBG) Slog.d(TAG, "Stop service discovery");
322 clientInfo = mClients.get(msg.replyTo);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700323
324 try {
325 id = clientInfo.mClientIds.get(msg.arg2).intValue();
326 } catch (NullPointerException e) {
327 replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED,
328 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700329 break;
330 }
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700331 removeRequestMap(msg.arg2, id, clientInfo);
332 if (stopServiceDiscovery(id)) {
333 replyToMessage(msg, NsdManager.STOP_DISCOVERY_SUCCEEDED);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700334 } else {
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700335 replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED,
336 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700337 }
338 break;
339 case NsdManager.REGISTER_SERVICE:
340 if (DBG) Slog.d(TAG, "Register service");
341 clientInfo = mClients.get(msg.replyTo);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700342 if (requestLimitReached(clientInfo)) {
343 replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED,
344 NsdManager.FAILURE_MAX_LIMIT);
345 break;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700346 }
347
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700348 id = getUniqueId();
349 if (registerService(id, (NsdServiceInfo) msg.obj)) {
350 if (DBG) Slog.d(TAG, "Register " + msg.arg2 + " " + id);
Dave Plattf31760c2014-03-07 14:48:22 -0800351 storeRequestMap(msg.arg2, id, clientInfo, msg.what);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700352 // Return success after mDns reports success
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700353 } else {
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700354 unregisterService(id);
355 replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED,
356 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700357 }
358 break;
359 case NsdManager.UNREGISTER_SERVICE:
360 if (DBG) Slog.d(TAG, "unregister service");
361 clientInfo = mClients.get(msg.replyTo);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700362 try {
363 id = clientInfo.mClientIds.get(msg.arg2).intValue();
364 } catch (NullPointerException e) {
365 replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED,
366 NsdManager.FAILURE_INTERNAL_ERROR);
367 break;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700368 }
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700369 removeRequestMap(msg.arg2, id, clientInfo);
370 if (unregisterService(id)) {
371 replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_SUCCEEDED);
372 } else {
373 replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED,
374 NsdManager.FAILURE_INTERNAL_ERROR);
375 }
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700376 break;
377 case NsdManager.RESOLVE_SERVICE:
378 if (DBG) Slog.d(TAG, "Resolve service");
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700379 servInfo = (NsdServiceInfo) msg.obj;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700380 clientInfo = mClients.get(msg.replyTo);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700381
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700382
383 if (clientInfo.mResolvedService != null) {
384 replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED,
385 NsdManager.FAILURE_ALREADY_ACTIVE);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700386 break;
387 }
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700388
389 id = getUniqueId();
390 if (resolveService(id, servInfo)) {
391 clientInfo.mResolvedService = new NsdServiceInfo();
Dave Plattf31760c2014-03-07 14:48:22 -0800392 storeRequestMap(msg.arg2, id, clientInfo, msg.what);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700393 } else {
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700394 replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED,
395 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700396 }
397 break;
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700398 case NsdManager.NATIVE_DAEMON_EVENT:
399 NativeEvent event = (NativeEvent) msg.obj;
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700400 if (!handleNativeEvent(event.code, event.raw,
401 NativeDaemonEvent.unescapeArgs(event.raw))) {
402 result = NOT_HANDLED;
403 }
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700404 break;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700405 default:
406 result = NOT_HANDLED;
407 break;
408 }
409 return result;
410 }
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700411
412 private boolean handleNativeEvent(int code, String raw, String[] cooked) {
413 boolean handled = true;
414 NsdServiceInfo servInfo;
415 int id = Integer.parseInt(cooked[1]);
416 ClientInfo clientInfo = mIdToClientInfoMap.get(id);
417 if (clientInfo == null) {
418 Slog.e(TAG, "Unique id with no client mapping: " + id);
419 handled = false;
420 return handled;
421 }
422
423 /* This goes in response as msg.arg2 */
Christopher Lane5a577902014-04-25 18:39:07 -0700424 int clientId = clientInfo.getClientId(id);
425 if (clientId < 0) {
Vinit Deshapnde8ed09e82013-06-25 19:45:03 -0700426 // This can happen because of race conditions. For example,
427 // SERVICE_FOUND may race with STOP_SERVICE_DISCOVERY,
428 // and we may get in this situation.
429 Slog.d(TAG, "Notification for a listener that is no longer active: " + id);
430 handled = false;
431 return handled;
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700432 }
Vinit Deshapnde8ed09e82013-06-25 19:45:03 -0700433
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700434 switch (code) {
435 case NativeResponseCode.SERVICE_FOUND:
436 /* NNN uniqueId serviceName regType domain */
437 if (DBG) Slog.d(TAG, "SERVICE_FOUND Raw: " + raw);
Christopher Laneb72d8b42014-03-17 16:35:45 -0700438 servInfo = new NsdServiceInfo(cooked[2], cooked[3]);
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700439 clientInfo.mChannel.sendMessage(NsdManager.SERVICE_FOUND, 0,
440 clientId, servInfo);
441 break;
442 case NativeResponseCode.SERVICE_LOST:
443 /* NNN uniqueId serviceName regType domain */
444 if (DBG) Slog.d(TAG, "SERVICE_LOST Raw: " + raw);
Christopher Laneb72d8b42014-03-17 16:35:45 -0700445 servInfo = new NsdServiceInfo(cooked[2], cooked[3]);
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700446 clientInfo.mChannel.sendMessage(NsdManager.SERVICE_LOST, 0,
447 clientId, servInfo);
448 break;
449 case NativeResponseCode.SERVICE_DISCOVERY_FAILED:
450 /* NNN uniqueId errorCode */
451 if (DBG) Slog.d(TAG, "SERVICE_DISC_FAILED Raw: " + raw);
452 clientInfo.mChannel.sendMessage(NsdManager.DISCOVER_SERVICES_FAILED,
453 NsdManager.FAILURE_INTERNAL_ERROR, clientId);
454 break;
455 case NativeResponseCode.SERVICE_REGISTERED:
456 /* NNN regId serviceName regType */
457 if (DBG) Slog.d(TAG, "SERVICE_REGISTERED Raw: " + raw);
Christopher Laneb72d8b42014-03-17 16:35:45 -0700458 servInfo = new NsdServiceInfo(cooked[2], null);
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700459 clientInfo.mChannel.sendMessage(NsdManager.REGISTER_SERVICE_SUCCEEDED,
460 id, clientId, servInfo);
461 break;
462 case NativeResponseCode.SERVICE_REGISTRATION_FAILED:
463 /* NNN regId errorCode */
464 if (DBG) Slog.d(TAG, "SERVICE_REGISTER_FAILED Raw: " + raw);
465 clientInfo.mChannel.sendMessage(NsdManager.REGISTER_SERVICE_FAILED,
466 NsdManager.FAILURE_INTERNAL_ERROR, clientId);
467 break;
468 case NativeResponseCode.SERVICE_UPDATED:
469 /* NNN regId */
470 break;
471 case NativeResponseCode.SERVICE_UPDATE_FAILED:
472 /* NNN regId errorCode */
473 break;
474 case NativeResponseCode.SERVICE_RESOLVED:
475 /* NNN resolveId fullName hostName port txtlen txtdata */
476 if (DBG) Slog.d(TAG, "SERVICE_RESOLVED Raw: " + raw);
477 int index = cooked[2].indexOf(".");
478 if (index == -1) {
479 Slog.e(TAG, "Invalid service found " + raw);
480 break;
481 }
482 String name = cooked[2].substring(0, index);
483 String rest = cooked[2].substring(index);
484 String type = rest.replace(".local.", "");
485
486 clientInfo.mResolvedService.setServiceName(name);
487 clientInfo.mResolvedService.setServiceType(type);
488 clientInfo.mResolvedService.setPort(Integer.parseInt(cooked[4]));
489
490 stopResolveService(id);
Vinit Deshapnde40387242013-11-12 15:36:37 -0800491 removeRequestMap(clientId, id, clientInfo);
492
493 int id2 = getUniqueId();
494 if (getAddrInfo(id2, cooked[3])) {
Dave Plattf31760c2014-03-07 14:48:22 -0800495 storeRequestMap(clientId, id2, clientInfo, NsdManager.RESOLVE_SERVICE);
Vinit Deshapnde40387242013-11-12 15:36:37 -0800496 } else {
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700497 clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
498 NsdManager.FAILURE_INTERNAL_ERROR, clientId);
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700499 clientInfo.mResolvedService = null;
500 }
501 break;
502 case NativeResponseCode.SERVICE_RESOLUTION_FAILED:
503 /* NNN resolveId errorCode */
504 if (DBG) Slog.d(TAG, "SERVICE_RESOLVE_FAILED Raw: " + raw);
505 stopResolveService(id);
506 removeRequestMap(clientId, id, clientInfo);
507 clientInfo.mResolvedService = null;
508 clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
509 NsdManager.FAILURE_INTERNAL_ERROR, clientId);
510 break;
511 case NativeResponseCode.SERVICE_GET_ADDR_FAILED:
512 /* NNN resolveId errorCode */
513 stopGetAddrInfo(id);
514 removeRequestMap(clientId, id, clientInfo);
515 clientInfo.mResolvedService = null;
516 if (DBG) Slog.d(TAG, "SERVICE_RESOLVE_FAILED Raw: " + raw);
517 clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
518 NsdManager.FAILURE_INTERNAL_ERROR, clientId);
519 break;
520 case NativeResponseCode.SERVICE_GET_ADDR_SUCCESS:
521 /* NNN resolveId hostname ttl addr */
522 if (DBG) Slog.d(TAG, "SERVICE_GET_ADDR_SUCCESS Raw: " + raw);
523 try {
524 clientInfo.mResolvedService.setHost(InetAddress.getByName(cooked[4]));
525 clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_SUCCEEDED,
526 0, clientId, clientInfo.mResolvedService);
527 } catch (java.net.UnknownHostException e) {
528 clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
529 NsdManager.FAILURE_INTERNAL_ERROR, clientId);
530 }
531 stopGetAddrInfo(id);
532 removeRequestMap(clientId, id, clientInfo);
533 clientInfo.mResolvedService = null;
534 break;
535 default:
536 handled = false;
537 break;
538 }
539 return handled;
540 }
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700541 }
542 }
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700543
544 private NativeDaemonConnector mNativeConnector;
545 private final CountDownLatch mNativeDaemonConnected = new CountDownLatch(1);
546
547 private NsdService(Context context) {
548 mContext = context;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700549 mContentResolver = context.getContentResolver();
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700550
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700551 mNativeConnector = new NativeDaemonConnector(new NativeCallbackReceiver(), "mdns", 10,
Dianne Hackborn77b987f2014-02-26 16:20:52 -0800552 MDNS_TAG, 25, null);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700553
554 mNsdStateMachine = new NsdStateMachine(TAG);
555 mNsdStateMachine.start();
556
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700557 Thread th = new Thread(mNativeConnector, MDNS_TAG);
558 th.start();
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700559 }
560
561 public static NsdService create(Context context) throws InterruptedException {
562 NsdService service = new NsdService(context);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700563 service.mNativeDaemonConnected.await();
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700564 return service;
565 }
566
567 public Messenger getMessenger() {
Irfan Sheriff92784672012-04-13 12:15:41 -0700568 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INTERNET,
569 "NsdService");
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700570 return new Messenger(mNsdStateMachine.getHandler());
571 }
572
573 public void setEnabled(boolean enable) {
574 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL,
575 "NsdService");
Jeff Sharkey625239a2012-09-26 22:03:49 -0700576 Settings.Global.putInt(mContentResolver, Settings.Global.NSD_ON, enable ? 1 : 0);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700577 if (enable) {
578 mNsdStateMachine.sendMessage(NsdManager.ENABLE);
579 } else {
580 mNsdStateMachine.sendMessage(NsdManager.DISABLE);
581 }
582 }
583
584 private void sendNsdStateChangeBroadcast(boolean enabled) {
Irfan Sheriff54ac7a52012-04-19 10:26:34 -0700585 final Intent intent = new Intent(NsdManager.ACTION_NSD_STATE_CHANGED);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700586 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
587 if (enabled) {
588 intent.putExtra(NsdManager.EXTRA_NSD_STATE, NsdManager.NSD_STATE_ENABLED);
589 } else {
590 intent.putExtra(NsdManager.EXTRA_NSD_STATE, NsdManager.NSD_STATE_DISABLED);
591 }
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700592 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700593 }
594
595 private boolean isNsdEnabled() {
Jeff Sharkey625239a2012-09-26 22:03:49 -0700596 boolean ret = Settings.Global.getInt(mContentResolver, Settings.Global.NSD_ON, 1) == 1;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700597 if (DBG) Slog.d(TAG, "Network service discovery enabled " + ret);
598 return ret;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700599 }
600
Irfan Sheriff817388e2012-04-11 14:52:19 -0700601 private int getUniqueId() {
602 if (++mUniqueId == INVALID_ID) return ++mUniqueId;
603 return mUniqueId;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700604 }
605
Sreeram Ramachandran03666c72014-07-19 23:21:46 -0700606 /* These should be in sync with system/netd/server/ResponseCode.h */
Irfan Sheriff817388e2012-04-11 14:52:19 -0700607 class NativeResponseCode {
608 public static final int SERVICE_DISCOVERY_FAILED = 602;
609 public static final int SERVICE_FOUND = 603;
610 public static final int SERVICE_LOST = 604;
611
612 public static final int SERVICE_REGISTRATION_FAILED = 605;
613 public static final int SERVICE_REGISTERED = 606;
614
615 public static final int SERVICE_RESOLUTION_FAILED = 607;
616 public static final int SERVICE_RESOLVED = 608;
617
618 public static final int SERVICE_UPDATED = 609;
619 public static final int SERVICE_UPDATE_FAILED = 610;
620
621 public static final int SERVICE_GET_ADDR_FAILED = 611;
622 public static final int SERVICE_GET_ADDR_SUCCESS = 612;
623 }
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700624
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700625 private class NativeEvent {
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700626 final int code;
627 final String raw;
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700628
629 NativeEvent(int code, String raw) {
630 this.code = code;
631 this.raw = raw;
632 }
633 }
634
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700635 class NativeCallbackReceiver implements INativeDaemonConnectorCallbacks {
636 public void onDaemonConnected() {
637 mNativeDaemonConnected.countDown();
638 }
639
Dianne Hackborn77b987f2014-02-26 16:20:52 -0800640 public boolean onCheckHoldWakeLock(int code) {
641 return false;
642 }
643
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700644 public boolean onEvent(int code, String raw, String[] cooked) {
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700645 // TODO: NDC translates a message to a callback, we could enhance NDC to
646 // directly interact with a state machine through messages
647 NativeEvent event = new NativeEvent(code, raw);
648 mNsdStateMachine.sendMessage(NsdManager.NATIVE_DAEMON_EVENT, event);
649 return true;
650 }
651 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700652
Irfan Sheriff817388e2012-04-11 14:52:19 -0700653 private boolean startMDnsDaemon() {
654 if (DBG) Slog.d(TAG, "startMDnsDaemon");
655 try {
656 mNativeConnector.execute("mdnssd", "start-service");
657 } catch(NativeDaemonConnectorException e) {
658 Slog.e(TAG, "Failed to start daemon" + e);
659 return false;
660 }
661 return true;
662 }
663
664 private boolean stopMDnsDaemon() {
665 if (DBG) Slog.d(TAG, "stopMDnsDaemon");
666 try {
667 mNativeConnector.execute("mdnssd", "stop-service");
668 } catch(NativeDaemonConnectorException e) {
669 Slog.e(TAG, "Failed to start daemon" + e);
670 return false;
671 }
672 return true;
673 }
674
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700675 private boolean registerService(int regId, NsdServiceInfo service) {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700676 if (DBG) Slog.d(TAG, "registerService: " + regId + " " + service);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700677 try {
Christopher Laneb72d8b42014-03-17 16:35:45 -0700678 Command cmd = new Command("mdnssd", "register", regId, service.getServiceName(),
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700679 service.getServiceType(), service.getPort());
Christopher Laneb72d8b42014-03-17 16:35:45 -0700680
681 // Add TXT records as additional arguments.
682 Map<String, byte[]> txtRecords = service.getAttributes();
683 for (String key : txtRecords.keySet()) {
684 try {
685 // TODO: Send encoded TXT record as bytes once NDC/netd supports binary data.
686 cmd.appendArg(String.format(Locale.US, "%s=%s", key,
687 new String(txtRecords.get(key), "UTF_8")));
688 } catch (UnsupportedEncodingException e) {
689 Slog.e(TAG, "Failed to encode txtRecord " + e);
690 }
691 }
692
693 mNativeConnector.execute(cmd);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700694 } catch(NativeDaemonConnectorException e) {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700695 Slog.e(TAG, "Failed to execute registerService " + e);
696 return false;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700697 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700698 return true;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700699 }
700
Irfan Sheriff817388e2012-04-11 14:52:19 -0700701 private boolean unregisterService(int regId) {
702 if (DBG) Slog.d(TAG, "unregisterService: " + regId);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700703 try {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700704 mNativeConnector.execute("mdnssd", "stop-register", regId);
705 } catch(NativeDaemonConnectorException e) {
706 Slog.e(TAG, "Failed to execute unregisterService " + e);
707 return false;
708 }
709 return true;
710 }
711
712 private boolean updateService(int regId, DnsSdTxtRecord t) {
713 if (DBG) Slog.d(TAG, "updateService: " + regId + " " + t);
714 try {
715 if (t == null) return false;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700716 mNativeConnector.execute("mdnssd", "update", regId, t.size(), t.getRawData());
717 } catch(NativeDaemonConnectorException e) {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700718 Slog.e(TAG, "Failed to updateServices " + e);
719 return false;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700720 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700721 return true;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700722 }
723
Irfan Sheriff817388e2012-04-11 14:52:19 -0700724 private boolean discoverServices(int discoveryId, String serviceType) {
725 if (DBG) Slog.d(TAG, "discoverServices: " + discoveryId + " " + serviceType);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700726 try {
727 mNativeConnector.execute("mdnssd", "discover", discoveryId, serviceType);
728 } catch(NativeDaemonConnectorException e) {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700729 Slog.e(TAG, "Failed to discoverServices " + e);
730 return false;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700731 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700732 return true;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700733 }
734
Irfan Sheriff817388e2012-04-11 14:52:19 -0700735 private boolean stopServiceDiscovery(int discoveryId) {
736 if (DBG) Slog.d(TAG, "stopServiceDiscovery: " + discoveryId);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700737 try {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700738 mNativeConnector.execute("mdnssd", "stop-discover", discoveryId);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700739 } catch(NativeDaemonConnectorException e) {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700740 Slog.e(TAG, "Failed to stopServiceDiscovery " + e);
741 return false;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700742 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700743 return true;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700744 }
745
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700746 private boolean resolveService(int resolveId, NsdServiceInfo service) {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700747 if (DBG) Slog.d(TAG, "resolveService: " + resolveId + " " + service);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700748 try {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700749 mNativeConnector.execute("mdnssd", "resolve", resolveId, service.getServiceName(),
750 service.getServiceType(), "local.");
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700751 } catch(NativeDaemonConnectorException e) {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700752 Slog.e(TAG, "Failed to resolveService " + e);
753 return false;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700754 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700755 return true;
756 }
757
758 private boolean stopResolveService(int resolveId) {
759 if (DBG) Slog.d(TAG, "stopResolveService: " + resolveId);
760 try {
761 mNativeConnector.execute("mdnssd", "stop-resolve", resolveId);
762 } catch(NativeDaemonConnectorException e) {
763 Slog.e(TAG, "Failed to stop resolve " + e);
764 return false;
765 }
766 return true;
767 }
768
769 private boolean getAddrInfo(int resolveId, String hostname) {
770 if (DBG) Slog.d(TAG, "getAdddrInfo: " + resolveId);
771 try {
772 mNativeConnector.execute("mdnssd", "getaddrinfo", resolveId, hostname);
773 } catch(NativeDaemonConnectorException e) {
774 Slog.e(TAG, "Failed to getAddrInfo " + e);
775 return false;
776 }
777 return true;
778 }
779
780 private boolean stopGetAddrInfo(int resolveId) {
781 if (DBG) Slog.d(TAG, "stopGetAdddrInfo: " + resolveId);
782 try {
783 mNativeConnector.execute("mdnssd", "stop-getaddrinfo", resolveId);
784 } catch(NativeDaemonConnectorException e) {
785 Slog.e(TAG, "Failed to stopGetAddrInfo " + e);
786 return false;
787 }
788 return true;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700789 }
790
791 @Override
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700792 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700793 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
794 != PackageManager.PERMISSION_GRANTED) {
795 pw.println("Permission Denial: can't dump ServiceDiscoverService from from pid="
796 + Binder.getCallingPid()
797 + ", uid=" + Binder.getCallingUid());
798 return;
799 }
800
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700801 for (ClientInfo client : mClients.values()) {
802 pw.println("Client Info");
803 pw.println(client);
804 }
805
806 mNsdStateMachine.dump(fd, pw, args);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700807 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700808
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700809 /* arg2 on the source message has an id that needs to be retained in replies
810 * see NsdManager for details */
811 private Message obtainMessage(Message srcMsg) {
812 Message msg = Message.obtain();
813 msg.arg2 = srcMsg.arg2;
814 return msg;
Irfan Sheriff817388e2012-04-11 14:52:19 -0700815 }
816
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700817 private void replyToMessage(Message msg, int what) {
818 if (msg.replyTo == null) return;
819 Message dstMsg = obtainMessage(msg);
820 dstMsg.what = what;
821 mReplyChannel.replyToMessage(msg, dstMsg);
Irfan Sheriff817388e2012-04-11 14:52:19 -0700822 }
823
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700824 private void replyToMessage(Message msg, int what, int arg1) {
825 if (msg.replyTo == null) return;
826 Message dstMsg = obtainMessage(msg);
827 dstMsg.what = what;
828 dstMsg.arg1 = arg1;
829 mReplyChannel.replyToMessage(msg, dstMsg);
830 }
831
832 private void replyToMessage(Message msg, int what, Object obj) {
833 if (msg.replyTo == null) return;
834 Message dstMsg = obtainMessage(msg);
835 dstMsg.what = what;
836 dstMsg.obj = obj;
837 mReplyChannel.replyToMessage(msg, dstMsg);
Irfan Sheriff817388e2012-04-11 14:52:19 -0700838 }
839
840 /* Information tracked per client */
841 private class ClientInfo {
842
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700843 private static final int MAX_LIMIT = 10;
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700844 private final AsyncChannel mChannel;
845 private final Messenger mMessenger;
Irfan Sheriff817388e2012-04-11 14:52:19 -0700846 /* Remembers a resolved service until getaddrinfo completes */
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700847 private NsdServiceInfo mResolvedService;
848
849 /* A map from client id to unique id sent to mDns */
850 private SparseArray<Integer> mClientIds = new SparseArray<Integer>();
Irfan Sheriff817388e2012-04-11 14:52:19 -0700851
Dave Plattf31760c2014-03-07 14:48:22 -0800852 /* A map from client id to the type of the request we had received */
853 private SparseArray<Integer> mClientRequests = new SparseArray<Integer>();
854
Irfan Sheriff817388e2012-04-11 14:52:19 -0700855 private ClientInfo(AsyncChannel c, Messenger m) {
856 mChannel = c;
857 mMessenger = m;
Irfan Sheriff817388e2012-04-11 14:52:19 -0700858 if (DBG) Slog.d(TAG, "New client, channel: " + c + " messenger: " + m);
859 }
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700860
861 @Override
862 public String toString() {
863 StringBuffer sb = new StringBuffer();
864 sb.append("mChannel ").append(mChannel).append("\n");
865 sb.append("mMessenger ").append(mMessenger).append("\n");
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700866 sb.append("mResolvedService ").append(mResolvedService).append("\n");
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700867 for(int i = 0; i< mClientIds.size(); i++) {
Dave Plattf31760c2014-03-07 14:48:22 -0800868 int clientID = mClientIds.keyAt(i);
869 sb.append("clientId ").append(clientID).
870 append(" mDnsId ").append(mClientIds.valueAt(i)).
871 append(" type ").append(mClientRequests.get(clientID)).append("\n");
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700872 }
873 return sb.toString();
874 }
Dave Plattf31760c2014-03-07 14:48:22 -0800875
876 // Remove any pending requests from the global map when we get rid of a client,
877 // and send cancellations to the daemon.
878 private void expungeAllRequests() {
879 int globalId, clientId, i;
880 for (i = 0; i < mClientIds.size(); i++) {
881 clientId = mClientIds.keyAt(i);
882 globalId = mClientIds.valueAt(i);
883 mIdToClientInfoMap.remove(globalId);
884 if (DBG) Slog.d(TAG, "Terminating client-ID " + clientId +
885 " global-ID " + globalId + " type " + mClientRequests.get(clientId));
886 switch (mClientRequests.get(clientId)) {
887 case NsdManager.DISCOVER_SERVICES:
888 stopServiceDiscovery(globalId);
889 break;
890 case NsdManager.RESOLVE_SERVICE:
891 stopResolveService(globalId);
892 break;
893 case NsdManager.REGISTER_SERVICE:
894 unregisterService(globalId);
895 break;
896 default:
897 break;
898 }
899 }
900 mClientIds.clear();
901 mClientRequests.clear();
902 }
903
Christopher Lane5a577902014-04-25 18:39:07 -0700904 // mClientIds is a sparse array of listener id -> mDnsClient id. For a given mDnsClient id,
905 // return the corresponding listener id. mDnsClient id is also called a global id.
906 private int getClientId(final int globalId) {
907 // This doesn't use mClientIds.indexOfValue because indexOfValue uses == (not .equals)
908 // while also coercing the int primitives to Integer objects.
909 for (int i = 0, nSize = mClientIds.size(); i < nSize; i++) {
910 int mDnsId = mClientIds.valueAt(i);
911 if (globalId == mDnsId) {
912 return mClientIds.keyAt(i);
913 }
914 }
915 return -1;
916 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700917 }
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700918}