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