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 
     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