Home | History | Annotate | Download | only in server
      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