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