123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756 |
- /*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #include "MDnsSdListener.h"
- #include <arpa/inet.h>
- #include <dirent.h>
- #include <errno.h>
- #include <linux/if.h>
- #include <netdb.h>
- #include <netinet/in.h>
- #include <pthread.h>
- #include <resolv.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/poll.h>
- #include <sys/socket.h>
- #include <sys/types.h>
- #define LOG_TAG "MDnsDS"
- #define DBG 1
- #define VDBG 1
- #include <cutils/properties.h>
- #include <log/log.h>
- #include <netdutils/ResponseCode.h>
- #include <netdutils/ThreadUtil.h>
- #include <sysutils/SocketClient.h>
- #define MDNS_SERVICE_NAME "mdnsd"
- #define MDNS_SERVICE_STATUS "init.svc.mdnsd"
- #define CEIL(x, y) (((x) + (y) - 1) / (y))
- constexpr char RESCAN[] = "1";
- using android::netdutils::ResponseCode;
- MDnsSdListener::MDnsSdListener() : FrameworkListener(SOCKET_NAME, true) {
- Monitor *m = new Monitor();
- registerCmd(new Handler(m, this));
- }
- MDnsSdListener::Handler::Handler(Monitor *m, MDnsSdListener *listener) :
- NetdCommand("mdnssd") {
- if (DBG) ALOGD("MDnsSdListener::Hander starting up");
- mMonitor = m;
- mListener = listener;
- }
- MDnsSdListener::Handler::~Handler() {}
- void MDnsSdListener::Handler::discover(SocketClient *cli,
- const char *iface,
- const char *regType,
- const char *domain,
- const int requestId,
- const int requestFlags) {
- if (VDBG) {
- ALOGD("discover(%s, %s, %s, %d, %d)", iface, regType, domain, requestId,
- requestFlags);
- }
- Context *context = new Context(requestId, mListener);
- DNSServiceRef *ref = mMonitor->allocateServiceRef(requestId, context);
- if (ref == nullptr) {
- ALOGE("requestId %d already in use during discover call", requestId);
- cli->sendMsg(ResponseCode::CommandParameterError,
- "RequestId already in use during discover call", false);
- return;
- }
- if (VDBG) ALOGD("using ref %p", ref);
- DNSServiceFlags nativeFlags = iToFlags(requestFlags);
- int interfaceInt = ifaceNameToI(iface);
- DNSServiceErrorType result = DNSServiceBrowse(ref, nativeFlags, interfaceInt, regType,
- domain, &MDnsSdListenerDiscoverCallback, context);
- if (result != kDNSServiceErr_NoError) {
- ALOGE("Discover request %d got an error from DNSServiceBrowse %d", requestId, result);
- mMonitor->freeServiceRef(requestId);
- cli->sendMsg(ResponseCode::CommandParameterError,
- "Discover request got an error from DNSServiceBrowse", false);
- return;
- }
- mMonitor->startMonitoring(requestId);
- if (VDBG) ALOGD("discover successful");
- cli->sendMsg(ResponseCode::CommandOkay, "Discover operation started", false);
- return;
- }
- void MDnsSdListenerDiscoverCallback(DNSServiceRef /* sdRef */, DNSServiceFlags flags,
- uint32_t /* interfaceIndex */, DNSServiceErrorType errorCode, const char *serviceName,
- const char *regType, const char *replyDomain, void *inContext) {
- MDnsSdListener::Context *context = reinterpret_cast<MDnsSdListener::Context *>(inContext);
- char *msg;
- int refNumber = context->mRefNumber;
- if (errorCode != kDNSServiceErr_NoError) {
- asprintf(&msg, "%d %d", refNumber, errorCode);
- context->mListener->sendBroadcast(ResponseCode::ServiceDiscoveryFailed, msg, false);
- if (DBG) ALOGE("discover failure for %d, error= %d", refNumber, errorCode);
- } else {
- int respCode;
- char *quotedServiceName = SocketClient::quoteArg(serviceName);
- if (flags & kDNSServiceFlagsAdd) {
- if (VDBG) {
- ALOGD("Discover found new serviceName %s, regType %s and domain %s for %d",
- serviceName, regType, replyDomain, refNumber);
- }
- respCode = ResponseCode::ServiceDiscoveryServiceAdded;
- } else {
- if (VDBG) {
- ALOGD("Discover lost serviceName %s, regType %s and domain %s for %d",
- serviceName, regType, replyDomain, refNumber);
- }
- respCode = ResponseCode::ServiceDiscoveryServiceRemoved;
- }
- asprintf(&msg, "%d %s %s %s", refNumber, quotedServiceName, regType, replyDomain);
- free(quotedServiceName);
- context->mListener->sendBroadcast(respCode, msg, false);
- }
- free(msg);
- }
- void MDnsSdListener::Handler::stop(SocketClient *cli, int argc, char **argv, const char *str) {
- if (argc != 3) {
- char *msg;
- asprintf(&msg, "Invalid number of arguments to %s", str);
- cli->sendMsg(ResponseCode::CommandParameterError, msg, false);
- free(msg);
- return;
- }
- int requestId = strtol(argv[2], nullptr, 10);
- DNSServiceRef *ref = mMonitor->lookupServiceRef(requestId);
- if (ref == nullptr) {
- if (DBG) ALOGE("%s stop used unknown requestId %d", str, requestId);
- cli->sendMsg(ResponseCode::CommandParameterError, "Unknown requestId", false);
- return;
- }
- if (VDBG) ALOGD("Stopping %s with ref %p", str, ref);
- mMonitor->deallocateServiceRef(ref);
- mMonitor->freeServiceRef(requestId);
- char *msg;
- asprintf(&msg, "%s stopped", str);
- cli->sendMsg(ResponseCode::CommandOkay, msg, false);
- free(msg);
- }
- void MDnsSdListener::Handler::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) {
- if (VDBG) {
- ALOGD("serviceRegister(%d, %s, %s, %s, %s, %s, %d, %d, <binary>)", requestId,
- interfaceName, serviceName, serviceType, domain, host, port, txtLen);
- }
- Context *context = new Context(requestId, mListener);
- DNSServiceRef *ref = mMonitor->allocateServiceRef(requestId, context);
- port = htons(port);
- if (ref == nullptr) {
- ALOGE("requestId %d already in use during register call", requestId);
- cli->sendMsg(ResponseCode::CommandParameterError,
- "RequestId already in use during register call", false);
- return;
- }
- DNSServiceFlags nativeFlags = 0;
- int interfaceInt = ifaceNameToI(interfaceName);
- DNSServiceErrorType result = DNSServiceRegister(ref, interfaceInt, nativeFlags, serviceName,
- serviceType, domain, host, port, txtLen, txtRecord, &MDnsSdListenerRegisterCallback,
- context);
- if (result != kDNSServiceErr_NoError) {
- ALOGE("service register request %d got an error from DNSServiceRegister %d", requestId,
- result);
- mMonitor->freeServiceRef(requestId);
- cli->sendMsg(ResponseCode::CommandParameterError,
- "serviceRegister request got an error from DNSServiceRegister", false);
- return;
- }
- mMonitor->startMonitoring(requestId);
- if (VDBG) ALOGD("serviceRegister successful");
- cli->sendMsg(ResponseCode::CommandOkay, "serviceRegister started", false);
- return;
- }
- void MDnsSdListenerRegisterCallback(DNSServiceRef /* sdRef */, DNSServiceFlags /* flags */,
- DNSServiceErrorType errorCode, const char *serviceName, const char * /* regType */,
- const char * /* domain */, void *inContext) {
- MDnsSdListener::Context *context = reinterpret_cast<MDnsSdListener::Context *>(inContext);
- char *msg;
- int refNumber = context->mRefNumber;
- if (errorCode != kDNSServiceErr_NoError) {
- asprintf(&msg, "%d %d", refNumber, errorCode);
- context->mListener->sendBroadcast(ResponseCode::ServiceRegistrationFailed, msg, false);
- if (DBG) ALOGE("register failure for %d, error= %d", refNumber, errorCode);
- } else {
- char *quotedServiceName = SocketClient::quoteArg(serviceName);
- asprintf(&msg, "%d %s", refNumber, quotedServiceName);
- free(quotedServiceName);
- context->mListener->sendBroadcast(ResponseCode::ServiceRegistrationSucceeded, msg, false);
- if (VDBG) ALOGD("register succeeded for %d as %s", refNumber, serviceName);
- }
- free(msg);
- }
- void MDnsSdListener::Handler::resolveService(SocketClient *cli, int requestId,
- const char *interfaceName, const char *serviceName, const char *regType,
- const char *domain) {
- if (VDBG) {
- ALOGD("resolveService(%d, %s, %s, %s, %s)", requestId, interfaceName,
- serviceName, regType, domain);
- }
- Context *context = new Context(requestId, mListener);
- DNSServiceRef *ref = mMonitor->allocateServiceRef(requestId, context);
- if (ref == nullptr) {
- ALOGE("request Id %d already in use during resolve call", requestId);
- cli->sendMsg(ResponseCode::CommandParameterError,
- "RequestId already in use during resolve call", false);
- return;
- }
- DNSServiceFlags nativeFlags = 0;
- int interfaceInt = ifaceNameToI(interfaceName);
- DNSServiceErrorType result = DNSServiceResolve(ref, nativeFlags, interfaceInt, serviceName,
- regType, domain, &MDnsSdListenerResolveCallback, context);
- if (result != kDNSServiceErr_NoError) {
- ALOGE("service resolve request %d got an error from DNSServiceResolve %d", requestId,
- result);
- mMonitor->freeServiceRef(requestId);
- cli->sendMsg(ResponseCode::CommandParameterError,
- "resolveService got an error from DNSServiceResolve", false);
- return;
- }
- mMonitor->startMonitoring(requestId);
- if (VDBG) ALOGD("resolveService successful");
- cli->sendMsg(ResponseCode::CommandOkay, "resolveService started", false);
- return;
- }
- void MDnsSdListenerResolveCallback(DNSServiceRef /* sdRef */, DNSServiceFlags /* flags */,
- uint32_t /* interface */, DNSServiceErrorType errorCode, const char *fullname,
- const char *hosttarget, uint16_t port, uint16_t txtLen,
- const unsigned char *txtRecord , void *inContext) {
- MDnsSdListener::Context *context = reinterpret_cast<MDnsSdListener::Context *>(inContext);
- char *msg;
- int refNumber = context->mRefNumber;
- port = ntohs(port);
- if (errorCode != kDNSServiceErr_NoError) {
- asprintf(&msg, "%d %d", refNumber, errorCode);
- context->mListener->sendBroadcast(ResponseCode::ServiceResolveFailed, msg, false);
- if (DBG) ALOGE("resolve failure for %d, error= %d", refNumber, errorCode);
- } else {
- char *quotedFullName = SocketClient::quoteArg(fullname);
- char *quotedHostTarget = SocketClient::quoteArg(hosttarget);
- // Base 64 encodes every 3 bytes into 4 characters, but then adds padding to the next
- // multiple of 4 and a \0
- size_t dstLength = CEIL(CEIL(txtLen * 4, 3), 4) * 4 + 1;
- char *dst = (char *)malloc(dstLength);
- b64_ntop(txtRecord, txtLen, dst, dstLength);
- asprintf(&msg, "%d %s %s %d %d \"%s\"", refNumber, quotedFullName, quotedHostTarget, port,
- txtLen, dst);
- free(quotedFullName);
- free(quotedHostTarget);
- free(dst);
- context->mListener->sendBroadcast(ResponseCode::ServiceResolveSuccess, msg, false);
- if (VDBG) {
- ALOGD("resolve succeeded for %d finding %s at %s:%d with txtLen %d",
- refNumber, fullname, hosttarget, port, txtLen);
- }
- }
- free(msg);
- }
- void MDnsSdListener::Handler::getAddrInfo(SocketClient *cli, int requestId,
- const char *interfaceName, uint32_t protocol, const char *hostname) {
- if (VDBG) ALOGD("getAddrInfo(%d, %s %d, %s)", requestId, interfaceName, protocol, hostname);
- Context *context = new Context(requestId, mListener);
- DNSServiceRef *ref = mMonitor->allocateServiceRef(requestId, context);
- if (ref == nullptr) {
- ALOGE("request ID %d already in use during getAddrInfo call", requestId);
- cli->sendMsg(ResponseCode::CommandParameterError,
- "RequestId already in use during getAddrInfo call", false);
- return;
- }
- DNSServiceFlags nativeFlags = 0;
- int interfaceInt = ifaceNameToI(interfaceName);
- DNSServiceErrorType result = DNSServiceGetAddrInfo(ref, nativeFlags, interfaceInt, protocol,
- hostname, &MDnsSdListenerGetAddrInfoCallback, context);
- if (result != kDNSServiceErr_NoError) {
- ALOGE("getAddrInfo request %d got an error from DNSServiceGetAddrInfo %d", requestId,
- result);
- mMonitor->freeServiceRef(requestId);
- cli->sendMsg(ResponseCode::CommandParameterError,
- "getAddrInfo request got an error from DNSServiceGetAddrInfo", false);
- return;
- }
- mMonitor->startMonitoring(requestId);
- if (VDBG) ALOGD("getAddrInfo successful");
- cli->sendMsg(ResponseCode::CommandOkay, "getAddrInfo started", false);
- return;
- }
- void MDnsSdListenerGetAddrInfoCallback(DNSServiceRef /* sdRef */, DNSServiceFlags /* flags */,
- uint32_t /* interface */, DNSServiceErrorType errorCode, const char *hostname,
- const struct sockaddr *const sa, uint32_t ttl, void *inContext) {
- MDnsSdListener::Context *context = reinterpret_cast<MDnsSdListener::Context *>(inContext);
- int refNumber = context->mRefNumber;
- if (errorCode != kDNSServiceErr_NoError) {
- char *msg;
- asprintf(&msg, "%d %d", refNumber, errorCode);
- context->mListener->sendBroadcast(ResponseCode::ServiceGetAddrInfoFailed, msg, false);
- if (DBG) ALOGE("getAddrInfo failure for %d, error= %d", refNumber, errorCode);
- free(msg);
- } else {
- char addr[INET6_ADDRSTRLEN];
- char *msg;
- char *quotedHostname = SocketClient::quoteArg(hostname);
- if (sa->sa_family == AF_INET) {
- inet_ntop(sa->sa_family, &(((struct sockaddr_in *)sa)->sin_addr), addr, sizeof(addr));
- } else {
- inet_ntop(sa->sa_family, &(((struct sockaddr_in6 *)sa)->sin6_addr), addr, sizeof(addr));
- }
- asprintf(&msg, "%d %s %d %s", refNumber, quotedHostname, ttl, addr);
- free(quotedHostname);
- context->mListener->sendBroadcast(ResponseCode::ServiceGetAddrInfoSuccess, msg, false);
- if (VDBG) {
- ALOGD("getAddrInfo succeeded for %d: %s", refNumber, msg);
- }
- free(msg);
- }
- }
- void MDnsSdListener::Handler::setHostname(SocketClient *cli, int requestId,
- const char *hostname) {
- if (VDBG) ALOGD("setHostname(%d, %s)", requestId, hostname);
- Context *context = new Context(requestId, mListener);
- DNSServiceRef *ref = mMonitor->allocateServiceRef(requestId, context);
- if (ref == nullptr) {
- ALOGE("request Id %d already in use during setHostname call", requestId);
- cli->sendMsg(ResponseCode::CommandParameterError,
- "RequestId already in use during setHostname call", false);
- return;
- }
- DNSServiceFlags nativeFlags = 0;
- DNSServiceErrorType result = DNSSetHostname(ref, nativeFlags, hostname,
- &MDnsSdListenerSetHostnameCallback, context);
- if (result != kDNSServiceErr_NoError) {
- ALOGE("setHostname request %d got an error from DNSSetHostname %d", requestId, result);
- mMonitor->freeServiceRef(requestId);
- cli->sendMsg(ResponseCode::CommandParameterError,
- "setHostname got an error from DNSSetHostname", false);
- return;
- }
- mMonitor->startMonitoring(requestId);
- if (VDBG) ALOGD("setHostname successful");
- cli->sendMsg(ResponseCode::CommandOkay, "setHostname started", false);
- return;
- }
- void MDnsSdListenerSetHostnameCallback(DNSServiceRef /* sdRef */, DNSServiceFlags /* flags */,
- DNSServiceErrorType errorCode, const char *hostname, void *inContext) {
- MDnsSdListener::Context *context = reinterpret_cast<MDnsSdListener::Context *>(inContext);
- char *msg;
- int refNumber = context->mRefNumber;
- if (errorCode != kDNSServiceErr_NoError) {
- asprintf(&msg, "%d %d", refNumber, errorCode);
- context->mListener->sendBroadcast(ResponseCode::ServiceSetHostnameFailed, msg, false);
- if (DBG) ALOGE("setHostname failure for %d, error= %d", refNumber, errorCode);
- } else {
- char *quotedHostname = SocketClient::quoteArg(hostname);
- asprintf(&msg, "%d %s", refNumber, quotedHostname);
- free(quotedHostname);
- context->mListener->sendBroadcast(ResponseCode::ServiceSetHostnameSuccess, msg, false);
- if (VDBG) ALOGD("setHostname succeeded for %d. Set to %s", refNumber, hostname);
- }
- free(msg);
- }
- int MDnsSdListener::Handler::ifaceNameToI(const char * /* iface */) {
- return 0;
- }
- const char *MDnsSdListener::Handler::iToIfaceName(int /* i */) {
- return nullptr;
- }
- DNSServiceFlags MDnsSdListener::Handler::iToFlags(int /* i */) {
- return 0;
- }
- int MDnsSdListener::Handler::flagsToI(DNSServiceFlags /* flags */) {
- return 0;
- }
- int MDnsSdListener::Handler::runCommand(SocketClient *cli,
- int argc, char **argv) {
- if (argc < 2) {
- char* msg = nullptr;
- asprintf( &msg, "Invalid number of arguments to mdnssd: %i", argc);
- ALOGW("%s", msg);
- cli->sendMsg(ResponseCode::CommandParameterError, msg, false);
- free(msg);
- return -1;
- }
- char* cmd = argv[1];
- if (strcmp(cmd, "discover") == 0) {
- if (argc != 4) {
- cli->sendMsg(ResponseCode::CommandParameterError,
- "Invalid number of arguments to mdnssd discover", false);
- return 0;
- }
- int requestId = strtol(argv[2], nullptr, 10);
- char *serviceType = argv[3];
- discover(cli, nullptr, serviceType, nullptr, requestId, 0);
- } else if (strcmp(cmd, "stop-discover") == 0) {
- stop(cli, argc, argv, "discover");
- } else if (strcmp(cmd, "register") == 0) {
- if (argc != 7) {
- cli->sendMsg(ResponseCode::CommandParameterError,
- "Invalid number of arguments to mdnssd register", false);
- return 0;
- }
- int requestId = atoi(argv[2]);
- char *serviceName = argv[3];
- char *serviceType = argv[4];
- int port = strtol(argv[5], nullptr, 10);
- char *interfaceName = nullptr; // will use all
- char *domain = nullptr; // will use default
- char *host = nullptr; // will use default hostname
- // TXT record length is <= 1300, see NsdServiceInfo.setAttribute
- char dst[1300];
- int length = b64_pton(argv[6], (u_char *)dst, 1300);
- if (length < 0) {
- cli->sendMsg(ResponseCode::CommandParameterError,
- "Could not decode txtRecord", false);
- return 0;
- }
- serviceRegister(cli, requestId, interfaceName, serviceName,
- serviceType, domain, host, port, length, dst);
- } else if (strcmp(cmd, "stop-register") == 0) {
- stop(cli, argc, argv, "register");
- } else if (strcmp(cmd, "resolve") == 0) {
- if (argc != 6) {
- cli->sendMsg(ResponseCode::CommandParameterError,
- "Invalid number of arguments to mdnssd resolve", false);
- return 0;
- }
- int requestId = atoi(argv[2]);
- char *interfaceName = nullptr; // will use all
- char *serviceName = argv[3];
- char *regType = argv[4];
- char *domain = argv[5];
- resolveService(cli, requestId, interfaceName, serviceName, regType, domain);
- } else if (strcmp(cmd, "stop-resolve") == 0) {
- stop(cli, argc, argv, "resolve");
- } else if (strcmp(cmd, "start-service") == 0) {
- if (mMonitor->startService()) {
- cli->sendMsg(ResponseCode::CommandOkay, "Service Started", false);
- } else {
- cli->sendMsg(ResponseCode::ServiceStartFailed, "Service already running", false);
- }
- } else if (strcmp(cmd, "stop-service") == 0) {
- if (mMonitor->stopService()) {
- cli->sendMsg(ResponseCode::CommandOkay, "Service Stopped", false);
- } else {
- cli->sendMsg(ResponseCode::ServiceStopFailed, "Service still in use", false);
- }
- } else if (strcmp(cmd, "sethostname") == 0) {
- if (argc != 4) {
- cli->sendMsg(ResponseCode::CommandParameterError,
- "Invalid number of arguments to mdnssd sethostname", false);
- return 0;
- }
- int requestId = strtol(argv[2], nullptr, 10);
- char *hostname = argv[3];
- setHostname(cli, requestId, hostname);
- } else if (strcmp(cmd, "stop-sethostname") == 0) {
- stop(cli, argc, argv, "sethostname");
- } else if (strcmp(cmd, "getaddrinfo") == 0) {
- if (argc != 4) {
- cli->sendMsg(ResponseCode::CommandParameterError,
- "Invalid number of arguments to mdnssd getaddrinfo", false);
- return 0;
- }
- int requestId = atoi(argv[2]);
- char *hostname = argv[3];
- char *interfaceName = nullptr; // default
- int protocol = 0; // intelligient heuristic (both v4 + v6)
- getAddrInfo(cli, requestId, interfaceName, protocol, hostname);
- } else if (strcmp(cmd, "stop-getaddrinfo") == 0) {
- stop(cli, argc, argv, "getaddrinfo");
- } else {
- if (VDBG) ALOGE("Unknown cmd %s", cmd);
- cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown mdnssd cmd", false);
- return 0;
- }
- return 0;
- }
- MDnsSdListener::Monitor::Monitor() {
- mHead = nullptr;
- mLiveCount = 0;
- mPollFds = nullptr;
- mPollRefs = nullptr;
- mPollSize = 10;
- socketpair(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, mCtrlSocketPair);
- const int rval = ::android::netdutils::threadLaunch(this);
- if (rval != 0) {
- ALOGW("Error spawning monitor thread: %s (%d)", strerror(-rval), -rval);
- }
- }
- #define NAP_TIME 200 // 200 ms between polls
- static int wait_for_property(const char *name, const char *desired_value, int maxwait)
- {
- char value[PROPERTY_VALUE_MAX] = {'\0'};
- int maxnaps = (maxwait * 1000) / NAP_TIME;
- if (maxnaps < 1) {
- maxnaps = 1;
- }
- while (maxnaps-- > 0) {
- usleep(NAP_TIME * 1000);
- if (property_get(name, value, nullptr)) {
- if (desired_value == nullptr || strcmp(value, desired_value) == 0) {
- return 0;
- }
- }
- }
- return -1; /* failure */
- }
- int MDnsSdListener::Monitor::startService() {
- char property_value[PROPERTY_VALUE_MAX];
- std::lock_guard guard(mMutex);
- property_get(MDNS_SERVICE_STATUS, property_value, "");
- if (strcmp("running", property_value) != 0) {
- ALOGD("Starting MDNSD");
- property_set("ctl.start", MDNS_SERVICE_NAME);
- wait_for_property(MDNS_SERVICE_STATUS, "running", 5);
- return -1;
- }
- return 0;
- }
- int MDnsSdListener::Monitor::stopService() {
- std::lock_guard guard(mMutex);
- if (mHead == nullptr) {
- ALOGD("Stopping MDNSD");
- property_set("ctl.stop", MDNS_SERVICE_NAME);
- wait_for_property(MDNS_SERVICE_STATUS, "stopped", 5);
- return -1;
- }
- return 0;
- }
- void MDnsSdListener::Monitor::run() {
- int pollCount = 1;
- mPollFds = (struct pollfd *)calloc(sizeof(struct pollfd), mPollSize);
- mPollRefs = (DNSServiceRef **)calloc(sizeof(DNSServiceRef *), mPollSize);
- LOG_ALWAYS_FATAL_IF((mPollFds == nullptr), "initial calloc failed on mPollFds with a size of %d",
- ((int)sizeof(struct pollfd)) * mPollSize);
- LOG_ALWAYS_FATAL_IF((mPollRefs == nullptr), "initial calloc failed on mPollRefs with a size of %d",
- ((int)sizeof(DNSServiceRef *)) * mPollSize);
- mPollFds[0].fd = mCtrlSocketPair[0];
- mPollFds[0].events = POLLIN;
- if (VDBG) ALOGD("MDnsSdListener starting to monitor");
- while (1) {
- if (VDBG) ALOGD("Going to poll with pollCount %d", pollCount);
- int pollResults = poll(mPollFds, pollCount, 10000000);
- if (pollResults < 0) {
- ALOGE("Error in poll - got %d", errno);
- } else if (pollResults > 0) {
- if (VDBG) ALOGD("Monitor poll got data pollCount = %d, %d", pollCount, pollResults);
- for(int i = 1; i < pollCount; i++) {
- if (mPollFds[i].revents != 0) {
- if (VDBG) {
- ALOGD("Monitor found [%d].revents = %d - calling ProcessResults",
- i, mPollFds[i].revents);
- }
- std::lock_guard guard(mMutex);
- DNSServiceProcessResult(*(mPollRefs[i]));
- mPollFds[i].revents = 0;
- }
- }
- if (VDBG) ALOGD("controlSocket shows revent= %d", mPollFds[0].revents);
- switch (mPollFds[0].revents) {
- case POLLIN: {
- char readBuf[2];
- read(mCtrlSocketPair[0], &readBuf, 1);
- if (DBG) ALOGD("MDnsSdListener::Monitor got %c", readBuf[0]);
- if (memcmp(RESCAN, readBuf, 1) == 0) {
- pollCount = rescan();
- }
- }
- }
- mPollFds[0].revents = 0;
- } else {
- if (VDBG) ALOGD("MDnsSdListener::Monitor poll timed out");
- }
- }
- free(mPollFds);
- free(mPollRefs);
- }
- #define DBG_RESCAN 0
- int MDnsSdListener::Monitor::rescan() {
- // rescan the list from mHead and make new pollfds and serviceRefs
- if (VDBG) {
- ALOGD("MDnsSdListener::Monitor poll rescanning - size=%d, live=%d", mPollSize, mLiveCount);
- }
- std::lock_guard guard(mMutex);
- Element **prevPtr = &mHead;
- int i = 1;
- if (mPollSize <= mLiveCount) {
- mPollSize = mLiveCount + 5;
- free(mPollFds);
- free(mPollRefs);
- mPollFds = (struct pollfd *)calloc(sizeof(struct pollfd), mPollSize);
- mPollRefs = (DNSServiceRef **)calloc(sizeof(DNSServiceRef *), mPollSize);
- LOG_ALWAYS_FATAL_IF((mPollFds == nullptr), "calloc failed on mPollFds with a size of %d",
- ((int)sizeof(struct pollfd)) * mPollSize);
- LOG_ALWAYS_FATAL_IF((mPollRefs == nullptr), "calloc failed on mPollRefs with a size of %d",
- ((int)sizeof(DNSServiceRef *)) * mPollSize);
- } else {
- memset(mPollFds, 0, sizeof(struct pollfd) * mPollSize);
- memset(mPollRefs, 0, sizeof(DNSServiceRef *) * mPollSize);
- }
- mPollFds[0].fd = mCtrlSocketPair[0];
- mPollFds[0].events = POLLIN;
- if (DBG_RESCAN) ALOGD("mHead = %p", mHead);
- while (*prevPtr != nullptr) {
- if (DBG_RESCAN) ALOGD("checking %p, mReady = %d", *prevPtr, (*prevPtr)->mReady);
- if ((*prevPtr)->mReady == 1) {
- int fd = DNSServiceRefSockFD((*prevPtr)->mRef);
- if (fd != -1) {
- if (DBG_RESCAN) ALOGD(" adding FD %d", fd);
- mPollFds[i].fd = fd;
- mPollFds[i].events = POLLIN;
- mPollRefs[i] = &((*prevPtr)->mRef);
- i++;
- } else {
- ALOGE("Error retreving socket FD for live ServiceRef");
- }
- prevPtr = &((*prevPtr)->mNext); // advance to the next element
- } else if ((*prevPtr)->mReady == -1) {
- if (DBG_RESCAN) ALOGD(" removing %p from play", *prevPtr);
- Element *cur = *prevPtr;
- *prevPtr = (cur)->mNext; // change our notion of this element and don't advance
- delete cur;
- } else if ((*prevPtr)->mReady == 0) {
- // Not ready so just skip this node and continue on
- if (DBG_RESCAN) ALOGD("%p not ready. Continuing.", *prevPtr);
- prevPtr = &((*prevPtr)->mNext);
- }
- }
- return i;
- }
- DNSServiceRef *MDnsSdListener::Monitor::allocateServiceRef(int id, Context *context) {
- if (lookupServiceRef(id) != nullptr) {
- delete(context);
- return nullptr;
- }
- Element *e = new Element(id, context);
- std::lock_guard guard(mMutex);
- e->mNext = mHead;
- mHead = e;
- return &(e->mRef);
- }
- DNSServiceRef *MDnsSdListener::Monitor::lookupServiceRef(int id) {
- std::lock_guard guard(mMutex);
- Element *cur = mHead;
- while (cur != nullptr) {
- if (cur->mId == id) {
- DNSServiceRef *result = &(cur->mRef);
- return result;
- }
- cur = cur->mNext;
- }
- return nullptr;
- }
- void MDnsSdListener::Monitor::startMonitoring(int id) {
- if (VDBG) ALOGD("startMonitoring %d", id);
- std::lock_guard guard(mMutex);
- for (Element* cur = mHead; cur != nullptr; cur = cur->mNext) {
- if (cur->mId == id) {
- if (DBG_RESCAN) ALOGD("marking %p as ready to be added", cur);
- mLiveCount++;
- cur->mReady = 1;
- write(mCtrlSocketPair[1], RESCAN, 1); // trigger a rescan for a fresh poll
- if (VDBG) ALOGD("triggering rescan");
- return;
- }
- }
- }
- void MDnsSdListener::Monitor::freeServiceRef(int id) {
- if (VDBG) ALOGD("freeServiceRef %d", id);
- std::lock_guard guard(mMutex);
- Element* cur;
- for (Element** prevPtr = &mHead; *prevPtr != nullptr; prevPtr = &(cur->mNext)) {
- cur = *prevPtr;
- if (cur->mId == id) {
- if (DBG_RESCAN) ALOGD("marking %p as ready to be removed", cur);
- mLiveCount--;
- if (cur->mReady == 1) {
- cur->mReady = -1; // tell poll thread to delete
- cur->mRef = nullptr; // do not process further results
- write(mCtrlSocketPair[1], RESCAN, 1); // trigger a rescan for a fresh poll
- if (VDBG) ALOGD("triggering rescan");
- } else {
- *prevPtr = cur->mNext;
- delete cur;
- }
- return;
- }
- }
- }
- void MDnsSdListener::Monitor::deallocateServiceRef(DNSServiceRef* ref) {
- std::lock_guard guard(mMutex);
- DNSServiceRefDeallocate(*ref);
- *ref = nullptr;
- }
|