OSDN Git Service

Initial release of mdns interface.
[android-x86/system-netd.git] / MDnsSdListener.cpp
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         if (flags & kDNSServiceFlagsAdd) {
110             if (VDBG) {
111                 ALOGD("Discover found new serviceName %s, regType %s and domain %s for %d",
112                         serviceName, regType, replyDomain, refNumber);
113             }
114             respCode = ResponseCode::ServiceDiscoveryServiceAdded;
115         } else {
116             if (VDBG) {
117                 ALOGD("Discover lost serviceName %s, regType %s and domain %s for %d",
118                         serviceName, regType, replyDomain, refNumber);
119             }
120             respCode = ResponseCode::ServiceDiscoveryServiceRemoved;
121         }
122         asprintf(&msg, "%d %s %s %s", refNumber, serviceName, regType, replyDomain);
123         context->mListener->sendBroadcast(respCode, msg, false);
124     }
125     free(msg);
126 }
127
128 void MDnsSdListener::Handler::stop(SocketClient *cli, int argc, char **argv, const char *str) {
129     if (argc != 3) {
130         char *msg;
131         asprintf(&msg, "Invalid number of arguments to %s", str);
132         cli->sendMsg(ResponseCode::CommandParameterError, msg, false);
133         free(msg);
134         return;
135     }
136     int requestId = atoi(argv[2]);
137     DNSServiceRef *ref = mMonitor->lookupServiceRef(requestId);
138     if (ref == NULL) {
139         if (DBG) ALOGE("%s stop used unknown requestId %d", str, requestId);
140         cli->sendMsg(ResponseCode::CommandParameterError, "Unknown requestId", false);
141         return;
142     }
143     if (VDBG) ALOGD("Stopping %s with ref %p", str, ref);
144     DNSServiceRefDeallocate(*ref);
145     mMonitor->freeServiceRef(requestId);
146     char *msg;
147     asprintf(&msg, "%s stopped", str);
148     cli->sendMsg(ResponseCode::CommandOkay, msg, false);
149     free(msg);
150 }
151
152 void MDnsSdListener::Handler::serviceRegister(SocketClient *cli, int requestId,
153         const char *interfaceName, const char *serviceName, const char *serviceType,
154         const char *domain, const char *host, int port, int txtLen, void *txtRecord) {
155     if (VDBG) {
156         ALOGD("serviceRegister(%d, %s, %s, %s, %s, %s, %d, %d, <binary>)", requestId,
157                 interfaceName, serviceName, serviceType, domain, host, port, txtLen);
158     }
159     Context *context = new Context(requestId, mListener);
160     DNSServiceRef *ref = mMonitor->allocateServiceRef(requestId, context);
161     port = htons(port);
162     if (ref == NULL) {
163         ALOGE("requestId %d already in use during register call", requestId);
164         cli->sendMsg(ResponseCode::CommandParameterError,
165                 "RequestId already in use during register call", false);
166         return;
167     }
168     DNSServiceFlags nativeFlags = 0;
169     int interfaceInt = ifaceNameToI(interfaceName);
170     DNSServiceErrorType result = DNSServiceRegister(ref, interfaceInt, nativeFlags, serviceName,
171             serviceType, domain, host, port, txtLen, txtRecord, &MDnsSdListenerRegisterCallback,
172             context);
173     if (result != kDNSServiceErr_NoError) {
174         ALOGE("service register request %d got an error from DNSServiceRegister %d", requestId,
175                 result);
176         mMonitor->freeServiceRef(requestId);
177         cli->sendMsg(ResponseCode::CommandParameterError,
178                 "serviceRegister request got an error from DNSServiceRegister", false);
179         return;
180     }
181     mMonitor->startMonitoring(requestId);
182     if (VDBG) ALOGD("serviceRegister successful");
183     cli->sendMsg(ResponseCode::CommandOkay, "serviceRegister started", false);
184     return;
185 }
186
187 void MDnsSdListenerRegisterCallback(DNSServiceRef sdRef, DNSServiceFlags flags,
188         DNSServiceErrorType errorCode, const char *serviceName, const char *regType,
189         const char *domain, void *inContext) {
190     MDnsSdListener::Context *context = reinterpret_cast<MDnsSdListener::Context *>(inContext);
191     char *msg;
192     int refNumber = context->mRefNumber;
193     if (errorCode != kDNSServiceErr_NoError) {
194         asprintf(&msg, "%d %d", refNumber, errorCode);
195         context->mListener->sendBroadcast(ResponseCode::ServiceRegistrationFailed, msg, false);
196         if (DBG) ALOGE("register failure for %d, error= %d", refNumber, errorCode);
197     } else {
198         asprintf(&msg, "%d %s", refNumber, serviceName);
199         context->mListener->sendBroadcast(ResponseCode::ServiceRegistrationSucceeded, msg, false);
200         if (VDBG) ALOGD("register succeeded for %d as %s", refNumber, serviceName);
201     }
202     free(msg);
203 }
204
205
206 void MDnsSdListener::Handler::resolveService(SocketClient *cli, int requestId,
207         const char *interfaceName, const char *serviceName, const char *regType,
208         const char *domain) {
209     if (VDBG) {
210         ALOGD("resolveService(%d, %s, %s, %s, %s)", requestId, interfaceName,
211                 serviceName, regType, domain);
212     }
213     Context *context = new Context(requestId, mListener);
214     DNSServiceRef *ref = mMonitor->allocateServiceRef(requestId, context);
215     if (ref == NULL) {
216         ALOGE("request Id %d already in use during resolve call", requestId);
217         cli->sendMsg(ResponseCode::CommandParameterError,
218                 "RequestId already in use during resolve call", false);
219         return;
220     }
221     DNSServiceFlags nativeFlags = 0;
222     int interfaceInt = ifaceNameToI(interfaceName);
223     DNSServiceErrorType result = DNSServiceResolve(ref, nativeFlags, interfaceInt, serviceName,
224             regType, domain, &MDnsSdListenerResolveCallback, context);
225     if (result != kDNSServiceErr_NoError) {
226         ALOGE("service resolve request %d got an error from DNSServiceResolve %d", requestId,
227                 result);
228         mMonitor->freeServiceRef(requestId);
229         cli->sendMsg(ResponseCode::CommandParameterError,
230                 "resolveService got an error from DNSServiceResolve", false);
231         return;
232     }
233     mMonitor->startMonitoring(requestId);
234     if (VDBG) ALOGD("resolveService successful");
235     cli->sendMsg(ResponseCode::CommandOkay, "resolveService started", false);
236     return;
237 }
238
239 void MDnsSdListenerResolveCallback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interface,
240         DNSServiceErrorType errorCode, const char *fullname, const char *hosttarget, uint16_t port,
241         uint16_t txtLen, const unsigned char *txtRecord, void *inContext) {
242     MDnsSdListener::Context *context = reinterpret_cast<MDnsSdListener::Context *>(inContext);
243     char *msg;
244     int refNumber = context->mRefNumber;
245     port = ntohs(port);
246     if (errorCode != kDNSServiceErr_NoError) {
247         asprintf(&msg, "%d %d", refNumber, errorCode);
248         context->mListener->sendBroadcast(ResponseCode::ServiceResolveFailed, msg, false);
249         if (DBG) ALOGE("resolve failure for %d, error= %d", refNumber, errorCode);
250     } else {
251         asprintf(&msg, "%d %s %s %d %d", refNumber, fullname, hosttarget, port, txtLen);
252         context->mListener->sendBroadcast(ResponseCode::ServiceResolveSuccess, msg, false);
253         if (VDBG) {
254             ALOGD("resolve succeeded for %d finding %s at %s:%d with txtLen %d",
255                     refNumber, fullname, hosttarget, port, txtLen);
256         }
257     }
258     free(msg);
259 }
260
261 void MDnsSdListener::Handler::getAddrInfo(SocketClient *cli, int requestId,
262         const char *interfaceName, uint32_t protocol, const char *hostname) {
263     if (VDBG) ALOGD("getAddrInfo(%d, %s %d, %s)", requestId, interfaceName, protocol, hostname);
264     Context *context = new Context(requestId, mListener);
265     DNSServiceRef *ref = mMonitor->allocateServiceRef(requestId, context);
266     if (ref == NULL) {
267         ALOGE("request ID %d already in use during getAddrInfo call", requestId);
268         cli->sendMsg(ResponseCode::CommandParameterError,
269                 "RequestId already in use during getAddrInfo call", false);
270         return;
271     }
272     DNSServiceFlags nativeFlags = 0;
273     int interfaceInt = ifaceNameToI(interfaceName);
274     DNSServiceErrorType result = DNSServiceGetAddrInfo(ref, nativeFlags, interfaceInt, protocol,
275             hostname, &MDnsSdListenerGetAddrInfoCallback, context);
276     if (result != kDNSServiceErr_NoError) {
277         ALOGE("getAddrInfo request %d got an error from DNSServiceGetAddrInfo %d", requestId,
278                 result);
279         mMonitor->freeServiceRef(requestId);
280         cli->sendMsg(ResponseCode::CommandParameterError,
281                 "getAddrInfo request got an error from DNSServiceGetAddrInfo", false);
282         return;
283     }
284     mMonitor->startMonitoring(requestId);
285     if (VDBG) ALOGD("getAddrInfo successful");
286     cli->sendMsg(ResponseCode::CommandOkay, "getAddrInfo started", false);
287     return;
288 }
289
290 void MDnsSdListenerGetAddrInfoCallback(DNSServiceRef sdRef, DNSServiceFlags flags,
291         uint32_t interface, DNSServiceErrorType errorCode, const char *hostname,
292         const struct sockaddr *const sa, uint32_t ttl, void *inContext) {
293     MDnsSdListener::Context *context = reinterpret_cast<MDnsSdListener::Context *>(inContext);
294     int refNumber = context->mRefNumber;
295
296     if (errorCode != kDNSServiceErr_NoError) {
297         char *msg;
298         asprintf(&msg, "%d %d", refNumber, errorCode);
299         context->mListener->sendBroadcast(ResponseCode::ServiceGetAddrInfoFailed, msg, false);
300         if (DBG) ALOGE("getAddrInfo failure for %d, error= %d", refNumber, errorCode);
301         free(msg);
302     } else {
303         char addr[INET6_ADDRSTRLEN];
304         char *msg;
305         if (sa->sa_family == AF_INET) {
306             inet_ntop(sa->sa_family, &(((struct sockaddr_in *)sa)->sin_addr), addr, sizeof(addr));
307         } else {
308             inet_ntop(sa->sa_family, &(((struct sockaddr_in6 *)sa)->sin6_addr), addr, sizeof(addr));
309         }
310         asprintf(&msg, "%d %s %d %s", refNumber, hostname, ttl, addr);
311         context->mListener->sendBroadcast(ResponseCode::ServiceGetAddrInfoSuccess, msg, false);
312         if (VDBG) {
313             ALOGD("getAddrInfo succeeded for %d: %s", refNumber, msg);
314         }
315         free(msg);
316     }
317 }
318
319 void MDnsSdListener::Handler::setHostname(SocketClient *cli, int requestId,
320         const char *hostname) {
321     if (VDBG) ALOGD("setHostname(%d, %s)", requestId, hostname);
322     Context *context = new Context(requestId, mListener);
323     DNSServiceRef *ref = mMonitor->allocateServiceRef(requestId, context);
324     if (ref == NULL) {
325         ALOGE("request Id %d already in use during setHostname call", requestId);
326         cli->sendMsg(ResponseCode::CommandParameterError,
327                 "RequestId already in use during setHostname call", false);
328         return;
329     }
330     DNSServiceFlags nativeFlags = 0;
331     DNSServiceErrorType result = DNSSetHostname(ref, nativeFlags, hostname,
332             &MDnsSdListenerSetHostnameCallback, context);
333     if (result != kDNSServiceErr_NoError) {
334         ALOGE("setHostname request %d got an error from DNSSetHostname %d", requestId, result);
335         mMonitor->freeServiceRef(requestId);
336         cli->sendMsg(ResponseCode::CommandParameterError,
337                 "setHostname got an error from DNSSetHostname", false);
338         return;
339     }
340     mMonitor->startMonitoring(requestId);
341     if (VDBG) ALOGD("setHostname successful");
342     cli->sendMsg(ResponseCode::CommandOkay, "setHostname started", false);
343     return;
344 }
345
346 void MDnsSdListenerSetHostnameCallback(DNSServiceRef sdRef, DNSServiceFlags flags,
347         DNSServiceErrorType errorCode, const char *hostname, void *inContext) {
348     MDnsSdListener::Context *context = reinterpret_cast<MDnsSdListener::Context *>(inContext);
349     char *msg;
350     int refNumber = context->mRefNumber;
351     if (errorCode != kDNSServiceErr_NoError) {
352         asprintf(&msg, "%d %d", refNumber, errorCode);
353         context->mListener->sendBroadcast(ResponseCode::ServiceSetHostnameFailed, msg, false);
354         if (DBG) ALOGE("setHostname failure for %d, error= %d", refNumber, errorCode);
355     } else {
356         asprintf(&msg, "%d %s", refNumber, hostname);
357         context->mListener->sendBroadcast(ResponseCode::ServiceSetHostnameSuccess, msg, false);
358         if (VDBG) ALOGD("setHostname succeeded for %d.  Set to %s", refNumber, hostname);
359     }
360     free(msg);
361 }
362
363
364 int MDnsSdListener::Handler::ifaceNameToI(const char *iface) {
365     return 0;
366 }
367
368 const char *MDnsSdListener::Handler::iToIfaceName(int i) {
369     return NULL;
370 }
371
372 DNSServiceFlags MDnsSdListener::Handler::iToFlags(int i) {
373     return 0;
374 }
375
376 int MDnsSdListener::Handler::flagsToI(DNSServiceFlags flags) {
377     return 0;
378 }
379
380 int MDnsSdListener::Handler::runCommand(SocketClient *cli,
381                                         int argc, char **argv) {
382     if (argc < 2) {
383         char* msg = NULL;
384         asprintf( &msg, "Invalid number of arguments to mdnssd: %i", argc);
385         ALOGW("%s", msg);
386         cli->sendMsg(ResponseCode::CommandParameterError, msg, false);
387         free(msg);
388         return -1;
389     }
390
391     char* cmd = argv[1];
392
393     if (strcmp(cmd, "discover") == 0) {
394         if (argc != 4) {
395             cli->sendMsg(ResponseCode::CommandParameterError,
396                     "Invalid number of arguments to mdnssd discover", false);
397             return 0;
398         }
399         int requestId = atoi(argv[2]);
400         char *serviceType = argv[3];
401
402         discover(cli, NULL, serviceType, NULL, requestId, 0);
403     } else if (strcmp(cmd, "stop-discover") == 0) {
404         stop(cli, argc, argv, "discover");
405     } else if (strcmp(cmd, "register") == 0) {
406         if (argc != 6) {
407             cli->sendMsg(ResponseCode::CommandParameterError,
408                     "Invalid number of arguments to mdnssd register", false);
409             return 0;
410         }
411         int requestId = atoi(argv[2]);
412         char *serviceName = argv[3];
413         char *serviceType = argv[4];
414         int port = atoi(argv[5]);
415         char *interfaceName = NULL; // will use all
416         char *domain = NULL;        // will use default
417         char *host = NULL;          // will use default hostname
418         int textLen = 0;
419         void *textRecord = NULL;
420
421         serviceRegister(cli, requestId, interfaceName, serviceName,
422                 serviceType, domain, host, port, textLen, textRecord);
423     } else if (strcmp(cmd, "stop-register") == 0) {
424         stop(cli, argc, argv, "register");
425     } else if (strcmp(cmd, "resolve") == 0) {
426         if (argc != 6) {
427             cli->sendMsg(ResponseCode::CommandParameterError,
428                     "Invalid number of arguments to mdnssd resolve", false);
429             return 0;
430         }
431         int requestId = atoi(argv[2]);
432         char *interfaceName = NULL;  // will use all
433         char *serviceName = argv[3];
434         char *regType = argv[4];
435         char *domain = argv[5];
436         resolveService(cli, requestId, interfaceName, serviceName, regType, domain);
437     } else if (strcmp(cmd, "stop-resolve") == 0) {
438         stop(cli, argc, argv, "resolve");
439     } else if (strcmp(cmd, "start-service") == 0) {
440         if (mMonitor->startService()) {
441             cli->sendMsg(ResponseCode::CommandOkay, "Service Started", false);
442         } else {
443             cli->sendMsg(ResponseCode::ServiceStartFailed, "Service already running", false);
444         }
445     } else if (strcmp(cmd, "stop-service") == 0) {
446         if (mMonitor->stopService()) {
447             cli->sendMsg(ResponseCode::CommandOkay, "Service Stopped", false);
448         } else {
449             cli->sendMsg(ResponseCode::ServiceStopFailed, "Service still in use", false);
450         }
451     } else if (strcmp(cmd, "sethostname") == 0) {
452         if (argc != 4) {
453             cli->sendMsg(ResponseCode::CommandParameterError,
454                     "Invalid number of arguments to mdnssd sethostname", false);
455             return 0;
456         }
457         int requestId = atoi(argv[2]);
458         char *hostname = argv[3];
459         setHostname(cli, requestId, hostname);
460     } else if (strcmp(cmd, "stop-sethostname") == 0) {
461         stop(cli, argc, argv, "sethostname");
462     } else if (strcmp(cmd, "getaddrinfo") == 0) {
463         if (argc != 4) {
464             cli->sendMsg(ResponseCode::CommandParameterError,
465                     "Invalid number of arguments to mdnssd getaddrinfo", false);
466             return 0;
467         }
468         int requestId = atoi(argv[2]);
469         char *hostname = argv[3];
470         char *interfaceName = NULL;  // default
471         int protocol = 0;            // intelligient heuristic (both v4 + v6)
472         getAddrInfo(cli, requestId, interfaceName, protocol, hostname);
473     } else if (strcmp(cmd, "stop-getaddrinfo") == 0) {
474         stop(cli, argc, argv, "getaddrinfo");
475     } else {
476         if (VDBG) ALOGE("Unknown cmd %s", cmd);
477         cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown mdnssd cmd", false);
478         return 0;
479     }
480     return 0;
481 }
482
483 MDnsSdListener::Monitor::Monitor() {
484     mHead = NULL;
485     pthread_mutex_init(&mHeadMutex, NULL);
486     socketpair(AF_LOCAL, SOCK_STREAM, 0, mCtrlSocketPair);
487     pthread_create(&mThread, NULL, MDnsSdListener::Monitor::threadStart, this);
488 }
489
490 void *MDnsSdListener::Monitor::threadStart(void *obj) {
491     Monitor *monitor = reinterpret_cast<Monitor *>(obj);
492
493     monitor->run();
494     delete monitor;
495     pthread_exit(NULL);
496     return NULL;
497 }
498
499 int MDnsSdListener::Monitor::startService() {
500     int result = 0;
501     char property_value[PROPERTY_VALUE_MAX];
502     pthread_mutex_lock(&mHeadMutex);
503     property_get(MDNS_SERVICE_STATUS, property_value, "");
504     if (strcmp("running", property_value) != 0) {
505         ALOGD("Starting MDNSD");
506         property_set("ctl.start", MDNS_SERVICE_NAME);
507         wait_for_property(MDNS_SERVICE_STATUS, "running", 5);
508         result = -1;
509     } else {
510         result = 0;
511     }
512     pthread_mutex_unlock(&mHeadMutex);
513     return result;
514 }
515
516 int MDnsSdListener::Monitor::stopService() {
517     int result = 0;
518     pthread_mutex_lock(&mHeadMutex);
519     if (mHead == NULL) {
520         ALOGD("Stopping MDNSD");
521         property_set("ctl.stop", MDNS_SERVICE_NAME);
522         wait_for_property(MDNS_SERVICE_STATUS, "stopped", 5);
523         result = -1;
524     } else {
525         result = 0;
526     }
527     pthread_mutex_unlock(&mHeadMutex);
528     return result;
529 }
530
531 void MDnsSdListener::Monitor::run() {
532     int pollCount = 1;
533     mPollSize = 10;
534
535     mPollFds = (struct pollfd *)calloc(sizeof(struct pollfd), mPollSize);
536     mPollRefs = (DNSServiceRef **)calloc(sizeof(DNSServiceRef *), mPollSize);
537
538     mPollFds[0].fd = mCtrlSocketPair[0];
539     mPollFds[0].events = POLLIN;
540
541     if (VDBG) ALOGD("MDnsSdListener starting to monitor");
542     while (1) {
543         if (VDBG) ALOGD("Going to poll with pollCount %d", pollCount);
544         int pollResults = poll(mPollFds, pollCount, 10000000);
545         if (pollResults < 0) {
546             ALOGE("Error in poll - got %d", errno);
547         } else if (pollResults > 0) {
548             if (VDBG) ALOGD("Monitor poll got data pollCount = %d, %d", pollCount, pollResults);
549             for(int i = 1; i < pollCount; i++) {
550                 if (mPollFds[i].revents != 0) {
551                     if (VDBG) {
552                         ALOGD("Monitor found [%d].revents = %d - calling ProcessResults",
553                                 i, mPollFds[i].revents);
554                     }
555                     DNSServiceProcessResult(*(mPollRefs[i]));
556                     mPollFds[i].revents = 0;
557                 }
558             }
559             if (VDBG) ALOGD("controlSocket shows revent= %d", mPollFds[0].revents);
560             switch (mPollFds[0].revents) {
561                 case POLLIN: {
562                     char readBuf[2];
563                     read(mCtrlSocketPair[0], &readBuf, 1);
564                     if (DBG) ALOGD("MDnsSdListener::Monitor got %c", readBuf[0]);
565                     if (memcmp(RESCAN, readBuf, 1) == 0) {
566                         pollCount = rescan();
567                     }
568                 }
569             }
570             mPollFds[0].revents = 0;
571         } else {
572             if (VDBG) ALOGD("MDnsSdListener::Monitor poll timed out");
573         }
574     }
575     free(mPollFds);
576     free(mPollRefs);
577 }
578
579 #define DBG_RESCAN 0
580
581 int MDnsSdListener::Monitor::rescan() {
582 // rescan the list from mHead and make new pollfds and serviceRefs
583     if (VDBG) {
584         ALOGD("MDnsSdListener::Monitor poll rescanning - size=%d, live=%d", mPollSize, mLiveCount);
585     }
586     int count = 0;
587     pthread_mutex_lock(&mHeadMutex);
588     Element **prevPtr = &mHead;
589     int i = 1;
590     if (mPollSize <= mLiveCount) {
591         mPollSize = mLiveCount + 5;
592         free(mPollFds);
593         free(mPollRefs);
594         mPollFds = (struct pollfd *)calloc(sizeof(struct pollfd), mPollSize);
595         mPollRefs = (DNSServiceRef **)calloc(sizeof(DNSServiceRef *), mPollSize);
596     } else {
597         memset(mPollFds, sizeof(struct pollfd) * mPollSize, 0);
598         memset(mPollRefs, sizeof(DNSServiceRef *) * mPollSize, 0);
599     }
600     mPollFds[0].fd = mCtrlSocketPair[0];
601     mPollFds[0].events = POLLIN;
602     if (DBG_RESCAN) ALOGD("mHead = %p", mHead);
603     while (*prevPtr != NULL) {
604         if (DBG_RESCAN) ALOGD("checking %p, mReady = %d", *prevPtr, (*prevPtr)->mReady);
605         if ((*prevPtr)->mReady == 1) {
606             int fd = DNSServiceRefSockFD((*prevPtr)->mRef);
607             if (fd != -1) {
608                 if (DBG_RESCAN) ALOGD("  adding FD %d", fd);
609                 mPollFds[i].fd = fd;
610                 mPollFds[i].events = POLLIN;
611                 mPollRefs[i] = &((*prevPtr)->mRef);
612                 i++;
613             } else {
614                 ALOGE("Error retreving socket FD for live ServiceRef");
615             }
616             prevPtr = &((*prevPtr)->mNext); // advance to the next element
617         } else if ((*prevPtr)->mReady == -1) {
618             if (DBG_RESCAN) ALOGD("  removing %p from  play", *prevPtr);
619             Element *cur = *prevPtr;
620             *prevPtr = (cur)->mNext; // change our notion of this element and don't advance
621             delete cur;
622         }
623     }
624     pthread_mutex_unlock(&mHeadMutex);
625     return i;
626 }
627
628 DNSServiceRef *MDnsSdListener::Monitor::allocateServiceRef(int id, Context *context) {
629     if (lookupServiceRef(id) != NULL) {
630         delete(context);
631         return NULL;
632     }
633     Element *e = new Element(id, context);
634     pthread_mutex_lock(&mHeadMutex);
635     e->mNext = mHead;
636     mHead = e;
637     pthread_mutex_unlock(&mHeadMutex);
638     return &(e->mRef);
639 }
640
641 DNSServiceRef *MDnsSdListener::Monitor::lookupServiceRef(int id) {
642     pthread_mutex_lock(&mHeadMutex);
643     Element *cur = mHead;
644     while (cur != NULL) {
645         if (cur->mId == id) {
646             DNSServiceRef *result = &(cur->mRef);
647             pthread_mutex_unlock(&mHeadMutex);
648             return result;
649         }
650         cur = cur->mNext;
651     }
652     pthread_mutex_unlock(&mHeadMutex);
653     return NULL;
654 }
655
656 void MDnsSdListener::Monitor::startMonitoring(int id) {
657     if (VDBG) ALOGD("startMonitoring %d", id);
658     pthread_mutex_lock(&mHeadMutex);
659     Element *cur = mHead;
660     while (cur != NULL) {
661         if (cur->mId == id) {
662             if (DBG_RESCAN) ALOGD("marking %p as ready to be added", cur);
663             mLiveCount++;
664             cur->mReady = 1;
665             pthread_mutex_unlock(&mHeadMutex);
666             write(mCtrlSocketPair[1], RESCAN, 1);  // trigger a rescan for a fresh poll
667             if (VDBG) ALOGD("triggering rescan");
668             return;
669         }
670         cur = cur->mNext;
671     }
672     pthread_mutex_unlock(&mHeadMutex);
673 }
674
675 #define NAP_TIME 200  // 200 ms between polls
676 static int wait_for_property(const char *name, const char *desired_value, int maxwait)
677 {
678     char value[PROPERTY_VALUE_MAX] = {'\0'};
679     int maxnaps = (maxwait * 1000) / NAP_TIME;
680
681     if (maxnaps < 1) {
682         maxnaps = 1;
683     }
684
685     while (maxnaps-- > 0) {
686         usleep(NAP_TIME * 1000);
687         if (property_get(name, value, NULL)) {
688             if (desired_value == NULL || strcmp(value, desired_value) == 0) {
689                 return 0;
690             }
691         }
692     }
693     return -1; /* failure */
694 }
695
696 void MDnsSdListener::Monitor::freeServiceRef(int id) {
697     if (VDBG) ALOGD("freeServiceRef %d", id);
698     pthread_mutex_lock(&mHeadMutex);
699     Element **prevPtr = &mHead;
700     Element *cur;
701     while (*prevPtr != NULL) {
702         cur = *prevPtr;
703         if (cur->mId == id) {
704             if (DBG_RESCAN) ALOGD("marking %p as ready to be removed", cur);
705             mLiveCount--;
706             if (cur->mReady == 1) {
707                 cur->mReady = -1; // tell poll thread to delete
708                 write(mCtrlSocketPair[1], RESCAN, 1); // trigger a rescan for a fresh poll
709                 if (VDBG) ALOGD("triggering rescan");
710             } else {
711                 *prevPtr = cur->mNext;
712                 delete cur;
713             }
714             pthread_mutex_unlock(&mHeadMutex);
715             return;
716         }
717         prevPtr = &(cur->mNext);
718     }
719     pthread_mutex_unlock(&mHeadMutex);
720 }