blob: f33bf8b24e631599a21d7b6f14ca41479db144ef [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;
23import android.net.nsd.DnsSdServiceInfo;
24import 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;
35
36import java.io.FileDescriptor;
37import java.io.PrintWriter;
Irfan Sheriff817388e2012-04-11 14:52:19 -070038import java.net.InetAddress;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070039import java.util.ArrayList;
Irfan Sheriff817388e2012-04-11 14:52:19 -070040import java.util.HashMap;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070041import java.util.List;
Irfan Sheriff817388e2012-04-11 14:52:19 -070042import java.util.concurrent.CountDownLatch;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070043
44import com.android.internal.app.IBatteryStats;
45import com.android.internal.telephony.TelephonyIntents;
46import 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;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070050import com.android.server.am.BatteryStatsService;
51import com.android.server.NativeDaemonConnector.Command;
52import com.android.internal.R;
53
54/**
55 * Network Service Discovery Service handles remote service discovery operation requests by
56 * implementing the INsdManager interface.
57 *
58 * @hide
59 */
60public class NsdService extends INsdManager.Stub {
61 private static final String TAG = "NsdService";
62 private static final String MDNS_TAG = "mDnsConnector";
63
64 private static final boolean DBG = true;
65
66 private Context mContext;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070067 private ContentResolver mContentResolver;
68 private NsdStateMachine mNsdStateMachine;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070069
70 /**
71 * Clients receiving asynchronous messages
72 */
Irfan Sheriff817388e2012-04-11 14:52:19 -070073 private HashMap<Messenger, ClientInfo> mClients = new HashMap<Messenger, ClientInfo>();
Irfan Sheriff7d024d32012-03-22 17:01:39 -070074
75 private AsyncChannel mReplyChannel = new AsyncChannel();
76
Irfan Sheriff817388e2012-04-11 14:52:19 -070077 private int INVALID_ID = 0;
78 private int mUniqueId = 1;
79
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070080 private static final int BASE = Protocol.BASE_NSD_MANAGER;
81 private static final int CMD_TO_STRING_COUNT = NsdManager.STOP_RESOLVE - BASE + 1;
82 private static String[] sCmdToString = new String[CMD_TO_STRING_COUNT];
Irfan Sheriff7d024d32012-03-22 17:01:39 -070083
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070084 static {
85 sCmdToString[NsdManager.DISCOVER_SERVICES - BASE] = "DISCOVER";
86 sCmdToString[NsdManager.STOP_DISCOVERY - BASE] = "STOP-DISCOVER";
87 sCmdToString[NsdManager.REGISTER_SERVICE - BASE] = "REGISTER";
88 sCmdToString[NsdManager.UNREGISTER_SERVICE - BASE] = "UNREGISTER";
89 sCmdToString[NsdManager.RESOLVE_SERVICE - BASE] = "RESOLVE";
90 sCmdToString[NsdManager.STOP_RESOLVE - BASE] = "STOP-RESOLVE";
91 }
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
104 private DefaultState mDefaultState = new DefaultState();
105 private DisabledState mDisabledState = new DisabledState();
106 private EnabledState mEnabledState = new EnabledState();
107
108 @Override
109 protected String getMessageInfo(Message msg) {
110 return cmdToString(msg.what);
111 }
112
113 NsdStateMachine(String name) {
114 super(name);
115 addState(mDefaultState);
116 addState(mDisabledState, mDefaultState);
117 addState(mEnabledState, mDefaultState);
118 if (isNsdEnabled()) {
119 setInitialState(mEnabledState);
120 } else {
121 setInitialState(mDisabledState);
122 }
123 setProcessedMessagesSize(25);
124 }
125
126 class DefaultState extends State {
127 @Override
128 public boolean processMessage(Message msg) {
129 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);
135 ClientInfo cInfo = new ClientInfo(c, msg.replyTo);
136 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:
142 if (msg.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) {
143 Slog.e(TAG, "Send failed, client connection lost");
144 } else {
145 if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1);
146 }
147 mClients.remove(msg.replyTo);
148 break;
149 case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION:
150 AsyncChannel ac = new AsyncChannel();
151 ac.connect(mContext, getHandler(), msg.replyTo);
152 break;
153 case NsdManager.DISCOVER_SERVICES:
154 mReplyChannel.replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED,
155 NsdManager.BUSY);
156 break;
157 case NsdManager.STOP_DISCOVERY:
158 mReplyChannel.replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED,
159 NsdManager.ERROR);
160 break;
161 case NsdManager.REGISTER_SERVICE:
162 mReplyChannel.replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED,
163 NsdManager.ERROR);
164 break;
165 case NsdManager.UNREGISTER_SERVICE:
166 mReplyChannel.replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED,
167 NsdManager.ERROR);
168 break;
169 case NsdManager.RESOLVE_SERVICE:
170 mReplyChannel.replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED,
171 NsdManager.ERROR);
172 break;
173 case NsdManager.STOP_RESOLVE:
174 mReplyChannel.replyToMessage(msg, NsdManager.STOP_RESOLVE_FAILED,
175 NsdManager.ERROR);
176 break;
177 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
220 @Override
221 public boolean processMessage(Message msg) {
222 ClientInfo clientInfo;
223 DnsSdServiceInfo servInfo;
224 boolean result = HANDLED;
225 switch (msg.what) {
226 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
227 //First client
228 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL &&
229 mClients.size() == 0) {
230 startMDnsDaemon();
231 }
232 result = NOT_HANDLED;
233 break;
234 case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
235 //Last client
236 if (mClients.size() == 1) {
237 stopMDnsDaemon();
238 }
239 result = NOT_HANDLED;
240 break;
241 case NsdManager.DISABLE:
242 //TODO: cleanup clients
243 transitionTo(mDisabledState);
244 break;
245 case NsdManager.DISCOVER_SERVICES:
246 if (DBG) Slog.d(TAG, "Discover services");
247 servInfo = (DnsSdServiceInfo) msg.obj;
248 clientInfo = mClients.get(msg.replyTo);
249 if (clientInfo.mDiscoveryId != INVALID_ID) {
250 //discovery already in progress
251 if (DBG) Slog.d(TAG, "discovery in progress");
252 mReplyChannel.replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED,
253 NsdManager.ALREADY_ACTIVE);
254 break;
255 }
256 clientInfo.mDiscoveryId = getUniqueId();
257 if (discoverServices(clientInfo.mDiscoveryId, servInfo.getServiceType())) {
258 mReplyChannel.replyToMessage(msg, NsdManager.DISCOVER_SERVICES_STARTED);
259 } else {
260 mReplyChannel.replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED,
261 NsdManager.ERROR);
262 clientInfo.mDiscoveryId = INVALID_ID;
263 }
264 break;
265 case NsdManager.STOP_DISCOVERY:
266 if (DBG) Slog.d(TAG, "Stop service discovery");
267 clientInfo = mClients.get(msg.replyTo);
268 if (clientInfo.mDiscoveryId == INVALID_ID) {
269 //already stopped
270 if (DBG) Slog.d(TAG, "discovery already stopped");
271 mReplyChannel.replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED,
272 NsdManager.ALREADY_ACTIVE);
273 break;
274 }
275 if (stopServiceDiscovery(clientInfo.mDiscoveryId)) {
276 clientInfo.mDiscoveryId = INVALID_ID;
277 mReplyChannel.replyToMessage(msg, NsdManager.STOP_DISCOVERY_SUCCEEDED);
278 } else {
279 mReplyChannel.replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED,
280 NsdManager.ERROR);
281 }
282 break;
283 case NsdManager.REGISTER_SERVICE:
284 if (DBG) Slog.d(TAG, "Register service");
285 clientInfo = mClients.get(msg.replyTo);
286 if (clientInfo.mRegisteredIds.size() >= ClientInfo.MAX_REG) {
287 if (DBG) Slog.d(TAG, "register service exceeds limit");
288 mReplyChannel.replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED,
289 NsdManager.MAX_REGS_REACHED);
290 }
291
292 int id = getUniqueId();
293 if (registerService(id, (DnsSdServiceInfo) msg.obj)) {
294 clientInfo.mRegisteredIds.add(id);
295 } else {
296 mReplyChannel.replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED,
297 NsdManager.ERROR);
298 }
299 break;
300 case NsdManager.UNREGISTER_SERVICE:
301 if (DBG) Slog.d(TAG, "unregister service");
302 clientInfo = mClients.get(msg.replyTo);
303 int regId = msg.arg1;
304 if (clientInfo.mRegisteredIds.remove(new Integer(regId)) &&
305 unregisterService(regId)) {
306 mReplyChannel.replyToMessage(msg,
307 NsdManager.UNREGISTER_SERVICE_SUCCEEDED);
308 } else {
309 mReplyChannel.replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED,
310 NsdManager.ERROR);
311 }
312 break;
313 case NsdManager.UPDATE_SERVICE:
314 if (DBG) Slog.d(TAG, "Update service");
315 //TODO: implement
316 mReplyChannel.replyToMessage(msg, NsdManager.UPDATE_SERVICE_FAILED);
317 break;
318 case NsdManager.RESOLVE_SERVICE:
319 if (DBG) Slog.d(TAG, "Resolve service");
320 servInfo = (DnsSdServiceInfo) msg.obj;
321 clientInfo = mClients.get(msg.replyTo);
322 if (clientInfo.mResolveId != INVALID_ID) {
323 //first cancel existing resolve
324 stopResolveService(clientInfo.mResolveId);
325 }
326
327 clientInfo.mResolveId = getUniqueId();
328 if (!resolveService(clientInfo.mResolveId, servInfo)) {
329 mReplyChannel.replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED,
330 NsdManager.ERROR);
331 clientInfo.mResolveId = INVALID_ID;
332 }
333 break;
334 case NsdManager.STOP_RESOLVE:
335 if (DBG) Slog.d(TAG, "Stop resolve");
336 clientInfo = mClients.get(msg.replyTo);
337 if (clientInfo.mResolveId == INVALID_ID) {
338 //already stopped
339 if (DBG) Slog.d(TAG, "resolve already stopped");
340 mReplyChannel.replyToMessage(msg, NsdManager.STOP_RESOLVE_FAILED,
341 NsdManager.ALREADY_ACTIVE);
342 break;
343 }
344 if (stopResolveService(clientInfo.mResolveId)) {
345 clientInfo.mResolveId = INVALID_ID;
346 mReplyChannel.replyToMessage(msg, NsdManager.STOP_RESOLVE_SUCCEEDED);
347 } else {
348 mReplyChannel.replyToMessage(msg, NsdManager.STOP_RESOLVE_FAILED,
349 NsdManager.ERROR);
350 }
351 break;
352 default:
353 result = NOT_HANDLED;
354 break;
355 }
356 return result;
357 }
358 }
359 }
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700360
361 private NativeDaemonConnector mNativeConnector;
362 private final CountDownLatch mNativeDaemonConnected = new CountDownLatch(1);
363
364 private NsdService(Context context) {
365 mContext = context;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700366 mContentResolver = context.getContentResolver();
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700367
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700368 mNativeConnector = new NativeDaemonConnector(new NativeCallbackReceiver(), "mdns", 10,
369 MDNS_TAG, 25);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700370
371 mNsdStateMachine = new NsdStateMachine(TAG);
372 mNsdStateMachine.start();
373
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700374 Thread th = new Thread(mNativeConnector, MDNS_TAG);
375 th.start();
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700376 }
377
378 public static NsdService create(Context context) throws InterruptedException {
379 NsdService service = new NsdService(context);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700380 service.mNativeDaemonConnected.await();
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700381 return service;
382 }
383
384 public Messenger getMessenger() {
Irfan Sheriff92784672012-04-13 12:15:41 -0700385 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INTERNET,
386 "NsdService");
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700387 return new Messenger(mNsdStateMachine.getHandler());
388 }
389
390 public void setEnabled(boolean enable) {
391 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL,
392 "NsdService");
393 Settings.Secure.putInt(mContentResolver, Settings.Secure.NSD_ON, enable ? 1 : 0);
394 if (enable) {
395 mNsdStateMachine.sendMessage(NsdManager.ENABLE);
396 } else {
397 mNsdStateMachine.sendMessage(NsdManager.DISABLE);
398 }
399 }
400
401 private void sendNsdStateChangeBroadcast(boolean enabled) {
Irfan Sheriff54ac7a52012-04-19 10:26:34 -0700402 final Intent intent = new Intent(NsdManager.ACTION_NSD_STATE_CHANGED);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700403 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
404 if (enabled) {
405 intent.putExtra(NsdManager.EXTRA_NSD_STATE, NsdManager.NSD_STATE_ENABLED);
406 } else {
407 intent.putExtra(NsdManager.EXTRA_NSD_STATE, NsdManager.NSD_STATE_DISABLED);
408 }
409 mContext.sendStickyBroadcast(intent);
410 }
411
412 private boolean isNsdEnabled() {
413 boolean ret = Settings.Secure.getInt(mContentResolver, Settings.Secure.NSD_ON, 1) == 1;
414 if (DBG) Slog.d(TAG, "Network service discovery enabled " + ret);
415 return ret;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700416 }
417
Irfan Sheriff817388e2012-04-11 14:52:19 -0700418 private int getUniqueId() {
419 if (++mUniqueId == INVALID_ID) return ++mUniqueId;
420 return mUniqueId;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700421 }
422
Irfan Sheriff817388e2012-04-11 14:52:19 -0700423 /* These should be in sync with system/netd/mDnsResponseCode.h */
424 class NativeResponseCode {
425 public static final int SERVICE_DISCOVERY_FAILED = 602;
426 public static final int SERVICE_FOUND = 603;
427 public static final int SERVICE_LOST = 604;
428
429 public static final int SERVICE_REGISTRATION_FAILED = 605;
430 public static final int SERVICE_REGISTERED = 606;
431
432 public static final int SERVICE_RESOLUTION_FAILED = 607;
433 public static final int SERVICE_RESOLVED = 608;
434
435 public static final int SERVICE_UPDATED = 609;
436 public static final int SERVICE_UPDATE_FAILED = 610;
437
438 public static final int SERVICE_GET_ADDR_FAILED = 611;
439 public static final int SERVICE_GET_ADDR_SUCCESS = 612;
440 }
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700441
442 class NativeCallbackReceiver implements INativeDaemonConnectorCallbacks {
443 public void onDaemonConnected() {
444 mNativeDaemonConnected.countDown();
445 }
446
447 public boolean onEvent(int code, String raw, String[] cooked) {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700448 ClientInfo clientInfo;
449 DnsSdServiceInfo servInfo;
450 int id = Integer.parseInt(cooked[1]);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700451 switch (code) {
452 case NativeResponseCode.SERVICE_FOUND:
Irfan Sheriff817388e2012-04-11 14:52:19 -0700453 /* NNN uniqueId serviceName regType domain */
454 if (DBG) Slog.d(TAG, "SERVICE_FOUND Raw: " + raw);
455 clientInfo = getClientByDiscovery(id);
456 if (clientInfo == null) break;
457
458 servInfo = new DnsSdServiceInfo(cooked[2], cooked[3], null);
459 clientInfo.mChannel.sendMessage(NsdManager.SERVICE_FOUND, servInfo);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700460 break;
461 case NativeResponseCode.SERVICE_LOST:
Irfan Sheriff817388e2012-04-11 14:52:19 -0700462 /* NNN uniqueId serviceName regType domain */
463 if (DBG) Slog.d(TAG, "SERVICE_LOST Raw: " + raw);
464 clientInfo = getClientByDiscovery(id);
465 if (clientInfo == null) break;
466
467 servInfo = new DnsSdServiceInfo(cooked[2], cooked[3], null);
468 clientInfo.mChannel.sendMessage(NsdManager.SERVICE_LOST, servInfo);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700469 break;
470 case NativeResponseCode.SERVICE_DISCOVERY_FAILED:
471 /* NNN uniqueId errorCode */
Irfan Sheriff817388e2012-04-11 14:52:19 -0700472 if (DBG) Slog.d(TAG, "SERVICE_DISC_FAILED Raw: " + raw);
473 clientInfo = getClientByDiscovery(id);
474 if (clientInfo == null) break;
475
476 clientInfo.mChannel.sendMessage(NsdManager.DISCOVER_SERVICES_FAILED,
477 NsdManager.ERROR);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700478 break;
479 case NativeResponseCode.SERVICE_REGISTERED:
480 /* NNN regId serviceName regType */
Irfan Sheriff817388e2012-04-11 14:52:19 -0700481 if (DBG) Slog.d(TAG, "SERVICE_REGISTERED Raw: " + raw);
482 clientInfo = getClientByRegistration(id);
483 if (clientInfo == null) break;
484
485 servInfo = new DnsSdServiceInfo(cooked[2], null, null);
486 clientInfo.mChannel.sendMessage(NsdManager.REGISTER_SERVICE_SUCCEEDED,
487 id, 0, servInfo);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700488 break;
489 case NativeResponseCode.SERVICE_REGISTRATION_FAILED:
490 /* NNN regId errorCode */
Irfan Sheriff817388e2012-04-11 14:52:19 -0700491 if (DBG) Slog.d(TAG, "SERVICE_REGISTER_FAILED Raw: " + raw);
492 clientInfo = getClientByRegistration(id);
493 if (clientInfo == null) break;
494
495 clientInfo.mChannel.sendMessage(NsdManager.REGISTER_SERVICE_FAILED,
496 NsdManager.ERROR);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700497 break;
498 case NativeResponseCode.SERVICE_UPDATED:
499 /* NNN regId */
500 break;
501 case NativeResponseCode.SERVICE_UPDATE_FAILED:
502 /* NNN regId errorCode */
503 break;
504 case NativeResponseCode.SERVICE_RESOLVED:
505 /* NNN resolveId fullName hostName port txtlen txtdata */
Irfan Sheriff817388e2012-04-11 14:52:19 -0700506 if (DBG) Slog.d(TAG, "SERVICE_RESOLVED Raw: " + raw);
507 clientInfo = getClientByResolve(id);
508 if (clientInfo == null) break;
509
510 int index = cooked[2].indexOf(".");
511 if (index == -1) {
512 Slog.e(TAG, "Invalid service found " + raw);
513 break;
514 }
515 String name = cooked[2].substring(0, index);
516 String rest = cooked[2].substring(index);
517 String type = rest.replace(".local.", "");
518
519 clientInfo.mResolvedService = new DnsSdServiceInfo(name, type, null);
520 clientInfo.mResolvedService.setPort(Integer.parseInt(cooked[4]));
521
522 stopResolveService(id);
523 getAddrInfo(id, cooked[3]);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700524 break;
525 case NativeResponseCode.SERVICE_RESOLUTION_FAILED:
Irfan Sheriff817388e2012-04-11 14:52:19 -0700526 case NativeResponseCode.SERVICE_GET_ADDR_FAILED:
527 /* NNN resolveId errorCode */
528 if (DBG) Slog.d(TAG, "SERVICE_RESOLVE_FAILED Raw: " + raw);
529 clientInfo = getClientByResolve(id);
530 if (clientInfo == null) break;
531
532 clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
533 NsdManager.ERROR);
534 break;
535 case NativeResponseCode.SERVICE_GET_ADDR_SUCCESS:
536 /* NNN resolveId hostname ttl addr */
537 if (DBG) Slog.d(TAG, "SERVICE_GET_ADDR_SUCCESS Raw: " + raw);
538 clientInfo = getClientByResolve(id);
539 if (clientInfo == null || clientInfo.mResolvedService == null) break;
540
541 try {
542 clientInfo.mResolvedService.setHost(InetAddress.getByName(cooked[4]));
543 clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_SUCCEEDED,
544 clientInfo.mResolvedService);
545 clientInfo.mResolvedService = null;
546 clientInfo.mResolveId = INVALID_ID;
547 } catch (java.net.UnknownHostException e) {
548 clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
549 NsdManager.ERROR);
550 }
551 stopGetAddrInfo(id);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700552 break;
553 default:
554 break;
555 }
556 return false;
557 }
558 }
559
Irfan Sheriff817388e2012-04-11 14:52:19 -0700560 private boolean startMDnsDaemon() {
561 if (DBG) Slog.d(TAG, "startMDnsDaemon");
562 try {
563 mNativeConnector.execute("mdnssd", "start-service");
564 } catch(NativeDaemonConnectorException e) {
565 Slog.e(TAG, "Failed to start daemon" + e);
566 return false;
567 }
568 return true;
569 }
570
571 private boolean stopMDnsDaemon() {
572 if (DBG) Slog.d(TAG, "stopMDnsDaemon");
573 try {
574 mNativeConnector.execute("mdnssd", "stop-service");
575 } catch(NativeDaemonConnectorException e) {
576 Slog.e(TAG, "Failed to start daemon" + e);
577 return false;
578 }
579 return true;
580 }
581
582 private boolean registerService(int regId, DnsSdServiceInfo service) {
583 if (DBG) Slog.d(TAG, "registerService: " + regId + " " + service);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700584 try {
585 //Add txtlen and txtdata
586 mNativeConnector.execute("mdnssd", "register", regId, service.getServiceName(),
587 service.getServiceType(), service.getPort());
588 } catch(NativeDaemonConnectorException e) {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700589 Slog.e(TAG, "Failed to execute registerService " + e);
590 return false;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700591 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700592 return true;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700593 }
594
Irfan Sheriff817388e2012-04-11 14:52:19 -0700595 private boolean unregisterService(int regId) {
596 if (DBG) Slog.d(TAG, "unregisterService: " + regId);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700597 try {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700598 mNativeConnector.execute("mdnssd", "stop-register", regId);
599 } catch(NativeDaemonConnectorException e) {
600 Slog.e(TAG, "Failed to execute unregisterService " + e);
601 return false;
602 }
603 return true;
604 }
605
606 private boolean updateService(int regId, DnsSdTxtRecord t) {
607 if (DBG) Slog.d(TAG, "updateService: " + regId + " " + t);
608 try {
609 if (t == null) return false;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700610 mNativeConnector.execute("mdnssd", "update", regId, t.size(), t.getRawData());
611 } catch(NativeDaemonConnectorException e) {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700612 Slog.e(TAG, "Failed to updateServices " + e);
613 return false;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700614 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700615 return true;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700616 }
617
Irfan Sheriff817388e2012-04-11 14:52:19 -0700618 private boolean discoverServices(int discoveryId, String serviceType) {
619 if (DBG) Slog.d(TAG, "discoverServices: " + discoveryId + " " + serviceType);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700620 try {
621 mNativeConnector.execute("mdnssd", "discover", discoveryId, serviceType);
622 } catch(NativeDaemonConnectorException e) {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700623 Slog.e(TAG, "Failed to discoverServices " + e);
624 return false;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700625 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700626 return true;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700627 }
628
Irfan Sheriff817388e2012-04-11 14:52:19 -0700629 private boolean stopServiceDiscovery(int discoveryId) {
630 if (DBG) Slog.d(TAG, "stopServiceDiscovery: " + discoveryId);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700631 try {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700632 mNativeConnector.execute("mdnssd", "stop-discover", discoveryId);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700633 } catch(NativeDaemonConnectorException e) {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700634 Slog.e(TAG, "Failed to stopServiceDiscovery " + e);
635 return false;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700636 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700637 return true;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700638 }
639
Irfan Sheriff817388e2012-04-11 14:52:19 -0700640 private boolean resolveService(int resolveId, DnsSdServiceInfo service) {
641 if (DBG) Slog.d(TAG, "resolveService: " + resolveId + " " + service);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700642 try {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700643 mNativeConnector.execute("mdnssd", "resolve", resolveId, service.getServiceName(),
644 service.getServiceType(), "local.");
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700645 } catch(NativeDaemonConnectorException e) {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700646 Slog.e(TAG, "Failed to resolveService " + e);
647 return false;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700648 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700649 return true;
650 }
651
652 private boolean stopResolveService(int resolveId) {
653 if (DBG) Slog.d(TAG, "stopResolveService: " + resolveId);
654 try {
655 mNativeConnector.execute("mdnssd", "stop-resolve", resolveId);
656 } catch(NativeDaemonConnectorException e) {
657 Slog.e(TAG, "Failed to stop resolve " + e);
658 return false;
659 }
660 return true;
661 }
662
663 private boolean getAddrInfo(int resolveId, String hostname) {
664 if (DBG) Slog.d(TAG, "getAdddrInfo: " + resolveId);
665 try {
666 mNativeConnector.execute("mdnssd", "getaddrinfo", resolveId, hostname);
667 } catch(NativeDaemonConnectorException e) {
668 Slog.e(TAG, "Failed to getAddrInfo " + e);
669 return false;
670 }
671 return true;
672 }
673
674 private boolean stopGetAddrInfo(int resolveId) {
675 if (DBG) Slog.d(TAG, "stopGetAdddrInfo: " + resolveId);
676 try {
677 mNativeConnector.execute("mdnssd", "stop-getaddrinfo", resolveId);
678 } catch(NativeDaemonConnectorException e) {
679 Slog.e(TAG, "Failed to stopGetAddrInfo " + e);
680 return false;
681 }
682 return true;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700683 }
684
685 @Override
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700686 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700687 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
688 != PackageManager.PERMISSION_GRANTED) {
689 pw.println("Permission Denial: can't dump ServiceDiscoverService from from pid="
690 + Binder.getCallingPid()
691 + ", uid=" + Binder.getCallingUid());
692 return;
693 }
694
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700695 for (ClientInfo client : mClients.values()) {
696 pw.println("Client Info");
697 pw.println(client);
698 }
699
700 mNsdStateMachine.dump(fd, pw, args);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700701 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700702
703 private ClientInfo getClientByDiscovery(int discoveryId) {
704 for (ClientInfo c: mClients.values()) {
705 if (c.mDiscoveryId == discoveryId) {
706 return c;
707 }
708 }
709 return null;
710 }
711
712 private ClientInfo getClientByResolve(int resolveId) {
713 for (ClientInfo c: mClients.values()) {
714 if (c.mResolveId == resolveId) {
715 return c;
716 }
717 }
718 return null;
719 }
720
721 private ClientInfo getClientByRegistration(int regId) {
722 for (ClientInfo c: mClients.values()) {
723 if (c.mRegisteredIds.contains(regId)) {
724 return c;
725 }
726 }
727 return null;
728 }
729
730 /* Information tracked per client */
731 private class ClientInfo {
732
733 private static final int MAX_REG = 5;
734 private AsyncChannel mChannel;
735 private Messenger mMessenger;
736 private int mDiscoveryId;
737 private int mResolveId;
738 /* Remembers a resolved service until getaddrinfo completes */
739 private DnsSdServiceInfo mResolvedService;
740 private ArrayList<Integer> mRegisteredIds = new ArrayList<Integer>();
741
742 private ClientInfo(AsyncChannel c, Messenger m) {
743 mChannel = c;
744 mMessenger = m;
745 mDiscoveryId = mResolveId = INVALID_ID;
746 if (DBG) Slog.d(TAG, "New client, channel: " + c + " messenger: " + m);
747 }
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700748
749 @Override
750 public String toString() {
751 StringBuffer sb = new StringBuffer();
752 sb.append("mChannel ").append(mChannel).append("\n");
753 sb.append("mMessenger ").append(mMessenger).append("\n");
754 sb.append("mDiscoveryId ").append(mDiscoveryId).append("\n");
755 sb.append("mResolveId ").append(mResolveId).append("\n");
756 sb.append("mResolvedService ").append(mResolvedService).append("\n");
757 for(int regId : mRegisteredIds) {
758 sb.append("regId ").append(regId).append("\n");
759 }
760 return sb.toString();
761 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700762 }
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700763}