MDnsSdListener.cpp revision 30ffdfa62cb6bd8807b3d8eb529e2e8abaa80386
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
44MDnsSdListener::MDnsSdListener() :
45                 FrameworkListener("mdns", true) {
46    Monitor *m = new Monitor();
47    registerCmd(new Handler(m, this));
48}
49
50MDnsSdListener::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
57MDnsSdListener::Handler::~Handler() {}
58
59void 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
96void 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
130void 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
154void 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
189void 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
210void 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
243void 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
270void 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
299void 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
330void 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
357void 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
377int MDnsSdListener::Handler::ifaceNameToI(const char * /* iface */) {
378    return 0;
379}
380
381const char *MDnsSdListener::Handler::iToIfaceName(int /* i */) {
382    return NULL;
383}
384
385DNSServiceFlags MDnsSdListener::Handler::iToFlags(int /* i */) {
386    return 0;
387}
388
389int MDnsSdListener::Handler::flagsToI(DNSServiceFlags /* flags */) {
390    return 0;
391}
392
393int 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
514MDnsSdListener::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
527void *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
537static 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
557int 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
574int 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
589void 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
595    mPollFds[0].fd = mCtrlSocketPair[0];
596    mPollFds[0].events = POLLIN;
597
598    if (VDBG) ALOGD("MDnsSdListener starting to monitor");
599    while (1) {
600        if (VDBG) ALOGD("Going to poll with pollCount %d", pollCount);
601        int pollResults = poll(mPollFds, pollCount, 10000000);
602        if (pollResults < 0) {
603            ALOGE("Error in poll - got %d", errno);
604        } else if (pollResults > 0) {
605            if (VDBG) ALOGD("Monitor poll got data pollCount = %d, %d", pollCount, pollResults);
606            for(int i = 1; i < pollCount; i++) {
607                if (mPollFds[i].revents != 0) {
608                    if (VDBG) {
609                        ALOGD("Monitor found [%d].revents = %d - calling ProcessResults",
610                                i, mPollFds[i].revents);
611                    }
612                    DNSServiceProcessResult(*(mPollRefs[i]));
613                    mPollFds[i].revents = 0;
614                }
615            }
616            if (VDBG) ALOGD("controlSocket shows revent= %d", mPollFds[0].revents);
617            switch (mPollFds[0].revents) {
618                case POLLIN: {
619                    char readBuf[2];
620                    read(mCtrlSocketPair[0], &readBuf, 1);
621                    if (DBG) ALOGD("MDnsSdListener::Monitor got %c", readBuf[0]);
622                    if (memcmp(RESCAN, readBuf, 1) == 0) {
623                        pollCount = rescan();
624                    }
625                }
626            }
627            mPollFds[0].revents = 0;
628        } else {
629            if (VDBG) ALOGD("MDnsSdListener::Monitor poll timed out");
630        }
631    }
632    free(mPollFds);
633    free(mPollRefs);
634}
635
636#define DBG_RESCAN 0
637
638int MDnsSdListener::Monitor::rescan() {
639// rescan the list from mHead and make new pollfds and serviceRefs
640    if (VDBG) {
641        ALOGD("MDnsSdListener::Monitor poll rescanning - size=%d, live=%d", mPollSize, mLiveCount);
642    }
643    pthread_mutex_lock(&mHeadMutex);
644    Element **prevPtr = &mHead;
645    int i = 1;
646    if (mPollSize <= mLiveCount) {
647        mPollSize = mLiveCount + 5;
648        free(mPollFds);
649        free(mPollRefs);
650        mPollFds = (struct pollfd *)calloc(sizeof(struct pollfd), mPollSize);
651        mPollRefs = (DNSServiceRef **)calloc(sizeof(DNSServiceRef *), mPollSize);
652    } else {
653        memset(mPollFds, 0, sizeof(struct pollfd) * mPollSize);
654        memset(mPollRefs, 0, sizeof(DNSServiceRef *) * mPollSize);
655    }
656    mPollFds[0].fd = mCtrlSocketPair[0];
657    mPollFds[0].events = POLLIN;
658    if (DBG_RESCAN) ALOGD("mHead = %p", mHead);
659    while (*prevPtr != NULL) {
660        if (DBG_RESCAN) ALOGD("checking %p, mReady = %d", *prevPtr, (*prevPtr)->mReady);
661        if ((*prevPtr)->mReady == 1) {
662            int fd = DNSServiceRefSockFD((*prevPtr)->mRef);
663            if (fd != -1) {
664                if (DBG_RESCAN) ALOGD("  adding FD %d", fd);
665                mPollFds[i].fd = fd;
666                mPollFds[i].events = POLLIN;
667                mPollRefs[i] = &((*prevPtr)->mRef);
668                i++;
669            } else {
670                ALOGE("Error retreving socket FD for live ServiceRef");
671            }
672            prevPtr = &((*prevPtr)->mNext); // advance to the next element
673        } else if ((*prevPtr)->mReady == -1) {
674            if (DBG_RESCAN) ALOGD("  removing %p from  play", *prevPtr);
675            Element *cur = *prevPtr;
676            *prevPtr = (cur)->mNext; // change our notion of this element and don't advance
677            delete cur;
678        } else if ((*prevPtr)->mReady == 0) {
679            // Not ready so just skip this node and continue on
680            if (DBG_RESCAN) ALOGD("%p not ready.  Continuing.", *prevPtr);
681            prevPtr = &((*prevPtr)->mNext);
682        }
683    }
684    pthread_mutex_unlock(&mHeadMutex);
685    return i;
686}
687
688DNSServiceRef *MDnsSdListener::Monitor::allocateServiceRef(int id, Context *context) {
689    if (lookupServiceRef(id) != NULL) {
690        delete(context);
691        return NULL;
692    }
693    Element *e = new Element(id, context);
694    pthread_mutex_lock(&mHeadMutex);
695    e->mNext = mHead;
696    mHead = e;
697    pthread_mutex_unlock(&mHeadMutex);
698    return &(e->mRef);
699}
700
701DNSServiceRef *MDnsSdListener::Monitor::lookupServiceRef(int id) {
702    pthread_mutex_lock(&mHeadMutex);
703    Element *cur = mHead;
704    while (cur != NULL) {
705        if (cur->mId == id) {
706            DNSServiceRef *result = &(cur->mRef);
707            pthread_mutex_unlock(&mHeadMutex);
708            return result;
709        }
710        cur = cur->mNext;
711    }
712    pthread_mutex_unlock(&mHeadMutex);
713    return NULL;
714}
715
716void MDnsSdListener::Monitor::startMonitoring(int id) {
717    if (VDBG) ALOGD("startMonitoring %d", id);
718    pthread_mutex_lock(&mHeadMutex);
719    Element *cur = mHead;
720    while (cur != NULL) {
721        if (cur->mId == id) {
722            if (DBG_RESCAN) ALOGD("marking %p as ready to be added", cur);
723            mLiveCount++;
724            cur->mReady = 1;
725            pthread_mutex_unlock(&mHeadMutex);
726            write(mCtrlSocketPair[1], RESCAN, 1);  // trigger a rescan for a fresh poll
727            if (VDBG) ALOGD("triggering rescan");
728            return;
729        }
730        cur = cur->mNext;
731    }
732    pthread_mutex_unlock(&mHeadMutex);
733}
734
735void MDnsSdListener::Monitor::freeServiceRef(int id) {
736    if (VDBG) ALOGD("freeServiceRef %d", id);
737    pthread_mutex_lock(&mHeadMutex);
738    Element **prevPtr = &mHead;
739    Element *cur;
740    while (*prevPtr != NULL) {
741        cur = *prevPtr;
742        if (cur->mId == id) {
743            if (DBG_RESCAN) ALOGD("marking %p as ready to be removed", cur);
744            mLiveCount--;
745            if (cur->mReady == 1) {
746                cur->mReady = -1; // tell poll thread to delete
747                write(mCtrlSocketPair[1], RESCAN, 1); // trigger a rescan for a fresh poll
748                if (VDBG) ALOGD("triggering rescan");
749            } else {
750                *prevPtr = cur->mNext;
751                delete cur;
752            }
753            pthread_mutex_unlock(&mHeadMutex);
754            return;
755        }
756        prevPtr = &(cur->mNext);
757    }
758    pthread_mutex_unlock(&mHeadMutex);
759}
760