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, uint32_t interface, 244 DNSServiceErrorType errorCode, const char *fullname, const char *hosttarget, uint16_t port, 245 uint16_t txtLen, const unsigned char *txtRecord, void *inContext) { 246 MDnsSdListener::Context *context = reinterpret_cast<MDnsSdListener::Context *>(inContext); 247 char *msg; 248 int refNumber = context->mRefNumber; 249 port = ntohs(port); 250 if (errorCode != kDNSServiceErr_NoError) { 251 asprintf(&msg, "%d %d", refNumber, errorCode); 252 context->mListener->sendBroadcast(ResponseCode::ServiceResolveFailed, msg, false); 253 if (DBG) ALOGE("resolve failure for %d, error= %d", refNumber, errorCode); 254 } else { 255 char *quotedFullName = SocketClient::quoteArg(fullname); 256 char *quotedHostTarget = SocketClient::quoteArg(hosttarget); 257 asprintf(&msg, "%d %s %s %d %d", refNumber, quotedFullName, quotedHostTarget, port, txtLen); 258 free(quotedFullName); 259 free(quotedHostTarget); 260 context->mListener->sendBroadcast(ResponseCode::ServiceResolveSuccess, msg, false); 261 if (VDBG) { 262 ALOGD("resolve succeeded for %d finding %s at %s:%d with txtLen %d", 263 refNumber, fullname, hosttarget, port, txtLen); 264 } 265 } 266 free(msg); 267} 268 269void MDnsSdListener::Handler::getAddrInfo(SocketClient *cli, int requestId, 270 const char *interfaceName, uint32_t protocol, const char *hostname) { 271 if (VDBG) ALOGD("getAddrInfo(%d, %s %d, %s)", requestId, interfaceName, protocol, hostname); 272 Context *context = new Context(requestId, mListener); 273 DNSServiceRef *ref = mMonitor->allocateServiceRef(requestId, context); 274 if (ref == NULL) { 275 ALOGE("request ID %d already in use during getAddrInfo call", requestId); 276 cli->sendMsg(ResponseCode::CommandParameterError, 277 "RequestId already in use during getAddrInfo call", false); 278 return; 279 } 280 DNSServiceFlags nativeFlags = 0; 281 int interfaceInt = ifaceNameToI(interfaceName); 282 DNSServiceErrorType result = DNSServiceGetAddrInfo(ref, nativeFlags, interfaceInt, protocol, 283 hostname, &MDnsSdListenerGetAddrInfoCallback, context); 284 if (result != kDNSServiceErr_NoError) { 285 ALOGE("getAddrInfo request %d got an error from DNSServiceGetAddrInfo %d", requestId, 286 result); 287 mMonitor->freeServiceRef(requestId); 288 cli->sendMsg(ResponseCode::CommandParameterError, 289 "getAddrInfo request got an error from DNSServiceGetAddrInfo", false); 290 return; 291 } 292 mMonitor->startMonitoring(requestId); 293 if (VDBG) ALOGD("getAddrInfo successful"); 294 cli->sendMsg(ResponseCode::CommandOkay, "getAddrInfo started", false); 295 return; 296} 297 298void MDnsSdListenerGetAddrInfoCallback(DNSServiceRef sdRef, DNSServiceFlags flags, 299 uint32_t interface, DNSServiceErrorType errorCode, const char *hostname, 300 const struct sockaddr *const sa, uint32_t ttl, void *inContext) { 301 MDnsSdListener::Context *context = reinterpret_cast<MDnsSdListener::Context *>(inContext); 302 int refNumber = context->mRefNumber; 303 304 if (errorCode != kDNSServiceErr_NoError) { 305 char *msg; 306 asprintf(&msg, "%d %d", refNumber, errorCode); 307 context->mListener->sendBroadcast(ResponseCode::ServiceGetAddrInfoFailed, msg, false); 308 if (DBG) ALOGE("getAddrInfo failure for %d, error= %d", refNumber, errorCode); 309 free(msg); 310 } else { 311 char addr[INET6_ADDRSTRLEN]; 312 char *msg; 313 char *quotedHostname = SocketClient::quoteArg(hostname); 314 if (sa->sa_family == AF_INET) { 315 inet_ntop(sa->sa_family, &(((struct sockaddr_in *)sa)->sin_addr), addr, sizeof(addr)); 316 } else { 317 inet_ntop(sa->sa_family, &(((struct sockaddr_in6 *)sa)->sin6_addr), addr, sizeof(addr)); 318 } 319 asprintf(&msg, "%d %s %d %s", refNumber, quotedHostname, ttl, addr); 320 free(quotedHostname); 321 context->mListener->sendBroadcast(ResponseCode::ServiceGetAddrInfoSuccess, msg, false); 322 if (VDBG) { 323 ALOGD("getAddrInfo succeeded for %d: %s", refNumber, msg); 324 } 325 free(msg); 326 } 327} 328 329void MDnsSdListener::Handler::setHostname(SocketClient *cli, int requestId, 330 const char *hostname) { 331 if (VDBG) ALOGD("setHostname(%d, %s)", requestId, hostname); 332 Context *context = new Context(requestId, mListener); 333 DNSServiceRef *ref = mMonitor->allocateServiceRef(requestId, context); 334 if (ref == NULL) { 335 ALOGE("request Id %d already in use during setHostname call", requestId); 336 cli->sendMsg(ResponseCode::CommandParameterError, 337 "RequestId already in use during setHostname call", false); 338 return; 339 } 340 DNSServiceFlags nativeFlags = 0; 341 DNSServiceErrorType result = DNSSetHostname(ref, nativeFlags, hostname, 342 &MDnsSdListenerSetHostnameCallback, context); 343 if (result != kDNSServiceErr_NoError) { 344 ALOGE("setHostname request %d got an error from DNSSetHostname %d", requestId, result); 345 mMonitor->freeServiceRef(requestId); 346 cli->sendMsg(ResponseCode::CommandParameterError, 347 "setHostname got an error from DNSSetHostname", false); 348 return; 349 } 350 mMonitor->startMonitoring(requestId); 351 if (VDBG) ALOGD("setHostname successful"); 352 cli->sendMsg(ResponseCode::CommandOkay, "setHostname started", false); 353 return; 354} 355 356void MDnsSdListenerSetHostnameCallback(DNSServiceRef sdRef, DNSServiceFlags flags, 357 DNSServiceErrorType errorCode, const char *hostname, void *inContext) { 358 MDnsSdListener::Context *context = reinterpret_cast<MDnsSdListener::Context *>(inContext); 359 char *msg; 360 int refNumber = context->mRefNumber; 361 if (errorCode != kDNSServiceErr_NoError) { 362 asprintf(&msg, "%d %d", refNumber, errorCode); 363 context->mListener->sendBroadcast(ResponseCode::ServiceSetHostnameFailed, msg, false); 364 if (DBG) ALOGE("setHostname failure for %d, error= %d", refNumber, errorCode); 365 } else { 366 char *quotedHostname = SocketClient::quoteArg(hostname); 367 asprintf(&msg, "%d %s", refNumber, quotedHostname); 368 free(quotedHostname); 369 context->mListener->sendBroadcast(ResponseCode::ServiceSetHostnameSuccess, msg, false); 370 if (VDBG) ALOGD("setHostname succeeded for %d. Set to %s", refNumber, hostname); 371 } 372 free(msg); 373} 374 375 376int MDnsSdListener::Handler::ifaceNameToI(const char *iface) { 377 return 0; 378} 379 380const char *MDnsSdListener::Handler::iToIfaceName(int i) { 381 return NULL; 382} 383 384DNSServiceFlags MDnsSdListener::Handler::iToFlags(int i) { 385 return 0; 386} 387 388int MDnsSdListener::Handler::flagsToI(DNSServiceFlags flags) { 389 return 0; 390} 391 392int MDnsSdListener::Handler::runCommand(SocketClient *cli, 393 int argc, char **argv) { 394 if (argc < 2) { 395 char* msg = NULL; 396 asprintf( &msg, "Invalid number of arguments to mdnssd: %i", argc); 397 ALOGW("%s", msg); 398 cli->sendMsg(ResponseCode::CommandParameterError, msg, false); 399 free(msg); 400 return -1; 401 } 402 403 char* cmd = argv[1]; 404 405 if (strcmp(cmd, "discover") == 0) { 406 if (argc != 4) { 407 cli->sendMsg(ResponseCode::CommandParameterError, 408 "Invalid number of arguments to mdnssd discover", false); 409 return 0; 410 } 411 int requestId = atoi(argv[2]); 412 char *serviceType = argv[3]; 413 414 discover(cli, NULL, serviceType, NULL, requestId, 0); 415 } else if (strcmp(cmd, "stop-discover") == 0) { 416 stop(cli, argc, argv, "discover"); 417 } else if (strcmp(cmd, "register") == 0) { 418 if (argc != 6) { 419 cli->sendMsg(ResponseCode::CommandParameterError, 420 "Invalid number of arguments to mdnssd register", false); 421 return 0; 422 } 423 int requestId = atoi(argv[2]); 424 char *serviceName = argv[3]; 425 char *serviceType = argv[4]; 426 int port = atoi(argv[5]); 427 char *interfaceName = NULL; // will use all 428 char *domain = NULL; // will use default 429 char *host = NULL; // will use default hostname 430 int textLen = 0; 431 void *textRecord = NULL; 432 433 serviceRegister(cli, requestId, interfaceName, serviceName, 434 serviceType, domain, host, port, textLen, textRecord); 435 } else if (strcmp(cmd, "stop-register") == 0) { 436 stop(cli, argc, argv, "register"); 437 } else if (strcmp(cmd, "resolve") == 0) { 438 if (argc != 6) { 439 cli->sendMsg(ResponseCode::CommandParameterError, 440 "Invalid number of arguments to mdnssd resolve", false); 441 return 0; 442 } 443 int requestId = atoi(argv[2]); 444 char *interfaceName = NULL; // will use all 445 char *serviceName = argv[3]; 446 char *regType = argv[4]; 447 char *domain = argv[5]; 448 resolveService(cli, requestId, interfaceName, serviceName, regType, domain); 449 } else if (strcmp(cmd, "stop-resolve") == 0) { 450 stop(cli, argc, argv, "resolve"); 451 } else if (strcmp(cmd, "start-service") == 0) { 452 if (mMonitor->startService()) { 453 cli->sendMsg(ResponseCode::CommandOkay, "Service Started", false); 454 } else { 455 cli->sendMsg(ResponseCode::ServiceStartFailed, "Service already running", false); 456 } 457 } else if (strcmp(cmd, "stop-service") == 0) { 458 if (mMonitor->stopService()) { 459 cli->sendMsg(ResponseCode::CommandOkay, "Service Stopped", false); 460 } else { 461 cli->sendMsg(ResponseCode::ServiceStopFailed, "Service still in use", false); 462 } 463 } else if (strcmp(cmd, "sethostname") == 0) { 464 if (argc != 4) { 465 cli->sendMsg(ResponseCode::CommandParameterError, 466 "Invalid number of arguments to mdnssd sethostname", false); 467 return 0; 468 } 469 int requestId = atoi(argv[2]); 470 char *hostname = argv[3]; 471 setHostname(cli, requestId, hostname); 472 } else if (strcmp(cmd, "stop-sethostname") == 0) { 473 stop(cli, argc, argv, "sethostname"); 474 } else if (strcmp(cmd, "getaddrinfo") == 0) { 475 if (argc != 4) { 476 cli->sendMsg(ResponseCode::CommandParameterError, 477 "Invalid number of arguments to mdnssd getaddrinfo", false); 478 return 0; 479 } 480 int requestId = atoi(argv[2]); 481 char *hostname = argv[3]; 482 char *interfaceName = NULL; // default 483 int protocol = 0; // intelligient heuristic (both v4 + v6) 484 getAddrInfo(cli, requestId, interfaceName, protocol, hostname); 485 } else if (strcmp(cmd, "stop-getaddrinfo") == 0) { 486 stop(cli, argc, argv, "getaddrinfo"); 487 } else { 488 if (VDBG) ALOGE("Unknown cmd %s", cmd); 489 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown mdnssd cmd", false); 490 return 0; 491 } 492 return 0; 493} 494 495MDnsSdListener::Monitor::Monitor() { 496 mHead = NULL; 497 pthread_mutex_init(&mHeadMutex, NULL); 498 socketpair(AF_LOCAL, SOCK_STREAM, 0, mCtrlSocketPair); 499 pthread_create(&mThread, NULL, MDnsSdListener::Monitor::threadStart, this); 500 pthread_detach(mThread); 501} 502 503void *MDnsSdListener::Monitor::threadStart(void *obj) { 504 Monitor *monitor = reinterpret_cast<Monitor *>(obj); 505 506 monitor->run(); 507 delete monitor; 508 pthread_exit(NULL); 509 return NULL; 510} 511 512int MDnsSdListener::Monitor::startService() { 513 int result = 0; 514 char property_value[PROPERTY_VALUE_MAX]; 515 pthread_mutex_lock(&mHeadMutex); 516 property_get(MDNS_SERVICE_STATUS, property_value, ""); 517 if (strcmp("running", property_value) != 0) { 518 ALOGD("Starting MDNSD"); 519 property_set("ctl.start", MDNS_SERVICE_NAME); 520 wait_for_property(MDNS_SERVICE_STATUS, "running", 5); 521 result = -1; 522 } else { 523 result = 0; 524 } 525 pthread_mutex_unlock(&mHeadMutex); 526 return result; 527} 528 529int MDnsSdListener::Monitor::stopService() { 530 int result = 0; 531 pthread_mutex_lock(&mHeadMutex); 532 if (mHead == NULL) { 533 ALOGD("Stopping MDNSD"); 534 property_set("ctl.stop", MDNS_SERVICE_NAME); 535 wait_for_property(MDNS_SERVICE_STATUS, "stopped", 5); 536 result = -1; 537 } else { 538 result = 0; 539 } 540 pthread_mutex_unlock(&mHeadMutex); 541 return result; 542} 543 544void MDnsSdListener::Monitor::run() { 545 int pollCount = 1; 546 mPollSize = 10; 547 548 mPollFds = (struct pollfd *)calloc(sizeof(struct pollfd), mPollSize); 549 mPollRefs = (DNSServiceRef **)calloc(sizeof(DNSServiceRef *), mPollSize); 550 551 mPollFds[0].fd = mCtrlSocketPair[0]; 552 mPollFds[0].events = POLLIN; 553 554 if (VDBG) ALOGD("MDnsSdListener starting to monitor"); 555 while (1) { 556 if (VDBG) ALOGD("Going to poll with pollCount %d", pollCount); 557 int pollResults = poll(mPollFds, pollCount, 10000000); 558 if (pollResults < 0) { 559 ALOGE("Error in poll - got %d", errno); 560 } else if (pollResults > 0) { 561 if (VDBG) ALOGD("Monitor poll got data pollCount = %d, %d", pollCount, pollResults); 562 for(int i = 1; i < pollCount; i++) { 563 if (mPollFds[i].revents != 0) { 564 if (VDBG) { 565 ALOGD("Monitor found [%d].revents = %d - calling ProcessResults", 566 i, mPollFds[i].revents); 567 } 568 DNSServiceProcessResult(*(mPollRefs[i])); 569 mPollFds[i].revents = 0; 570 } 571 } 572 if (VDBG) ALOGD("controlSocket shows revent= %d", mPollFds[0].revents); 573 switch (mPollFds[0].revents) { 574 case POLLIN: { 575 char readBuf[2]; 576 read(mCtrlSocketPair[0], &readBuf, 1); 577 if (DBG) ALOGD("MDnsSdListener::Monitor got %c", readBuf[0]); 578 if (memcmp(RESCAN, readBuf, 1) == 0) { 579 pollCount = rescan(); 580 } 581 } 582 } 583 mPollFds[0].revents = 0; 584 } else { 585 if (VDBG) ALOGD("MDnsSdListener::Monitor poll timed out"); 586 } 587 } 588 free(mPollFds); 589 free(mPollRefs); 590} 591 592#define DBG_RESCAN 0 593 594int MDnsSdListener::Monitor::rescan() { 595// rescan the list from mHead and make new pollfds and serviceRefs 596 if (VDBG) { 597 ALOGD("MDnsSdListener::Monitor poll rescanning - size=%d, live=%d", mPollSize, mLiveCount); 598 } 599 int count = 0; 600 pthread_mutex_lock(&mHeadMutex); 601 Element **prevPtr = &mHead; 602 int i = 1; 603 if (mPollSize <= mLiveCount) { 604 mPollSize = mLiveCount + 5; 605 free(mPollFds); 606 free(mPollRefs); 607 mPollFds = (struct pollfd *)calloc(sizeof(struct pollfd), mPollSize); 608 mPollRefs = (DNSServiceRef **)calloc(sizeof(DNSServiceRef *), mPollSize); 609 } else { 610 memset(mPollFds, 0, sizeof(struct pollfd) * mPollSize); 611 memset(mPollRefs, 0, sizeof(DNSServiceRef *) * mPollSize); 612 } 613 mPollFds[0].fd = mCtrlSocketPair[0]; 614 mPollFds[0].events = POLLIN; 615 if (DBG_RESCAN) ALOGD("mHead = %p", mHead); 616 while (*prevPtr != NULL) { 617 if (DBG_RESCAN) ALOGD("checking %p, mReady = %d", *prevPtr, (*prevPtr)->mReady); 618 if ((*prevPtr)->mReady == 1) { 619 int fd = DNSServiceRefSockFD((*prevPtr)->mRef); 620 if (fd != -1) { 621 if (DBG_RESCAN) ALOGD(" adding FD %d", fd); 622 mPollFds[i].fd = fd; 623 mPollFds[i].events = POLLIN; 624 mPollRefs[i] = &((*prevPtr)->mRef); 625 i++; 626 } else { 627 ALOGE("Error retreving socket FD for live ServiceRef"); 628 } 629 prevPtr = &((*prevPtr)->mNext); // advance to the next element 630 } else if ((*prevPtr)->mReady == -1) { 631 if (DBG_RESCAN) ALOGD(" removing %p from play", *prevPtr); 632 Element *cur = *prevPtr; 633 *prevPtr = (cur)->mNext; // change our notion of this element and don't advance 634 delete cur; 635 } 636 } 637 pthread_mutex_unlock(&mHeadMutex); 638 return i; 639} 640 641DNSServiceRef *MDnsSdListener::Monitor::allocateServiceRef(int id, Context *context) { 642 if (lookupServiceRef(id) != NULL) { 643 delete(context); 644 return NULL; 645 } 646 Element *e = new Element(id, context); 647 pthread_mutex_lock(&mHeadMutex); 648 e->mNext = mHead; 649 mHead = e; 650 pthread_mutex_unlock(&mHeadMutex); 651 return &(e->mRef); 652} 653 654DNSServiceRef *MDnsSdListener::Monitor::lookupServiceRef(int id) { 655 pthread_mutex_lock(&mHeadMutex); 656 Element *cur = mHead; 657 while (cur != NULL) { 658 if (cur->mId == id) { 659 DNSServiceRef *result = &(cur->mRef); 660 pthread_mutex_unlock(&mHeadMutex); 661 return result; 662 } 663 cur = cur->mNext; 664 } 665 pthread_mutex_unlock(&mHeadMutex); 666 return NULL; 667} 668 669void MDnsSdListener::Monitor::startMonitoring(int id) { 670 if (VDBG) ALOGD("startMonitoring %d", id); 671 pthread_mutex_lock(&mHeadMutex); 672 Element *cur = mHead; 673 while (cur != NULL) { 674 if (cur->mId == id) { 675 if (DBG_RESCAN) ALOGD("marking %p as ready to be added", cur); 676 mLiveCount++; 677 cur->mReady = 1; 678 pthread_mutex_unlock(&mHeadMutex); 679 write(mCtrlSocketPair[1], RESCAN, 1); // trigger a rescan for a fresh poll 680 if (VDBG) ALOGD("triggering rescan"); 681 return; 682 } 683 cur = cur->mNext; 684 } 685 pthread_mutex_unlock(&mHeadMutex); 686} 687 688#define NAP_TIME 200 // 200 ms between polls 689static int wait_for_property(const char *name, const char *desired_value, int maxwait) 690{ 691 char value[PROPERTY_VALUE_MAX] = {'\0'}; 692 int maxnaps = (maxwait * 1000) / NAP_TIME; 693 694 if (maxnaps < 1) { 695 maxnaps = 1; 696 } 697 698 while (maxnaps-- > 0) { 699 usleep(NAP_TIME * 1000); 700 if (property_get(name, value, NULL)) { 701 if (desired_value == NULL || strcmp(value, desired_value) == 0) { 702 return 0; 703 } 704 } 705 } 706 return -1; /* failure */ 707} 708 709void MDnsSdListener::Monitor::freeServiceRef(int id) { 710 if (VDBG) ALOGD("freeServiceRef %d", id); 711 pthread_mutex_lock(&mHeadMutex); 712 Element **prevPtr = &mHead; 713 Element *cur; 714 while (*prevPtr != NULL) { 715 cur = *prevPtr; 716 if (cur->mId == id) { 717 if (DBG_RESCAN) ALOGD("marking %p as ready to be removed", cur); 718 mLiveCount--; 719 if (cur->mReady == 1) { 720 cur->mReady = -1; // tell poll thread to delete 721 write(mCtrlSocketPair[1], RESCAN, 1); // trigger a rescan for a fresh poll 722 if (VDBG) ALOGD("triggering rescan"); 723 } else { 724 *prevPtr = cur->mNext; 725 delete cur; 726 } 727 pthread_mutex_unlock(&mHeadMutex); 728 return; 729 } 730 prevPtr = &(cur->mNext); 731 } 732 pthread_mutex_unlock(&mHeadMutex); 733} 734