diff options
author | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
---|---|---|
committer | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
commit | ce4a32fe52ef09d8f5ff1dd22c001110902b60a2 (patch) | |
tree | 5ac38a06f3dde268dc7927dc155896926aaf7012 /dnssd/publicservice.cpp | |
download | tdelibs-ce4a32fe52ef09d8f5ff1dd22c001110902b60a2.tar.gz tdelibs-ce4a32fe52ef09d8f5ff1dd22c001110902b60a2.zip |
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdelibs@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'dnssd/publicservice.cpp')
-rw-r--r-- | dnssd/publicservice.cpp | 230 |
1 files changed, 230 insertions, 0 deletions
diff --git a/dnssd/publicservice.cpp b/dnssd/publicservice.cpp new file mode 100644 index 000000000..7ba749c53 --- /dev/null +++ b/dnssd/publicservice.cpp @@ -0,0 +1,230 @@ +/* This file is part of the KDE project + * + * Copyright (C) 2004, 2005 Jakub Stachowski <qbast@go2.pl> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#include "publicservice.h" +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#include <netinet/in.h> +#include <sys/socket.h> +#include <qapplication.h> +#include <network/ksocketaddress.h> +#include <kurl.h> +#include <unistd.h> +#include "sdevent.h" +#include "responder.h" +#include "servicebrowser.h" +#include "settings.h" + +namespace DNSSD +{ +static unsigned long publicIP(); +#ifdef HAVE_DNSSD +void publish_callback (DNSServiceRef, DNSServiceFlags, DNSServiceErrorType errorCode, const char *name, + const char*, const char*, void *context); +#endif +class PublicServicePrivate : public Responder +{ +public: + PublicServicePrivate() : m_published(false) + {} + bool m_published; +}; + +PublicService::PublicService(const QString& name, const QString& type, unsigned int port, + const QString& domain) + : QObject(), ServiceBase(name, type, QString::null, domain, port) +{ + d = new PublicServicePrivate; + if (domain.isNull()) + if (Configuration::publishType()==Configuration::EnumPublishType::LAN) m_domain="local."; + else m_domain=Configuration::publishDomain(); +} + + +PublicService::~PublicService() +{ + stop(); + delete d; +} + +void PublicService::setServiceName(const QString& serviceName) +{ + m_serviceName = serviceName; + if (d->isRunning()) { + stop(); + publishAsync(); + } +} + +void PublicService::setDomain(const QString& domain) +{ + m_domain = domain; + if (d->isRunning()) { + stop(); + publishAsync(); + } +} + + +void PublicService::setType(const QString& type) +{ + m_type = type; + if (d->isRunning()) { + stop(); + publishAsync(); + } +} + +void PublicService::setPort(unsigned short port) +{ + m_port = port; + if (d->isRunning()) { + stop(); + publishAsync(); + } +} + +bool PublicService::isPublished() const +{ + return d->m_published; +} + +void PublicService::setTextData(const QMap<QString,QString>& textData) +{ + m_textData = textData; + if (d->isRunning()) { + stop(); + publishAsync(); + } +} + +bool PublicService::publish() +{ + publishAsync(); + while (d->isRunning() && !d->m_published) d->process(); + return d->m_published; +} + +void PublicService::stop() +{ + d->stop(); + d->m_published = false; +} + +void PublicService::publishAsync() +{ + if (d->isRunning()) stop(); +#ifdef HAVE_DNSSD + if (ServiceBrowser::isAvailable()==ServiceBrowser::Working) { + TXTRecordRef txt; + TXTRecordCreate(&txt,0,0); + QMap<QString,QString>::ConstIterator itEnd = m_textData.end(); + for (QMap<QString,QString>::ConstIterator it = m_textData.begin(); it!=itEnd ; ++it) { + QCString value = it.data().utf8(); + if (TXTRecordSetValue(&txt,it.key().utf8(),value.length(),value)!=kDNSServiceErr_NoError) { + TXTRecordDeallocate(&txt); + emit published(false); + return; + } + } + DNSServiceRef ref; + if (DNSServiceRegister(&ref,0,0,m_serviceName.utf8(),m_type.ascii(),domainToDNS(m_domain),NULL, + htons(m_port),TXTRecordGetLength(&txt),TXTRecordGetBytesPtr(&txt),publish_callback, + reinterpret_cast<void*>(this)) == kDNSServiceErr_NoError) d->setRef(ref); + TXTRecordDeallocate(&txt); + } +#endif + if (!d->isRunning()) emit published(false); +} + +#ifdef HAVE_DNSSD +void publish_callback (DNSServiceRef, DNSServiceFlags, DNSServiceErrorType errorCode, const char *name, + const char*, const char*, void *context) +{ + QObject *obj = reinterpret_cast<QObject*>(context); + if (errorCode != kDNSServiceErr_NoError) { + ErrorEvent err; + QApplication::sendEvent(obj, &err); + } else { + PublishEvent pev(QString::fromUtf8(name)); + QApplication::sendEvent(obj, &pev); + } +} +#endif + +const KURL PublicService::toInvitation(const QString& host) +{ + KURL url; + url.setProtocol("invitation"); + if (host.isEmpty()) { // select best address + unsigned long s_address = publicIP(); + if (!s_address) return KURL(); + KNetwork::KIpAddress addr(s_address); + url.setHost(addr.toString()); + } else url.setHost(host); + //FIXME: if there is no public interface, select any non-loopback + url.setPort(m_port); + url.setPath("/"+m_type+"/"+KURL::encode_string(m_serviceName)); + QString query; + QMap<QString,QString>::ConstIterator itEnd = m_textData.end(); + for (QMap<QString,QString>::ConstIterator it = m_textData.begin(); it!=itEnd ; ++it) + url.addQueryItem(it.key(),it.data());; + return url; +} + +void PublicService::customEvent(QCustomEvent* event) +{ + if (event->type()==QEvent::User+SD_ERROR) { + stop(); + emit published(false); + } + if (event->type()==QEvent::User+SD_PUBLISH) { + d->m_published=true; + emit published(true); + m_serviceName = static_cast<PublishEvent*>(event)->m_name; + } +} + +void PublicService::virtual_hook(int, void*) +{ +} + +static unsigned long publicIP() +{ + struct sockaddr_in addr; + socklen_t len = sizeof(addr); + int sock = socket(AF_INET,SOCK_DGRAM,0); + if (sock == -1) return 0; + addr.sin_family = AF_INET; + addr.sin_port = 1; // Not important, any port and public address will do + addr.sin_addr.s_addr = 0x11111111; + if ((connect(sock,(const struct sockaddr*)&addr,sizeof(addr))) == -1) { close(sock); return 0; } + if ((getsockname(sock,(struct sockaddr*)&addr, &len)) == -1) { close(sock); return 0; } + ::close(sock); + return addr.sin_addr.s_addr; +} + + +} + +#include "publicservice.moc" |