blob: cc8e6a4b2d3b666cec810a09cf127bcf6c8f5e70 [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 Sheriff22af38c2012-05-03 16:44:27 -070023import android.net.nsd.NsdServiceInfo;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070024import android.net.nsd.DnsSdTxtRecord;
25import android.net.nsd.INsdManager;
26import android.net.nsd.NsdManager;
27import android.os.Binder;
28import android.os.Handler;
29import android.os.HandlerThread;
30import android.os.Message;
31import android.os.Messenger;
32import android.os.IBinder;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070033import android.provider.Settings;
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 Sheriff7d024d32012-03-22 17:01:39 -070040import java.util.ArrayList;
Irfan Sheriff817388e2012-04-11 14:52:19 -070041import java.util.HashMap;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070042import java.util.List;
Irfan Sheriff817388e2012-04-11 14:52:19 -070043import java.util.concurrent.CountDownLatch;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070044
45import com.android.internal.app.IBatteryStats;
46import com.android.internal.telephony.TelephonyIntents;
47import com.android.internal.util.AsyncChannel;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070048import com.android.internal.util.Protocol;
49import com.android.internal.util.State;
50import com.android.internal.util.StateMachine;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070051import com.android.server.am.BatteryStatsService;
52import com.android.server.NativeDaemonConnector.Command;
53import com.android.internal.R;
54
55/**
56 * Network Service Discovery Service handles remote service discovery operation requests by
57 * implementing the INsdManager interface.
58 *
59 * @hide
60 */
61public class NsdService extends INsdManager.Stub {
62 private static final String TAG = "NsdService";
63 private static final String MDNS_TAG = "mDnsConnector";
64
65 private static final boolean DBG = true;
66
67 private Context mContext;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070068 private ContentResolver mContentResolver;
69 private NsdStateMachine mNsdStateMachine;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070070
71 /**
72 * Clients receiving asynchronous messages
73 */
Irfan Sheriff817388e2012-04-11 14:52:19 -070074 private HashMap<Messenger, ClientInfo> mClients = new HashMap<Messenger, ClientInfo>();
Irfan Sheriff7d024d32012-03-22 17:01:39 -070075
Irfan Sheriff22af38c2012-05-03 16:44:27 -070076 /* A map from unique id to client info */
77 private SparseArray<ClientInfo> mIdToClientInfoMap= new SparseArray<ClientInfo>();
78
Irfan Sheriff7d024d32012-03-22 17:01:39 -070079 private AsyncChannel mReplyChannel = new AsyncChannel();
80
Irfan Sheriff817388e2012-04-11 14:52:19 -070081 private int INVALID_ID = 0;
82 private int mUniqueId = 1;
83
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070084 private static final int BASE = Protocol.BASE_NSD_MANAGER;
Irfan Sheriff22af38c2012-05-03 16:44:27 -070085 private static final int CMD_TO_STRING_COUNT = NsdManager.RESOLVE_SERVICE - BASE + 1;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070086 private static String[] sCmdToString = new String[CMD_TO_STRING_COUNT];
Irfan Sheriff7d024d32012-03-22 17:01:39 -070087
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070088 static {
89 sCmdToString[NsdManager.DISCOVER_SERVICES - BASE] = "DISCOVER";
90 sCmdToString[NsdManager.STOP_DISCOVERY - BASE] = "STOP-DISCOVER";
91 sCmdToString[NsdManager.REGISTER_SERVICE - BASE] = "REGISTER";
92 sCmdToString[NsdManager.UNREGISTER_SERVICE - BASE] = "UNREGISTER";
93 sCmdToString[NsdManager.RESOLVE_SERVICE - BASE] = "RESOLVE";
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070094 }
Irfan Sheriff7d024d32012-03-22 17:01:39 -070095
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070096 private static String cmdToString(int cmd) {
97 cmd -= BASE;
98 if ((cmd >= 0) && (cmd < sCmdToString.length)) {
99 return sCmdToString[cmd];
100 } else {
101 return null;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700102 }
103 }
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700104
105 private class NsdStateMachine extends StateMachine {
106
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700107 private final DefaultState mDefaultState = new DefaultState();
108 private final DisabledState mDisabledState = new DisabledState();
109 private final EnabledState mEnabledState = new EnabledState();
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700110
111 @Override
112 protected String getMessageInfo(Message msg) {
113 return cmdToString(msg.what);
114 }
115
116 NsdStateMachine(String name) {
117 super(name);
118 addState(mDefaultState);
119 addState(mDisabledState, mDefaultState);
120 addState(mEnabledState, mDefaultState);
121 if (isNsdEnabled()) {
122 setInitialState(mEnabledState);
123 } else {
124 setInitialState(mDisabledState);
125 }
126 setProcessedMessagesSize(25);
127 }
128
129 class DefaultState extends State {
130 @Override
131 public boolean processMessage(Message msg) {
132 switch (msg.what) {
133 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
134 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
135 AsyncChannel c = (AsyncChannel) msg.obj;
136 if (DBG) Slog.d(TAG, "New client listening to asynchronous messages");
137 c.sendMessage(AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED);
138 ClientInfo cInfo = new ClientInfo(c, msg.replyTo);
139 mClients.put(msg.replyTo, cInfo);
140 } else {
141 Slog.e(TAG, "Client connection failure, error=" + msg.arg1);
142 }
143 break;
144 case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
145 if (msg.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) {
146 Slog.e(TAG, "Send failed, client connection lost");
147 } else {
148 if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1);
149 }
150 mClients.remove(msg.replyTo);
151 break;
152 case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION:
153 AsyncChannel ac = new AsyncChannel();
154 ac.connect(mContext, getHandler(), msg.replyTo);
155 break;
156 case NsdManager.DISCOVER_SERVICES:
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700157 replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED,
158 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700159 break;
160 case NsdManager.STOP_DISCOVERY:
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700161 replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED,
162 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700163 break;
164 case NsdManager.REGISTER_SERVICE:
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700165 replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED,
166 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700167 break;
168 case NsdManager.UNREGISTER_SERVICE:
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700169 replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED,
170 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700171 break;
172 case NsdManager.RESOLVE_SERVICE:
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700173 replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED,
174 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700175 break;
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700176 case NsdManager.NATIVE_DAEMON_EVENT:
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700177 default:
178 Slog.e(TAG, "Unhandled " + msg);
179 return NOT_HANDLED;
180 }
181 return HANDLED;
182 }
183 }
184
185 class DisabledState extends State {
186 @Override
187 public void enter() {
188 sendNsdStateChangeBroadcast(false);
189 }
190
191 @Override
192 public boolean processMessage(Message msg) {
193 switch (msg.what) {
194 case NsdManager.ENABLE:
195 transitionTo(mEnabledState);
196 break;
197 default:
198 return NOT_HANDLED;
199 }
200 return HANDLED;
201 }
202 }
203
204 class EnabledState extends State {
205 @Override
206 public void enter() {
207 sendNsdStateChangeBroadcast(true);
208 if (mClients.size() > 0) {
209 startMDnsDaemon();
210 }
211 }
212
213 @Override
214 public void exit() {
215 if (mClients.size() > 0) {
216 stopMDnsDaemon();
217 }
218 }
219
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700220 private boolean requestLimitReached(ClientInfo clientInfo) {
221 if (clientInfo.mClientIds.size() >= ClientInfo.MAX_LIMIT) {
222 if (DBG) Slog.d(TAG, "Exceeded max outstanding requests " + clientInfo);
223 return true;
224 }
225 return false;
226 }
227
228 private void storeRequestMap(int clientId, int globalId, ClientInfo clientInfo) {
229 clientInfo.mClientIds.put(clientId, globalId);
230 mIdToClientInfoMap.put(globalId, clientInfo);
231 }
232
233 private void removeRequestMap(int clientId, int globalId, ClientInfo clientInfo) {
234 clientInfo.mClientIds.remove(clientId);
235 mIdToClientInfoMap.remove(globalId);
236 }
237
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700238 @Override
239 public boolean processMessage(Message msg) {
240 ClientInfo clientInfo;
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700241 NsdServiceInfo servInfo;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700242 boolean result = HANDLED;
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700243 int id;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700244 switch (msg.what) {
245 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
246 //First client
247 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL &&
248 mClients.size() == 0) {
249 startMDnsDaemon();
250 }
251 result = NOT_HANDLED;
252 break;
253 case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
254 //Last client
255 if (mClients.size() == 1) {
256 stopMDnsDaemon();
257 }
258 result = NOT_HANDLED;
259 break;
260 case NsdManager.DISABLE:
261 //TODO: cleanup clients
262 transitionTo(mDisabledState);
263 break;
264 case NsdManager.DISCOVER_SERVICES:
265 if (DBG) Slog.d(TAG, "Discover services");
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700266 servInfo = (NsdServiceInfo) msg.obj;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700267 clientInfo = mClients.get(msg.replyTo);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700268
269 if (requestLimitReached(clientInfo)) {
270 replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED,
271 NsdManager.FAILURE_MAX_LIMIT);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700272 break;
273 }
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700274
275 id = getUniqueId();
276 if (discoverServices(id, servInfo.getServiceType())) {
277 if (DBG) {
278 Slog.d(TAG, "Discover " + msg.arg2 + " " + id +
279 servInfo.getServiceType());
280 }
281 storeRequestMap(msg.arg2, id, clientInfo);
282 replyToMessage(msg, NsdManager.DISCOVER_SERVICES_STARTED, servInfo);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700283 } else {
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700284 stopServiceDiscovery(id);
285 replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED,
286 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700287 }
288 break;
289 case NsdManager.STOP_DISCOVERY:
290 if (DBG) Slog.d(TAG, "Stop service discovery");
291 clientInfo = mClients.get(msg.replyTo);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700292
293 try {
294 id = clientInfo.mClientIds.get(msg.arg2).intValue();
295 } catch (NullPointerException e) {
296 replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED,
297 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700298 break;
299 }
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700300 removeRequestMap(msg.arg2, id, clientInfo);
301 if (stopServiceDiscovery(id)) {
302 replyToMessage(msg, NsdManager.STOP_DISCOVERY_SUCCEEDED);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700303 } else {
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700304 replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED,
305 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700306 }
307 break;
308 case NsdManager.REGISTER_SERVICE:
309 if (DBG) Slog.d(TAG, "Register service");
310 clientInfo = mClients.get(msg.replyTo);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700311 if (requestLimitReached(clientInfo)) {
312 replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED,
313 NsdManager.FAILURE_MAX_LIMIT);
314 break;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700315 }
316
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700317 id = getUniqueId();
318 if (registerService(id, (NsdServiceInfo) msg.obj)) {
319 if (DBG) Slog.d(TAG, "Register " + msg.arg2 + " " + id);
320 storeRequestMap(msg.arg2, id, clientInfo);
321 // Return success after mDns reports success
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700322 } else {
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700323 unregisterService(id);
324 replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED,
325 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700326 }
327 break;
328 case NsdManager.UNREGISTER_SERVICE:
329 if (DBG) Slog.d(TAG, "unregister service");
330 clientInfo = mClients.get(msg.replyTo);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700331 try {
332 id = clientInfo.mClientIds.get(msg.arg2).intValue();
333 } catch (NullPointerException e) {
334 replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED,
335 NsdManager.FAILURE_INTERNAL_ERROR);
336 break;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700337 }
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700338 removeRequestMap(msg.arg2, id, clientInfo);
339 if (unregisterService(id)) {
340 replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_SUCCEEDED);
341 } else {
342 replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED,
343 NsdManager.FAILURE_INTERNAL_ERROR);
344 }
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700345 break;
346 case NsdManager.RESOLVE_SERVICE:
347 if (DBG) Slog.d(TAG, "Resolve service");
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700348 servInfo = (NsdServiceInfo) msg.obj;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700349 clientInfo = mClients.get(msg.replyTo);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700350
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700351
352 if (clientInfo.mResolvedService != null) {
353 replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED,
354 NsdManager.FAILURE_ALREADY_ACTIVE);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700355 break;
356 }
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700357
358 id = getUniqueId();
359 if (resolveService(id, servInfo)) {
360 clientInfo.mResolvedService = new NsdServiceInfo();
361 storeRequestMap(msg.arg2, id, clientInfo);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700362 } else {
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700363 replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED,
364 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700365 }
366 break;
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700367 case NsdManager.NATIVE_DAEMON_EVENT:
368 NativeEvent event = (NativeEvent) msg.obj;
369 handleNativeEvent(event.code, event.raw,
370 NativeDaemonEvent.unescapeArgs(event.raw));
371 break;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700372 default:
373 result = NOT_HANDLED;
374 break;
375 }
376 return result;
377 }
378 }
379 }
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700380
381 private NativeDaemonConnector mNativeConnector;
382 private final CountDownLatch mNativeDaemonConnected = new CountDownLatch(1);
383
384 private NsdService(Context context) {
385 mContext = context;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700386 mContentResolver = context.getContentResolver();
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700387
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700388 mNativeConnector = new NativeDaemonConnector(new NativeCallbackReceiver(), "mdns", 10,
389 MDNS_TAG, 25);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700390
391 mNsdStateMachine = new NsdStateMachine(TAG);
392 mNsdStateMachine.start();
393
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700394 Thread th = new Thread(mNativeConnector, MDNS_TAG);
395 th.start();
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700396 }
397
398 public static NsdService create(Context context) throws InterruptedException {
399 NsdService service = new NsdService(context);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700400 service.mNativeDaemonConnected.await();
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700401 return service;
402 }
403
404 public Messenger getMessenger() {
Irfan Sheriff92784672012-04-13 12:15:41 -0700405 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INTERNET,
406 "NsdService");
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700407 return new Messenger(mNsdStateMachine.getHandler());
408 }
409
410 public void setEnabled(boolean enable) {
411 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL,
412 "NsdService");
413 Settings.Secure.putInt(mContentResolver, Settings.Secure.NSD_ON, enable ? 1 : 0);
414 if (enable) {
415 mNsdStateMachine.sendMessage(NsdManager.ENABLE);
416 } else {
417 mNsdStateMachine.sendMessage(NsdManager.DISABLE);
418 }
419 }
420
421 private void sendNsdStateChangeBroadcast(boolean enabled) {
Irfan Sheriff54ac7a52012-04-19 10:26:34 -0700422 final Intent intent = new Intent(NsdManager.ACTION_NSD_STATE_CHANGED);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700423 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
424 if (enabled) {
425 intent.putExtra(NsdManager.EXTRA_NSD_STATE, NsdManager.NSD_STATE_ENABLED);
426 } else {
427 intent.putExtra(NsdManager.EXTRA_NSD_STATE, NsdManager.NSD_STATE_DISABLED);
428 }
429 mContext.sendStickyBroadcast(intent);
430 }
431
432 private boolean isNsdEnabled() {
433 boolean ret = Settings.Secure.getInt(mContentResolver, Settings.Secure.NSD_ON, 1) == 1;
434 if (DBG) Slog.d(TAG, "Network service discovery enabled " + ret);
435 return ret;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700436 }
437
Irfan Sheriff817388e2012-04-11 14:52:19 -0700438 private int getUniqueId() {
439 if (++mUniqueId == INVALID_ID) return ++mUniqueId;
440 return mUniqueId;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700441 }
442
Irfan Sheriff817388e2012-04-11 14:52:19 -0700443 /* These should be in sync with system/netd/mDnsResponseCode.h */
444 class NativeResponseCode {
445 public static final int SERVICE_DISCOVERY_FAILED = 602;
446 public static final int SERVICE_FOUND = 603;
447 public static final int SERVICE_LOST = 604;
448
449 public static final int SERVICE_REGISTRATION_FAILED = 605;
450 public static final int SERVICE_REGISTERED = 606;
451
452 public static final int SERVICE_RESOLUTION_FAILED = 607;
453 public static final int SERVICE_RESOLVED = 608;
454
455 public static final int SERVICE_UPDATED = 609;
456 public static final int SERVICE_UPDATE_FAILED = 610;
457
458 public static final int SERVICE_GET_ADDR_FAILED = 611;
459 public static final int SERVICE_GET_ADDR_SUCCESS = 612;
460 }
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700461
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700462 private class NativeEvent {
463 int code;
464 String raw;
465
466 NativeEvent(int code, String raw) {
467 this.code = code;
468 this.raw = raw;
469 }
470 }
471
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700472 class NativeCallbackReceiver implements INativeDaemonConnectorCallbacks {
473 public void onDaemonConnected() {
474 mNativeDaemonConnected.countDown();
475 }
476
477 public boolean onEvent(int code, String raw, String[] cooked) {
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700478 // TODO: NDC translates a message to a callback, we could enhance NDC to
479 // directly interact with a state machine through messages
480 NativeEvent event = new NativeEvent(code, raw);
481 mNsdStateMachine.sendMessage(NsdManager.NATIVE_DAEMON_EVENT, event);
482 return true;
483 }
484 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700485
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700486 private void handleNativeEvent(int code, String raw, String[] cooked) {
487 NsdServiceInfo servInfo;
488 int id = Integer.parseInt(cooked[1]);
489 ClientInfo clientInfo = mIdToClientInfoMap.get(id);
490 if (clientInfo == null) {
491 Slog.e(TAG, "Unique id with no client mapping: " + id);
492 return;
493 }
494
495 /* This goes in response as msg.arg2 */
496 int clientId = -1;
497 int keyId = clientInfo.mClientIds.indexOfValue(id);
498 if (keyId != -1) {
499 clientId = clientInfo.mClientIds.keyAt(keyId);
500 }
501 switch (code) {
502 case NativeResponseCode.SERVICE_FOUND:
503 /* NNN uniqueId serviceName regType domain */
504 if (DBG) Slog.d(TAG, "SERVICE_FOUND Raw: " + raw);
505 servInfo = new NsdServiceInfo(cooked[2], cooked[3], null);
506 clientInfo.mChannel.sendMessage(NsdManager.SERVICE_FOUND, 0,
507 clientId, servInfo);
508 break;
509 case NativeResponseCode.SERVICE_LOST:
510 /* NNN uniqueId serviceName regType domain */
511 if (DBG) Slog.d(TAG, "SERVICE_LOST Raw: " + raw);
512 servInfo = new NsdServiceInfo(cooked[2], cooked[3], null);
513 clientInfo.mChannel.sendMessage(NsdManager.SERVICE_LOST, 0,
514 clientId, servInfo);
515 break;
516 case NativeResponseCode.SERVICE_DISCOVERY_FAILED:
517 /* NNN uniqueId errorCode */
518 if (DBG) Slog.d(TAG, "SERVICE_DISC_FAILED Raw: " + raw);
519 clientInfo.mChannel.sendMessage(NsdManager.DISCOVER_SERVICES_FAILED,
520 NsdManager.FAILURE_INTERNAL_ERROR, clientId);
521 break;
522 case NativeResponseCode.SERVICE_REGISTERED:
523 /* NNN regId serviceName regType */
524 if (DBG) Slog.d(TAG, "SERVICE_REGISTERED Raw: " + raw);
525 servInfo = new NsdServiceInfo(cooked[2], null, null);
526 clientInfo.mChannel.sendMessage(NsdManager.REGISTER_SERVICE_SUCCEEDED,
527 id, clientId, servInfo);
528 break;
529 case NativeResponseCode.SERVICE_REGISTRATION_FAILED:
530 /* NNN regId errorCode */
531 if (DBG) Slog.d(TAG, "SERVICE_REGISTER_FAILED Raw: " + raw);
532 clientInfo.mChannel.sendMessage(NsdManager.REGISTER_SERVICE_FAILED,
533 NsdManager.FAILURE_INTERNAL_ERROR, clientId);
534 break;
535 case NativeResponseCode.SERVICE_UPDATED:
536 /* NNN regId */
537 break;
538 case NativeResponseCode.SERVICE_UPDATE_FAILED:
539 /* NNN regId errorCode */
540 break;
541 case NativeResponseCode.SERVICE_RESOLVED:
542 /* NNN resolveId fullName hostName port txtlen txtdata */
543 if (DBG) Slog.d(TAG, "SERVICE_RESOLVED Raw: " + raw);
544 int index = cooked[2].indexOf(".");
545 if (index == -1) {
546 Slog.e(TAG, "Invalid service found " + raw);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700547 break;
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700548 }
549 String name = cooked[2].substring(0, index);
550 String rest = cooked[2].substring(index);
551 String type = rest.replace(".local.", "");
Irfan Sheriff817388e2012-04-11 14:52:19 -0700552
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700553 clientInfo.mResolvedService.setServiceName(name);
554 clientInfo.mResolvedService.setServiceType(type);
555 clientInfo.mResolvedService.setPort(Integer.parseInt(cooked[4]));
Irfan Sheriff817388e2012-04-11 14:52:19 -0700556
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700557 stopResolveService(id);
558 if (!getAddrInfo(id, cooked[3])) {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700559 clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700560 NsdManager.FAILURE_INTERNAL_ERROR, clientId);
561 mIdToClientInfoMap.remove(id);
562 clientInfo.mResolvedService = null;
563 }
564 break;
565 case NativeResponseCode.SERVICE_RESOLUTION_FAILED:
566 /* NNN resolveId errorCode */
567 if (DBG) Slog.d(TAG, "SERVICE_RESOLVE_FAILED Raw: " + raw);
568 stopResolveService(id);
569 mIdToClientInfoMap.remove(id);
570 clientInfo.mResolvedService = null;
571 clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
572 NsdManager.FAILURE_INTERNAL_ERROR, clientId);
573 break;
574 case NativeResponseCode.SERVICE_GET_ADDR_FAILED:
575 /* NNN resolveId errorCode */
576 stopGetAddrInfo(id);
577 mIdToClientInfoMap.remove(id);
578 clientInfo.mResolvedService = null;
579 if (DBG) Slog.d(TAG, "SERVICE_RESOLVE_FAILED Raw: " + raw);
580 clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
581 NsdManager.FAILURE_INTERNAL_ERROR, clientId);
582 break;
583 case NativeResponseCode.SERVICE_GET_ADDR_SUCCESS:
584 /* NNN resolveId hostname ttl addr */
585 if (DBG) Slog.d(TAG, "SERVICE_GET_ADDR_SUCCESS Raw: " + raw);
586 try {
587 clientInfo.mResolvedService.setHost(InetAddress.getByName(cooked[4]));
588 clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_SUCCEEDED,
589 0, clientId, clientInfo.mResolvedService);
590 } catch (java.net.UnknownHostException e) {
591 clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
592 NsdManager.FAILURE_INTERNAL_ERROR, clientId);
593 }
594 stopGetAddrInfo(id);
595 mIdToClientInfoMap.remove(id);
596 clientInfo.mResolvedService = null;
597 break;
598 default:
599 break;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700600 }
601 }
602
Irfan Sheriff817388e2012-04-11 14:52:19 -0700603 private boolean startMDnsDaemon() {
604 if (DBG) Slog.d(TAG, "startMDnsDaemon");
605 try {
606 mNativeConnector.execute("mdnssd", "start-service");
607 } catch(NativeDaemonConnectorException e) {
608 Slog.e(TAG, "Failed to start daemon" + e);
609 return false;
610 }
611 return true;
612 }
613
614 private boolean stopMDnsDaemon() {
615 if (DBG) Slog.d(TAG, "stopMDnsDaemon");
616 try {
617 mNativeConnector.execute("mdnssd", "stop-service");
618 } catch(NativeDaemonConnectorException e) {
619 Slog.e(TAG, "Failed to start daemon" + e);
620 return false;
621 }
622 return true;
623 }
624
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700625 private boolean registerService(int regId, NsdServiceInfo service) {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700626 if (DBG) Slog.d(TAG, "registerService: " + regId + " " + service);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700627 try {
628 //Add txtlen and txtdata
629 mNativeConnector.execute("mdnssd", "register", regId, service.getServiceName(),
630 service.getServiceType(), service.getPort());
631 } catch(NativeDaemonConnectorException e) {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700632 Slog.e(TAG, "Failed to execute registerService " + e);
633 return false;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700634 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700635 return true;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700636 }
637
Irfan Sheriff817388e2012-04-11 14:52:19 -0700638 private boolean unregisterService(int regId) {
639 if (DBG) Slog.d(TAG, "unregisterService: " + regId);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700640 try {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700641 mNativeConnector.execute("mdnssd", "stop-register", regId);
642 } catch(NativeDaemonConnectorException e) {
643 Slog.e(TAG, "Failed to execute unregisterService " + e);
644 return false;
645 }
646 return true;
647 }
648
649 private boolean updateService(int regId, DnsSdTxtRecord t) {
650 if (DBG) Slog.d(TAG, "updateService: " + regId + " " + t);
651 try {
652 if (t == null) return false;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700653 mNativeConnector.execute("mdnssd", "update", regId, t.size(), t.getRawData());
654 } catch(NativeDaemonConnectorException e) {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700655 Slog.e(TAG, "Failed to updateServices " + e);
656 return false;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700657 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700658 return true;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700659 }
660
Irfan Sheriff817388e2012-04-11 14:52:19 -0700661 private boolean discoverServices(int discoveryId, String serviceType) {
662 if (DBG) Slog.d(TAG, "discoverServices: " + discoveryId + " " + serviceType);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700663 try {
664 mNativeConnector.execute("mdnssd", "discover", discoveryId, serviceType);
665 } catch(NativeDaemonConnectorException e) {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700666 Slog.e(TAG, "Failed to discoverServices " + e);
667 return false;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700668 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700669 return true;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700670 }
671
Irfan Sheriff817388e2012-04-11 14:52:19 -0700672 private boolean stopServiceDiscovery(int discoveryId) {
673 if (DBG) Slog.d(TAG, "stopServiceDiscovery: " + discoveryId);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700674 try {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700675 mNativeConnector.execute("mdnssd", "stop-discover", discoveryId);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700676 } catch(NativeDaemonConnectorException e) {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700677 Slog.e(TAG, "Failed to stopServiceDiscovery " + e);
678 return false;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700679 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700680 return true;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700681 }
682
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700683 private boolean resolveService(int resolveId, NsdServiceInfo service) {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700684 if (DBG) Slog.d(TAG, "resolveService: " + resolveId + " " + service);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700685 try {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700686 mNativeConnector.execute("mdnssd", "resolve", resolveId, service.getServiceName(),
687 service.getServiceType(), "local.");
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700688 } catch(NativeDaemonConnectorException e) {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700689 Slog.e(TAG, "Failed to resolveService " + e);
690 return false;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700691 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700692 return true;
693 }
694
695 private boolean stopResolveService(int resolveId) {
696 if (DBG) Slog.d(TAG, "stopResolveService: " + resolveId);
697 try {
698 mNativeConnector.execute("mdnssd", "stop-resolve", resolveId);
699 } catch(NativeDaemonConnectorException e) {
700 Slog.e(TAG, "Failed to stop resolve " + e);
701 return false;
702 }
703 return true;
704 }
705
706 private boolean getAddrInfo(int resolveId, String hostname) {
707 if (DBG) Slog.d(TAG, "getAdddrInfo: " + resolveId);
708 try {
709 mNativeConnector.execute("mdnssd", "getaddrinfo", resolveId, hostname);
710 } catch(NativeDaemonConnectorException e) {
711 Slog.e(TAG, "Failed to getAddrInfo " + e);
712 return false;
713 }
714 return true;
715 }
716
717 private boolean stopGetAddrInfo(int resolveId) {
718 if (DBG) Slog.d(TAG, "stopGetAdddrInfo: " + resolveId);
719 try {
720 mNativeConnector.execute("mdnssd", "stop-getaddrinfo", resolveId);
721 } catch(NativeDaemonConnectorException e) {
722 Slog.e(TAG, "Failed to stopGetAddrInfo " + e);
723 return false;
724 }
725 return true;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700726 }
727
728 @Override
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700729 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700730 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
731 != PackageManager.PERMISSION_GRANTED) {
732 pw.println("Permission Denial: can't dump ServiceDiscoverService from from pid="
733 + Binder.getCallingPid()
734 + ", uid=" + Binder.getCallingUid());
735 return;
736 }
737
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700738 for (ClientInfo client : mClients.values()) {
739 pw.println("Client Info");
740 pw.println(client);
741 }
742
743 mNsdStateMachine.dump(fd, pw, args);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700744 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700745
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700746 /* arg2 on the source message has an id that needs to be retained in replies
747 * see NsdManager for details */
748 private Message obtainMessage(Message srcMsg) {
749 Message msg = Message.obtain();
750 msg.arg2 = srcMsg.arg2;
751 return msg;
Irfan Sheriff817388e2012-04-11 14:52:19 -0700752 }
753
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700754 private void replyToMessage(Message msg, int what) {
755 if (msg.replyTo == null) return;
756 Message dstMsg = obtainMessage(msg);
757 dstMsg.what = what;
758 mReplyChannel.replyToMessage(msg, dstMsg);
Irfan Sheriff817388e2012-04-11 14:52:19 -0700759 }
760
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700761 private void replyToMessage(Message msg, int what, int arg1) {
762 if (msg.replyTo == null) return;
763 Message dstMsg = obtainMessage(msg);
764 dstMsg.what = what;
765 dstMsg.arg1 = arg1;
766 mReplyChannel.replyToMessage(msg, dstMsg);
767 }
768
769 private void replyToMessage(Message msg, int what, Object obj) {
770 if (msg.replyTo == null) return;
771 Message dstMsg = obtainMessage(msg);
772 dstMsg.what = what;
773 dstMsg.obj = obj;
774 mReplyChannel.replyToMessage(msg, dstMsg);
Irfan Sheriff817388e2012-04-11 14:52:19 -0700775 }
776
777 /* Information tracked per client */
778 private class ClientInfo {
779
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700780 private static final int MAX_LIMIT = 10;
Irfan Sheriff817388e2012-04-11 14:52:19 -0700781 private AsyncChannel mChannel;
782 private Messenger mMessenger;
Irfan Sheriff817388e2012-04-11 14:52:19 -0700783 /* Remembers a resolved service until getaddrinfo completes */
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700784 private NsdServiceInfo mResolvedService;
785
786 /* A map from client id to unique id sent to mDns */
787 private SparseArray<Integer> mClientIds = new SparseArray<Integer>();
Irfan Sheriff817388e2012-04-11 14:52:19 -0700788
789 private ClientInfo(AsyncChannel c, Messenger m) {
790 mChannel = c;
791 mMessenger = m;
Irfan Sheriff817388e2012-04-11 14:52:19 -0700792 if (DBG) Slog.d(TAG, "New client, channel: " + c + " messenger: " + m);
793 }
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700794
795 @Override
796 public String toString() {
797 StringBuffer sb = new StringBuffer();
798 sb.append("mChannel ").append(mChannel).append("\n");
799 sb.append("mMessenger ").append(mMessenger).append("\n");
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700800 sb.append("mResolvedService ").append(mResolvedService).append("\n");
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700801 for(int i = 0; i< mClientIds.size(); i++) {
802 sb.append("clientId ").append(mClientIds.keyAt(i));
803 sb.append(" mDnsId ").append(mClientIds.valueAt(i)).append("\n");
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700804 }
805 return sb.toString();
806 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700807 }
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700808}