From 6582af7d3ce90b1626ebd41febff342be82fcae2 Mon Sep 17 00:00:00 2001 From: Stefan Hacker Date: Wed, 10 Jun 2009 20:32:32 +0200 Subject: [PATCH] Bonjour support. --- scripts/murmur.ini | 6 + src/bonjour/bonjourrecord.h | 60 +++ src/bonjour/bonjourservicebrowser.cpp | 90 ++++ src/bonjour/bonjourservicebrowser.h | 65 +++ src/bonjour/bonjourserviceregister.cpp | 100 ++++ src/bonjour/bonjourserviceregister.h | 72 +++ src/bonjour/bonjourserviceresolver.cpp | 111 ++++ src/bonjour/bonjourserviceresolver.h | 68 +++ src/mumble/BonjourClient.cpp | 51 ++ src/mumble/BonjourClient.h | 52 ++ src/mumble/ConnectDialog.cpp | 88 ++- src/mumble/ConnectDialog.h | 14 + src/mumble/ConnectDialog.ui | 714 ++++++++++++++----------- src/mumble/Global.h | 2 + src/mumble/main.cpp | 11 + src/mumble/mumble.pro | 19 + src/murmur/BonjourServer.cpp | 51 ++ src/murmur/BonjourServer.h | 52 ++ src/murmur/Meta.cpp | 2 + src/murmur/Meta.h | 1 + src/murmur/Server.cpp | 25 +- src/murmur/Server.h | 9 + src/murmur/murmur.pro | 19 + 23 files changed, 1351 insertions(+), 331 deletions(-) create mode 100644 src/bonjour/bonjourrecord.h create mode 100644 src/bonjour/bonjourservicebrowser.cpp create mode 100644 src/bonjour/bonjourservicebrowser.h create mode 100644 src/bonjour/bonjourserviceregister.cpp create mode 100644 src/bonjour/bonjourserviceregister.h create mode 100644 src/bonjour/bonjourserviceresolver.cpp create mode 100644 src/bonjour/bonjourserviceresolver.h create mode 100644 src/mumble/BonjourClient.cpp create mode 100644 src/mumble/BonjourClient.h create mode 100644 src/murmur/BonjourServer.cpp create mode 100644 src/murmur/BonjourServer.h diff --git a/scripts/murmur.ini b/scripts/murmur.ini index 39246f962..853034013 100644 --- a/scripts/murmur.ini +++ b/scripts/murmur.ini @@ -89,6 +89,12 @@ users=100 #registerUrl=http://mumble.sourceforge.net/ #registerHostname= +# To enable bonjour service discovery uncomment the following line. +# To change the name announced by bonjour adjust the registerName variable. +# See http://developer.apple.com/networking/bonjour/index.html for more information +# about bonjour. +#bonjour=True + # If you have a proper SSL certificate, you can provide the filenames here. #sslCert= #sslKey= diff --git a/src/bonjour/bonjourrecord.h b/src/bonjour/bonjourrecord.h new file mode 100644 index 000000000..ae2ebc004 --- /dev/null +++ b/src/bonjour/bonjourrecord.h @@ -0,0 +1,60 @@ +/* +Copyright (c) 2007, Trenton Schulz + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef BONJOURRECORD_H +#define BONJOURRECORD_H + +#include +#include + +class BonjourRecord +{ +public: + BonjourRecord() {} + BonjourRecord(const QString &name, const QString ®Type, const QString &domain) + : serviceName(name), registeredType(regType), replyDomain(domain) + {} + BonjourRecord(const char *name, const char *regType, const char *domain) + { + serviceName = QString::fromUtf8(name); + registeredType = QString::fromUtf8(regType); + replyDomain = QString::fromUtf8(domain); + } + QString serviceName; + QString registeredType; + QString replyDomain; + bool operator==(const BonjourRecord &other) const { + return serviceName == other.serviceName + && registeredType == other.registeredType + && replyDomain == other.replyDomain; + } +}; + +Q_DECLARE_METATYPE(BonjourRecord) + +#endif // BONJOURRECORD_H diff --git a/src/bonjour/bonjourservicebrowser.cpp b/src/bonjour/bonjourservicebrowser.cpp new file mode 100644 index 000000000..3689b689d --- /dev/null +++ b/src/bonjour/bonjourservicebrowser.cpp @@ -0,0 +1,90 @@ +/* +Copyright (c) 2007, Trenton Schulz + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "bonjourservicebrowser.h" + +#include + +BonjourServiceBrowser::BonjourServiceBrowser(QObject *parent) + : QObject(parent), dnssref(0), bonjourSocket(0) +{ +} + +BonjourServiceBrowser::~BonjourServiceBrowser() +{ + if (dnssref) { + DNSServiceRefDeallocate(dnssref); + dnssref = 0; + } +} + +void BonjourServiceBrowser::browseForServiceType(const QString &serviceType) +{ + DNSServiceErrorType err = DNSServiceBrowse(&dnssref, 0, 0, serviceType.toUtf8().constData(), 0, + bonjourBrowseReply, this); + if (err != kDNSServiceErr_NoError) { + emit error(err); + } else { + int sockfd = DNSServiceRefSockFD(dnssref); + if (sockfd == -1) { + emit error(kDNSServiceErr_Invalid); + } else { + bonjourSocket = new QSocketNotifier(sockfd, QSocketNotifier::Read, this); + connect(bonjourSocket, SIGNAL(activated(int)), this, SLOT(bonjourSocketReadyRead())); + } + } +} + +void BonjourServiceBrowser::bonjourSocketReadyRead() +{ + DNSServiceErrorType err = DNSServiceProcessResult(dnssref); + if (err != kDNSServiceErr_NoError) + emit error(err); +} + +void BonjourServiceBrowser::bonjourBrowseReply(DNSServiceRef , DNSServiceFlags flags, + quint32 , DNSServiceErrorType errorCode, + const char *serviceName, const char *regType, + const char *replyDomain, void *context) +{ + BonjourServiceBrowser *serviceBrowser = static_cast(context); + if (errorCode != kDNSServiceErr_NoError) { + emit serviceBrowser->error(errorCode); + } else { + BonjourRecord bonjourRecord(serviceName, regType, replyDomain); + if (flags & kDNSServiceFlagsAdd) { + if (!serviceBrowser->bonjourRecords.contains(bonjourRecord)) + serviceBrowser->bonjourRecords.append(bonjourRecord); + } else { + serviceBrowser->bonjourRecords.removeAll(bonjourRecord); + } + if (!(flags & kDNSServiceFlagsMoreComing)) { + emit serviceBrowser->currentBonjourRecordsChanged(serviceBrowser->bonjourRecords); + } + } +} diff --git a/src/bonjour/bonjourservicebrowser.h b/src/bonjour/bonjourservicebrowser.h new file mode 100644 index 000000000..c590792b3 --- /dev/null +++ b/src/bonjour/bonjourservicebrowser.h @@ -0,0 +1,65 @@ +/* +Copyright (c) 2007, Trenton Schulz +Copyright (c) 2009, Stefan Hacker + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef BONJOURSERVICEBROWSER_H +#define BONJOURSERVICEBROWSER_H + +#include +#include +#include "bonjourrecord.h" + +class QSocketNotifier; +class BonjourServiceBrowser : public QObject +{ + Q_OBJECT +public: + BonjourServiceBrowser(QObject *parent = 0); + ~BonjourServiceBrowser(); + void browseForServiceType(const QString &serviceType); + inline QList currentRecords() const { return bonjourRecords; } + inline QString serviceType() const { return browsingType; } + +signals: + void currentBonjourRecordsChanged(const QList &list); + void error(DNSServiceErrorType err); + +private slots: + void bonjourSocketReadyRead(); + +private: + static void DNSSD_API bonjourBrowseReply(DNSServiceRef , DNSServiceFlags flags, quint32, + DNSServiceErrorType errorCode, const char *serviceName, + const char *regType, const char *replyDomain, void *context); + DNSServiceRef dnssref; + QSocketNotifier *bonjourSocket; + QList bonjourRecords; + QString browsingType; +}; + +#endif // BONJOURSERVICEBROWSER_H diff --git a/src/bonjour/bonjourserviceregister.cpp b/src/bonjour/bonjourserviceregister.cpp new file mode 100644 index 000000000..a592f2764 --- /dev/null +++ b/src/bonjour/bonjourserviceregister.cpp @@ -0,0 +1,100 @@ +/* +Copyright (c) 2007, Trenton Schulz +Copyright (c) 2009, Stefan Hacker + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "bonjourserviceregister.h" +#include + +BonjourServiceRegister::BonjourServiceRegister(QObject *parent) + : QObject(parent), dnssref(0), bonjourSocket(0) +{ +} + +BonjourServiceRegister::~BonjourServiceRegister() +{ + if (dnssref) { + DNSServiceRefDeallocate(dnssref); + dnssref = 0; + } +} + +void BonjourServiceRegister::registerService(const BonjourRecord &record, quint16 servicePort) +{ + if (dnssref) { + qWarning("Warning: Already registered a service for this object, aborting new register"); + return; + } + quint16 bigEndianPort = servicePort; +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN + { + bigEndianPort = 0 | ((servicePort & 0x00ff) << 8) | ((servicePort & 0xff00) >> 8); + } +#endif + + DNSServiceErrorType err = DNSServiceRegister(&dnssref, 0, 0, record.serviceName.toUtf8().constData(), + record.registeredType.toUtf8().constData(), + record.replyDomain.isEmpty() ? 0 + : record.replyDomain.toUtf8().constData(), 0, + bigEndianPort, 0, 0, bonjourRegisterService, this); + if (err != kDNSServiceErr_NoError) { + emit error(err); + } else { + int sockfd = DNSServiceRefSockFD(dnssref); + if (sockfd == -1) { + emit error(kDNSServiceErr_Invalid); + } else { + bonjourSocket = new QSocketNotifier(sockfd, QSocketNotifier::Read, this); + connect(bonjourSocket, SIGNAL(activated(int)), this, SLOT(bonjourSocketReadyRead())); + } + } +} + + +void BonjourServiceRegister::bonjourSocketReadyRead() +{ + DNSServiceErrorType err = DNSServiceProcessResult(dnssref); + if (err != kDNSServiceErr_NoError) + emit error(err); +} + + +void DNSSD_API BonjourServiceRegister::bonjourRegisterService(DNSServiceRef, DNSServiceFlags, + DNSServiceErrorType errorCode, const char *name, + const char *regtype, const char *domain, + void *data) +{ + BonjourServiceRegister *serviceRegister = static_cast(data); + if (errorCode != kDNSServiceErr_NoError) { + emit serviceRegister->error(errorCode); + } else { + serviceRegister->finalRecord = BonjourRecord(QString::fromUtf8(name), + QString::fromUtf8(regtype), + QString::fromUtf8(domain)); + emit serviceRegister->serviceRegistered(serviceRegister->finalRecord); + } +} diff --git a/src/bonjour/bonjourserviceregister.h b/src/bonjour/bonjourserviceregister.h new file mode 100644 index 000000000..374a889fc --- /dev/null +++ b/src/bonjour/bonjourserviceregister.h @@ -0,0 +1,72 @@ +/* +Copyright (c) 2007, Trenton Schulz +Copyright (c) 2009, Stefan Hacker + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef BONJOURSERVICEREGISTER_H +#define BONJOURSERVICEREGISTER_H + +#include + +#include "bonjourrecord.h" +class QSocketNotifier; + +// Bonjour flags +#include + +typedef uint32_t DNSServiceFlags; +typedef int32_t DNSServiceErrorType; +typedef struct _DNSServiceRef_t *DNSServiceRef; + +class BonjourServiceRegister : public QObject +{ + Q_OBJECT +public: + BonjourServiceRegister(QObject *parent = 0); + ~BonjourServiceRegister(); + + void registerService(const BonjourRecord &record, quint16 servicePort); + inline BonjourRecord registeredRecord() const {return finalRecord; } + +signals: + void error(DNSServiceErrorType error); + void serviceRegistered(const BonjourRecord &record); + +private slots: + void bonjourSocketReadyRead(); + +private: + static void DNSSD_API bonjourRegisterService(DNSServiceRef sdRef, DNSServiceFlags, + DNSServiceErrorType errorCode, const char *name, + const char *regtype, const char *domain, + void *context); + DNSServiceRef dnssref; + QSocketNotifier *bonjourSocket; + BonjourRecord finalRecord; +}; + +#endif // BONJOURSERVICEREGISTER_H diff --git a/src/bonjour/bonjourserviceresolver.cpp b/src/bonjour/bonjourserviceresolver.cpp new file mode 100644 index 000000000..3471c8553 --- /dev/null +++ b/src/bonjour/bonjourserviceresolver.cpp @@ -0,0 +1,111 @@ +/* +Copyright (c) 2007, Trenton Schulz + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include + +#include "bonjourrecord.h" +#include "bonjourserviceresolver.h" + +BonjourServiceResolver::BonjourServiceResolver(QObject *parent) + : QObject(parent), dnssref(0), bonjourSocket(0), bonjourPort(-1) +{ +} + +BonjourServiceResolver::~BonjourServiceResolver() +{ + cleanupResolve(); +} + +void BonjourServiceResolver::cleanupResolve() +{ + if (dnssref) { + DNSServiceRefDeallocate(dnssref); + dnssref = 0; + delete bonjourSocket; + bonjourPort = -1; + } +} + +void BonjourServiceResolver::resolveBonjourRecord(const BonjourRecord &record) +{ + if (dnssref) { + qWarning("resolve in process, aborting"); + return; + } + DNSServiceErrorType err = DNSServiceResolve(&dnssref, 0, 0, + record.serviceName.toUtf8().constData(), + record.registeredType.toUtf8().constData(), + record.replyDomain.toUtf8().constData(), + (DNSServiceResolveReply)bonjourResolveReply, this); + if (err != kDNSServiceErr_NoError) { + emit error(err); + } else { + int sockfd = DNSServiceRefSockFD(dnssref); + if (sockfd == -1) { + emit error(kDNSServiceErr_Invalid); + } else { + bonjourSocket = new QSocketNotifier(sockfd, QSocketNotifier::Read, this); + connect(bonjourSocket, SIGNAL(activated(int)), this, SLOT(bonjourSocketReadyRead())); + } + } +} + +void BonjourServiceResolver::bonjourSocketReadyRead() +{ + DNSServiceErrorType err = DNSServiceProcessResult(dnssref); + if (err != kDNSServiceErr_NoError) + emit error(err); +} + + +void BonjourServiceResolver::bonjourResolveReply(DNSServiceRef, DNSServiceFlags , + quint32 , DNSServiceErrorType errorCode, + const char *, const char *hosttarget, quint16 port, + quint16 , const char *, void *context) +{ + BonjourServiceResolver *serviceResolver = static_cast(context); + if (errorCode != kDNSServiceErr_NoError) { + emit serviceResolver->error(errorCode); + return; + } +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN + { + port = 0 | ((port & 0x00ff) << 8) | ((port & 0xff00) >> 8); + } +#endif + serviceResolver->bonjourPort = port; + QHostInfo::lookupHost(QString::fromUtf8(hosttarget), + serviceResolver, SLOT(finishConnect(const QHostInfo &))); +} + +void BonjourServiceResolver::finishConnect(const QHostInfo &hostInfo) +{ + emit bonjourRecordResolved(hostInfo, bonjourPort); + QMetaObject::invokeMethod(this, "cleanupResolve", Qt::QueuedConnection); +} diff --git a/src/bonjour/bonjourserviceresolver.h b/src/bonjour/bonjourserviceresolver.h new file mode 100644 index 000000000..d9547f618 --- /dev/null +++ b/src/bonjour/bonjourserviceresolver.h @@ -0,0 +1,68 @@ +/* +Copyright (c) 2007, Trenton Schulz +Copyright (c) 2009, Stefan Hacker + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef BONJOURSERVICERESOLVER_H +#define BONJOURSERVICERESOLVER_H + +#include +#include + +class QSocketNotifier; +class QHostInfo; +class BonjourRecord; + +class BonjourServiceResolver : public QObject +{ + Q_OBJECT +public: + BonjourServiceResolver(QObject *parent); + ~BonjourServiceResolver(); + + void resolveBonjourRecord(const BonjourRecord &record); + +signals: + void bonjourRecordResolved(const QHostInfo &hostInfo, int port); + void error(DNSServiceErrorType error); + +private slots: + void bonjourSocketReadyRead(); + void cleanupResolve(); + void finishConnect(const QHostInfo &hostInfo); + +private: + static void DNSSD_API bonjourResolveReply(DNSServiceRef sdRef, DNSServiceFlags flags, + quint32 interfaceIndex, DNSServiceErrorType errorCode, + const char *fullName, const char *hosttarget, quint16 port, + quint16 txtLen, const char *txtRecord, void *context); + DNSServiceRef dnssref; + QSocketNotifier *bonjourSocket; + int bonjourPort; +}; + +#endif // BONJOURSERVICERESOLVER_H diff --git a/src/mumble/BonjourClient.cpp b/src/mumble/BonjourClient.cpp new file mode 100644 index 000000000..164db1c97 --- /dev/null +++ b/src/mumble/BonjourClient.cpp @@ -0,0 +1,51 @@ +/* Copyright (C) 2009, Stefan Hacker + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + - Neither the name of the Mumble Developers nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#include "BonjourClient.h" + +BonjourClient::BonjourClient() : bsrResolver(NULL), bsbBrowser(NULL) { + HMODULE hLib = LoadLibrary(L"DNSSD.DLL"); + if (hLib == NULL) { + qWarning("Bonjour: Failed to load dnssd.dll"); + return; + } + FreeLibrary(hLib); + + bsbBrowser = new BonjourServiceBrowser(this); + bsbBrowser->browseForServiceType(QLatin1String("_murmur._tcp")); + bsrResolver = new BonjourServiceResolver(this); + return; +} + +BonjourClient::~BonjourClient() { + if (bsbBrowser) + delete bsbBrowser; + if (bsrResolver) + delete bsrResolver; +} diff --git a/src/mumble/BonjourClient.h b/src/mumble/BonjourClient.h new file mode 100644 index 000000000..6788cbdff --- /dev/null +++ b/src/mumble/BonjourClient.h @@ -0,0 +1,52 @@ +/* Copyright (C) 2009, Stefan Hacker + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + - Neither the name of the Mumble Developers nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef _BONJOURCLIENT_H +#define _BONJOURCLIENT_H + +#include +#include "../Bonjour/bonjourservicebrowser.h" +#include "../Bonjour/bonjourserviceresolver.h" + +class BonjourClient : public QObject { + private: + Q_OBJECT + Q_DISABLE_COPY(BonjourClient) + public: + BonjourClient(); + ~BonjourClient(); + + BonjourServiceBrowser *bsbBrowser; + BonjourServiceResolver *bsrResolver; +}; + +#else +class Bonjour; +class BonjourServer; +#endif diff --git a/src/mumble/ConnectDialog.cpp b/src/mumble/ConnectDialog.cpp index 0cb16cd0a..100373030 100644 --- a/src/mumble/ConnectDialog.cpp +++ b/src/mumble/ConnectDialog.cpp @@ -58,7 +58,6 @@ ConnectDialog::ConnectDialog(QWidget *p) : QDialog(p) { #ifdef Q_OS_MAC setWindowFlags(Qt::Sheet); #endif - bPublicInit = false; bDirty = false; @@ -86,6 +85,9 @@ ConnectDialog::ConnectDialog(QWidget *p) : QDialog(p) { connect(qleServer, SIGNAL(textEdited(const QString &)), this, SLOT(onDirty(const QString &))); connect(qleUsername, SIGNAL(textEdited(const QString &)), this, SLOT(onDirty(const QString &))); connect(qlePort, SIGNAL(textEdited(const QString &)), this, SLOT(onDirty(const QString &))); +#ifdef USE_BONJOUR + connect(qtwLanServers, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(on_qpbLanBrowserConnect_clicked())); +#endif qlePort->setValidator(new QIntValidator(1, 65535, qlePort)); @@ -101,12 +103,15 @@ ConnectDialog::ConnectDialog(QWidget *p) : QDialog(p) { } fillList(); - qtwTab->setCurrentIndex(0); - if (qstmServers->rowCount() < 1) { on_qpbAdd_clicked(); qtwTab->setCurrentIndex(1); } + + if (!initLanList()) + qtwTab->removeTab(qtwTab->indexOf(qwTabLan)); + + qtwTab->setCurrentIndex(0); } void ConnectDialog::accept() { @@ -173,6 +178,80 @@ void ConnectDialog::initList() { connect(rep, SIGNAL(finished()), this, SLOT(finished())); } +bool ConnectDialog::initLanList() { +#ifdef USE_BONJOUR + // Make sure the we got the objects we need, then wire them up + if (g.bc->bsbBrowser == NULL || g.bc->bsrResolver == NULL) return false; + connect(g.bc->bsbBrowser, SIGNAL(error(DNSServiceErrorType)), + this, SLOT(onLanBrowseError(DNSServiceErrorType))); + connect(g.bc->bsbBrowser, SIGNAL(currentBonjourRecordsChanged(const QList &)), + this, SLOT(onUpdateLanList(const QList &))); + connect(g.bc->bsrResolver, SIGNAL(error(DNSServiceErrorType)), + this, SLOT(onLanResolveError(DNSServiceErrorType))); + connect(g.bc->bsrResolver, SIGNAL(bonjourRecordResolved(const QHostInfo &, int)), + this, SLOT(accept(const QHostInfo &, int))); + // Manually update list + onUpdateLanList(g.bc->bsbBrowser->currentRecords()); + return true; +#else + return false; +#endif +} + +#ifdef USE_BONJOUR +void ConnectDialog::accept(const QHostInfo &host, int port) { + if (!bResolving) return; + bResolving = false; + + const QList &addrs = host.addresses(); + if (addrs.isEmpty()) return; + + QHostAddress addr(addrs.first()); + + bool ok; + QString defUserName = QInputDialog::getText(this, tr("Connecting to %1").arg(host.hostName()), tr("Enter username"), QLineEdit::Normal, g.s.qsUsername, &ok).trimmed(); + if (! ok) + return; + g.s.qsUsername = defUserName; + qsUsername = defUserName; + qsPassword = QString(); + qsServer = addr.toString(); + usPort = port; + + QDialog::accept(); +} + +void ConnectDialog::onUpdateLanList(const QList &list) { + qtwLanServers->clear(); + + foreach (BonjourRecord record, list) { + QVariant hrecord; + hrecord.setValue(record); + QTreeWidgetItem *tmp = new QTreeWidgetItem(qtwLanServers, QStringList() << record.serviceName); + tmp->setData(0, Qt::UserRole, hrecord); + } +} + +void ConnectDialog::onLanBrowseError(DNSServiceErrorType err) { + /*DEBUG REMOVE LATER TOFIX TODO*/qWarning()<<"Bonjour reported browser error "<< err; +} + +void ConnectDialog::onLanResolveError(DNSServiceErrorType err) { + bResolving = false; // Make sure we don't get stuck due to failed resolving + /*DEBUG REMOVE LATER TOFIX TODO*/qWarning()<<"Bonjour reported resolver error "<< err; +} + +void ConnectDialog::on_qpbLanBrowserConnect_clicked() { + QTreeWidgetItem *item = qtwLanServers->currentItem(); + if (! item) + return; + + QVariant hrecord = item->data(0, Qt::UserRole); + g.bc->bsrResolver->resolveBonjourRecord(hrecord.value()); + bResolving = true; +} +#endif + void ConnectDialog::fillList() { qtwServers->clear(); @@ -386,5 +465,6 @@ void ConnectDialog::on_qtwTab_currentChanged(int idx) { if (idx != 1) return; - initList(); + if (idx == 1) + initList(); } diff --git a/src/mumble/ConnectDialog.h b/src/mumble/ConnectDialog.h index 3a08b1a36..06bfc2da5 100644 --- a/src/mumble/ConnectDialog.h +++ b/src/mumble/ConnectDialog.h @@ -35,6 +35,10 @@ #include "ui_ConnectDialog.h" #include "Timer.h" +#ifdef USE_BONJOUR +#include "BonjourClient.h" +#endif + struct PublicInfo { QString name; QUrl url; @@ -61,14 +65,24 @@ class ConnectDialog : public QDialog, public Ui::ConnectDialog { QModelIndex qmiDirty; QSqlRecord toRecord() const; bool bDirty; + bool bResolving; QHttp *qhList; + bool initLanList(); void initList(); void fillList(); void fillEmpty(); public slots: void accept(); void finished(); +#ifdef USE_BONJOUR + void accept(const QHostInfo &, int); + void onUpdateLanList(const QList &); + void onLanBrowseError(DNSServiceErrorType); + void onLanResolveError(DNSServiceErrorType); + + void on_qpbLanBrowserConnect_clicked(); +#endif void on_qpbAdd_clicked(); void on_qpbRemove_clicked(); void onSelection_Changed(const QModelIndex &n, const QModelIndex &p); diff --git a/src/mumble/ConnectDialog.ui b/src/mumble/ConnectDialog.ui index cda774f08..38793fbc9 100644 --- a/src/mumble/ConnectDialog.ui +++ b/src/mumble/ConnectDialog.ui @@ -1,326 +1,388 @@ - - - ConnectDialog - - - - 0 - 0 - 505 - 296 - - - - Mumble Server Connect - - - - - - 0 - - - - &Custom Servers - - - - - - - - QAbstractItemView::NoEditTriggers - - - - - - - - - &Label - - - qleName - - - - - - - A&ddress - - - qleServer - - - - - - - &Port - - - qlePort - - - - - - - &Username - - - qleUsername - - - - - - - - - - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - - - &Connect - - - true - - - - - - - &Cancel - - - - - - - &Add - - - - - - - false - - - &Remove - - - - - - - - - - Server &Browser - - - - - - true - - - false - - - true - - - false - - - true - - - - Label - - - - - Address - - - - - URL - - - - - - - - - - &Connect - - - true - - - - - - - Cancel - - - - - - - C&opy to custom - - - - - - - &View Webpage - - - - - - - - - - - - - - - qpbConnect - clicked() - ConnectDialog - accept() - - - 21 - 248 - - - 199 - 541 - - - - - qpbCancel - clicked() - ConnectDialog - reject() - - - 248 - 248 - - - 444 - 541 - - - - - qlwServers - doubleClicked(QModelIndex) - ConnectDialog - accept() - - - 109 - 196 - - - 133 - 654 - - - - - qpbBrowserConnect - clicked() - ConnectDialog - accept() - - - 119 - 263 - - - 117 - 370 - - - - - qpbBrowserCancel - clicked() - ConnectDialog - reject() - - - 138 - 248 - - - 20 - 20 - - - - - qtwServers - doubleClicked(QModelIndex) - ConnectDialog - accept() - - - 158 - 128 - - - 185 - 436 - - - - - + + + ConnectDialog + + + + 0 + 0 + 505 + 296 + + + + Mumble Server Connect + + + + + + 0 + + + + &Custom Servers + + + + + + + + QAbstractItemView::NoEditTriggers + + + + + + + + + &Label + + + qleName + + + + + + + A&ddress + + + qleServer + + + + + + + &Port + + + qlePort + + + + + + + &Username + + + qleUsername + + + + + + + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + &Connect + + + true + + + + + + + &Cancel + + + + + + + &Add + + + + + + + false + + + &Remove + + + + + + + + + + Server &Browser + + + + + + true + + + false + + + true + + + false + + + true + + + + Label + + + + + Address + + + + + URL + + + + + + + + + + &Connect + + + true + + + + + + + Cancel + + + + + + + C&opy to custom + + + + + + + &View Webpage + + + + + + + + + + &LAN Browser + + + + + + true + + + false + + + true + + + false + + + true + + + + Label + + + + + + + + + + &Connect + + + true + + + + + + + Cancel + + + + + + + false + + + C&opy to custom + + + + + + + + + + + + + + + qpbConnect + clicked() + ConnectDialog + accept() + + + 21 + 248 + + + 199 + 541 + + + + + qpbCancel + clicked() + ConnectDialog + reject() + + + 248 + 248 + + + 444 + 541 + + + + + qlwServers + doubleClicked(QModelIndex) + ConnectDialog + accept() + + + 109 + 196 + + + 133 + 654 + + + + + qpbBrowserConnect + clicked() + ConnectDialog + accept() + + + 119 + 263 + + + 117 + 370 + + + + + qpbBrowserCancel + clicked() + ConnectDialog + reject() + + + 138 + 248 + + + 20 + 20 + + + + + qtwServers + doubleClicked(QModelIndex) + ConnectDialog + accept() + + + 158 + 128 + + + 185 + 436 + + + + + diff --git a/src/mumble/Global.h b/src/mumble/Global.h index 8c750471d..25feaf76a 100644 --- a/src/mumble/Global.h +++ b/src/mumble/Global.h @@ -48,6 +48,7 @@ class Plugins; class QSettings; class Overlay; class LCD; +class BonjourClient; struct Global { private: @@ -65,6 +66,7 @@ public: QSettings *qs; Overlay *o; LCD *lcd; + BonjourClient *bc; QNetworkAccessManager *nam; int iPushToTalk; Timer tDoublePush; diff --git a/src/mumble/main.cpp b/src/mumble/main.cpp index 5ef9cbc5b..ec90ce302 100644 --- a/src/mumble/main.cpp +++ b/src/mumble/main.cpp @@ -40,6 +40,9 @@ #include "Plugins.h" #include "Global.h" #include "LCD.h" +#ifdef USE_BONJOUR +#include "BonjourClient.h" +#endif #ifdef USE_DBUS #include "DBus.h" #endif @@ -201,6 +204,11 @@ int main(int argc, char **argv) { // Initialize database g.db = new Database(); +#ifdef USE_BONJOUR + // Initialize bonjour + g.bc = new BonjourClient(); +#endif + // Initialize the serverhandler g.sh = new ServerHandler(); g.sh->moveToThread(g.sh); @@ -294,6 +302,9 @@ int main(int argc, char **argv) { delete g.p; delete g.l; +#ifdef USE_BONJOUR + delete g.bc; +#endif delete g.o; diff --git a/src/mumble/mumble.pro b/src/mumble/mumble.pro index eab82c1fd..fffd764ba 100644 --- a/src/mumble/mumble.pro +++ b/src/mumble/mumble.pro @@ -58,6 +58,10 @@ CONFIG(no-bundled-celt) { CONFIG *= g15 } +!CONFIG(no-bonjour) { + CONFIG *= bonjour +} + win32 { RC_FILE = mumble.rc HEADERS *= GlobalShortcut_win.h @@ -178,6 +182,21 @@ asio { INCLUDEPATH *= ../../asio/common ../../asio/host ../../asio/host/pc } +bonjour { + DEFINES *= USE_BONJOUR + + HEADERS *= ../bonjour/bonjourrecord.h ../bonjour/bonjourserviceresolver.h ../bonjour/bonjourservicebrowser.h BonjourClient.h + SOURCES *= ../bonjour/bonjourserviceresolver.cpp ../bonjour/bonjourservicebrowser.cpp BonjourClient.cpp + win32 { + INCLUDEPATH *= /dev/Bonjour/include + LIBPATH *= /dev/Bonjour/lib/win32 + LIBS *= -ldelayimp -lDNSSD -delayload:DNSSD.DLL + } + unix { + PKGCONFIG *= avahi-compat-libdns_sd + } +} + dbus { DEFINES *= USE_DBUS CONFIG *= qdbus diff --git a/src/murmur/BonjourServer.cpp b/src/murmur/BonjourServer.cpp new file mode 100644 index 000000000..47665a0d0 --- /dev/null +++ b/src/murmur/BonjourServer.cpp @@ -0,0 +1,51 @@ +/* Copyright (C) 2009, Stefan Hacker + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + - Neither the name of the Mumble Developers nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#include "BonjourServer.h" + +bool BonjourServer::bDelayLoadFailed = false; + +BonjourServer::BonjourServer() : bsrRegister(NULL) { + if (bDelayLoadFailed) return; + + HMODULE hLib = LoadLibrary(L"DNSSD.DLL"); + if (hLib == NULL) { + bDelayLoadFailed = true; + qWarning("Bonjour: Failed to load dnssd.dll"); + return; + } + FreeLibrary(hLib); + + bsrRegister = new BonjourServiceRegister(this); +} + +BonjourServer::~BonjourServer() { + if (bsrRegister) + delete bsrRegister; +} diff --git a/src/murmur/BonjourServer.h b/src/murmur/BonjourServer.h new file mode 100644 index 000000000..797f1b6e1 --- /dev/null +++ b/src/murmur/BonjourServer.h @@ -0,0 +1,52 @@ +/* Copyright (C) 2009, Stefan Hacker + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + - Neither the name of the Mumble Developers nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef _BONJOURSERVER_H +#define _BONJOURSERVER_H + +#include +#include "../Bonjour/bonjourserviceregister.h" + +class BonjourServer : public QObject { + private: + Q_OBJECT + Q_DISABLE_COPY(BonjourServer) + protected: + static bool bDelayLoadFailed; + public: + BonjourServer(); + ~BonjourServer(); + + BonjourServiceRegister *bsrRegister; +}; + +#else +class Bonjour; +class BonjourServer; +#endif diff --git a/src/murmur/Meta.cpp b/src/murmur/Meta.cpp index 005e5b254..6d6c0103d 100644 --- a/src/murmur/Meta.cpp +++ b/src/murmur/Meta.cpp @@ -188,6 +188,7 @@ void MetaParams::read(QString fname) { qsRegPassword = qs.value("registerPassword", qsRegPassword).toString(); qsRegHost = qs.value("registerHostname", qsRegHost).toString(); qurlRegWeb = QUrl(qs.value("registerUrl", qurlRegWeb.toString()).toString()); + bBonjour = qs.value("bonjour", bBonjour).toBool(); iBanTries = qs.value("autobanAttempts", iBanTries).toInt(); iBanTimeframe = qs.value("autobanTimeframe", iBanTimeframe).toInt(); @@ -326,6 +327,7 @@ void MetaParams::read(QString fname) { qmConfig.insert(QLatin1String("registerpassword"),qsRegPassword); qmConfig.insert(QLatin1String("registerhostname"),qsRegHost); qmConfig.insert(QLatin1String("registerurl"),qurlRegWeb.toString()); + qmConfig.insert(QLatin1String("bonjour"), bBonjour ? QLatin1String("true") : QLatin1String("false")); qmConfig.insert(QLatin1String("certificate"),qscCert.toPem()); qmConfig.insert(QLatin1String("key"),qskKey.toPem()); qmConfig.insert(QLatin1String("obfuscate"),bObfuscate ? QLatin1String("true") : QLatin1String("false")); diff --git a/src/murmur/Meta.h b/src/murmur/Meta.h index 386f2cd36..5f9d615b1 100644 --- a/src/murmur/Meta.h +++ b/src/murmur/Meta.h @@ -75,6 +75,7 @@ struct MetaParams { QString qsRegPassword; QString qsRegHost; QUrl qurlRegWeb; + bool bBonjour; QRegExp qrUserName; QRegExp qrChannelName; diff --git a/src/murmur/Server.cpp b/src/murmur/Server.cpp index 3e5467d72..a09ffd352 100644 --- a/src/murmur/Server.cpp +++ b/src/murmur/Server.cpp @@ -81,6 +81,9 @@ ServerUser::ServerUser(Server *p, QSslSocket *socket) : Connection(p, socket), U Server::Server(int snum, QObject *p) : QThread(p) { bValid = true; iServerNum = snum; +#ifdef USE_BONJOUR + bsRegistration = NULL; +#endif #ifdef Q_OS_UNIX aiNotify[0] = aiNotify[1] = -1; @@ -181,7 +184,18 @@ Server::Server(int snum, QObject *p) : QThread(p) { readLinks(); initializeCert(); - initRegister(); + if (bValid) { +#ifdef USE_BONJOUR + bsRegistration = new BonjourServer(); + if (bsRegistration->bsrRegister) { + log("Announcing server via bonjour"); + bsRegistration->bsrRegister->registerService(BonjourRecord(qsRegName, "_murmur._tcp", ""), + usPort); + } +#endif + initRegister(); + + } } void Server::startThread() { @@ -220,6 +234,11 @@ void Server::stopThread() { } Server::~Server() { +#ifdef USE_BONJOUR + if (bsRegistration) + delete bsRegistration; +#endif + stopThread(); #ifdef Q_OS_UNIX @@ -254,6 +273,7 @@ void Server::readParams() { qsRegPassword = Meta::mp.qsRegPassword; qsRegHost = Meta::mp.qsRegHost; qurlRegWeb = Meta::mp.qurlRegWeb; + bBonjour = Meta::mp.bBonjour; qrUserName = Meta::mp.qrUserName; qrChannelName = Meta::mp.qrChannelName; @@ -296,6 +316,7 @@ void Server::readParams() { qsRegPassword = getConf("registerpassword", qsRegPassword).toString(); qsRegHost = getConf("registerhostname", qsRegHost).toString(); qurlRegWeb = QUrl(getConf("registerurl", qurlRegWeb.toString()).toString()); + bBonjour = getConf("bonjour", bBonjour).toBool(); qrUserName=QRegExp(getConf("username", qrUserName.pattern()).toString()); qrChannelName=QRegExp(getConf("channelname", qrChannelName.pattern()).toString()); @@ -324,6 +345,8 @@ void Server::setLiveConf(const QString &key, const QString &value) { qsRegHost = !v.isNull() ? v : Meta::mp.qsRegHost; else if (key == "registerurl") qurlRegWeb = !v.isNull() ? v : Meta::mp.qurlRegWeb; + else if (key == "bonjour") + bBonjour = !v.isNull() ? (v.toLower() == QLatin1String("true") || v.toLower() == QLatin1String("1") ) : Meta::mp.bBonjour; else if (key == "username") qrUserName=!v.isNull() ? QRegExp(v) : Meta::mp.qrUserName; else if (key == "channelname") diff --git a/src/murmur/Server.h b/src/murmur/Server.h index 362ea75a7..9b29734e0 100644 --- a/src/murmur/Server.h +++ b/src/murmur/Server.h @@ -40,6 +40,10 @@ #include "ACL.h" #include "DBus.h" +#ifdef USE_BONJOUR +#include "BonjourServer.h" +#endif + class Channel; class PacketDataStream; @@ -162,6 +166,10 @@ class Server : public QThread { protected: bool bRunning; +#ifdef USE_BONJOUR + BonjourServer *bsRegistration; +#endif + void startThread(); void stopThread(); @@ -181,6 +189,7 @@ class Server : public QThread { QString qsRegPassword; QString qsRegHost; QUrl qurlRegWeb; + bool bBonjour; QRegExp qrUserName; QRegExp qrChannelName; diff --git a/src/murmur/murmur.pro b/src/murmur/murmur.pro index a11abd788..f6ea50a59 100644 --- a/src/murmur/murmur.pro +++ b/src/murmur/murmur.pro @@ -29,6 +29,9 @@ PRECOMPILED_HEADER = murmur_pch.h CONFIG *= dbus } +!CONFIG(no-bonjour) { + CONFIG *= bonjour +} win32 { RC_FILE = murmur.rc @@ -106,3 +109,19 @@ ice { slice.commands = /opt/Ice-3.3/bin/slice2cpp Murmur.ice } } + +bonjour { + DEFINES *= USE_BONJOUR + + HEADERS *= ../bonjour/bonjourrecord.h ../bonjour/bonjourserviceregister.h BonjourServer.h + SOURCES *= ../bonjour/bonjourserviceregister.cpp BonjourServer.cpp + win32 { + INCLUDEPATH *= /dev/Bonjour/include + LIBPATH *= /dev/Bonjour/lib/win32 + LIBS *= -ldelayimp -lDNSSD -delayload:DNSSD.DLL + } + unix { + PKGCONFIG *= avahi-compat-libdns_sd + } +} +