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 47 MDnsSdListener::MDnsSdListener() : 48 FrameworkListener("mdns", 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 pthread_create(&mThread, NULL, MDnsSdListener::Monitor::threadStart, this); 528 pthread_detach(mThread); 529 } 530 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 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 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 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 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 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 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 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 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 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