1 /*
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
17 #include <arpa/inet.h>
18 #include <dirent.h>
19 #include <errno.h>
20 #include <linux/if.h>
21 #include <netdb.h>
22 #include <netinet/in.h>
23 #include <pthread.h>
24 #include <stdlib.h>
25 #include <sys/poll.h>
26 #include <sys/socket.h>
27 #include <sys/types.h>
28 #include <string.h>
29 #include <resolv.h>
30
31 #define LOG_TAG "MDnsDS"
32 #define DBG 1
33 #define VDBG 1
34
35 #include <cutils/log.h>
36 #include <cutils/properties.h>
37 #include <sysutils/SocketClient.h>
38
39 #include "MDnsSdListener.h"
40 #include "ResponseCode.h"
41
42 #define MDNS_SERVICE_NAME "mdnsd"
43 #define MDNS_SERVICE_STATUS "init.svc.mdnsd"
44
45 #define CEIL(x, y) (((x) + (y) - 1) / (y))
46
MDnsSdListener()47 MDnsSdListener::MDnsSdListener() :
48 FrameworkListener("mdns", true) {
49 Monitor *m = new Monitor();
50 registerCmd(new Handler(m, this));
51 }
52
Handler(Monitor * m,MDnsSdListener * listener)53 MDnsSdListener::Handler::Handler(Monitor *m, MDnsSdListener *listener) :
54 NetdCommand("mdnssd") {
55 if (DBG) ALOGD("MDnsSdListener::Hander starting up");
56 mMonitor = m;
57 mListener = listener;
58 }
59
~Handler()60 MDnsSdListener::Handler::~Handler() {}
61
discover(SocketClient * cli,const char * iface,const char * regType,const char * domain,const int requestId,const int requestFlags)62 void MDnsSdListener::Handler::discover(SocketClient *cli,
63 const char *iface,
64 const char *regType,
65 const char *domain,
66 const int requestId,
67 const int requestFlags) {
68 if (VDBG) {
69 ALOGD("discover(%s, %s, %s, %d, %d)", iface, regType, domain, requestId,
70 requestFlags);
71 }
72 Context *context = new Context(requestId, mListener);
73 DNSServiceRef *ref = mMonitor->allocateServiceRef(requestId, context);
74 if (ref == NULL) {
75 ALOGE("requestId %d already in use during discover call", requestId);
76 cli->sendMsg(ResponseCode::CommandParameterError,
77 "RequestId already in use during discover call", false);
78 return;
79 }
80 if (VDBG) ALOGD("using ref %p", ref);
81 DNSServiceFlags nativeFlags = iToFlags(requestFlags);
82 int interfaceInt = ifaceNameToI(iface);
83
84 DNSServiceErrorType result = DNSServiceBrowse(ref, nativeFlags, interfaceInt, regType,
85 domain, &MDnsSdListenerDiscoverCallback, context);
86 if (result != kDNSServiceErr_NoError) {
87 ALOGE("Discover request %d got an error from DNSServiceBrowse %d", requestId, result);
88 mMonitor->freeServiceRef(requestId);
89 cli->sendMsg(ResponseCode::CommandParameterError,
90 "Discover request got an error from DNSServiceBrowse", false);
91 return;
92 }
93 mMonitor->startMonitoring(requestId);
94 if (VDBG) ALOGD("discover successful");
95 cli->sendMsg(ResponseCode::CommandOkay, "Discover operation started", false);
96 return;
97 }
98
MDnsSdListenerDiscoverCallback(DNSServiceRef,DNSServiceFlags flags,uint32_t,DNSServiceErrorType errorCode,const char * serviceName,const char * regType,const char * replyDomain,void * inContext)99 void MDnsSdListenerDiscoverCallback(DNSServiceRef /* sdRef */, DNSServiceFlags flags,
100 uint32_t /* interfaceIndex */, DNSServiceErrorType errorCode, const char *serviceName,
101 const char *regType, const char *replyDomain, void *inContext) {
102 MDnsSdListener::Context *context = reinterpret_cast<MDnsSdListener::Context *>(inContext);
103 char *msg;
104 int refNumber = context->mRefNumber;
105
106 if (errorCode != kDNSServiceErr_NoError) {
107 asprintf(&msg, "%d %d", refNumber, errorCode);
108 context->mListener->sendBroadcast(ResponseCode::ServiceDiscoveryFailed, msg, false);
109 if (DBG) ALOGE("discover failure for %d, error= %d", refNumber, errorCode);
110 } else {
111 int respCode;
112 char *quotedServiceName = SocketClient::quoteArg(serviceName);
113 if (flags & kDNSServiceFlagsAdd) {
114 if (VDBG) {
115 ALOGD("Discover found new serviceName %s, regType %s and domain %s for %d",
116 serviceName, regType, replyDomain, refNumber);
117 }
118 respCode = ResponseCode::ServiceDiscoveryServiceAdded;
119 } else {
120 if (VDBG) {
121 ALOGD("Discover lost serviceName %s, regType %s and domain %s for %d",
122 serviceName, regType, replyDomain, refNumber);
123 }
124 respCode = ResponseCode::ServiceDiscoveryServiceRemoved;
125 }
126 asprintf(&msg, "%d %s %s %s", refNumber, quotedServiceName, regType, replyDomain);
127 free(quotedServiceName);
128 context->mListener->sendBroadcast(respCode, msg, false);
129 }
130 free(msg);
131 }
132
stop(SocketClient * cli,int argc,char ** argv,const char * str)133 void MDnsSdListener::Handler::stop(SocketClient *cli, int argc, char **argv, const char *str) {
134 if (argc != 3) {
135 char *msg;
136 asprintf(&msg, "Invalid number of arguments to %s", str);
137 cli->sendMsg(ResponseCode::CommandParameterError, msg, false);
138 free(msg);
139 return;
140 }
141 int requestId = atoi(argv[2]);
142 DNSServiceRef *ref = mMonitor->lookupServiceRef(requestId);
143 if (ref == NULL) {
144 if (DBG) ALOGE("%s stop used unknown requestId %d", str, requestId);
145 cli->sendMsg(ResponseCode::CommandParameterError, "Unknown requestId", false);
146 return;
147 }
148 if (VDBG) ALOGD("Stopping %s with ref %p", str, ref);
149 DNSServiceRefDeallocate(*ref);
150 mMonitor->freeServiceRef(requestId);
151 char *msg;
152 asprintf(&msg, "%s stopped", str);
153 cli->sendMsg(ResponseCode::CommandOkay, msg, false);
154 free(msg);
155 }
156
serviceRegister(SocketClient * cli,int requestId,const char * interfaceName,const char * serviceName,const char * serviceType,const char * domain,const char * host,int port,int txtLen,void * txtRecord)157 void MDnsSdListener::Handler::serviceRegister(SocketClient *cli, int requestId,
158 const char *interfaceName, const char *serviceName, const char *serviceType,
159 const char *domain, const char *host, int port, int txtLen, void *txtRecord) {
160 if (VDBG) {
161 ALOGD("serviceRegister(%d, %s, %s, %s, %s, %s, %d, %d, <binary>)", requestId,
162 interfaceName, serviceName, serviceType, domain, host, port, txtLen);
163 }
164 Context *context = new Context(requestId, mListener);
165 DNSServiceRef *ref = mMonitor->allocateServiceRef(requestId, context);
166 port = htons(port);
167 if (ref == NULL) {
168 ALOGE("requestId %d already in use during register call", requestId);
169 cli->sendMsg(ResponseCode::CommandParameterError,
170 "RequestId already in use during register call", false);
171 return;
172 }
173 DNSServiceFlags nativeFlags = 0;
174 int interfaceInt = ifaceNameToI(interfaceName);
175 DNSServiceErrorType result = DNSServiceRegister(ref, interfaceInt, nativeFlags, serviceName,
176 serviceType, domain, host, port, txtLen, txtRecord, &MDnsSdListenerRegisterCallback,
177 context);
178 if (result != kDNSServiceErr_NoError) {
179 ALOGE("service register request %d got an error from DNSServiceRegister %d", requestId,
180 result);
181 mMonitor->freeServiceRef(requestId);
182 cli->sendMsg(ResponseCode::CommandParameterError,
183 "serviceRegister request got an error from DNSServiceRegister", false);
184 return;
185 }
186 mMonitor->startMonitoring(requestId);
187 if (VDBG) ALOGD("serviceRegister successful");
188 cli->sendMsg(ResponseCode::CommandOkay, "serviceRegister started", false);
189 return;
190 }
191
MDnsSdListenerRegisterCallback(DNSServiceRef,DNSServiceFlags,DNSServiceErrorType errorCode,const char * serviceName,const char *,const char *,void * inContext)192 void MDnsSdListenerRegisterCallback(DNSServiceRef /* sdRef */, DNSServiceFlags /* flags */,
193 DNSServiceErrorType errorCode, const char *serviceName, const char * /* regType */,
194 const char * /* domain */, void *inContext) {
195 MDnsSdListener::Context *context = reinterpret_cast<MDnsSdListener::Context *>(inContext);
196 char *msg;
197 int refNumber = context->mRefNumber;
198 if (errorCode != kDNSServiceErr_NoError) {
199 asprintf(&msg, "%d %d", refNumber, errorCode);
200 context->mListener->sendBroadcast(ResponseCode::ServiceRegistrationFailed, msg, false);
201 if (DBG) ALOGE("register failure for %d, error= %d", refNumber, errorCode);
202 } else {
203 char *quotedServiceName = SocketClient::quoteArg(serviceName);
204 asprintf(&msg, "%d %s", refNumber, quotedServiceName);
205 free(quotedServiceName);
206 context->mListener->sendBroadcast(ResponseCode::ServiceRegistrationSucceeded, msg, false);
207 if (VDBG) ALOGD("register succeeded for %d as %s", refNumber, serviceName);
208 }
209 free(msg);
210 }
211
212
resolveService(SocketClient * cli,int requestId,const char * interfaceName,const char * serviceName,const char * regType,const char * domain)213 void MDnsSdListener::Handler::resolveService(SocketClient *cli, int requestId,
214 const char *interfaceName, const char *serviceName, const char *regType,
215 const char *domain) {
216 if (VDBG) {
217 ALOGD("resolveService(%d, %s, %s, %s, %s)", requestId, interfaceName,
218 serviceName, regType, domain);
219 }
220 Context *context = new Context(requestId, mListener);
221 DNSServiceRef *ref = mMonitor->allocateServiceRef(requestId, context);
222 if (ref == NULL) {
223 ALOGE("request Id %d already in use during resolve call", requestId);
224 cli->sendMsg(ResponseCode::CommandParameterError,
225 "RequestId already in use during resolve call", false);
226 return;
227 }
228 DNSServiceFlags nativeFlags = 0;
229 int interfaceInt = ifaceNameToI(interfaceName);
230 DNSServiceErrorType result = DNSServiceResolve(ref, nativeFlags, interfaceInt, serviceName,
231 regType, domain, &MDnsSdListenerResolveCallback, context);
232 if (result != kDNSServiceErr_NoError) {
233 ALOGE("service resolve request %d got an error from DNSServiceResolve %d", requestId,
234 result);
235 mMonitor->freeServiceRef(requestId);
236 cli->sendMsg(ResponseCode::CommandParameterError,
237 "resolveService got an error from DNSServiceResolve", false);
238 return;
239 }
240 mMonitor->startMonitoring(requestId);
241 if (VDBG) ALOGD("resolveService successful");
242 cli->sendMsg(ResponseCode::CommandOkay, "resolveService started", false);
243 return;
244 }
245
MDnsSdListenerResolveCallback(DNSServiceRef,DNSServiceFlags,uint32_t,DNSServiceErrorType errorCode,const char * fullname,const char * hosttarget,uint16_t port,uint16_t txtLen,const unsigned char * txtRecord,void * inContext)246 void MDnsSdListenerResolveCallback(DNSServiceRef /* sdRef */, DNSServiceFlags /* flags */,
247 uint32_t /* interface */, DNSServiceErrorType errorCode, const char *fullname,
248 const char *hosttarget, uint16_t port, uint16_t txtLen,
249 const unsigned char *txtRecord , void *inContext) {
250 MDnsSdListener::Context *context = reinterpret_cast<MDnsSdListener::Context *>(inContext);
251 char *msg;
252 int refNumber = context->mRefNumber;
253 port = ntohs(port);
254 if (errorCode != kDNSServiceErr_NoError) {
255 asprintf(&msg, "%d %d", refNumber, errorCode);
256 context->mListener->sendBroadcast(ResponseCode::ServiceResolveFailed, msg, false);
257 if (DBG) ALOGE("resolve failure for %d, error= %d", refNumber, errorCode);
258 } else {
259 char *quotedFullName = SocketClient::quoteArg(fullname);
260 char *quotedHostTarget = SocketClient::quoteArg(hosttarget);
261
262 // Base 64 encodes every 3 bytes into 4 characters, but then adds padding to the next
263 // multiple of 4 and a \0
264 size_t dstLength = CEIL(CEIL(txtLen * 4, 3), 4) * 4 + 1;
265
266 char *dst = (char *)malloc(dstLength);
267 b64_ntop(txtRecord, txtLen, dst, dstLength);
268
269 asprintf(&msg, "%d %s %s %d %d \"%s\"", refNumber, quotedFullName, quotedHostTarget, port,
270 txtLen, dst);
271 free(quotedFullName);
272 free(quotedHostTarget);
273 free(dst);
274 context->mListener->sendBroadcast(ResponseCode::ServiceResolveSuccess, msg, false);
275 if (VDBG) {
276 ALOGD("resolve succeeded for %d finding %s at %s:%d with txtLen %d",
277 refNumber, fullname, hosttarget, port, txtLen);
278 }
279 }
280 free(msg);
281 }
282
getAddrInfo(SocketClient * cli,int requestId,const char * interfaceName,uint32_t protocol,const char * hostname)283 void MDnsSdListener::Handler::getAddrInfo(SocketClient *cli, int requestId,
284 const char *interfaceName, uint32_t protocol, const char *hostname) {
285 if (VDBG) ALOGD("getAddrInfo(%d, %s %d, %s)", requestId, interfaceName, protocol, hostname);
286 Context *context = new Context(requestId, mListener);
287 DNSServiceRef *ref = mMonitor->allocateServiceRef(requestId, context);
288 if (ref == NULL) {
289 ALOGE("request ID %d already in use during getAddrInfo call", requestId);
290 cli->sendMsg(ResponseCode::CommandParameterError,
291 "RequestId already in use during getAddrInfo call", false);
292 return;
293 }
294 DNSServiceFlags nativeFlags = 0;
295 int interfaceInt = ifaceNameToI(interfaceName);
296 DNSServiceErrorType result = DNSServiceGetAddrInfo(ref, nativeFlags, interfaceInt, protocol,
297 hostname, &MDnsSdListenerGetAddrInfoCallback, context);
298 if (result != kDNSServiceErr_NoError) {
299 ALOGE("getAddrInfo request %d got an error from DNSServiceGetAddrInfo %d", requestId,
300 result);
301 mMonitor->freeServiceRef(requestId);
302 cli->sendMsg(ResponseCode::CommandParameterError,
303 "getAddrInfo request got an error from DNSServiceGetAddrInfo", false);
304 return;
305 }
306 mMonitor->startMonitoring(requestId);
307 if (VDBG) ALOGD("getAddrInfo successful");
308 cli->sendMsg(ResponseCode::CommandOkay, "getAddrInfo started", false);
309 return;
310 }
311
MDnsSdListenerGetAddrInfoCallback(DNSServiceRef,DNSServiceFlags,uint32_t,DNSServiceErrorType errorCode,const char * hostname,const struct sockaddr * const sa,uint32_t ttl,void * inContext)312 void MDnsSdListenerGetAddrInfoCallback(DNSServiceRef /* sdRef */, DNSServiceFlags /* flags */,
313 uint32_t /* interface */, DNSServiceErrorType errorCode, const char *hostname,
314 const struct sockaddr *const sa, uint32_t ttl, void *inContext) {
315 MDnsSdListener::Context *context = reinterpret_cast<MDnsSdListener::Context *>(inContext);
316 int refNumber = context->mRefNumber;
317
318 if (errorCode != kDNSServiceErr_NoError) {
319 char *msg;
320 asprintf(&msg, "%d %d", refNumber, errorCode);
321 context->mListener->sendBroadcast(ResponseCode::ServiceGetAddrInfoFailed, msg, false);
322 if (DBG) ALOGE("getAddrInfo failure for %d, error= %d", refNumber, errorCode);
323 free(msg);
324 } else {
325 char addr[INET6_ADDRSTRLEN];
326 char *msg;
327 char *quotedHostname = SocketClient::quoteArg(hostname);
328 if (sa->sa_family == AF_INET) {
329 inet_ntop(sa->sa_family, &(((struct sockaddr_in *)sa)->sin_addr), addr, sizeof(addr));
330 } else {
331 inet_ntop(sa->sa_family, &(((struct sockaddr_in6 *)sa)->sin6_addr), addr, sizeof(addr));
332 }
333 asprintf(&msg, "%d %s %d %s", refNumber, quotedHostname, ttl, addr);
334 free(quotedHostname);
335 context->mListener->sendBroadcast(ResponseCode::ServiceGetAddrInfoSuccess, msg, false);
336 if (VDBG) {
337 ALOGD("getAddrInfo succeeded for %d: %s", refNumber, msg);
338 }
339 free(msg);
340 }
341 }
342
setHostname(SocketClient * cli,int requestId,const char * hostname)343 void MDnsSdListener::Handler::setHostname(SocketClient *cli, int requestId,
344 const char *hostname) {
345 if (VDBG) ALOGD("setHostname(%d, %s)", requestId, hostname);
346 Context *context = new Context(requestId, mListener);
347 DNSServiceRef *ref = mMonitor->allocateServiceRef(requestId, context);
348 if (ref == NULL) {
349 ALOGE("request Id %d already in use during setHostname call", requestId);
350 cli->sendMsg(ResponseCode::CommandParameterError,
351 "RequestId already in use during setHostname call", false);
352 return;
353 }
354 DNSServiceFlags nativeFlags = 0;
355 DNSServiceErrorType result = DNSSetHostname(ref, nativeFlags, hostname,
356 &MDnsSdListenerSetHostnameCallback, context);
357 if (result != kDNSServiceErr_NoError) {
358 ALOGE("setHostname request %d got an error from DNSSetHostname %d", requestId, result);
359 mMonitor->freeServiceRef(requestId);
360 cli->sendMsg(ResponseCode::CommandParameterError,
361 "setHostname got an error from DNSSetHostname", false);
362 return;
363 }
364 mMonitor->startMonitoring(requestId);
365 if (VDBG) ALOGD("setHostname successful");
366 cli->sendMsg(ResponseCode::CommandOkay, "setHostname started", false);
367 return;
368 }
369
MDnsSdListenerSetHostnameCallback(DNSServiceRef,DNSServiceFlags,DNSServiceErrorType errorCode,const char * hostname,void * inContext)370 void MDnsSdListenerSetHostnameCallback(DNSServiceRef /* sdRef */, DNSServiceFlags /* flags */,
371 DNSServiceErrorType errorCode, const char *hostname, void *inContext) {
372 MDnsSdListener::Context *context = reinterpret_cast<MDnsSdListener::Context *>(inContext);
373 char *msg;
374 int refNumber = context->mRefNumber;
375 if (errorCode != kDNSServiceErr_NoError) {
376 asprintf(&msg, "%d %d", refNumber, errorCode);
377 context->mListener->sendBroadcast(ResponseCode::ServiceSetHostnameFailed, msg, false);
378 if (DBG) ALOGE("setHostname failure for %d, error= %d", refNumber, errorCode);
379 } else {
380 char *quotedHostname = SocketClient::quoteArg(hostname);
381 asprintf(&msg, "%d %s", refNumber, quotedHostname);
382 free(quotedHostname);
383 context->mListener->sendBroadcast(ResponseCode::ServiceSetHostnameSuccess, msg, false);
384 if (VDBG) ALOGD("setHostname succeeded for %d. Set to %s", refNumber, hostname);
385 }
386 free(msg);
387 }
388
389
ifaceNameToI(const char *)390 int MDnsSdListener::Handler::ifaceNameToI(const char * /* iface */) {
391 return 0;
392 }
393
iToIfaceName(int)394 const char *MDnsSdListener::Handler::iToIfaceName(int /* i */) {
395 return NULL;
396 }
397
iToFlags(int)398 DNSServiceFlags MDnsSdListener::Handler::iToFlags(int /* i */) {
399 return 0;
400 }
401
flagsToI(DNSServiceFlags)402 int MDnsSdListener::Handler::flagsToI(DNSServiceFlags /* flags */) {
403 return 0;
404 }
405
runCommand(SocketClient * cli,int argc,char ** argv)406 int MDnsSdListener::Handler::runCommand(SocketClient *cli,
407 int argc, char **argv) {
408 if (argc < 2) {
409 char* msg = NULL;
410 asprintf( &msg, "Invalid number of arguments to mdnssd: %i", argc);
411 ALOGW("%s", msg);
412 cli->sendMsg(ResponseCode::CommandParameterError, msg, false);
413 free(msg);
414 return -1;
415 }
416
417 char* cmd = argv[1];
418
419 if (strcmp(cmd, "discover") == 0) {
420 if (argc != 4) {
421 cli->sendMsg(ResponseCode::CommandParameterError,
422 "Invalid number of arguments to mdnssd discover", false);
423 return 0;
424 }
425 int requestId = atoi(argv[2]);
426 char *serviceType = argv[3];
427
428 discover(cli, NULL, serviceType, NULL, requestId, 0);
429 } else if (strcmp(cmd, "stop-discover") == 0) {
430 stop(cli, argc, argv, "discover");
431 } else if (strcmp(cmd, "register") == 0) {
432 if (argc != 7) {
433 cli->sendMsg(ResponseCode::CommandParameterError,
434 "Invalid number of arguments to mdnssd register", false);
435 return 0;
436 }
437 int requestId = atoi(argv[2]);
438 char *serviceName = argv[3];
439 char *serviceType = argv[4];
440 int port = atoi(argv[5]);
441 char *interfaceName = NULL; // will use all
442 char *domain = NULL; // will use default
443 char *host = NULL; // will use default hostname
444
445 // TXT record length is <= 1300, see NsdServiceInfo.setAttribute
446 char dst[1300];
447
448 int length = b64_pton(argv[6], (u_char *)dst, 1300);
449
450 if (length < 0) {
451 cli->sendMsg(ResponseCode::CommandParameterError,
452 "Could not decode txtRecord", false);
453 return 0;
454 }
455
456 serviceRegister(cli, requestId, interfaceName, serviceName,
457 serviceType, domain, host, port, length, dst);
458 } else if (strcmp(cmd, "stop-register") == 0) {
459 stop(cli, argc, argv, "register");
460 } else if (strcmp(cmd, "resolve") == 0) {
461 if (argc != 6) {
462 cli->sendMsg(ResponseCode::CommandParameterError,
463 "Invalid number of arguments to mdnssd resolve", false);
464 return 0;
465 }
466 int requestId = atoi(argv[2]);
467 char *interfaceName = NULL; // will use all
468 char *serviceName = argv[3];
469 char *regType = argv[4];
470 char *domain = argv[5];
471 resolveService(cli, requestId, interfaceName, serviceName, regType, domain);
472 } else if (strcmp(cmd, "stop-resolve") == 0) {
473 stop(cli, argc, argv, "resolve");
474 } else if (strcmp(cmd, "start-service") == 0) {
475 if (mMonitor->startService()) {
476 cli->sendMsg(ResponseCode::CommandOkay, "Service Started", false);
477 } else {
478 cli->sendMsg(ResponseCode::ServiceStartFailed, "Service already running", false);
479 }
480 } else if (strcmp(cmd, "stop-service") == 0) {
481 if (mMonitor->stopService()) {
482 cli->sendMsg(ResponseCode::CommandOkay, "Service Stopped", false);
483 } else {
484 cli->sendMsg(ResponseCode::ServiceStopFailed, "Service still in use", false);
485 }
486 } else if (strcmp(cmd, "sethostname") == 0) {
487 if (argc != 4) {
488 cli->sendMsg(ResponseCode::CommandParameterError,
489 "Invalid number of arguments to mdnssd sethostname", false);
490 return 0;
491 }
492 int requestId = atoi(argv[2]);
493 char *hostname = argv[3];
494 setHostname(cli, requestId, hostname);
495 } else if (strcmp(cmd, "stop-sethostname") == 0) {
496 stop(cli, argc, argv, "sethostname");
497 } else if (strcmp(cmd, "getaddrinfo") == 0) {
498 if (argc != 4) {
499 cli->sendMsg(ResponseCode::CommandParameterError,
500 "Invalid number of arguments to mdnssd getaddrinfo", false);
501 return 0;
502 }
503 int requestId = atoi(argv[2]);
504 char *hostname = argv[3];
505 char *interfaceName = NULL; // default
506 int protocol = 0; // intelligient heuristic (both v4 + v6)
507 getAddrInfo(cli, requestId, interfaceName, protocol, hostname);
508 } else if (strcmp(cmd, "stop-getaddrinfo") == 0) {
509 stop(cli, argc, argv, "getaddrinfo");
510 } else {
511 if (VDBG) ALOGE("Unknown cmd %s", cmd);
512 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown mdnssd cmd", false);
513 return 0;
514 }
515 return 0;
516 }
517
Monitor()518 MDnsSdListener::Monitor::Monitor() {
519 mHead = NULL;
520 mLiveCount = 0;
521 mPollFds = NULL;
522 mPollRefs = NULL;
523 mPollSize = 10;
524 socketpair(AF_LOCAL, SOCK_STREAM, 0, mCtrlSocketPair);
525 pthread_mutex_init(&mHeadMutex, NULL);
526
527 pthread_create(&mThread, NULL, MDnsSdListener::Monitor::threadStart, this);
528 pthread_detach(mThread);
529 }
530
threadStart(void * obj)531 void *MDnsSdListener::Monitor::threadStart(void *obj) {
532 Monitor *monitor = reinterpret_cast<Monitor *>(obj);
533
534 monitor->run();
535 delete monitor;
536 pthread_exit(NULL);
537 return NULL;
538 }
539
540 #define NAP_TIME 200 // 200 ms between polls
wait_for_property(const char * name,const char * desired_value,int maxwait)541 static int wait_for_property(const char *name, const char *desired_value, int maxwait)
542 {
543 char value[PROPERTY_VALUE_MAX] = {'\0'};
544 int maxnaps = (maxwait * 1000) / NAP_TIME;
545
546 if (maxnaps < 1) {
547 maxnaps = 1;
548 }
549
550 while (maxnaps-- > 0) {
551 usleep(NAP_TIME * 1000);
552 if (property_get(name, value, NULL)) {
553 if (desired_value == NULL || strcmp(value, desired_value) == 0) {
554 return 0;
555 }
556 }
557 }
558 return -1; /* failure */
559 }
560
startService()561 int MDnsSdListener::Monitor::startService() {
562 int result = 0;
563 char property_value[PROPERTY_VALUE_MAX];
564 pthread_mutex_lock(&mHeadMutex);
565 property_get(MDNS_SERVICE_STATUS, property_value, "");
566 if (strcmp("running", property_value) != 0) {
567 ALOGD("Starting MDNSD");
568 property_set("ctl.start", MDNS_SERVICE_NAME);
569 wait_for_property(MDNS_SERVICE_STATUS, "running", 5);
570 result = -1;
571 } else {
572 result = 0;
573 }
574 pthread_mutex_unlock(&mHeadMutex);
575 return result;
576 }
577
stopService()578 int MDnsSdListener::Monitor::stopService() {
579 int result = 0;
580 pthread_mutex_lock(&mHeadMutex);
581 if (mHead == NULL) {
582 ALOGD("Stopping MDNSD");
583 property_set("ctl.stop", MDNS_SERVICE_NAME);
584 wait_for_property(MDNS_SERVICE_STATUS, "stopped", 5);
585 result = -1;
586 } else {
587 result = 0;
588 }
589 pthread_mutex_unlock(&mHeadMutex);
590 return result;
591 }
592
run()593 void MDnsSdListener::Monitor::run() {
594 int pollCount = 1;
595
596 mPollFds = (struct pollfd *)calloc(sizeof(struct pollfd), mPollSize);
597 mPollRefs = (DNSServiceRef **)calloc(sizeof(DNSServiceRef *), mPollSize);
598 LOG_ALWAYS_FATAL_IF((mPollFds == NULL), "initial calloc failed on mPollFds with a size of %d",
599 ((int)sizeof(struct pollfd)) * mPollSize);
600 LOG_ALWAYS_FATAL_IF((mPollRefs == NULL), "initial calloc failed on mPollRefs with a size of %d",
601 ((int)sizeof(DNSServiceRef *)) * mPollSize);
602
603 mPollFds[0].fd = mCtrlSocketPair[0];
604 mPollFds[0].events = POLLIN;
605
606 if (VDBG) ALOGD("MDnsSdListener starting to monitor");
607 while (1) {
608 if (VDBG) ALOGD("Going to poll with pollCount %d", pollCount);
609 int pollResults = poll(mPollFds, pollCount, 10000000);
610 if (pollResults < 0) {
611 ALOGE("Error in poll - got %d", errno);
612 } else if (pollResults > 0) {
613 if (VDBG) ALOGD("Monitor poll got data pollCount = %d, %d", pollCount, pollResults);
614 for(int i = 1; i < pollCount; i++) {
615 if (mPollFds[i].revents != 0) {
616 if (VDBG) {
617 ALOGD("Monitor found [%d].revents = %d - calling ProcessResults",
618 i, mPollFds[i].revents);
619 }
620 DNSServiceProcessResult(*(mPollRefs[i]));
621 mPollFds[i].revents = 0;
622 }
623 }
624 if (VDBG) ALOGD("controlSocket shows revent= %d", mPollFds[0].revents);
625 switch (mPollFds[0].revents) {
626 case POLLIN: {
627 char readBuf[2];
628 read(mCtrlSocketPair[0], &readBuf, 1);
629 if (DBG) ALOGD("MDnsSdListener::Monitor got %c", readBuf[0]);
630 if (memcmp(RESCAN, readBuf, 1) == 0) {
631 pollCount = rescan();
632 }
633 }
634 }
635 mPollFds[0].revents = 0;
636 } else {
637 if (VDBG) ALOGD("MDnsSdListener::Monitor poll timed out");
638 }
639 }
640 free(mPollFds);
641 free(mPollRefs);
642 }
643
644 #define DBG_RESCAN 0
645
rescan()646 int MDnsSdListener::Monitor::rescan() {
647 // rescan the list from mHead and make new pollfds and serviceRefs
648 if (VDBG) {
649 ALOGD("MDnsSdListener::Monitor poll rescanning - size=%d, live=%d", mPollSize, mLiveCount);
650 }
651 pthread_mutex_lock(&mHeadMutex);
652 Element **prevPtr = &mHead;
653 int i = 1;
654 if (mPollSize <= mLiveCount) {
655 mPollSize = mLiveCount + 5;
656 free(mPollFds);
657 free(mPollRefs);
658 mPollFds = (struct pollfd *)calloc(sizeof(struct pollfd), mPollSize);
659 mPollRefs = (DNSServiceRef **)calloc(sizeof(DNSServiceRef *), mPollSize);
660 LOG_ALWAYS_FATAL_IF((mPollFds == NULL), "calloc failed on mPollFds with a size of %d",
661 ((int)sizeof(struct pollfd)) * mPollSize);
662 LOG_ALWAYS_FATAL_IF((mPollRefs == NULL), "calloc failed on mPollRefs with a size of %d",
663 ((int)sizeof(DNSServiceRef *)) * mPollSize);
664 } else {
665 memset(mPollFds, 0, sizeof(struct pollfd) * mPollSize);
666 memset(mPollRefs, 0, sizeof(DNSServiceRef *) * mPollSize);
667 }
668 mPollFds[0].fd = mCtrlSocketPair[0];
669 mPollFds[0].events = POLLIN;
670 if (DBG_RESCAN) ALOGD("mHead = %p", mHead);
671 while (*prevPtr != NULL) {
672 if (DBG_RESCAN) ALOGD("checking %p, mReady = %d", *prevPtr, (*prevPtr)->mReady);
673 if ((*prevPtr)->mReady == 1) {
674 int fd = DNSServiceRefSockFD((*prevPtr)->mRef);
675 if (fd != -1) {
676 if (DBG_RESCAN) ALOGD(" adding FD %d", fd);
677 mPollFds[i].fd = fd;
678 mPollFds[i].events = POLLIN;
679 mPollRefs[i] = &((*prevPtr)->mRef);
680 i++;
681 } else {
682 ALOGE("Error retreving socket FD for live ServiceRef");
683 }
684 prevPtr = &((*prevPtr)->mNext); // advance to the next element
685 } else if ((*prevPtr)->mReady == -1) {
686 if (DBG_RESCAN) ALOGD(" removing %p from play", *prevPtr);
687 Element *cur = *prevPtr;
688 *prevPtr = (cur)->mNext; // change our notion of this element and don't advance
689 delete cur;
690 } else if ((*prevPtr)->mReady == 0) {
691 // Not ready so just skip this node and continue on
692 if (DBG_RESCAN) ALOGD("%p not ready. Continuing.", *prevPtr);
693 prevPtr = &((*prevPtr)->mNext);
694 }
695 }
696 pthread_mutex_unlock(&mHeadMutex);
697 return i;
698 }
699
allocateServiceRef(int id,Context * context)700 DNSServiceRef *MDnsSdListener::Monitor::allocateServiceRef(int id, Context *context) {
701 if (lookupServiceRef(id) != NULL) {
702 delete(context);
703 return NULL;
704 }
705 Element *e = new Element(id, context);
706 pthread_mutex_lock(&mHeadMutex);
707 e->mNext = mHead;
708 mHead = e;
709 pthread_mutex_unlock(&mHeadMutex);
710 return &(e->mRef);
711 }
712
lookupServiceRef(int id)713 DNSServiceRef *MDnsSdListener::Monitor::lookupServiceRef(int id) {
714 pthread_mutex_lock(&mHeadMutex);
715 Element *cur = mHead;
716 while (cur != NULL) {
717 if (cur->mId == id) {
718 DNSServiceRef *result = &(cur->mRef);
719 pthread_mutex_unlock(&mHeadMutex);
720 return result;
721 }
722 cur = cur->mNext;
723 }
724 pthread_mutex_unlock(&mHeadMutex);
725 return NULL;
726 }
727
startMonitoring(int id)728 void MDnsSdListener::Monitor::startMonitoring(int id) {
729 if (VDBG) ALOGD("startMonitoring %d", id);
730 pthread_mutex_lock(&mHeadMutex);
731 Element *cur = mHead;
732 while (cur != NULL) {
733 if (cur->mId == id) {
734 if (DBG_RESCAN) ALOGD("marking %p as ready to be added", cur);
735 mLiveCount++;
736 cur->mReady = 1;
737 pthread_mutex_unlock(&mHeadMutex);
738 write(mCtrlSocketPair[1], RESCAN, 1); // trigger a rescan for a fresh poll
739 if (VDBG) ALOGD("triggering rescan");
740 return;
741 }
742 cur = cur->mNext;
743 }
744 pthread_mutex_unlock(&mHeadMutex);
745 }
746
freeServiceRef(int id)747 void MDnsSdListener::Monitor::freeServiceRef(int id) {
748 if (VDBG) ALOGD("freeServiceRef %d", id);
749 pthread_mutex_lock(&mHeadMutex);
750 Element **prevPtr = &mHead;
751 Element *cur;
752 while (*prevPtr != NULL) {
753 cur = *prevPtr;
754 if (cur->mId == id) {
755 if (DBG_RESCAN) ALOGD("marking %p as ready to be removed", cur);
756 mLiveCount--;
757 if (cur->mReady == 1) {
758 cur->mReady = -1; // tell poll thread to delete
759 write(mCtrlSocketPair[1], RESCAN, 1); // trigger a rescan for a fresh poll
760 if (VDBG) ALOGD("triggering rescan");
761 } else {
762 *prevPtr = cur->mNext;
763 delete cur;
764 }
765 pthread_mutex_unlock(&mHeadMutex);
766 return;
767 }
768 prevPtr = &(cur->mNext);
769 }
770 pthread_mutex_unlock(&mHeadMutex);
771 }
772