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