Skip to content
Snippets Groups Projects
Commit 8870e48b authored by yanmorin's avatar yanmorin
Browse files

Zeroconf integration
parent b399adc0
Branches
No related tags found
No related merge requests found
/**
* Copyright (C) 2005 Savoir-Faire Linux inc.
* Author: Yan Morin <yan.morin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "DNSQueryThread.h"
#include "DNSService.h"
/**
* Construct a DNSQueryThread and initialize the cancel to deferred
*/
DNSQueryThread::DNSQueryThread(DNSService *parent, const char *regtype) : ost::Thread()
{
_parent = parent;
_regtype = regtype;
_serviceRef = NULL;
setCancel(cancelDeferred);
}
/**
* Destruct a DNSQueryThread
*/
DNSQueryThread::~DNSQueryThread()
{
if (_serviceRef) {
DNSServiceRefDeallocate(_serviceRef);
}
terminate();
_parent = NULL;
_regtype = NULL;
_serviceRef = NULL;
}
/**
* Running loop
*/
void
DNSQueryThread::run() {
DNSServiceErrorType theErr=0; // NULL;
DNSServiceFlags resultFlags=0;
theErr = DNSServiceBrowse(&_serviceRef,
resultFlags,
0, // all interfaces
_regtype,
NULL,
DNSServiceAddServicesCallback,
(void*)_parent);
if (theErr == kDNSServiceErr_NoError) {
while(true) {
DNSServiceProcessResult(_serviceRef); // blockage if none...
}
}
}
/**
* Copyright (C) 2005 Savoir-Faire Linux inc.
* Author: Yan Morin <yan.morin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __DNSSD_DNSQUERYTHREAD_H__
#define __DNSSD_DNSQUERYTHREAD_H__
#include <cc++/thread.h>
#include <dns_sd.h>
class DNSService;
class DNSQueryThread : public ost::Thread
{
public:
DNSQueryThread(DNSService *parent, const char *regtype);
~DNSQueryThread();
virtual void run(); // looking for services
private:
DNSService *_parent; // parent service
DNSServiceRef _serviceRef; // service reference
const char *_regtype; // service type and socket type (_sip._udp by example)
};
#endif // __DNSSD_DNSQUERYTHREAD_H__
/**
* Copyright (C) 2005 Savoir-Faire Linux inc.
* Author: Yan Morin <yan.morin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/**
* Inspired by http://braden.machacking.net/zerobrowse.cpp and
* http://developer.kde.org/documentation/library/3.4-api/dnssd/html/remoteservice_8cpp-source.html
*/
#include "DNSService.h"
#include "DNSServiceTXTRecord.h"
#include "DNSQueryThread.h"
#include "../global.h" // for _debug()
#include <cc++/thread.h>
/**
* Simple Empty Constructor
*/
DNSService::DNSService()
{
_regtypeList.push_back("_sip._udp");
#ifdef USE_IAX2
_regtypeList.push_back("_iax._udp");
#endif
// for the thread, the ifdef add a dynamic _regtypeList problem
int iThread=0; // _queryThread index for the loop
for (std::list<std::string>::iterator iterThread=_regtypeList.begin();
iterThread!=_regtypeList.end();
iterThread++) {
_queryThread.push_back(new DNSQueryThread(this, (*iterThread).c_str()));
iThread++;
}
}
/**
* Simple Empty Destructor
*/
DNSService::~DNSService()
{
int cntThread = _queryThread.size();
for (int iThread=0;iThread<cntThread;iThread++) {
delete _queryThread[iThread];
_queryThread[iThread] = NULL;
}
}
/**
* Look for zeroconf services and add them to _services
*/
void
DNSService::scanServices()
{
for (std::vector<DNSQueryThread *>::iterator iter = _queryThread.begin();iter!=_queryThread.end();iter++) {
(*iter)->start();
}
}
/**
* Add one service to the list of actual services
* @param service Service to add to the list
*/
void DNSService::addService(const std::string &service)
{
// does push_back do a copy and I can use a reference & instead as service argument
DNSServiceTXTRecord txtRecord;
_mutex.enterMutex();
_services[service] = txtRecord;
// we leave before the queryService since, each
// thread will modify a DNSServiceTXTRecord of a difference services
_mutex.leaveMutex();
queryService(service);
}
/**
* Remove one service to the list of actual services
* @param service Service to remove to the list
*/
void DNSService::removeService(const std::string &service)
{
_mutex.enterMutex();
_services.erase(service);
_mutex.leaveMutex();
}
/**
* Display the list of available services
* run() method should be call before
*/
void
DNSService::listServices()
{
_debug("Number of services detected: %d\n", _services.size());
std::map<std::string, DNSServiceTXTRecord>::iterator iterTR;
for (iterTR = _services.begin(); iterTR != _services.end(); iterTR++) {
_debug("name: %s\n", iterTR->first.c_str());
_debug("size: %d\n", iterTR->second.size());
iterTR->second.listValue();
}
}
/**
* Query a service and wait for the anwser
* the queryCallback will show the result
* @param service The service full adress
*/
void
DNSService::queryService(const std::string &service)
{
DNSServiceErrorType theErr=0;
DNSServiceRef myServRef=0;
DNSServiceFlags resultFlags=0;
theErr = DNSServiceQueryRecord(&myServRef, resultFlags, 0, service.c_str(), kDNSServiceType_TXT, kDNSServiceClass_IN, DNSServiceQueryRecordCallback, (void*)this);
if (theErr == kDNSServiceErr_NoError) {
DNSServiceProcessResult(myServRef); // blockage...
DNSServiceRefDeallocate(myServRef);
}
}
/**
* Overloadding queryService
* @param service service name
* @param regtype registred type of service
* @param domain domain (habitually local.)
*/
void
DNSService::queryService(const char *service, const char *regtype, const char *domain)
{
char serviceName[kDNSServiceMaxDomainName+1];
DNSServiceConstructFullName(serviceName, service, regtype, domain);
queryService(std::string(serviceName));
}
/**
* Add a txt record with the queryService callback answser data
* @param rdlen the length of the txt record data
* @param rdata txt record data
*/
void
DNSService::addTXTRecord(const char *fullname, uint16_t rdlen, const void *rdata)
{
char key[256];
const char *value;
uint8_t valueLen; // 0 to 256 by type restriction
char valueTab[256];
uint16_t keyCount = TXTRecordGetCount(rdlen, rdata);
for (int iKey=0; iKey<keyCount; iKey++) {
TXTRecordGetItemAtIndex (rdlen, rdata, iKey, 256, key, &valueLen, (const void **)(&value));
if (value) {
bcopy(value, valueTab, valueLen);
valueTab[valueLen]='\0';
_services[std::string(fullname)].addKeyValue(std::string(key), std::string(valueTab));
} else {
_services[std::string(fullname)].addKeyValue(std::string(key), std::string(""));
}
}
// TODO: remove this call, when we do not debug..
// addTXTRecord is a good function to know changes...
listServices();
}
void
DNSServiceAddServicesCallback(DNSServiceRef sdRef,
DNSServiceFlags flags,
uint32_t interfaceIndex,
DNSServiceErrorType errorCode,
const char *serviceName,
const char *replyType,
const char *replyDomain,
void *context)
{
if (errorCode==kDNSServiceErr_NoError) {
if (flags) {
DNSService *service = (DNSService*)context;
std::string tempService;
tempService = std::string(serviceName) + "." + std::string(replyType) + std::string(replyDomain);
if (flags&kDNSServiceFlagsAdd) {
service->addService(tempService);
} else {
service->removeService(tempService);
}
}
} else {
// TODO: error handling
}
}
void
DNSServiceQueryRecordCallback(
DNSServiceRef DNSServiceRef,
DNSServiceFlags flags,
uint32_t interfaceIndex,
DNSServiceErrorType errorCode,
const char *fullname,
uint16_t rrtype,
uint16_t rrclass,
uint16_t rdlen,
const void *rdata,
uint32_t ttl,
void *context)
{
if (errorCode==kDNSServiceErr_NoError) {
if (flags) {
if (flags&kDNSServiceFlagsAdd) {
((DNSService *)context)->addTXTRecord(fullname, rdlen, rdata);
}
}
if (!(flags&kDNSServiceFlagsMoreComing)) {
// TODO: stoping, if no blocking process here
}
}
}
/**
* Copyright (C) 2005 Savoir-Faire Linux inc.
* Author: Yan Morin <yan.morin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __DNSSD_DNSSERVICE_H__
#define __DNSSD_DNSSERVICE_H__
#include <string>
#include <map>
#include <list>
#include <vector>
#include <dns_sd.h>
#include <cc++/thread.h>
class DNSQueryThread;
class DNSServiceTXTRecord;
class DNSService
{
public:
DNSService();
~DNSService();
void scanServices(); // looking for services
void addService(const std::string &service); // adding every services
void removeService(const std::string &service); // remove a service
void listServices(); // listing services (call addService before)
void stop(); // after the browsing loop stop
void queryService(const std::string &service); // query the TXT record of a service
void queryService(const char *service, const char *regtype, const char *domain);
void addTXTRecord(const char *fullname, uint16_t rdlen, const void *rdata);
private:
std::map<std::string, DNSServiceTXTRecord> _services; //map
std::vector<DNSQueryThread *> _queryThread;
/**
* Mutex to protect access to _services on add/erase
*/
ost::Mutex _mutex;
/**
* RegType List contains zeroconf services to register, like sip, iax2, ...
* It will be use to initialize the DNSQueryThread
*/
std::list<std::string> _regtypeList;
};
void DNSServiceAddServicesCallback(DNSServiceRef sdRef,
DNSServiceFlags flags,
uint32_t interfaceIndex,
DNSServiceErrorType errorCode,
const char *serviceName,
const char *replyType,
const char *replyDomain,
void *context);
void DNSServiceQueryRecordCallback(DNSServiceRef DNSServiceRef,
DNSServiceFlags flags,
uint32_t interfaceIndex,
DNSServiceErrorType errorCode,
const char *fullname,
uint16_t rrtype,
uint16_t rrclass,
uint16_t rdlen,
const void *rdata,
uint32_t ttl,
void *context);
#endif // __DNSSD_DNSSERVICE_H__
/**
* Copyright (C) 2005 Savoir-Faire Linux inc.
* Author: Yan Morin <yan.morin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "DNSServiceTXTRecord.h"
#include "../global.h" // for _debug
/**
* Simple constructor
*/
DNSServiceTXTRecord::DNSServiceTXTRecord()
{
}
/**
* Simple destructor
*/
DNSServiceTXTRecord::~DNSServiceTXTRecord()
{
}
/**
* add a pair of key/value inside the associative std::map
* @param key unique key inside the std::map
* @param value value associated to the key
*/
void
DNSServiceTXTRecord::addKeyValue(const std::string &key, const std::string &value)
{
_map[key] = value;
}
/**
* get a value from a key
* @param key unique key inside the std::map
* @return the value or empty
*/
const std::string &
DNSServiceTXTRecord::getValue(const std::string &key)
{
return _map[key]; // return std::string("") if it's not there
}
/**
* get a value from a key
* @param key unique key inside the std::map
* @return the value or empty
*/
const std::string &
DNSServiceTXTRecord::getValue(const char* key)
{
return getValue(std::string(key));
}
void
DNSServiceTXTRecord::listValue()
{
std::map<std::string, std::string>::iterator iter;
for (iter=_map.begin(); iter != _map.end(); iter++) {
_debug ( "\t%s:%s\n", iter->first.c_str(), iter->second.c_str());
}
}
/**
* Copyright (C) 2005 Savoir-Faire Linux inc.
* Author: Yan Morin <yan.morin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __DNSSD_DNSSERVICETXTRECORD_H__
#define __DNSSD_DNSSERVICETXTRECORD_H__
#include <string>
#include <map>
class DNSServiceTXTRecord
{
public:
DNSServiceTXTRecord();
~DNSServiceTXTRecord();
void addKeyValue(const std::string &key, const std::string &value);
const std::string &getValue(const std::string &key);
const std::string &getValue(const char *key);
inline void clear(void) { _map.clear(); };
inline int size(void) { return _map.size(); };
void listValue();
private:
std::map<std::string, std::string> _map;
};
#endif // __DNSSD_DNSSERVICETXTRECORD_H__
Installing Apple mDNSResponder:
WARNING: this is NOT Howl's mDNSResponder and it does not come in Debian package called mdnsresponder.
You can see the difference by checking daemon's name: Apple's one (the correct one) is named 'mdnsd'
Howl's one is named 'mDNSResponder'.
1) download mDNSResponder
- from Apple site (http://www.opensource.apple.com/darwinsource/tarballs/apsl/mDNSResponder-98.tar.gz)
- or you can get tarball from: http://helios.et.put.poznan.pl/~jstachow/pub/mDNSResponder-98.tar.gz
(for those who don't like registration)
- you can also use the last mDNSResponder
2) compile and install
Build system for mDNSResponder is quite weird so here are instructions:
cd mDNSPosix
make os=linux (make without parameters gives list of supported systems)
now as root:
make os=linux install
make sure that mdnsd.sh init script is properly installed and will be executed at boot time
Inspired by kdelibs/dnssd/INSTALL
This diff is collapsed.
SUBDIRS =
noinst_LTLIBRARIES = libzeroconf.la
libzeroconf_la_SOURCES = \
DNSQueryThread.cpp DNSQueryThread.h \
DNSService.cpp DNSService.h \
DNSServiceTXTRecord.cpp DNSServiceTXTRecord.h
AM_CXXFLAGS = $(libccext2_CFLAGS)
libzeroconf_la_LIBADD = $(LIB_DNSSD)
This diff is collapsed.
# inspired by kdelibs/dnssd/configure.in.bot
if test "$have_libdns_sd" = "no"; then
echo ""
echo "You're missing Apple mDNSResponder 85 or later, therefore"
echo "dnssd will be compiled as stub, without any real functionality."
echo "If you want zeroconf support (www.zeroconf.org), you should install mDNSResponder first."
echo "See src/zeroconf/INSTALL for details."
echo ""
all_tests=bad
fi
#MIN_CONFIG
AC_ARG_ENABLE(USE_ZEROCONF, [ --disable-zeroconf don't require libdns_sd (browsing and publishing DNS-SD services will not be possible) ], with_zeroconf=$enableval, with_zeroconf=yes)
if test "$with_zeroconf" = "yes"; then
AC_MSG_CHECKING(for DNS-SD support)
save_dnssdtest_LIBS="$LIBS"
save_dnssdtest_LDFLAGS="$LDFLAGS"
save_dnssdtest_CPPFLAGS="$CPPFLAGS"
LDFLAGS="$all_libraries $LDFLAGS"
CPPFLAGS="$CPPFLAGS $all_includes"
case $host_os in
darwin*) LIBS="" ;;
*) LIBS="-ldns_sd" ;;
esac
have_libdns_sd="no"
AC_TRY_LINK( [
#include <dns_sd.h>
],[
DNSServiceRefDeallocate( (DNSServiceRef*) 0);
TXTRecordDeallocate( (TXTRecordRef*) 0);
],[
AC_DEFINE(HAVE_DNSSD,1,[Define if dns-sd is available])
case $host_os in
darwin*) LIB_DNSSD="" ;;
*) LIB_DNSSD="-ldns_sd" ;;
esac
have_libdns_sd="yes"
AC_MSG_RESULT(yes)
],[
AC_MSG_RESULT(no)
LIB_DNSSD=""
])
CPPFLAGS=$save_dnssdtest_CPPFLAGS
LDFLAGS=$save_dnssdtest_LDFLAGS
LIBS=$save_dnssdtest_LIBS
fi
AC_SUBST(LIB_DNSSD)
AM_CONDITIONAL(HAVE_ZEROCONF, test "$have_libdns_sd" = "yes")
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment