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