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