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