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