• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
MDnsSdListener()44 MDnsSdListener::MDnsSdListener() :
45                  FrameworkListener("mdns", true) {
46     Monitor *m = new Monitor();
47     registerCmd(new Handler(m, this));
48 }
49 
Handler(Monitor * m,MDnsSdListener * listener)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 
~Handler()57 MDnsSdListener::Handler::~Handler() {}
58 
discover(SocketClient * cli,const char * iface,const char * regType,const char * domain,const int requestId,const int requestFlags)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 
MDnsSdListenerDiscoverCallback(DNSServiceRef,DNSServiceFlags flags,uint32_t,DNSServiceErrorType errorCode,const char * serviceName,const char * regType,const char * replyDomain,void * inContext)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 
stop(SocketClient * cli,int argc,char ** argv,const char * str)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 
serviceRegister(SocketClient * cli,int requestId,const char * interfaceName,const char * serviceName,const char * serviceType,const char * domain,const char * host,int port,int txtLen,void * txtRecord)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 
MDnsSdListenerRegisterCallback(DNSServiceRef,DNSServiceFlags,DNSServiceErrorType errorCode,const char * serviceName,const char *,const char *,void * inContext)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 
resolveService(SocketClient * cli,int requestId,const char * interfaceName,const char * serviceName,const char * regType,const char * domain)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 
MDnsSdListenerResolveCallback(DNSServiceRef,DNSServiceFlags,uint32_t,DNSServiceErrorType errorCode,const char * fullname,const char * hosttarget,uint16_t port,uint16_t txtLen,const unsigned char *,void * inContext)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 
getAddrInfo(SocketClient * cli,int requestId,const char * interfaceName,uint32_t protocol,const char * hostname)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 
MDnsSdListenerGetAddrInfoCallback(DNSServiceRef,DNSServiceFlags,uint32_t,DNSServiceErrorType errorCode,const char * hostname,const struct sockaddr * const sa,uint32_t ttl,void * inContext)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 
setHostname(SocketClient * cli,int requestId,const char * hostname)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 
MDnsSdListenerSetHostnameCallback(DNSServiceRef,DNSServiceFlags,DNSServiceErrorType errorCode,const char * hostname,void * inContext)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 
ifaceNameToI(const char *)377 int MDnsSdListener::Handler::ifaceNameToI(const char * /* iface */) {
378     return 0;
379 }
380 
iToIfaceName(int)381 const char *MDnsSdListener::Handler::iToIfaceName(int /* i */) {
382     return NULL;
383 }
384 
iToFlags(int)385 DNSServiceFlags MDnsSdListener::Handler::iToFlags(int /* i */) {
386     return 0;
387 }
388 
flagsToI(DNSServiceFlags)389 int MDnsSdListener::Handler::flagsToI(DNSServiceFlags /* flags */) {
390     return 0;
391 }
392 
runCommand(SocketClient * cli,int argc,char ** argv)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 
Monitor()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 
threadStart(void * obj)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
wait_for_property(const char * name,const char * desired_value,int maxwait)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 
startService()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 
stopService()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 
run()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 
rescan()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 
allocateServiceRef(int id,Context * context)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 
lookupServiceRef(int id)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 
startMonitoring(int id)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 
freeServiceRef(int id)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