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