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 #include "thread_util.h" 42 43 #define MDNS_SERVICE_NAME "mdnsd" 44 #define MDNS_SERVICE_STATUS "init.svc.mdnsd" 45 46 #define CEIL(x, y) (((x) + (y) - 1) / (y)) 47 48 MDnsSdListener::MDnsSdListener() : FrameworkListener(SOCKET_NAME, true) { 49 Monitor *m = new Monitor(); 50 registerCmd(new Handler(m, this)); 51 } 52 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 60 MDnsSdListener::Handler::~Handler() {} 61 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 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 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 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 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 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 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 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 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 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 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 390 int MDnsSdListener::Handler::ifaceNameToI(const char * /* iface */) { 391 return 0; 392 } 393 394 const char *MDnsSdListener::Handler::iToIfaceName(int /* i */) { 395 return NULL; 396 } 397 398 DNSServiceFlags MDnsSdListener::Handler::iToFlags(int /* i */) { 399 return 0; 400 } 401 402 int MDnsSdListener::Handler::flagsToI(DNSServiceFlags /* flags */) { 403 return 0; 404 } 405 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 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 const int rval = ::android::net::threadLaunch(this); 528 if (rval != 0) { 529 ALOGW("Error spawning monitor thread: %s (%d)", strerror(-rval), -rval); 530 } 531 } 532 533 #define NAP_TIME 200 // 200 ms between polls 534 static int wait_for_property(const char *name, const char *desired_value, int maxwait) 535 { 536 char value[PROPERTY_VALUE_MAX] = {'\0'}; 537 int maxnaps = (maxwait * 1000) / NAP_TIME; 538 539 if (maxnaps < 1) { 540 maxnaps = 1; 541 } 542 543 while (maxnaps-- > 0) { 544 usleep(NAP_TIME * 1000); 545 if (property_get(name, value, NULL)) { 546 if (desired_value == NULL || strcmp(value, desired_value) == 0) { 547 return 0; 548 } 549 } 550 } 551 return -1; /* failure */ 552 } 553 554 int MDnsSdListener::Monitor::startService() { 555 int result = 0; 556 char property_value[PROPERTY_VALUE_MAX]; 557 pthread_mutex_lock(&mHeadMutex); 558 property_get(MDNS_SERVICE_STATUS, property_value, ""); 559 if (strcmp("running", property_value) != 0) { 560 ALOGD("Starting MDNSD"); 561 property_set("ctl.start", MDNS_SERVICE_NAME); 562 wait_for_property(MDNS_SERVICE_STATUS, "running", 5); 563 result = -1; 564 } else { 565 result = 0; 566 } 567 pthread_mutex_unlock(&mHeadMutex); 568 return result; 569 } 570 571 int MDnsSdListener::Monitor::stopService() { 572 int result = 0; 573 pthread_mutex_lock(&mHeadMutex); 574 if (mHead == NULL) { 575 ALOGD("Stopping MDNSD"); 576 property_set("ctl.stop", MDNS_SERVICE_NAME); 577 wait_for_property(MDNS_SERVICE_STATUS, "stopped", 5); 578 result = -1; 579 } else { 580 result = 0; 581 } 582 pthread_mutex_unlock(&mHeadMutex); 583 return result; 584 } 585 586 void MDnsSdListener::Monitor::run() { 587 int pollCount = 1; 588 589 mPollFds = (struct pollfd *)calloc(sizeof(struct pollfd), mPollSize); 590 mPollRefs = (DNSServiceRef **)calloc(sizeof(DNSServiceRef *), mPollSize); 591 LOG_ALWAYS_FATAL_IF((mPollFds == NULL), "initial calloc failed on mPollFds with a size of %d", 592 ((int)sizeof(struct pollfd)) * mPollSize); 593 LOG_ALWAYS_FATAL_IF((mPollRefs == NULL), "initial calloc failed on mPollRefs with a size of %d", 594 ((int)sizeof(DNSServiceRef *)) * mPollSize); 595 596 mPollFds[0].fd = mCtrlSocketPair[0]; 597 mPollFds[0].events = POLLIN; 598 599 if (VDBG) ALOGD("MDnsSdListener starting to monitor"); 600 while (1) { 601 if (VDBG) ALOGD("Going to poll with pollCount %d", pollCount); 602 int pollResults = poll(mPollFds, pollCount, 10000000); 603 if (pollResults < 0) { 604 ALOGE("Error in poll - got %d", errno); 605 } else if (pollResults > 0) { 606 if (VDBG) ALOGD("Monitor poll got data pollCount = %d, %d", pollCount, pollResults); 607 for(int i = 1; i < pollCount; i++) { 608 if (mPollFds[i].revents != 0) { 609 if (VDBG) { 610 ALOGD("Monitor found [%d].revents = %d - calling ProcessResults", 611 i, mPollFds[i].revents); 612 } 613 DNSServiceProcessResult(*(mPollRefs[i])); 614 mPollFds[i].revents = 0; 615 } 616 } 617 if (VDBG) ALOGD("controlSocket shows revent= %d", mPollFds[0].revents); 618 switch (mPollFds[0].revents) { 619 case POLLIN: { 620 char readBuf[2]; 621 read(mCtrlSocketPair[0], &readBuf, 1); 622 if (DBG) ALOGD("MDnsSdListener::Monitor got %c", readBuf[0]); 623 if (memcmp(RESCAN, readBuf, 1) == 0) { 624 pollCount = rescan(); 625 } 626 } 627 } 628 mPollFds[0].revents = 0; 629 } else { 630 if (VDBG) ALOGD("MDnsSdListener::Monitor poll timed out"); 631 } 632 } 633 free(mPollFds); 634 free(mPollRefs); 635 } 636 637 #define DBG_RESCAN 0 638 639 int MDnsSdListener::Monitor::rescan() { 640 // rescan the list from mHead and make new pollfds and serviceRefs 641 if (VDBG) { 642 ALOGD("MDnsSdListener::Monitor poll rescanning - size=%d, live=%d", mPollSize, mLiveCount); 643 } 644 pthread_mutex_lock(&mHeadMutex); 645 Element **prevPtr = &mHead; 646 int i = 1; 647 if (mPollSize <= mLiveCount) { 648 mPollSize = mLiveCount + 5; 649 free(mPollFds); 650 free(mPollRefs); 651 mPollFds = (struct pollfd *)calloc(sizeof(struct pollfd), mPollSize); 652 mPollRefs = (DNSServiceRef **)calloc(sizeof(DNSServiceRef *), mPollSize); 653 LOG_ALWAYS_FATAL_IF((mPollFds == NULL), "calloc failed on mPollFds with a size of %d", 654 ((int)sizeof(struct pollfd)) * mPollSize); 655 LOG_ALWAYS_FATAL_IF((mPollRefs == NULL), "calloc failed on mPollRefs with a size of %d", 656 ((int)sizeof(DNSServiceRef *)) * mPollSize); 657 } else { 658 memset(mPollFds, 0, sizeof(struct pollfd) * mPollSize); 659 memset(mPollRefs, 0, sizeof(DNSServiceRef *) * mPollSize); 660 } 661 mPollFds[0].fd = mCtrlSocketPair[0]; 662 mPollFds[0].events = POLLIN; 663 if (DBG_RESCAN) ALOGD("mHead = %p", mHead); 664 while (*prevPtr != NULL) { 665 if (DBG_RESCAN) ALOGD("checking %p, mReady = %d", *prevPtr, (*prevPtr)->mReady); 666 if ((*prevPtr)->mReady == 1) { 667 int fd = DNSServiceRefSockFD((*prevPtr)->mRef); 668 if (fd != -1) { 669 if (DBG_RESCAN) ALOGD(" adding FD %d", fd); 670 mPollFds[i].fd = fd; 671 mPollFds[i].events = POLLIN; 672 mPollRefs[i] = &((*prevPtr)->mRef); 673 i++; 674 } else { 675 ALOGE("Error retreving socket FD for live ServiceRef"); 676 } 677 prevPtr = &((*prevPtr)->mNext); // advance to the next element 678 } else if ((*prevPtr)->mReady == -1) { 679 if (DBG_RESCAN) ALOGD(" removing %p from play", *prevPtr); 680 Element *cur = *prevPtr; 681 *prevPtr = (cur)->mNext; // change our notion of this element and don't advance 682 delete cur; 683 } else if ((*prevPtr)->mReady == 0) { 684 // Not ready so just skip this node and continue on 685 if (DBG_RESCAN) ALOGD("%p not ready. Continuing.", *prevPtr); 686 prevPtr = &((*prevPtr)->mNext); 687 } 688 } 689 pthread_mutex_unlock(&mHeadMutex); 690 return i; 691 } 692 693 DNSServiceRef *MDnsSdListener::Monitor::allocateServiceRef(int id, Context *context) { 694 if (lookupServiceRef(id) != NULL) { 695 delete(context); 696 return NULL; 697 } 698 Element *e = new Element(id, context); 699 pthread_mutex_lock(&mHeadMutex); 700 e->mNext = mHead; 701 mHead = e; 702 pthread_mutex_unlock(&mHeadMutex); 703 return &(e->mRef); 704 } 705 706 DNSServiceRef *MDnsSdListener::Monitor::lookupServiceRef(int id) { 707 pthread_mutex_lock(&mHeadMutex); 708 Element *cur = mHead; 709 while (cur != NULL) { 710 if (cur->mId == id) { 711 DNSServiceRef *result = &(cur->mRef); 712 pthread_mutex_unlock(&mHeadMutex); 713 return result; 714 } 715 cur = cur->mNext; 716 } 717 pthread_mutex_unlock(&mHeadMutex); 718 return NULL; 719 } 720 721 void MDnsSdListener::Monitor::startMonitoring(int id) { 722 if (VDBG) ALOGD("startMonitoring %d", id); 723 pthread_mutex_lock(&mHeadMutex); 724 Element *cur = mHead; 725 while (cur != NULL) { 726 if (cur->mId == id) { 727 if (DBG_RESCAN) ALOGD("marking %p as ready to be added", cur); 728 mLiveCount++; 729 cur->mReady = 1; 730 pthread_mutex_unlock(&mHeadMutex); 731 write(mCtrlSocketPair[1], RESCAN, 1); // trigger a rescan for a fresh poll 732 if (VDBG) ALOGD("triggering rescan"); 733 return; 734 } 735 cur = cur->mNext; 736 } 737 pthread_mutex_unlock(&mHeadMutex); 738 } 739 740 void MDnsSdListener::Monitor::freeServiceRef(int id) { 741 if (VDBG) ALOGD("freeServiceRef %d", id); 742 pthread_mutex_lock(&mHeadMutex); 743 Element **prevPtr = &mHead; 744 Element *cur; 745 while (*prevPtr != NULL) { 746 cur = *prevPtr; 747 if (cur->mId == id) { 748 if (DBG_RESCAN) ALOGD("marking %p as ready to be removed", cur); 749 mLiveCount--; 750 if (cur->mReady == 1) { 751 cur->mReady = -1; // tell poll thread to delete 752 write(mCtrlSocketPair[1], RESCAN, 1); // trigger a rescan for a fresh poll 753 if (VDBG) ALOGD("triggering rescan"); 754 } else { 755 *prevPtr = cur->mNext; 756 delete cur; 757 } 758 pthread_mutex_unlock(&mHeadMutex); 759 return; 760 } 761 prevPtr = &(cur->mNext); 762 } 763 pthread_mutex_unlock(&mHeadMutex); 764 } 765