1745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt/* 2745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt * Copyright (C) 2010 The Android Open Source Project 3745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt * 4745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt * Licensed under the Apache License, Version 2.0 (the "License"); 5745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt * you may not use this file except in compliance with the License. 6745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt * You may obtain a copy of the License at 7745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt * 8745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt * http://www.apache.org/licenses/LICENSE-2.0 9745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt * 10745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt * Unless required by applicable law or agreed to in writing, software 11745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt * distributed under the License is distributed on an "AS IS" BASIS, 12745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt * See the License for the specific language governing permissions and 14745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt * limitations under the License. 15745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt */ 16745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt 17745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt#include <arpa/inet.h> 18745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt#include <dirent.h> 19745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt#include <errno.h> 20745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt#include <linux/if.h> 21745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt#include <netdb.h> 22745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt#include <netinet/in.h> 23745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt#include <pthread.h> 24745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt#include <stdlib.h> 25745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt#include <sys/poll.h> 26745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt#include <sys/socket.h> 27745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt#include <sys/types.h> 28745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt#include <string.h> 290082f0330ac6d755c19e1d40d5e64180a65fdadcPhilip P. Moltmann#include <resolv.h> 30745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt 31745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt#define LOG_TAG "MDnsDS" 32745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt#define DBG 1 33745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt#define VDBG 1 34745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt 35745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt#include <cutils/log.h> 36745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt#include <cutils/properties.h> 37745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt#include <sysutils/SocketClient.h> 38745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt 39745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt#include "MDnsSdListener.h" 40745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt#include "ResponseCode.h" 41745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt 42745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt#define MDNS_SERVICE_NAME "mdnsd" 43745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt#define MDNS_SERVICE_STATUS "init.svc.mdnsd" 44745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt 450082f0330ac6d755c19e1d40d5e64180a65fdadcPhilip P. Moltmann#define CEIL(x, y) (((x) + (y) - 1) / (y)) 460082f0330ac6d755c19e1d40d5e64180a65fdadcPhilip P. Moltmann 47745e09fc5694e73920aaad18a626275597bdddb1Robert GreenwaltMDnsSdListener::MDnsSdListener() : 48745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt FrameworkListener("mdns", true) { 49745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt Monitor *m = new Monitor(); 50745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt registerCmd(new Handler(m, this)); 51745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt} 52745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt 53745e09fc5694e73920aaad18a626275597bdddb1Robert GreenwaltMDnsSdListener::Handler::Handler(Monitor *m, MDnsSdListener *listener) : 54745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt NetdCommand("mdnssd") { 55745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (DBG) ALOGD("MDnsSdListener::Hander starting up"); 56745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt mMonitor = m; 57745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt mListener = listener; 58745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt} 59745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt 60745e09fc5694e73920aaad18a626275597bdddb1Robert GreenwaltMDnsSdListener::Handler::~Handler() {} 61745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt 62745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwaltvoid MDnsSdListener::Handler::discover(SocketClient *cli, 63745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt const char *iface, 64745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt const char *regType, 65745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt const char *domain, 66745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt const int requestId, 67745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt const int requestFlags) { 68745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (VDBG) { 69745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt ALOGD("discover(%s, %s, %s, %d, %d)", iface, regType, domain, requestId, 70745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt requestFlags); 71745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 72745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt Context *context = new Context(requestId, mListener); 73745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt DNSServiceRef *ref = mMonitor->allocateServiceRef(requestId, context); 74745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (ref == NULL) { 75745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt ALOGE("requestId %d already in use during discover call", requestId); 76745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt cli->sendMsg(ResponseCode::CommandParameterError, 77745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt "RequestId already in use during discover call", false); 78745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt return; 79745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 80745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (VDBG) ALOGD("using ref %p", ref); 81745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt DNSServiceFlags nativeFlags = iToFlags(requestFlags); 82745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt int interfaceInt = ifaceNameToI(iface); 83745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt 84745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt DNSServiceErrorType result = DNSServiceBrowse(ref, nativeFlags, interfaceInt, regType, 85745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt domain, &MDnsSdListenerDiscoverCallback, context); 86745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (result != kDNSServiceErr_NoError) { 87745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt ALOGE("Discover request %d got an error from DNSServiceBrowse %d", requestId, result); 88745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt mMonitor->freeServiceRef(requestId); 89745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt cli->sendMsg(ResponseCode::CommandParameterError, 90745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt "Discover request got an error from DNSServiceBrowse", false); 91745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt return; 92745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 93745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt mMonitor->startMonitoring(requestId); 94745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (VDBG) ALOGD("discover successful"); 95745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt cli->sendMsg(ResponseCode::CommandOkay, "Discover operation started", false); 96745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt return; 97745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt} 98745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt 9956afacf838d24cf8e54d2cf0d8ab9182ab704125Sreeram Ramachandranvoid MDnsSdListenerDiscoverCallback(DNSServiceRef /* sdRef */, DNSServiceFlags flags, 10056afacf838d24cf8e54d2cf0d8ab9182ab704125Sreeram Ramachandran uint32_t /* interfaceIndex */, DNSServiceErrorType errorCode, const char *serviceName, 101745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt const char *regType, const char *replyDomain, void *inContext) { 102745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt MDnsSdListener::Context *context = reinterpret_cast<MDnsSdListener::Context *>(inContext); 103745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt char *msg; 104745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt int refNumber = context->mRefNumber; 105745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt 106745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (errorCode != kDNSServiceErr_NoError) { 107745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt asprintf(&msg, "%d %d", refNumber, errorCode); 108745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt context->mListener->sendBroadcast(ResponseCode::ServiceDiscoveryFailed, msg, false); 109745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (DBG) ALOGE("discover failure for %d, error= %d", refNumber, errorCode); 110745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } else { 111745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt int respCode; 1124833e47bb886db80cf4ec23a00cc4ba2a1f113e7Robert Greenwalt char *quotedServiceName = SocketClient::quoteArg(serviceName); 113745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (flags & kDNSServiceFlagsAdd) { 114745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (VDBG) { 115745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt ALOGD("Discover found new serviceName %s, regType %s and domain %s for %d", 116745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt serviceName, regType, replyDomain, refNumber); 117745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 118745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt respCode = ResponseCode::ServiceDiscoveryServiceAdded; 119745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } else { 120745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (VDBG) { 121745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt ALOGD("Discover lost serviceName %s, regType %s and domain %s for %d", 122745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt serviceName, regType, replyDomain, refNumber); 123745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 124745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt respCode = ResponseCode::ServiceDiscoveryServiceRemoved; 125745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 1264833e47bb886db80cf4ec23a00cc4ba2a1f113e7Robert Greenwalt asprintf(&msg, "%d %s %s %s", refNumber, quotedServiceName, regType, replyDomain); 1274833e47bb886db80cf4ec23a00cc4ba2a1f113e7Robert Greenwalt free(quotedServiceName); 128745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt context->mListener->sendBroadcast(respCode, msg, false); 129745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 130745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt free(msg); 131745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt} 132745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt 133745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwaltvoid MDnsSdListener::Handler::stop(SocketClient *cli, int argc, char **argv, const char *str) { 134745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (argc != 3) { 135745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt char *msg; 136745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt asprintf(&msg, "Invalid number of arguments to %s", str); 137745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt cli->sendMsg(ResponseCode::CommandParameterError, msg, false); 138745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt free(msg); 139745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt return; 140745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 141745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt int requestId = atoi(argv[2]); 142745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt DNSServiceRef *ref = mMonitor->lookupServiceRef(requestId); 143745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (ref == NULL) { 144745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (DBG) ALOGE("%s stop used unknown requestId %d", str, requestId); 145745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt cli->sendMsg(ResponseCode::CommandParameterError, "Unknown requestId", false); 146745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt return; 147745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 148745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (VDBG) ALOGD("Stopping %s with ref %p", str, ref); 149745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt DNSServiceRefDeallocate(*ref); 150745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt mMonitor->freeServiceRef(requestId); 151745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt char *msg; 152745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt asprintf(&msg, "%s stopped", str); 153745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt cli->sendMsg(ResponseCode::CommandOkay, msg, false); 154745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt free(msg); 155745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt} 156745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt 157745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwaltvoid MDnsSdListener::Handler::serviceRegister(SocketClient *cli, int requestId, 158745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt const char *interfaceName, const char *serviceName, const char *serviceType, 159745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt const char *domain, const char *host, int port, int txtLen, void *txtRecord) { 160745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (VDBG) { 161745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt ALOGD("serviceRegister(%d, %s, %s, %s, %s, %s, %d, %d, <binary>)", requestId, 162745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt interfaceName, serviceName, serviceType, domain, host, port, txtLen); 163745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 164745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt Context *context = new Context(requestId, mListener); 165745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt DNSServiceRef *ref = mMonitor->allocateServiceRef(requestId, context); 166745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt port = htons(port); 167745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (ref == NULL) { 168745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt ALOGE("requestId %d already in use during register call", requestId); 169745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt cli->sendMsg(ResponseCode::CommandParameterError, 170745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt "RequestId already in use during register call", false); 171745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt return; 172745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 173745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt DNSServiceFlags nativeFlags = 0; 174745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt int interfaceInt = ifaceNameToI(interfaceName); 175745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt DNSServiceErrorType result = DNSServiceRegister(ref, interfaceInt, nativeFlags, serviceName, 176745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt serviceType, domain, host, port, txtLen, txtRecord, &MDnsSdListenerRegisterCallback, 177745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt context); 178745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (result != kDNSServiceErr_NoError) { 179745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt ALOGE("service register request %d got an error from DNSServiceRegister %d", requestId, 180745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt result); 181745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt mMonitor->freeServiceRef(requestId); 182745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt cli->sendMsg(ResponseCode::CommandParameterError, 183745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt "serviceRegister request got an error from DNSServiceRegister", false); 184745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt return; 185745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 186745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt mMonitor->startMonitoring(requestId); 187745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (VDBG) ALOGD("serviceRegister successful"); 188745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt cli->sendMsg(ResponseCode::CommandOkay, "serviceRegister started", false); 189745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt return; 190745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt} 191745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt 19256afacf838d24cf8e54d2cf0d8ab9182ab704125Sreeram Ramachandranvoid MDnsSdListenerRegisterCallback(DNSServiceRef /* sdRef */, DNSServiceFlags /* flags */, 19356afacf838d24cf8e54d2cf0d8ab9182ab704125Sreeram Ramachandran DNSServiceErrorType errorCode, const char *serviceName, const char * /* regType */, 19456afacf838d24cf8e54d2cf0d8ab9182ab704125Sreeram Ramachandran const char * /* domain */, void *inContext) { 195745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt MDnsSdListener::Context *context = reinterpret_cast<MDnsSdListener::Context *>(inContext); 196745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt char *msg; 197745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt int refNumber = context->mRefNumber; 198745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (errorCode != kDNSServiceErr_NoError) { 199745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt asprintf(&msg, "%d %d", refNumber, errorCode); 200745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt context->mListener->sendBroadcast(ResponseCode::ServiceRegistrationFailed, msg, false); 201745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (DBG) ALOGE("register failure for %d, error= %d", refNumber, errorCode); 202745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } else { 2034833e47bb886db80cf4ec23a00cc4ba2a1f113e7Robert Greenwalt char *quotedServiceName = SocketClient::quoteArg(serviceName); 2044833e47bb886db80cf4ec23a00cc4ba2a1f113e7Robert Greenwalt asprintf(&msg, "%d %s", refNumber, quotedServiceName); 2054833e47bb886db80cf4ec23a00cc4ba2a1f113e7Robert Greenwalt free(quotedServiceName); 206745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt context->mListener->sendBroadcast(ResponseCode::ServiceRegistrationSucceeded, msg, false); 207745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (VDBG) ALOGD("register succeeded for %d as %s", refNumber, serviceName); 208745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 209745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt free(msg); 210745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt} 211745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt 212745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt 213745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwaltvoid MDnsSdListener::Handler::resolveService(SocketClient *cli, int requestId, 214745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt const char *interfaceName, const char *serviceName, const char *regType, 215745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt const char *domain) { 216745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (VDBG) { 217745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt ALOGD("resolveService(%d, %s, %s, %s, %s)", requestId, interfaceName, 218745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt serviceName, regType, domain); 219745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 220745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt Context *context = new Context(requestId, mListener); 221745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt DNSServiceRef *ref = mMonitor->allocateServiceRef(requestId, context); 222745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (ref == NULL) { 223745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt ALOGE("request Id %d already in use during resolve call", requestId); 224745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt cli->sendMsg(ResponseCode::CommandParameterError, 225745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt "RequestId already in use during resolve call", false); 226745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt return; 227745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 228745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt DNSServiceFlags nativeFlags = 0; 229745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt int interfaceInt = ifaceNameToI(interfaceName); 230745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt DNSServiceErrorType result = DNSServiceResolve(ref, nativeFlags, interfaceInt, serviceName, 231745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt regType, domain, &MDnsSdListenerResolveCallback, context); 232745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (result != kDNSServiceErr_NoError) { 233745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt ALOGE("service resolve request %d got an error from DNSServiceResolve %d", requestId, 234745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt result); 235745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt mMonitor->freeServiceRef(requestId); 236745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt cli->sendMsg(ResponseCode::CommandParameterError, 237745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt "resolveService got an error from DNSServiceResolve", false); 238745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt return; 239745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 240745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt mMonitor->startMonitoring(requestId); 241745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (VDBG) ALOGD("resolveService successful"); 242745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt cli->sendMsg(ResponseCode::CommandOkay, "resolveService started", false); 243745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt return; 244745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt} 245745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt 24656afacf838d24cf8e54d2cf0d8ab9182ab704125Sreeram Ramachandranvoid MDnsSdListenerResolveCallback(DNSServiceRef /* sdRef */, DNSServiceFlags /* flags */, 24756afacf838d24cf8e54d2cf0d8ab9182ab704125Sreeram Ramachandran uint32_t /* interface */, DNSServiceErrorType errorCode, const char *fullname, 24856afacf838d24cf8e54d2cf0d8ab9182ab704125Sreeram Ramachandran const char *hosttarget, uint16_t port, uint16_t txtLen, 2490082f0330ac6d755c19e1d40d5e64180a65fdadcPhilip P. Moltmann const unsigned char *txtRecord , void *inContext) { 250745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt MDnsSdListener::Context *context = reinterpret_cast<MDnsSdListener::Context *>(inContext); 251745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt char *msg; 252745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt int refNumber = context->mRefNumber; 253745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt port = ntohs(port); 254745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (errorCode != kDNSServiceErr_NoError) { 255745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt asprintf(&msg, "%d %d", refNumber, errorCode); 256745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt context->mListener->sendBroadcast(ResponseCode::ServiceResolveFailed, msg, false); 257745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (DBG) ALOGE("resolve failure for %d, error= %d", refNumber, errorCode); 258745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } else { 2594833e47bb886db80cf4ec23a00cc4ba2a1f113e7Robert Greenwalt char *quotedFullName = SocketClient::quoteArg(fullname); 2604833e47bb886db80cf4ec23a00cc4ba2a1f113e7Robert Greenwalt char *quotedHostTarget = SocketClient::quoteArg(hosttarget); 2610082f0330ac6d755c19e1d40d5e64180a65fdadcPhilip P. Moltmann 2620082f0330ac6d755c19e1d40d5e64180a65fdadcPhilip P. Moltmann // Base 64 encodes every 3 bytes into 4 characters, but then adds padding to the next 2630082f0330ac6d755c19e1d40d5e64180a65fdadcPhilip P. Moltmann // multiple of 4 and a \0 2640082f0330ac6d755c19e1d40d5e64180a65fdadcPhilip P. Moltmann size_t dstLength = CEIL(CEIL(txtLen * 4, 3), 4) * 4 + 1; 2650082f0330ac6d755c19e1d40d5e64180a65fdadcPhilip P. Moltmann 2660082f0330ac6d755c19e1d40d5e64180a65fdadcPhilip P. Moltmann char *dst = (char *)malloc(dstLength); 2670082f0330ac6d755c19e1d40d5e64180a65fdadcPhilip P. Moltmann b64_ntop(txtRecord, txtLen, dst, dstLength); 2680082f0330ac6d755c19e1d40d5e64180a65fdadcPhilip P. Moltmann 2690082f0330ac6d755c19e1d40d5e64180a65fdadcPhilip P. Moltmann asprintf(&msg, "%d %s %s %d %d \"%s\"", refNumber, quotedFullName, quotedHostTarget, port, 2700082f0330ac6d755c19e1d40d5e64180a65fdadcPhilip P. Moltmann txtLen, dst); 2714833e47bb886db80cf4ec23a00cc4ba2a1f113e7Robert Greenwalt free(quotedFullName); 2724833e47bb886db80cf4ec23a00cc4ba2a1f113e7Robert Greenwalt free(quotedHostTarget); 2730082f0330ac6d755c19e1d40d5e64180a65fdadcPhilip P. Moltmann free(dst); 274745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt context->mListener->sendBroadcast(ResponseCode::ServiceResolveSuccess, msg, false); 275745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (VDBG) { 276745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt ALOGD("resolve succeeded for %d finding %s at %s:%d with txtLen %d", 277745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt refNumber, fullname, hosttarget, port, txtLen); 278745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 279745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 280745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt free(msg); 281745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt} 282745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt 283745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwaltvoid MDnsSdListener::Handler::getAddrInfo(SocketClient *cli, int requestId, 284745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt const char *interfaceName, uint32_t protocol, const char *hostname) { 285745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (VDBG) ALOGD("getAddrInfo(%d, %s %d, %s)", requestId, interfaceName, protocol, hostname); 286745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt Context *context = new Context(requestId, mListener); 287745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt DNSServiceRef *ref = mMonitor->allocateServiceRef(requestId, context); 288745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (ref == NULL) { 289745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt ALOGE("request ID %d already in use during getAddrInfo call", requestId); 290745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt cli->sendMsg(ResponseCode::CommandParameterError, 291745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt "RequestId already in use during getAddrInfo call", false); 292745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt return; 293745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 294745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt DNSServiceFlags nativeFlags = 0; 295745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt int interfaceInt = ifaceNameToI(interfaceName); 296745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt DNSServiceErrorType result = DNSServiceGetAddrInfo(ref, nativeFlags, interfaceInt, protocol, 297745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt hostname, &MDnsSdListenerGetAddrInfoCallback, context); 298745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (result != kDNSServiceErr_NoError) { 299745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt ALOGE("getAddrInfo request %d got an error from DNSServiceGetAddrInfo %d", requestId, 300745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt result); 301745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt mMonitor->freeServiceRef(requestId); 302745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt cli->sendMsg(ResponseCode::CommandParameterError, 303745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt "getAddrInfo request got an error from DNSServiceGetAddrInfo", false); 304745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt return; 305745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 306745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt mMonitor->startMonitoring(requestId); 307745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (VDBG) ALOGD("getAddrInfo successful"); 308745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt cli->sendMsg(ResponseCode::CommandOkay, "getAddrInfo started", false); 309745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt return; 310745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt} 311745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt 31256afacf838d24cf8e54d2cf0d8ab9182ab704125Sreeram Ramachandranvoid MDnsSdListenerGetAddrInfoCallback(DNSServiceRef /* sdRef */, DNSServiceFlags /* flags */, 31356afacf838d24cf8e54d2cf0d8ab9182ab704125Sreeram Ramachandran uint32_t /* interface */, DNSServiceErrorType errorCode, const char *hostname, 314745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt const struct sockaddr *const sa, uint32_t ttl, void *inContext) { 315745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt MDnsSdListener::Context *context = reinterpret_cast<MDnsSdListener::Context *>(inContext); 316745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt int refNumber = context->mRefNumber; 317745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt 318745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (errorCode != kDNSServiceErr_NoError) { 319745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt char *msg; 320745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt asprintf(&msg, "%d %d", refNumber, errorCode); 321745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt context->mListener->sendBroadcast(ResponseCode::ServiceGetAddrInfoFailed, msg, false); 322745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (DBG) ALOGE("getAddrInfo failure for %d, error= %d", refNumber, errorCode); 323745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt free(msg); 324745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } else { 325745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt char addr[INET6_ADDRSTRLEN]; 326745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt char *msg; 3274833e47bb886db80cf4ec23a00cc4ba2a1f113e7Robert Greenwalt char *quotedHostname = SocketClient::quoteArg(hostname); 328745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (sa->sa_family == AF_INET) { 329745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt inet_ntop(sa->sa_family, &(((struct sockaddr_in *)sa)->sin_addr), addr, sizeof(addr)); 330745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } else { 331745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt inet_ntop(sa->sa_family, &(((struct sockaddr_in6 *)sa)->sin6_addr), addr, sizeof(addr)); 332745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 3334833e47bb886db80cf4ec23a00cc4ba2a1f113e7Robert Greenwalt asprintf(&msg, "%d %s %d %s", refNumber, quotedHostname, ttl, addr); 3344833e47bb886db80cf4ec23a00cc4ba2a1f113e7Robert Greenwalt free(quotedHostname); 335745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt context->mListener->sendBroadcast(ResponseCode::ServiceGetAddrInfoSuccess, msg, false); 336745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (VDBG) { 337745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt ALOGD("getAddrInfo succeeded for %d: %s", refNumber, msg); 338745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 339745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt free(msg); 340745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 341745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt} 342745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt 343745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwaltvoid MDnsSdListener::Handler::setHostname(SocketClient *cli, int requestId, 344745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt const char *hostname) { 345745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (VDBG) ALOGD("setHostname(%d, %s)", requestId, hostname); 346745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt Context *context = new Context(requestId, mListener); 347745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt DNSServiceRef *ref = mMonitor->allocateServiceRef(requestId, context); 348745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (ref == NULL) { 349745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt ALOGE("request Id %d already in use during setHostname call", requestId); 350745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt cli->sendMsg(ResponseCode::CommandParameterError, 351745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt "RequestId already in use during setHostname call", false); 352745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt return; 353745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 354745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt DNSServiceFlags nativeFlags = 0; 355745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt DNSServiceErrorType result = DNSSetHostname(ref, nativeFlags, hostname, 356745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt &MDnsSdListenerSetHostnameCallback, context); 357745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (result != kDNSServiceErr_NoError) { 358745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt ALOGE("setHostname request %d got an error from DNSSetHostname %d", requestId, result); 359745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt mMonitor->freeServiceRef(requestId); 360745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt cli->sendMsg(ResponseCode::CommandParameterError, 361745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt "setHostname got an error from DNSSetHostname", false); 362745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt return; 363745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 364745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt mMonitor->startMonitoring(requestId); 365745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (VDBG) ALOGD("setHostname successful"); 366745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt cli->sendMsg(ResponseCode::CommandOkay, "setHostname started", false); 367745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt return; 368745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt} 369745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt 37056afacf838d24cf8e54d2cf0d8ab9182ab704125Sreeram Ramachandranvoid MDnsSdListenerSetHostnameCallback(DNSServiceRef /* sdRef */, DNSServiceFlags /* flags */, 371745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt DNSServiceErrorType errorCode, const char *hostname, void *inContext) { 372745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt MDnsSdListener::Context *context = reinterpret_cast<MDnsSdListener::Context *>(inContext); 373745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt char *msg; 374745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt int refNumber = context->mRefNumber; 375745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (errorCode != kDNSServiceErr_NoError) { 376745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt asprintf(&msg, "%d %d", refNumber, errorCode); 377745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt context->mListener->sendBroadcast(ResponseCode::ServiceSetHostnameFailed, msg, false); 378745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (DBG) ALOGE("setHostname failure for %d, error= %d", refNumber, errorCode); 379745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } else { 3804833e47bb886db80cf4ec23a00cc4ba2a1f113e7Robert Greenwalt char *quotedHostname = SocketClient::quoteArg(hostname); 3814833e47bb886db80cf4ec23a00cc4ba2a1f113e7Robert Greenwalt asprintf(&msg, "%d %s", refNumber, quotedHostname); 3824833e47bb886db80cf4ec23a00cc4ba2a1f113e7Robert Greenwalt free(quotedHostname); 383745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt context->mListener->sendBroadcast(ResponseCode::ServiceSetHostnameSuccess, msg, false); 384745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (VDBG) ALOGD("setHostname succeeded for %d. Set to %s", refNumber, hostname); 385745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 386745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt free(msg); 387745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt} 388745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt 389745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt 39056afacf838d24cf8e54d2cf0d8ab9182ab704125Sreeram Ramachandranint MDnsSdListener::Handler::ifaceNameToI(const char * /* iface */) { 391745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt return 0; 392745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt} 393745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt 39456afacf838d24cf8e54d2cf0d8ab9182ab704125Sreeram Ramachandranconst char *MDnsSdListener::Handler::iToIfaceName(int /* i */) { 395745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt return NULL; 396745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt} 397745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt 39856afacf838d24cf8e54d2cf0d8ab9182ab704125Sreeram RamachandranDNSServiceFlags MDnsSdListener::Handler::iToFlags(int /* i */) { 399745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt return 0; 400745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt} 401745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt 40256afacf838d24cf8e54d2cf0d8ab9182ab704125Sreeram Ramachandranint MDnsSdListener::Handler::flagsToI(DNSServiceFlags /* flags */) { 403745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt return 0; 404745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt} 405745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt 406745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwaltint MDnsSdListener::Handler::runCommand(SocketClient *cli, 407745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt int argc, char **argv) { 408745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (argc < 2) { 409745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt char* msg = NULL; 410745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt asprintf( &msg, "Invalid number of arguments to mdnssd: %i", argc); 411745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt ALOGW("%s", msg); 412745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt cli->sendMsg(ResponseCode::CommandParameterError, msg, false); 413745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt free(msg); 414745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt return -1; 415745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 416745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt 417745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt char* cmd = argv[1]; 418745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt 419745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (strcmp(cmd, "discover") == 0) { 420745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (argc != 4) { 421745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt cli->sendMsg(ResponseCode::CommandParameterError, 422745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt "Invalid number of arguments to mdnssd discover", false); 423745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt return 0; 424745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 425745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt int requestId = atoi(argv[2]); 426745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt char *serviceType = argv[3]; 427745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt 428745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt discover(cli, NULL, serviceType, NULL, requestId, 0); 429745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } else if (strcmp(cmd, "stop-discover") == 0) { 430745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt stop(cli, argc, argv, "discover"); 431745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } else if (strcmp(cmd, "register") == 0) { 4320082f0330ac6d755c19e1d40d5e64180a65fdadcPhilip P. Moltmann if (argc != 7) { 433745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt cli->sendMsg(ResponseCode::CommandParameterError, 434745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt "Invalid number of arguments to mdnssd register", false); 435745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt return 0; 436745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 437745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt int requestId = atoi(argv[2]); 438745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt char *serviceName = argv[3]; 439745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt char *serviceType = argv[4]; 440745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt int port = atoi(argv[5]); 441745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt char *interfaceName = NULL; // will use all 442745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt char *domain = NULL; // will use default 443745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt char *host = NULL; // will use default hostname 4440082f0330ac6d755c19e1d40d5e64180a65fdadcPhilip P. Moltmann 4450082f0330ac6d755c19e1d40d5e64180a65fdadcPhilip P. Moltmann // TXT record length is <= 1300, see NsdServiceInfo.setAttribute 4460082f0330ac6d755c19e1d40d5e64180a65fdadcPhilip P. Moltmann char dst[1300]; 4470082f0330ac6d755c19e1d40d5e64180a65fdadcPhilip P. Moltmann 4480082f0330ac6d755c19e1d40d5e64180a65fdadcPhilip P. Moltmann int length = b64_pton(argv[6], (u_char *)dst, 1300); 4490082f0330ac6d755c19e1d40d5e64180a65fdadcPhilip P. Moltmann 4500082f0330ac6d755c19e1d40d5e64180a65fdadcPhilip P. Moltmann if (length < 0) { 4510082f0330ac6d755c19e1d40d5e64180a65fdadcPhilip P. Moltmann cli->sendMsg(ResponseCode::CommandParameterError, 4520082f0330ac6d755c19e1d40d5e64180a65fdadcPhilip P. Moltmann "Could not decode txtRecord", false); 4530082f0330ac6d755c19e1d40d5e64180a65fdadcPhilip P. Moltmann return 0; 454c0bc14a3c2f0efe1f368f2120de38e99ccb6d9f0Christopher Lane } 4550082f0330ac6d755c19e1d40d5e64180a65fdadcPhilip P. Moltmann 456745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt serviceRegister(cli, requestId, interfaceName, serviceName, 4570082f0330ac6d755c19e1d40d5e64180a65fdadcPhilip P. Moltmann serviceType, domain, host, port, length, dst); 458745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } else if (strcmp(cmd, "stop-register") == 0) { 459745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt stop(cli, argc, argv, "register"); 460745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } else if (strcmp(cmd, "resolve") == 0) { 461745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (argc != 6) { 462745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt cli->sendMsg(ResponseCode::CommandParameterError, 463745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt "Invalid number of arguments to mdnssd resolve", false); 464745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt return 0; 465745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 466745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt int requestId = atoi(argv[2]); 467745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt char *interfaceName = NULL; // will use all 468745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt char *serviceName = argv[3]; 469745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt char *regType = argv[4]; 470745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt char *domain = argv[5]; 471745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt resolveService(cli, requestId, interfaceName, serviceName, regType, domain); 472745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } else if (strcmp(cmd, "stop-resolve") == 0) { 473745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt stop(cli, argc, argv, "resolve"); 474745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } else if (strcmp(cmd, "start-service") == 0) { 475745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (mMonitor->startService()) { 476745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt cli->sendMsg(ResponseCode::CommandOkay, "Service Started", false); 477745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } else { 478745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt cli->sendMsg(ResponseCode::ServiceStartFailed, "Service already running", false); 479745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 480745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } else if (strcmp(cmd, "stop-service") == 0) { 481745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (mMonitor->stopService()) { 482745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt cli->sendMsg(ResponseCode::CommandOkay, "Service Stopped", false); 483745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } else { 484745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt cli->sendMsg(ResponseCode::ServiceStopFailed, "Service still in use", false); 485745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 486745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } else if (strcmp(cmd, "sethostname") == 0) { 487745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (argc != 4) { 488745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt cli->sendMsg(ResponseCode::CommandParameterError, 489745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt "Invalid number of arguments to mdnssd sethostname", false); 490745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt return 0; 491745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 492745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt int requestId = atoi(argv[2]); 493745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt char *hostname = argv[3]; 494745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt setHostname(cli, requestId, hostname); 495745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } else if (strcmp(cmd, "stop-sethostname") == 0) { 496745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt stop(cli, argc, argv, "sethostname"); 497745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } else if (strcmp(cmd, "getaddrinfo") == 0) { 498745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (argc != 4) { 499745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt cli->sendMsg(ResponseCode::CommandParameterError, 500745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt "Invalid number of arguments to mdnssd getaddrinfo", false); 501745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt return 0; 502745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 503745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt int requestId = atoi(argv[2]); 504745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt char *hostname = argv[3]; 505745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt char *interfaceName = NULL; // default 506745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt int protocol = 0; // intelligient heuristic (both v4 + v6) 507745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt getAddrInfo(cli, requestId, interfaceName, protocol, hostname); 508745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } else if (strcmp(cmd, "stop-getaddrinfo") == 0) { 509745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt stop(cli, argc, argv, "getaddrinfo"); 510745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } else { 511745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (VDBG) ALOGE("Unknown cmd %s", cmd); 512745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown mdnssd cmd", false); 513745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt return 0; 514745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 515745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt return 0; 516745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt} 517745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt 518745e09fc5694e73920aaad18a626275597bdddb1Robert GreenwaltMDnsSdListener::Monitor::Monitor() { 519745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt mHead = NULL; 52030ffdfa62cb6bd8807b3d8eb529e2e8abaa80386Narayan Kamath mLiveCount = 0; 52130ffdfa62cb6bd8807b3d8eb529e2e8abaa80386Narayan Kamath mPollFds = NULL; 52230ffdfa62cb6bd8807b3d8eb529e2e8abaa80386Narayan Kamath mPollRefs = NULL; 52330ffdfa62cb6bd8807b3d8eb529e2e8abaa80386Narayan Kamath mPollSize = 10; 524745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt socketpair(AF_LOCAL, SOCK_STREAM, 0, mCtrlSocketPair); 52530ffdfa62cb6bd8807b3d8eb529e2e8abaa80386Narayan Kamath pthread_mutex_init(&mHeadMutex, NULL); 52630ffdfa62cb6bd8807b3d8eb529e2e8abaa80386Narayan Kamath 527745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt pthread_create(&mThread, NULL, MDnsSdListener::Monitor::threadStart, this); 5282d4610ec34cc78799a3353638fa05ee53276892aMattias Falk pthread_detach(mThread); 529745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt} 530745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt 531745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwaltvoid *MDnsSdListener::Monitor::threadStart(void *obj) { 532745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt Monitor *monitor = reinterpret_cast<Monitor *>(obj); 533745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt 534745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt monitor->run(); 535745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt delete monitor; 536745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt pthread_exit(NULL); 537745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt return NULL; 538745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt} 539745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt 54056afacf838d24cf8e54d2cf0d8ab9182ab704125Sreeram Ramachandran#define NAP_TIME 200 // 200 ms between polls 54156afacf838d24cf8e54d2cf0d8ab9182ab704125Sreeram Ramachandranstatic int wait_for_property(const char *name, const char *desired_value, int maxwait) 54256afacf838d24cf8e54d2cf0d8ab9182ab704125Sreeram Ramachandran{ 54356afacf838d24cf8e54d2cf0d8ab9182ab704125Sreeram Ramachandran char value[PROPERTY_VALUE_MAX] = {'\0'}; 54456afacf838d24cf8e54d2cf0d8ab9182ab704125Sreeram Ramachandran int maxnaps = (maxwait * 1000) / NAP_TIME; 54556afacf838d24cf8e54d2cf0d8ab9182ab704125Sreeram Ramachandran 54656afacf838d24cf8e54d2cf0d8ab9182ab704125Sreeram Ramachandran if (maxnaps < 1) { 54756afacf838d24cf8e54d2cf0d8ab9182ab704125Sreeram Ramachandran maxnaps = 1; 54856afacf838d24cf8e54d2cf0d8ab9182ab704125Sreeram Ramachandran } 54956afacf838d24cf8e54d2cf0d8ab9182ab704125Sreeram Ramachandran 55056afacf838d24cf8e54d2cf0d8ab9182ab704125Sreeram Ramachandran while (maxnaps-- > 0) { 55156afacf838d24cf8e54d2cf0d8ab9182ab704125Sreeram Ramachandran usleep(NAP_TIME * 1000); 55256afacf838d24cf8e54d2cf0d8ab9182ab704125Sreeram Ramachandran if (property_get(name, value, NULL)) { 55356afacf838d24cf8e54d2cf0d8ab9182ab704125Sreeram Ramachandran if (desired_value == NULL || strcmp(value, desired_value) == 0) { 55456afacf838d24cf8e54d2cf0d8ab9182ab704125Sreeram Ramachandran return 0; 55556afacf838d24cf8e54d2cf0d8ab9182ab704125Sreeram Ramachandran } 55656afacf838d24cf8e54d2cf0d8ab9182ab704125Sreeram Ramachandran } 55756afacf838d24cf8e54d2cf0d8ab9182ab704125Sreeram Ramachandran } 55856afacf838d24cf8e54d2cf0d8ab9182ab704125Sreeram Ramachandran return -1; /* failure */ 55956afacf838d24cf8e54d2cf0d8ab9182ab704125Sreeram Ramachandran} 56056afacf838d24cf8e54d2cf0d8ab9182ab704125Sreeram Ramachandran 561745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwaltint MDnsSdListener::Monitor::startService() { 562745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt int result = 0; 563745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt char property_value[PROPERTY_VALUE_MAX]; 564745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt pthread_mutex_lock(&mHeadMutex); 565745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt property_get(MDNS_SERVICE_STATUS, property_value, ""); 566745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (strcmp("running", property_value) != 0) { 567745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt ALOGD("Starting MDNSD"); 568745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt property_set("ctl.start", MDNS_SERVICE_NAME); 569745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt wait_for_property(MDNS_SERVICE_STATUS, "running", 5); 570745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt result = -1; 571745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } else { 572745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt result = 0; 573745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 574745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt pthread_mutex_unlock(&mHeadMutex); 575745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt return result; 576745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt} 577745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt 578745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwaltint MDnsSdListener::Monitor::stopService() { 579745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt int result = 0; 580745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt pthread_mutex_lock(&mHeadMutex); 581745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (mHead == NULL) { 582745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt ALOGD("Stopping MDNSD"); 583745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt property_set("ctl.stop", MDNS_SERVICE_NAME); 584745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt wait_for_property(MDNS_SERVICE_STATUS, "stopped", 5); 585745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt result = -1; 586745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } else { 587745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt result = 0; 588745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 589745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt pthread_mutex_unlock(&mHeadMutex); 590745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt return result; 591745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt} 592745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt 593745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwaltvoid MDnsSdListener::Monitor::run() { 594745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt int pollCount = 1; 595745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt 596745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt mPollFds = (struct pollfd *)calloc(sizeof(struct pollfd), mPollSize); 597745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt mPollRefs = (DNSServiceRef **)calloc(sizeof(DNSServiceRef *), mPollSize); 59847f8597b42b849d22c6cc128f27bba4a7692d371Robert Greenwalt LOG_ALWAYS_FATAL_IF((mPollFds == NULL), "initial calloc failed on mPollFds with a size of %d", 59947f8597b42b849d22c6cc128f27bba4a7692d371Robert Greenwalt ((int)sizeof(struct pollfd)) * mPollSize); 60047f8597b42b849d22c6cc128f27bba4a7692d371Robert Greenwalt LOG_ALWAYS_FATAL_IF((mPollRefs == NULL), "initial calloc failed on mPollRefs with a size of %d", 60147f8597b42b849d22c6cc128f27bba4a7692d371Robert Greenwalt ((int)sizeof(DNSServiceRef *)) * mPollSize); 602745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt 603745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt mPollFds[0].fd = mCtrlSocketPair[0]; 604745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt mPollFds[0].events = POLLIN; 605745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt 606745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (VDBG) ALOGD("MDnsSdListener starting to monitor"); 607745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt while (1) { 608745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (VDBG) ALOGD("Going to poll with pollCount %d", pollCount); 609745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt int pollResults = poll(mPollFds, pollCount, 10000000); 610745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (pollResults < 0) { 611745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt ALOGE("Error in poll - got %d", errno); 612745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } else if (pollResults > 0) { 613745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (VDBG) ALOGD("Monitor poll got data pollCount = %d, %d", pollCount, pollResults); 614745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt for(int i = 1; i < pollCount; i++) { 615745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (mPollFds[i].revents != 0) { 616745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (VDBG) { 617745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt ALOGD("Monitor found [%d].revents = %d - calling ProcessResults", 618745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt i, mPollFds[i].revents); 619745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 620745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt DNSServiceProcessResult(*(mPollRefs[i])); 621745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt mPollFds[i].revents = 0; 622745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 623745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 624745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (VDBG) ALOGD("controlSocket shows revent= %d", mPollFds[0].revents); 625745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt switch (mPollFds[0].revents) { 626745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt case POLLIN: { 627745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt char readBuf[2]; 628745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt read(mCtrlSocketPair[0], &readBuf, 1); 629745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (DBG) ALOGD("MDnsSdListener::Monitor got %c", readBuf[0]); 630745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (memcmp(RESCAN, readBuf, 1) == 0) { 631745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt pollCount = rescan(); 632745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 633745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 634745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 635745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt mPollFds[0].revents = 0; 636745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } else { 637745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (VDBG) ALOGD("MDnsSdListener::Monitor poll timed out"); 638745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 639745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 640745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt free(mPollFds); 641745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt free(mPollRefs); 642745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt} 643745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt 644745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt#define DBG_RESCAN 0 645745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt 646745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwaltint MDnsSdListener::Monitor::rescan() { 647745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt// rescan the list from mHead and make new pollfds and serviceRefs 648745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (VDBG) { 649745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt ALOGD("MDnsSdListener::Monitor poll rescanning - size=%d, live=%d", mPollSize, mLiveCount); 650745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 651745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt pthread_mutex_lock(&mHeadMutex); 652745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt Element **prevPtr = &mHead; 653745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt int i = 1; 654745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (mPollSize <= mLiveCount) { 655745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt mPollSize = mLiveCount + 5; 656745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt free(mPollFds); 657745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt free(mPollRefs); 658745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt mPollFds = (struct pollfd *)calloc(sizeof(struct pollfd), mPollSize); 659745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt mPollRefs = (DNSServiceRef **)calloc(sizeof(DNSServiceRef *), mPollSize); 66047f8597b42b849d22c6cc128f27bba4a7692d371Robert Greenwalt LOG_ALWAYS_FATAL_IF((mPollFds == NULL), "calloc failed on mPollFds with a size of %d", 66147f8597b42b849d22c6cc128f27bba4a7692d371Robert Greenwalt ((int)sizeof(struct pollfd)) * mPollSize); 66247f8597b42b849d22c6cc128f27bba4a7692d371Robert Greenwalt LOG_ALWAYS_FATAL_IF((mPollRefs == NULL), "calloc failed on mPollRefs with a size of %d", 66347f8597b42b849d22c6cc128f27bba4a7692d371Robert Greenwalt ((int)sizeof(DNSServiceRef *)) * mPollSize); 664745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } else { 665a3ebcb8c2ceef6b92a672a24529cbd098f487965Edward Savage-Jones memset(mPollFds, 0, sizeof(struct pollfd) * mPollSize); 666a3ebcb8c2ceef6b92a672a24529cbd098f487965Edward Savage-Jones memset(mPollRefs, 0, sizeof(DNSServiceRef *) * mPollSize); 667745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 668745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt mPollFds[0].fd = mCtrlSocketPair[0]; 669745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt mPollFds[0].events = POLLIN; 670745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (DBG_RESCAN) ALOGD("mHead = %p", mHead); 671745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt while (*prevPtr != NULL) { 672745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (DBG_RESCAN) ALOGD("checking %p, mReady = %d", *prevPtr, (*prevPtr)->mReady); 673745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if ((*prevPtr)->mReady == 1) { 674745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt int fd = DNSServiceRefSockFD((*prevPtr)->mRef); 675745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (fd != -1) { 676745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (DBG_RESCAN) ALOGD(" adding FD %d", fd); 677745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt mPollFds[i].fd = fd; 678745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt mPollFds[i].events = POLLIN; 679745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt mPollRefs[i] = &((*prevPtr)->mRef); 680745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt i++; 681745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } else { 682745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt ALOGE("Error retreving socket FD for live ServiceRef"); 683745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 684745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt prevPtr = &((*prevPtr)->mNext); // advance to the next element 685745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } else if ((*prevPtr)->mReady == -1) { 686745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (DBG_RESCAN) ALOGD(" removing %p from play", *prevPtr); 687745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt Element *cur = *prevPtr; 688745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt *prevPtr = (cur)->mNext; // change our notion of this element and don't advance 689745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt delete cur; 69079c5214e31471e75d79f50b6a282eebe76d2609bKenneth Tateno } else if ((*prevPtr)->mReady == 0) { 69179c5214e31471e75d79f50b6a282eebe76d2609bKenneth Tateno // Not ready so just skip this node and continue on 69279c5214e31471e75d79f50b6a282eebe76d2609bKenneth Tateno if (DBG_RESCAN) ALOGD("%p not ready. Continuing.", *prevPtr); 69379c5214e31471e75d79f50b6a282eebe76d2609bKenneth Tateno prevPtr = &((*prevPtr)->mNext); 694745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 695745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 696745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt pthread_mutex_unlock(&mHeadMutex); 697745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt return i; 698745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt} 699745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt 700745e09fc5694e73920aaad18a626275597bdddb1Robert GreenwaltDNSServiceRef *MDnsSdListener::Monitor::allocateServiceRef(int id, Context *context) { 701745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (lookupServiceRef(id) != NULL) { 702745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt delete(context); 703745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt return NULL; 704745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 705745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt Element *e = new Element(id, context); 706745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt pthread_mutex_lock(&mHeadMutex); 707745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt e->mNext = mHead; 708745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt mHead = e; 709745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt pthread_mutex_unlock(&mHeadMutex); 710745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt return &(e->mRef); 711745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt} 712745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt 713745e09fc5694e73920aaad18a626275597bdddb1Robert GreenwaltDNSServiceRef *MDnsSdListener::Monitor::lookupServiceRef(int id) { 714745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt pthread_mutex_lock(&mHeadMutex); 715745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt Element *cur = mHead; 716745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt while (cur != NULL) { 717745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (cur->mId == id) { 718745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt DNSServiceRef *result = &(cur->mRef); 719745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt pthread_mutex_unlock(&mHeadMutex); 720745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt return result; 721745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 722745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt cur = cur->mNext; 723745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 724745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt pthread_mutex_unlock(&mHeadMutex); 725745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt return NULL; 726745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt} 727745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt 728745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwaltvoid MDnsSdListener::Monitor::startMonitoring(int id) { 729745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (VDBG) ALOGD("startMonitoring %d", id); 730745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt pthread_mutex_lock(&mHeadMutex); 731745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt Element *cur = mHead; 732745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt while (cur != NULL) { 733745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (cur->mId == id) { 734745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (DBG_RESCAN) ALOGD("marking %p as ready to be added", cur); 735745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt mLiveCount++; 736745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt cur->mReady = 1; 737745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt pthread_mutex_unlock(&mHeadMutex); 738745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt write(mCtrlSocketPair[1], RESCAN, 1); // trigger a rescan for a fresh poll 739745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (VDBG) ALOGD("triggering rescan"); 740745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt return; 741745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 742745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt cur = cur->mNext; 743745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 744745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt pthread_mutex_unlock(&mHeadMutex); 745745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt} 746745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt 747745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwaltvoid MDnsSdListener::Monitor::freeServiceRef(int id) { 748745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (VDBG) ALOGD("freeServiceRef %d", id); 749745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt pthread_mutex_lock(&mHeadMutex); 750745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt Element **prevPtr = &mHead; 751745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt Element *cur; 752745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt while (*prevPtr != NULL) { 753745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt cur = *prevPtr; 754745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (cur->mId == id) { 755745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (DBG_RESCAN) ALOGD("marking %p as ready to be removed", cur); 756745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt mLiveCount--; 757745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (cur->mReady == 1) { 758745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt cur->mReady = -1; // tell poll thread to delete 759745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt write(mCtrlSocketPair[1], RESCAN, 1); // trigger a rescan for a fresh poll 760745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt if (VDBG) ALOGD("triggering rescan"); 761745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } else { 762745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt *prevPtr = cur->mNext; 763745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt delete cur; 764745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 765745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt pthread_mutex_unlock(&mHeadMutex); 766745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt return; 767745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 768745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt prevPtr = &(cur->mNext); 769745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt } 770745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt pthread_mutex_unlock(&mHeadMutex); 771745e09fc5694e73920aaad18a626275597bdddb1Robert Greenwalt} 772