blob: a691af9c01a7fb27f9ae5cbe1d07d7665669e34b [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;
Philip P. Moltmann312c61e2016-03-16 10:15:39 -070033import android.util.Base64;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070034import android.util.Slog;
Irfan Sheriff22af38c2012-05-03 16:44:27 -070035import android.util.SparseArray;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070036
37import java.io.FileDescriptor;
38import java.io.PrintWriter;
Irfan Sheriff817388e2012-04-11 14:52:19 -070039import java.net.InetAddress;
Irfan Sheriff817388e2012-04-11 14:52:19 -070040import java.util.HashMap;
Irfan Sheriff817388e2012-04-11 14:52:19 -070041import java.util.concurrent.CountDownLatch;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070042
Irfan Sheriff7d024d32012-03-22 17:01:39 -070043import com.android.internal.util.AsyncChannel;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070044import com.android.internal.util.Protocol;
45import com.android.internal.util.State;
46import com.android.internal.util.StateMachine;
Christopher Lane771cd652014-04-14 16:31:27 -070047import com.android.server.NativeDaemonConnector.Command;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070048
49/**
50 * Network Service Discovery Service handles remote service discovery operation requests by
51 * implementing the INsdManager interface.
52 *
53 * @hide
54 */
55public class NsdService extends INsdManager.Stub {
56 private static final String TAG = "NsdService";
57 private static final String MDNS_TAG = "mDnsConnector";
58
Hugo Benichi2183ba92017-04-05 14:06:11 +090059 private static final boolean DBG = true;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070060
Hugo Benichi2183ba92017-04-05 14:06:11 +090061 private final Context mContext;
62 private final ContentResolver mContentResolver;
63 private final NsdStateMachine mNsdStateMachine;
64 private final NativeDaemonConnector mNativeConnector;
65 private final CountDownLatch mNativeDaemonConnected = new CountDownLatch(1);
Irfan Sheriff7d024d32012-03-22 17:01:39 -070066
67 /**
68 * Clients receiving asynchronous messages
69 */
Hugo Benichi2183ba92017-04-05 14:06:11 +090070 private final HashMap<Messenger, ClientInfo> mClients = new HashMap<>();
Irfan Sheriff7d024d32012-03-22 17:01:39 -070071
Irfan Sheriff22af38c2012-05-03 16:44:27 -070072 /* A map from unique id to client info */
Hugo Benichi2183ba92017-04-05 14:06:11 +090073 private final SparseArray<ClientInfo> mIdToClientInfoMap= new SparseArray<>();
Irfan Sheriff22af38c2012-05-03 16:44:27 -070074
Hugo Benichi2183ba92017-04-05 14:06:11 +090075 private final AsyncChannel mReplyChannel = new AsyncChannel();
Irfan Sheriff7d024d32012-03-22 17:01:39 -070076
Hugo Benichi2183ba92017-04-05 14:06:11 +090077 private static final int INVALID_ID = 0;
Irfan Sheriff817388e2012-04-11 14:52:19 -070078 private int mUniqueId = 1;
79
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070080 private class NsdStateMachine extends StateMachine {
81
Irfan Sheriff22af38c2012-05-03 16:44:27 -070082 private final DefaultState mDefaultState = new DefaultState();
83 private final DisabledState mDisabledState = new DisabledState();
84 private final EnabledState mEnabledState = new EnabledState();
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070085
86 @Override
Wink Savillebbf30dfd2012-05-29 12:40:46 -070087 protected String getWhatToString(int what) {
Hugo Benichi2183ba92017-04-05 14:06:11 +090088 return NsdManager.nameOf(what);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070089 }
90
Irfan Sheriff919aca52012-06-01 16:44:13 -070091 /**
92 * Observes the NSD on/off setting, and takes action when changed.
93 */
94 private void registerForNsdSetting() {
95 ContentObserver contentObserver = new ContentObserver(this.getHandler()) {
96 @Override
Hugo Benichi2183ba92017-04-05 14:06:11 +090097 public void onChange(boolean selfChange) {
98 if (isNsdEnabled()) {
99 mNsdStateMachine.sendMessage(NsdManager.ENABLE);
100 } else {
101 mNsdStateMachine.sendMessage(NsdManager.DISABLE);
Irfan Sheriff919aca52012-06-01 16:44:13 -0700102 }
Hugo Benichi2183ba92017-04-05 14:06:11 +0900103 }
Irfan Sheriff919aca52012-06-01 16:44:13 -0700104 };
105
106 mContext.getContentResolver().registerContentObserver(
Jeff Sharkey625239a2012-09-26 22:03:49 -0700107 Settings.Global.getUriFor(Settings.Global.NSD_ON),
Irfan Sheriff919aca52012-06-01 16:44:13 -0700108 false, contentObserver);
109 }
110
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700111 NsdStateMachine(String name) {
112 super(name);
113 addState(mDefaultState);
114 addState(mDisabledState, mDefaultState);
115 addState(mEnabledState, mDefaultState);
116 if (isNsdEnabled()) {
117 setInitialState(mEnabledState);
118 } else {
119 setInitialState(mDisabledState);
120 }
Wink Savillebbf30dfd2012-05-29 12:40:46 -0700121 setLogRecSize(25);
Irfan Sheriff919aca52012-06-01 16:44:13 -0700122 registerForNsdSetting();
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700123 }
124
125 class DefaultState extends State {
126 @Override
127 public boolean processMessage(Message msg) {
Dave Plattf31760c2014-03-07 14:48:22 -0800128 ClientInfo cInfo = null;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700129 switch (msg.what) {
130 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
131 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
132 AsyncChannel c = (AsyncChannel) msg.obj;
133 if (DBG) Slog.d(TAG, "New client listening to asynchronous messages");
134 c.sendMessage(AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED);
Dave Plattf31760c2014-03-07 14:48:22 -0800135 cInfo = new ClientInfo(c, msg.replyTo);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700136 mClients.put(msg.replyTo, cInfo);
137 } else {
138 Slog.e(TAG, "Client connection failure, error=" + msg.arg1);
139 }
140 break;
141 case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
Dave Plattf31760c2014-03-07 14:48:22 -0800142 switch (msg.arg1) {
143 case AsyncChannel.STATUS_SEND_UNSUCCESSFUL:
144 Slog.e(TAG, "Send failed, client connection lost");
145 break;
146 case AsyncChannel.STATUS_REMOTE_DISCONNECTION:
147 if (DBG) Slog.d(TAG, "Client disconnected");
148 break;
149 default:
150 if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1);
151 break;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700152 }
Dave Plattf31760c2014-03-07 14:48:22 -0800153 cInfo = mClients.get(msg.replyTo);
154 if (cInfo != null) {
155 cInfo.expungeAllRequests();
156 mClients.remove(msg.replyTo);
157 }
158 //Last client
159 if (mClients.size() == 0) {
160 stopMDnsDaemon();
161 }
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700162 break;
163 case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION:
164 AsyncChannel ac = new AsyncChannel();
165 ac.connect(mContext, getHandler(), msg.replyTo);
166 break;
167 case NsdManager.DISCOVER_SERVICES:
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700168 replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED,
169 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700170 break;
171 case NsdManager.STOP_DISCOVERY:
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700172 replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED,
173 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700174 break;
175 case NsdManager.REGISTER_SERVICE:
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700176 replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED,
177 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700178 break;
179 case NsdManager.UNREGISTER_SERVICE:
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700180 replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED,
181 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700182 break;
183 case NsdManager.RESOLVE_SERVICE:
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700184 replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED,
185 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700186 break;
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700187 case NsdManager.NATIVE_DAEMON_EVENT:
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700188 default:
189 Slog.e(TAG, "Unhandled " + msg);
190 return NOT_HANDLED;
191 }
192 return HANDLED;
193 }
194 }
195
196 class DisabledState extends State {
197 @Override
198 public void enter() {
199 sendNsdStateChangeBroadcast(false);
200 }
201
202 @Override
203 public boolean processMessage(Message msg) {
204 switch (msg.what) {
205 case NsdManager.ENABLE:
206 transitionTo(mEnabledState);
207 break;
208 default:
209 return NOT_HANDLED;
210 }
211 return HANDLED;
212 }
213 }
214
215 class EnabledState extends State {
216 @Override
217 public void enter() {
218 sendNsdStateChangeBroadcast(true);
219 if (mClients.size() > 0) {
220 startMDnsDaemon();
221 }
222 }
223
224 @Override
225 public void exit() {
226 if (mClients.size() > 0) {
227 stopMDnsDaemon();
228 }
229 }
230
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700231 private boolean requestLimitReached(ClientInfo clientInfo) {
232 if (clientInfo.mClientIds.size() >= ClientInfo.MAX_LIMIT) {
233 if (DBG) Slog.d(TAG, "Exceeded max outstanding requests " + clientInfo);
234 return true;
235 }
236 return false;
237 }
238
Dave Plattf31760c2014-03-07 14:48:22 -0800239 private void storeRequestMap(int clientId, int globalId, ClientInfo clientInfo, int what) {
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700240 clientInfo.mClientIds.put(clientId, globalId);
Dave Plattf31760c2014-03-07 14:48:22 -0800241 clientInfo.mClientRequests.put(clientId, what);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700242 mIdToClientInfoMap.put(globalId, clientInfo);
243 }
244
245 private void removeRequestMap(int clientId, int globalId, ClientInfo clientInfo) {
246 clientInfo.mClientIds.remove(clientId);
Dave Plattf31760c2014-03-07 14:48:22 -0800247 clientInfo.mClientRequests.remove(clientId);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700248 mIdToClientInfoMap.remove(globalId);
249 }
250
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700251 @Override
252 public boolean processMessage(Message msg) {
253 ClientInfo clientInfo;
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700254 NsdServiceInfo servInfo;
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700255 int id;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700256 switch (msg.what) {
Hugo Benichi23dba852017-04-05 14:43:29 +0900257 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700258 //First client
259 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL &&
260 mClients.size() == 0) {
261 startMDnsDaemon();
262 }
Hugo Benichi23dba852017-04-05 14:43:29 +0900263 return NOT_HANDLED;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700264 case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
Hugo Benichi23dba852017-04-05 14:43:29 +0900265 return NOT_HANDLED;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700266 case NsdManager.DISABLE:
267 //TODO: cleanup clients
268 transitionTo(mDisabledState);
269 break;
270 case NsdManager.DISCOVER_SERVICES:
271 if (DBG) Slog.d(TAG, "Discover services");
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700272 servInfo = (NsdServiceInfo) msg.obj;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700273 clientInfo = mClients.get(msg.replyTo);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700274
275 if (requestLimitReached(clientInfo)) {
276 replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED,
277 NsdManager.FAILURE_MAX_LIMIT);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700278 break;
279 }
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700280
281 id = getUniqueId();
282 if (discoverServices(id, servInfo.getServiceType())) {
283 if (DBG) {
284 Slog.d(TAG, "Discover " + msg.arg2 + " " + id +
285 servInfo.getServiceType());
286 }
Dave Plattf31760c2014-03-07 14:48:22 -0800287 storeRequestMap(msg.arg2, id, clientInfo, msg.what);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700288 replyToMessage(msg, NsdManager.DISCOVER_SERVICES_STARTED, servInfo);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700289 } else {
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700290 stopServiceDiscovery(id);
291 replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED,
292 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700293 }
294 break;
295 case NsdManager.STOP_DISCOVERY:
296 if (DBG) Slog.d(TAG, "Stop service discovery");
297 clientInfo = mClients.get(msg.replyTo);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700298
299 try {
300 id = clientInfo.mClientIds.get(msg.arg2).intValue();
301 } catch (NullPointerException e) {
302 replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED,
303 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700304 break;
305 }
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700306 removeRequestMap(msg.arg2, id, clientInfo);
307 if (stopServiceDiscovery(id)) {
308 replyToMessage(msg, NsdManager.STOP_DISCOVERY_SUCCEEDED);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700309 } else {
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700310 replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED,
311 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700312 }
313 break;
314 case NsdManager.REGISTER_SERVICE:
315 if (DBG) Slog.d(TAG, "Register service");
316 clientInfo = mClients.get(msg.replyTo);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700317 if (requestLimitReached(clientInfo)) {
318 replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED,
319 NsdManager.FAILURE_MAX_LIMIT);
320 break;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700321 }
322
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700323 id = getUniqueId();
324 if (registerService(id, (NsdServiceInfo) msg.obj)) {
325 if (DBG) Slog.d(TAG, "Register " + msg.arg2 + " " + id);
Dave Plattf31760c2014-03-07 14:48:22 -0800326 storeRequestMap(msg.arg2, id, clientInfo, msg.what);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700327 // Return success after mDns reports success
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700328 } else {
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700329 unregisterService(id);
330 replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED,
331 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700332 }
333 break;
334 case NsdManager.UNREGISTER_SERVICE:
335 if (DBG) Slog.d(TAG, "unregister service");
336 clientInfo = mClients.get(msg.replyTo);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700337 try {
338 id = clientInfo.mClientIds.get(msg.arg2).intValue();
339 } catch (NullPointerException e) {
340 replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED,
341 NsdManager.FAILURE_INTERNAL_ERROR);
342 break;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700343 }
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700344 removeRequestMap(msg.arg2, id, clientInfo);
345 if (unregisterService(id)) {
346 replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_SUCCEEDED);
347 } else {
348 replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED,
349 NsdManager.FAILURE_INTERNAL_ERROR);
350 }
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700351 break;
352 case NsdManager.RESOLVE_SERVICE:
353 if (DBG) Slog.d(TAG, "Resolve service");
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700354 servInfo = (NsdServiceInfo) msg.obj;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700355 clientInfo = mClients.get(msg.replyTo);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700356
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700357
358 if (clientInfo.mResolvedService != null) {
359 replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED,
360 NsdManager.FAILURE_ALREADY_ACTIVE);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700361 break;
362 }
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700363
364 id = getUniqueId();
365 if (resolveService(id, servInfo)) {
366 clientInfo.mResolvedService = new NsdServiceInfo();
Dave Plattf31760c2014-03-07 14:48:22 -0800367 storeRequestMap(msg.arg2, id, clientInfo, msg.what);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700368 } else {
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700369 replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED,
370 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700371 }
372 break;
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700373 case NsdManager.NATIVE_DAEMON_EVENT:
374 NativeEvent event = (NativeEvent) msg.obj;
Sreeram Ramachandranef128842014-09-03 15:45:59 -0700375 if (!handleNativeEvent(event.code, event.raw, event.cooked)) {
Hugo Benichi23dba852017-04-05 14:43:29 +0900376 return NOT_HANDLED;
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700377 }
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700378 break;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700379 default:
Hugo Benichi23dba852017-04-05 14:43:29 +0900380 return NOT_HANDLED;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700381 }
Hugo Benichi23dba852017-04-05 14:43:29 +0900382 return HANDLED;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700383 }
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700384
385 private boolean handleNativeEvent(int code, String raw, String[] cooked) {
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700386 NsdServiceInfo servInfo;
387 int id = Integer.parseInt(cooked[1]);
388 ClientInfo clientInfo = mIdToClientInfoMap.get(id);
389 if (clientInfo == null) {
Hugo Benichi2183ba92017-04-05 14:06:11 +0900390 String name = NativeResponseCode.nameOf(code);
391 Slog.e(TAG, String.format("id %d for %s has no client mapping", id, name));
Hugo Benichi23dba852017-04-05 14:43:29 +0900392 return false;
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700393 }
394
395 /* This goes in response as msg.arg2 */
Christopher Lane5a577902014-04-25 18:39:07 -0700396 int clientId = clientInfo.getClientId(id);
397 if (clientId < 0) {
Vinit Deshapnde8ed09e82013-06-25 19:45:03 -0700398 // This can happen because of race conditions. For example,
399 // SERVICE_FOUND may race with STOP_SERVICE_DISCOVERY,
400 // and we may get in this situation.
Hugo Benichi2183ba92017-04-05 14:06:11 +0900401 String name = NativeResponseCode.nameOf(code);
402 Slog.d(TAG, String.format(
403 "Notification %s for listener id %d that is no longer active",
404 name, id));
Hugo Benichi23dba852017-04-05 14:43:29 +0900405 return false;
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700406 }
Hugo Benichi2183ba92017-04-05 14:06:11 +0900407 if (DBG) {
408 String name = NativeResponseCode.nameOf(code);
409 Slog.d(TAG, String.format("Native daemon message %s: %s", name, raw));
410 }
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700411 switch (code) {
412 case NativeResponseCode.SERVICE_FOUND:
413 /* NNN uniqueId serviceName regType domain */
Christopher Laneb72d8b42014-03-17 16:35:45 -0700414 servInfo = new NsdServiceInfo(cooked[2], cooked[3]);
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700415 clientInfo.mChannel.sendMessage(NsdManager.SERVICE_FOUND, 0,
416 clientId, servInfo);
417 break;
418 case NativeResponseCode.SERVICE_LOST:
419 /* NNN uniqueId serviceName regType domain */
Christopher Laneb72d8b42014-03-17 16:35:45 -0700420 servInfo = new NsdServiceInfo(cooked[2], cooked[3]);
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700421 clientInfo.mChannel.sendMessage(NsdManager.SERVICE_LOST, 0,
422 clientId, servInfo);
423 break;
424 case NativeResponseCode.SERVICE_DISCOVERY_FAILED:
425 /* NNN uniqueId errorCode */
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700426 clientInfo.mChannel.sendMessage(NsdManager.DISCOVER_SERVICES_FAILED,
427 NsdManager.FAILURE_INTERNAL_ERROR, clientId);
428 break;
429 case NativeResponseCode.SERVICE_REGISTERED:
430 /* NNN regId serviceName regType */
Christopher Laneb72d8b42014-03-17 16:35:45 -0700431 servInfo = new NsdServiceInfo(cooked[2], null);
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700432 clientInfo.mChannel.sendMessage(NsdManager.REGISTER_SERVICE_SUCCEEDED,
433 id, clientId, servInfo);
434 break;
435 case NativeResponseCode.SERVICE_REGISTRATION_FAILED:
436 /* NNN regId errorCode */
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700437 clientInfo.mChannel.sendMessage(NsdManager.REGISTER_SERVICE_FAILED,
438 NsdManager.FAILURE_INTERNAL_ERROR, clientId);
439 break;
440 case NativeResponseCode.SERVICE_UPDATED:
441 /* NNN regId */
442 break;
443 case NativeResponseCode.SERVICE_UPDATE_FAILED:
444 /* NNN regId errorCode */
445 break;
446 case NativeResponseCode.SERVICE_RESOLVED:
447 /* NNN resolveId fullName hostName port txtlen txtdata */
Sreeram Ramachandranef128842014-09-03 15:45:59 -0700448 int index = 0;
449 while (index < cooked[2].length() && cooked[2].charAt(index) != '.') {
450 if (cooked[2].charAt(index) == '\\') {
451 ++index;
452 }
453 ++index;
454 }
455 if (index >= cooked[2].length()) {
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700456 Slog.e(TAG, "Invalid service found " + raw);
457 break;
458 }
459 String name = cooked[2].substring(0, index);
460 String rest = cooked[2].substring(index);
461 String type = rest.replace(".local.", "");
462
Sreeram Ramachandranef128842014-09-03 15:45:59 -0700463 name = unescape(name);
464
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700465 clientInfo.mResolvedService.setServiceName(name);
466 clientInfo.mResolvedService.setServiceType(type);
467 clientInfo.mResolvedService.setPort(Integer.parseInt(cooked[4]));
Philip P. Moltmann312c61e2016-03-16 10:15:39 -0700468 clientInfo.mResolvedService.setTxtRecords(cooked[6]);
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700469
470 stopResolveService(id);
Vinit Deshapnde40387242013-11-12 15:36:37 -0800471 removeRequestMap(clientId, id, clientInfo);
472
473 int id2 = getUniqueId();
474 if (getAddrInfo(id2, cooked[3])) {
Dave Plattf31760c2014-03-07 14:48:22 -0800475 storeRequestMap(clientId, id2, clientInfo, NsdManager.RESOLVE_SERVICE);
Vinit Deshapnde40387242013-11-12 15:36:37 -0800476 } else {
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700477 clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
478 NsdManager.FAILURE_INTERNAL_ERROR, clientId);
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700479 clientInfo.mResolvedService = null;
480 }
481 break;
482 case NativeResponseCode.SERVICE_RESOLUTION_FAILED:
483 /* NNN resolveId errorCode */
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700484 stopResolveService(id);
485 removeRequestMap(clientId, id, clientInfo);
486 clientInfo.mResolvedService = null;
487 clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
488 NsdManager.FAILURE_INTERNAL_ERROR, clientId);
489 break;
490 case NativeResponseCode.SERVICE_GET_ADDR_FAILED:
491 /* NNN resolveId errorCode */
492 stopGetAddrInfo(id);
493 removeRequestMap(clientId, id, clientInfo);
494 clientInfo.mResolvedService = null;
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700495 clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
496 NsdManager.FAILURE_INTERNAL_ERROR, clientId);
497 break;
498 case NativeResponseCode.SERVICE_GET_ADDR_SUCCESS:
499 /* NNN resolveId hostname ttl addr */
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700500 try {
501 clientInfo.mResolvedService.setHost(InetAddress.getByName(cooked[4]));
502 clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_SUCCEEDED,
503 0, clientId, clientInfo.mResolvedService);
504 } catch (java.net.UnknownHostException e) {
505 clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
506 NsdManager.FAILURE_INTERNAL_ERROR, clientId);
507 }
508 stopGetAddrInfo(id);
509 removeRequestMap(clientId, id, clientInfo);
510 clientInfo.mResolvedService = null;
511 break;
512 default:
Hugo Benichi23dba852017-04-05 14:43:29 +0900513 return false;
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700514 }
Hugo Benichi23dba852017-04-05 14:43:29 +0900515 return true;
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700516 }
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700517 }
518 }
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700519
Sreeram Ramachandranef128842014-09-03 15:45:59 -0700520 private String unescape(String s) {
521 StringBuilder sb = new StringBuilder(s.length());
522 for (int i = 0; i < s.length(); ++i) {
523 char c = s.charAt(i);
524 if (c == '\\') {
525 if (++i >= s.length()) {
526 Slog.e(TAG, "Unexpected end of escape sequence in: " + s);
527 break;
528 }
529 c = s.charAt(i);
530 if (c != '.' && c != '\\') {
531 if (i + 2 >= s.length()) {
532 Slog.e(TAG, "Unexpected end of escape sequence in: " + s);
533 break;
534 }
535 c = (char) ((c-'0') * 100 + (s.charAt(i+1)-'0') * 10 + (s.charAt(i+2)-'0'));
536 i += 2;
537 }
538 }
539 sb.append(c);
540 }
541 return sb.toString();
542 }
543
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700544 private NsdService(Context context) {
545 mContext = context;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700546 mContentResolver = context.getContentResolver();
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700547
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700548 mNativeConnector = new NativeDaemonConnector(new NativeCallbackReceiver(), "mdns", 10,
Dianne Hackborn77b987f2014-02-26 16:20:52 -0800549 MDNS_TAG, 25, null);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700550
551 mNsdStateMachine = new NsdStateMachine(TAG);
552 mNsdStateMachine.start();
553
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700554 Thread th = new Thread(mNativeConnector, MDNS_TAG);
555 th.start();
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700556 }
557
558 public static NsdService create(Context context) throws InterruptedException {
559 NsdService service = new NsdService(context);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700560 service.mNativeDaemonConnected.await();
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700561 return service;
562 }
563
564 public Messenger getMessenger() {
Irfan Sheriff92784672012-04-13 12:15:41 -0700565 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INTERNET,
566 "NsdService");
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700567 return new Messenger(mNsdStateMachine.getHandler());
568 }
569
570 public void setEnabled(boolean enable) {
571 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL,
572 "NsdService");
Jeff Sharkey625239a2012-09-26 22:03:49 -0700573 Settings.Global.putInt(mContentResolver, Settings.Global.NSD_ON, enable ? 1 : 0);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700574 if (enable) {
575 mNsdStateMachine.sendMessage(NsdManager.ENABLE);
576 } else {
577 mNsdStateMachine.sendMessage(NsdManager.DISABLE);
578 }
579 }
580
581 private void sendNsdStateChangeBroadcast(boolean enabled) {
Irfan Sheriff54ac7a52012-04-19 10:26:34 -0700582 final Intent intent = new Intent(NsdManager.ACTION_NSD_STATE_CHANGED);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700583 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
584 if (enabled) {
585 intent.putExtra(NsdManager.EXTRA_NSD_STATE, NsdManager.NSD_STATE_ENABLED);
586 } else {
587 intent.putExtra(NsdManager.EXTRA_NSD_STATE, NsdManager.NSD_STATE_DISABLED);
588 }
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700589 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700590 }
591
592 private boolean isNsdEnabled() {
Jeff Sharkey625239a2012-09-26 22:03:49 -0700593 boolean ret = Settings.Global.getInt(mContentResolver, Settings.Global.NSD_ON, 1) == 1;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700594 if (DBG) Slog.d(TAG, "Network service discovery enabled " + ret);
595 return ret;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700596 }
597
Irfan Sheriff817388e2012-04-11 14:52:19 -0700598 private int getUniqueId() {
599 if (++mUniqueId == INVALID_ID) return ++mUniqueId;
600 return mUniqueId;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700601 }
602
Sreeram Ramachandran03666c72014-07-19 23:21:46 -0700603 /* These should be in sync with system/netd/server/ResponseCode.h */
Hugo Benichi2183ba92017-04-05 14:06:11 +0900604 static final class NativeResponseCode {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700605 public static final int SERVICE_DISCOVERY_FAILED = 602;
606 public static final int SERVICE_FOUND = 603;
607 public static final int SERVICE_LOST = 604;
608
609 public static final int SERVICE_REGISTRATION_FAILED = 605;
610 public static final int SERVICE_REGISTERED = 606;
611
612 public static final int SERVICE_RESOLUTION_FAILED = 607;
613 public static final int SERVICE_RESOLVED = 608;
614
615 public static final int SERVICE_UPDATED = 609;
616 public static final int SERVICE_UPDATE_FAILED = 610;
617
618 public static final int SERVICE_GET_ADDR_FAILED = 611;
619 public static final int SERVICE_GET_ADDR_SUCCESS = 612;
Hugo Benichi2183ba92017-04-05 14:06:11 +0900620
621 private static final SparseArray<String> CODE_NAMES = new SparseArray<>();
622 static {
623 CODE_NAMES.put(SERVICE_DISCOVERY_FAILED, "SERVICE_DISCOVERY_FAILED");
624 CODE_NAMES.put(SERVICE_FOUND, "SERVICE_FOUND");
625 CODE_NAMES.put(SERVICE_LOST, "SERVICE_LOST");
626 CODE_NAMES.put(SERVICE_REGISTRATION_FAILED, "SERVICE_REGISTRATION_FAILED");
627 CODE_NAMES.put(SERVICE_REGISTERED, "SERVICE_REGISTERED");
628 CODE_NAMES.put(SERVICE_RESOLUTION_FAILED, "SERVICE_RESOLUTION_FAILED");
629 CODE_NAMES.put(SERVICE_RESOLVED, "SERVICE_RESOLVED");
630 CODE_NAMES.put(SERVICE_UPDATED, "SERVICE_UPDATED");
631 CODE_NAMES.put(SERVICE_UPDATE_FAILED, "SERVICE_UPDATE_FAILED");
632 CODE_NAMES.put(SERVICE_GET_ADDR_FAILED, "SERVICE_GET_ADDR_FAILED");
633 CODE_NAMES.put(SERVICE_GET_ADDR_SUCCESS, "SERVICE_GET_ADDR_SUCCESS");
634 }
635
636 static String nameOf(int code) {
637 String name = CODE_NAMES.get(code);
638 if (name == null) {
639 return Integer.toString(code);
640 }
641 return name;
642 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700643 }
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700644
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700645 private class NativeEvent {
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700646 final int code;
647 final String raw;
Sreeram Ramachandranef128842014-09-03 15:45:59 -0700648 final String[] cooked;
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700649
Sreeram Ramachandranef128842014-09-03 15:45:59 -0700650 NativeEvent(int code, String raw, String[] cooked) {
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700651 this.code = code;
652 this.raw = raw;
Sreeram Ramachandranef128842014-09-03 15:45:59 -0700653 this.cooked = cooked;
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700654 }
655 }
656
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700657 class NativeCallbackReceiver implements INativeDaemonConnectorCallbacks {
658 public void onDaemonConnected() {
659 mNativeDaemonConnected.countDown();
660 }
661
Dianne Hackborn77b987f2014-02-26 16:20:52 -0800662 public boolean onCheckHoldWakeLock(int code) {
663 return false;
664 }
665
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700666 public boolean onEvent(int code, String raw, String[] cooked) {
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700667 // TODO: NDC translates a message to a callback, we could enhance NDC to
668 // directly interact with a state machine through messages
Sreeram Ramachandranef128842014-09-03 15:45:59 -0700669 NativeEvent event = new NativeEvent(code, raw, cooked);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700670 mNsdStateMachine.sendMessage(NsdManager.NATIVE_DAEMON_EVENT, event);
671 return true;
672 }
673 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700674
Irfan Sheriff817388e2012-04-11 14:52:19 -0700675 private boolean startMDnsDaemon() {
676 if (DBG) Slog.d(TAG, "startMDnsDaemon");
677 try {
678 mNativeConnector.execute("mdnssd", "start-service");
679 } catch(NativeDaemonConnectorException e) {
680 Slog.e(TAG, "Failed to start daemon" + e);
681 return false;
682 }
683 return true;
684 }
685
686 private boolean stopMDnsDaemon() {
687 if (DBG) Slog.d(TAG, "stopMDnsDaemon");
688 try {
689 mNativeConnector.execute("mdnssd", "stop-service");
690 } catch(NativeDaemonConnectorException e) {
691 Slog.e(TAG, "Failed to start daemon" + e);
692 return false;
693 }
694 return true;
695 }
696
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700697 private boolean registerService(int regId, NsdServiceInfo service) {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700698 if (DBG) Slog.d(TAG, "registerService: " + regId + " " + service);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700699 try {
Christopher Laneb72d8b42014-03-17 16:35:45 -0700700 Command cmd = new Command("mdnssd", "register", regId, service.getServiceName(),
Philip P. Moltmann312c61e2016-03-16 10:15:39 -0700701 service.getServiceType(), service.getPort(),
702 Base64.encodeToString(service.getTxtRecord(), Base64.DEFAULT)
703 .replace("\n", ""));
Christopher Laneb72d8b42014-03-17 16:35:45 -0700704
705 mNativeConnector.execute(cmd);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700706 } catch(NativeDaemonConnectorException e) {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700707 Slog.e(TAG, "Failed to execute registerService " + e);
708 return false;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700709 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700710 return true;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700711 }
712
Irfan Sheriff817388e2012-04-11 14:52:19 -0700713 private boolean unregisterService(int regId) {
714 if (DBG) Slog.d(TAG, "unregisterService: " + regId);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700715 try {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700716 mNativeConnector.execute("mdnssd", "stop-register", regId);
717 } catch(NativeDaemonConnectorException e) {
718 Slog.e(TAG, "Failed to execute unregisterService " + e);
719 return false;
720 }
721 return true;
722 }
723
724 private boolean updateService(int regId, DnsSdTxtRecord t) {
725 if (DBG) Slog.d(TAG, "updateService: " + regId + " " + t);
726 try {
727 if (t == null) return false;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700728 mNativeConnector.execute("mdnssd", "update", regId, t.size(), t.getRawData());
729 } catch(NativeDaemonConnectorException e) {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700730 Slog.e(TAG, "Failed to updateServices " + e);
731 return false;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700732 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700733 return true;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700734 }
735
Irfan Sheriff817388e2012-04-11 14:52:19 -0700736 private boolean discoverServices(int discoveryId, String serviceType) {
737 if (DBG) Slog.d(TAG, "discoverServices: " + discoveryId + " " + serviceType);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700738 try {
739 mNativeConnector.execute("mdnssd", "discover", discoveryId, serviceType);
740 } catch(NativeDaemonConnectorException e) {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700741 Slog.e(TAG, "Failed to discoverServices " + e);
742 return false;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700743 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700744 return true;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700745 }
746
Irfan Sheriff817388e2012-04-11 14:52:19 -0700747 private boolean stopServiceDiscovery(int discoveryId) {
748 if (DBG) Slog.d(TAG, "stopServiceDiscovery: " + discoveryId);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700749 try {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700750 mNativeConnector.execute("mdnssd", "stop-discover", discoveryId);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700751 } catch(NativeDaemonConnectorException e) {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700752 Slog.e(TAG, "Failed to stopServiceDiscovery " + e);
753 return false;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700754 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700755 return true;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700756 }
757
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700758 private boolean resolveService(int resolveId, NsdServiceInfo service) {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700759 if (DBG) Slog.d(TAG, "resolveService: " + resolveId + " " + service);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700760 try {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700761 mNativeConnector.execute("mdnssd", "resolve", resolveId, service.getServiceName(),
762 service.getServiceType(), "local.");
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700763 } catch(NativeDaemonConnectorException e) {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700764 Slog.e(TAG, "Failed to resolveService " + e);
765 return false;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700766 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700767 return true;
768 }
769
770 private boolean stopResolveService(int resolveId) {
771 if (DBG) Slog.d(TAG, "stopResolveService: " + resolveId);
772 try {
773 mNativeConnector.execute("mdnssd", "stop-resolve", resolveId);
774 } catch(NativeDaemonConnectorException e) {
775 Slog.e(TAG, "Failed to stop resolve " + e);
776 return false;
777 }
778 return true;
779 }
780
781 private boolean getAddrInfo(int resolveId, String hostname) {
782 if (DBG) Slog.d(TAG, "getAdddrInfo: " + resolveId);
783 try {
784 mNativeConnector.execute("mdnssd", "getaddrinfo", resolveId, hostname);
785 } catch(NativeDaemonConnectorException e) {
786 Slog.e(TAG, "Failed to getAddrInfo " + e);
787 return false;
788 }
789 return true;
790 }
791
792 private boolean stopGetAddrInfo(int resolveId) {
793 if (DBG) Slog.d(TAG, "stopGetAdddrInfo: " + resolveId);
794 try {
795 mNativeConnector.execute("mdnssd", "stop-getaddrinfo", resolveId);
796 } catch(NativeDaemonConnectorException e) {
797 Slog.e(TAG, "Failed to stopGetAddrInfo " + e);
798 return false;
799 }
800 return true;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700801 }
802
803 @Override
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700804 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700805 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
806 != PackageManager.PERMISSION_GRANTED) {
807 pw.println("Permission Denial: can't dump ServiceDiscoverService from from pid="
808 + Binder.getCallingPid()
809 + ", uid=" + Binder.getCallingUid());
810 return;
811 }
812
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700813 for (ClientInfo client : mClients.values()) {
814 pw.println("Client Info");
815 pw.println(client);
816 }
817
818 mNsdStateMachine.dump(fd, pw, args);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700819 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700820
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700821 /* arg2 on the source message has an id that needs to be retained in replies
822 * see NsdManager for details */
823 private Message obtainMessage(Message srcMsg) {
824 Message msg = Message.obtain();
825 msg.arg2 = srcMsg.arg2;
826 return msg;
Irfan Sheriff817388e2012-04-11 14:52:19 -0700827 }
828
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700829 private void replyToMessage(Message msg, int what) {
830 if (msg.replyTo == null) return;
831 Message dstMsg = obtainMessage(msg);
832 dstMsg.what = what;
833 mReplyChannel.replyToMessage(msg, dstMsg);
Irfan Sheriff817388e2012-04-11 14:52:19 -0700834 }
835
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700836 private void replyToMessage(Message msg, int what, int arg1) {
837 if (msg.replyTo == null) return;
838 Message dstMsg = obtainMessage(msg);
839 dstMsg.what = what;
840 dstMsg.arg1 = arg1;
841 mReplyChannel.replyToMessage(msg, dstMsg);
842 }
843
844 private void replyToMessage(Message msg, int what, Object obj) {
845 if (msg.replyTo == null) return;
846 Message dstMsg = obtainMessage(msg);
847 dstMsg.what = what;
848 dstMsg.obj = obj;
849 mReplyChannel.replyToMessage(msg, dstMsg);
Irfan Sheriff817388e2012-04-11 14:52:19 -0700850 }
851
852 /* Information tracked per client */
853 private class ClientInfo {
854
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700855 private static final int MAX_LIMIT = 10;
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700856 private final AsyncChannel mChannel;
857 private final Messenger mMessenger;
Irfan Sheriff817388e2012-04-11 14:52:19 -0700858 /* Remembers a resolved service until getaddrinfo completes */
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700859 private NsdServiceInfo mResolvedService;
860
861 /* A map from client id to unique id sent to mDns */
Hugo Benichi2183ba92017-04-05 14:06:11 +0900862 private final SparseArray<Integer> mClientIds = new SparseArray<>();
Irfan Sheriff817388e2012-04-11 14:52:19 -0700863
Dave Plattf31760c2014-03-07 14:48:22 -0800864 /* A map from client id to the type of the request we had received */
Hugo Benichi2183ba92017-04-05 14:06:11 +0900865 private final SparseArray<Integer> mClientRequests = new SparseArray<>();
Dave Plattf31760c2014-03-07 14:48:22 -0800866
Irfan Sheriff817388e2012-04-11 14:52:19 -0700867 private ClientInfo(AsyncChannel c, Messenger m) {
868 mChannel = c;
869 mMessenger = m;
Irfan Sheriff817388e2012-04-11 14:52:19 -0700870 if (DBG) Slog.d(TAG, "New client, channel: " + c + " messenger: " + m);
871 }
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700872
873 @Override
874 public String toString() {
875 StringBuffer sb = new StringBuffer();
876 sb.append("mChannel ").append(mChannel).append("\n");
877 sb.append("mMessenger ").append(mMessenger).append("\n");
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700878 sb.append("mResolvedService ").append(mResolvedService).append("\n");
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700879 for(int i = 0; i< mClientIds.size(); i++) {
Dave Plattf31760c2014-03-07 14:48:22 -0800880 int clientID = mClientIds.keyAt(i);
881 sb.append("clientId ").append(clientID).
882 append(" mDnsId ").append(mClientIds.valueAt(i)).
883 append(" type ").append(mClientRequests.get(clientID)).append("\n");
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700884 }
885 return sb.toString();
886 }
Dave Plattf31760c2014-03-07 14:48:22 -0800887
888 // Remove any pending requests from the global map when we get rid of a client,
889 // and send cancellations to the daemon.
890 private void expungeAllRequests() {
891 int globalId, clientId, i;
892 for (i = 0; i < mClientIds.size(); i++) {
893 clientId = mClientIds.keyAt(i);
894 globalId = mClientIds.valueAt(i);
895 mIdToClientInfoMap.remove(globalId);
896 if (DBG) Slog.d(TAG, "Terminating client-ID " + clientId +
897 " global-ID " + globalId + " type " + mClientRequests.get(clientId));
898 switch (mClientRequests.get(clientId)) {
899 case NsdManager.DISCOVER_SERVICES:
900 stopServiceDiscovery(globalId);
901 break;
902 case NsdManager.RESOLVE_SERVICE:
903 stopResolveService(globalId);
904 break;
905 case NsdManager.REGISTER_SERVICE:
906 unregisterService(globalId);
907 break;
908 default:
909 break;
910 }
911 }
912 mClientIds.clear();
913 mClientRequests.clear();
914 }
915
Christopher Lane5a577902014-04-25 18:39:07 -0700916 // mClientIds is a sparse array of listener id -> mDnsClient id. For a given mDnsClient id,
917 // return the corresponding listener id. mDnsClient id is also called a global id.
918 private int getClientId(final int globalId) {
919 // This doesn't use mClientIds.indexOfValue because indexOfValue uses == (not .equals)
920 // while also coercing the int primitives to Integer objects.
921 for (int i = 0, nSize = mClientIds.size(); i < nSize; i++) {
922 int mDnsId = mClientIds.valueAt(i);
923 if (globalId == mDnsId) {
924 return mClientIds.keyAt(i);
925 }
926 }
927 return -1;
928 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700929 }
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700930}