• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • dnssd
 

dnssd

publicservice.cpp
00001 /* This file is part of the KDE project
00002  *
00003  * Copyright (C) 2004, 2005 Jakub Stachowski <qbast@go2.pl>
00004  *
00005  * This library is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU Library General Public
00007  * License as published by the Free Software Foundation; either
00008  * version 2 of the License, or (at your option) any later version.
00009  *
00010  * This library is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  * Library General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU Library General Public License
00016  * along with this library; see the file COPYING.LIB.  If not, write to
00017  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018  * Boston, MA 02110-1301, USA.
00019  */
00020 
00021 #include "config.h"
00022 
00023 #include "publicservice.h"
00024 #ifdef HAVE_SYS_TYPES_H
00025 #include <sys/types.h>
00026 #endif
00027 #include <netinet/in.h>
00028 #include <sys/socket.h>
00029 #include <tqapplication.h>
00030 #include <network/ksocketaddress.h>
00031 #include <kurl.h>
00032 #include <unistd.h>
00033 #ifdef HAVE_DNSSD
00034 #include <avahi-client/client.h>
00035 #ifdef AVAHI_API_0_6
00036 #include <avahi-client/publish.h>
00037 #endif
00038 #include <avahi-common/alternative.h>
00039 #include <avahi-common/strlst.h>
00040 #endif
00041 #include "sdevent.h"
00042 #include "responder.h"
00043 #include "servicebrowser.h"
00044 #include "settings.h"
00045 
00046 namespace DNSSD
00047 {
00048 static unsigned long publicIP();
00049 
00050 #ifdef HAVE_DNSSD
00051 void publish_callback (AvahiEntryGroup*, AvahiEntryGroupState s,  void *context);
00052 #endif
00053 
00054 class PublicServicePrivate
00055 {
00056 public:
00057     PublicServicePrivate() : m_published(false), m_running(false), m_collision(false)
00058 #ifdef HAVE_DNSSD
00059     , m_group(0)
00060 #endif
00061     {}
00062     bool m_published;
00063     bool m_running;
00064     bool m_collision;
00065 #ifdef HAVE_DNSSD
00066     AvahiEntryGroup* m_group;
00067 #endif
00068     void commit()
00069     {
00070 #ifdef HAVE_DNSSD
00071         if (!m_collision) avahi_entry_group_commit(m_group);
00072 #endif
00073     }
00074 
00075 };
00076 
00077 PublicService::PublicService(const TQString& name, const TQString& type, unsigned int port,
00078                   const TQString& domain)
00079         : TQObject(), ServiceBase(name, type, TQString::null, domain, port)
00080 {
00081     d = new PublicServicePrivate;
00082 #ifdef HAVE_DNSSD
00083     if (Responder::self().client()) {
00084         d->m_group = avahi_entry_group_new(Responder::self().client(), publish_callback,this);
00085         connect(&Responder::self(),TQT_SIGNAL(stateChanged(AvahiClientState)),this,TQT_SLOT(clientState(AvahiClientState)));
00086     }
00087 #endif
00088     if (domain.isNull())
00089         if (Configuration::publishType()==Configuration::EnumPublishType::LAN) m_domain="local.";
00090         else m_domain=Configuration::publishDomain();
00091 }
00092 
00093 
00094 PublicService::~PublicService()
00095 {
00096 #ifdef HAVE_DNSSD
00097     if (d->m_group) avahi_entry_group_free(d->m_group);
00098 #endif
00099     delete d;
00100 }
00101 
00102 void PublicService::tryApply()
00103 {
00104     if (fillEntryGroup()) d->commit();
00105     else {
00106     stop();
00107     emit published(false);
00108     }
00109 }
00110 
00111 void PublicService::setServiceName(const TQString& serviceName)
00112 {
00113     m_serviceName = serviceName;
00114 #ifdef HAVE_DNSSD
00115     if (d->m_running) {
00116         avahi_entry_group_reset(d->m_group);
00117         tryApply();
00118     }
00119 #endif
00120 }
00121 
00122 void PublicService::setDomain(const TQString& domain)
00123 {
00124     m_domain = domain;
00125 #ifdef HAVE_DNSSD
00126     if (d->m_running) {
00127         avahi_entry_group_reset(d->m_group);
00128         tryApply();
00129     }
00130 #endif
00131 }
00132 
00133 
00134 void PublicService::setType(const TQString& type)
00135 {
00136     m_type = type;
00137 #ifdef HAVE_DNSSD
00138     if (d->m_running) {
00139         avahi_entry_group_reset(d->m_group);
00140         tryApply();
00141     }
00142 #endif
00143 }
00144 
00145 void PublicService::setPort(unsigned short port)
00146 {
00147     m_port = port;
00148 #ifdef HAVE_DNSSD
00149     if (d->m_running) {
00150         avahi_entry_group_reset(d->m_group);
00151         tryApply();
00152         }
00153 #endif
00154 }
00155 
00156 void PublicService::setTextData(const TQMap<TQString,TQString>& textData)
00157 {
00158     m_textData = textData;
00159 #ifdef HAVE_DNSSD
00160     if (d->m_running) {
00161         avahi_entry_group_reset(d->m_group);
00162         tryApply();
00163     }
00164 #endif
00165 }
00166 
00167 bool PublicService::isPublished() const
00168 {
00169     return d->m_published;
00170 }
00171 
00172 bool PublicService::publish()
00173 {
00174     publishAsync();
00175     while (d->m_running && !d->m_published) Responder::self().process();
00176     return d->m_published;
00177 }
00178 
00179 void PublicService::stop()
00180 {
00181 #ifdef HAVE_DNSSD
00182     if (d->m_group) avahi_entry_group_reset(d->m_group);
00183 #endif
00184     d->m_published = false;
00185 }
00186 bool PublicService::fillEntryGroup()
00187 {
00188 #ifdef HAVE_DNSSD
00189     AvahiStringList *s=0;
00190     TQMap<TQString,TQString>::ConstIterator itEnd = m_textData.end();
00191     for (TQMap<TQString,TQString>::ConstIterator it = m_textData.begin(); it!=itEnd ; ++it)
00192     s = avahi_string_list_add_pair(s, it.key().utf8(),it.data().utf8());
00193 #ifdef AVAHI_API_0_6
00194     bool res = (!avahi_entry_group_add_service_strlst(d->m_group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, (AvahiPublishFlags)0,
00195     m_serviceName.isNull() ? avahi_client_get_host_name(Responder::self().client()) : m_serviceName.utf8().data(),
00196     m_type.ascii(),domainToDNS(m_domain),m_hostName.utf8(),m_port,s));
00197 #else
00198     bool res = (!avahi_entry_group_add_service_strlst(d->m_group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
00199     m_serviceName.isNull() ? avahi_client_get_host_name(Responder::self().client()) : m_serviceName.utf8().data(),
00200     m_type.ascii(),m_domain.utf8(),m_hostName.utf8(),m_port,s));
00201 #endif
00202     avahi_string_list_free(s);
00203     return res;
00204 #else
00205     return FALSE;
00206 #endif
00207 }
00208 
00209 void PublicService::clientState(AvahiClientState s)
00210 {
00211     if (!d->m_running) return;
00212 #ifdef HAVE_DNSSD
00213     switch (s) {
00214 #ifdef AVAHI_API_0_6
00215     case AVAHI_CLIENT_FAILURE:
00216 #else
00217     case AVAHI_CLIENT_S_INVALID:
00218     case AVAHI_CLIENT_DISCONNECTED:
00219 #endif
00220         stop();
00221         emit published(false);
00222         break;
00223     case AVAHI_CLIENT_S_REGISTERING:
00224     case AVAHI_CLIENT_S_COLLISION:
00225         avahi_entry_group_reset(d->m_group);
00226         d->m_collision=true;
00227         break;
00228     case AVAHI_CLIENT_S_RUNNING:
00229         if (d->m_collision) {
00230         d->m_collision=false;
00231         tryApply();
00232         }
00233     }
00234 #endif
00235 }
00236 
00237 void PublicService::publishAsync()
00238 {
00239     if (d->m_running) stop();
00240 
00241 #ifdef HAVE_DNSSD
00242     if (!d->m_group) {
00243         emit published(false);
00244         return;
00245     }
00246     AvahiClientState s=Responder::self().state();
00247 #endif
00248     d->m_running=true;
00249     d->m_collision=true; // make it look like server is getting out of collision to force registering
00250 #ifdef HAVE_DNSSD
00251     clientState(s);
00252 #endif
00253 }
00254 
00255 #ifdef HAVE_DNSSD
00256 void publish_callback (AvahiEntryGroup*, AvahiEntryGroupState s,  void *context)
00257 {
00258     TQObject *obj = reinterpret_cast<TQObject*>(context);
00259     if (s!=AVAHI_ENTRY_GROUP_ESTABLISHED && s!=AVAHI_ENTRY_GROUP_COLLISION) return;
00260     PublishEvent* pev=new PublishEvent(s==AVAHI_ENTRY_GROUP_ESTABLISHED);
00261     TQApplication::postEvent(obj, pev);
00262 }
00263 #endif
00264 
00265 const KURL PublicService::toInvitation(const TQString& host)
00266 {
00267     KURL url;
00268     url.setProtocol("invitation");
00269     if (host.isEmpty()) { // select best address
00270         unsigned long s_address = publicIP();
00271         if (!s_address) return KURL();
00272         KNetwork::KIpAddress addr(s_address);
00273         url.setHost(addr.toString());
00274     } else  url.setHost(host);
00275     //FIXME: if there is no public interface, select any non-loopback
00276     url.setPort(m_port);
00277     url.setPath("/"+m_type+"/"+KURL::encode_string(m_serviceName));
00278     TQString query;
00279     TQMap<TQString,TQString>::ConstIterator itEnd = m_textData.end();
00280     for (TQMap<TQString,TQString>::ConstIterator it = m_textData.begin(); it!=itEnd ; ++it)
00281         url.addQueryItem(it.key(),it.data());;
00282     return url;
00283 }
00284 
00285 void PublicService::customEvent(TQCustomEvent* event)
00286 {
00287 #ifdef HAVE_DNSSD
00288     if (event->type()==TQEvent::User+SD_PUBLISH) {
00289         if (!static_cast<PublishEvent*>(event)->m_ok) {
00290             setServiceName(TQString::fromUtf8(avahi_alternative_service_name(m_serviceName.utf8())));
00291             return;
00292         }
00293         d->m_published=true;
00294         emit published(true);
00295     }
00296 #endif
00297 }
00298 
00299 void PublicService::virtual_hook(int, void*)
00300 {
00301 }
00302 
00303 static unsigned long publicIP()
00304 {
00305     struct sockaddr_in addr;
00306     socklen_t len = sizeof(addr);
00307     int sock = socket(AF_INET,SOCK_DGRAM,0);
00308     if (sock == -1) return 0;
00309     addr.sin_family = AF_INET;
00310     addr.sin_port = 1;  // Not important, any port and public address will do
00311     addr.sin_addr.s_addr = 0x11111111;
00312     if ((connect(sock,(const struct sockaddr*)&addr,sizeof(addr))) == -1) { close(sock); return 0; }
00313     if ((getsockname(sock,(struct sockaddr*)&addr, &len)) == -1) { close(sock); return 0; }
00314     ::close(sock);
00315     return addr.sin_addr.s_addr;
00316 }
00317 
00318 
00319 }
00320 
00321 #include "publicservice.moc"

dnssd

Skip menu "dnssd"
  • Main Page
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

dnssd

Skip menu "dnssd"
  • arts
  • dcop
  • dnssd
  • interfaces
  •     interface
  •     library
  •   kspeech
  •   ktexteditor
  • kabc
  • kate
  • kcmshell
  • kdecore
  • kded
  • kdefx
  • kdeprint
  • kdesu
  • kdeui
  • kdoctools
  • khtml
  • kimgio
  • kinit
  • kio
  •   bookmarks
  •   httpfilter
  •   kfile
  •   kio
  •   kioexec
  •   kpasswdserver
  •   kssl
  • kioslave
  •   http
  • kjs
  • kmdi
  •   kmdi
  • knewstuff
  • kparts
  • krandr
  • kresources
  • kspell2
  • kunittest
  • kutils
  • kwallet
  • libkmid
  • libkscreensaver
Generated for dnssd by doxygen 1.7.6.1
This website is maintained by Timothy Pearson.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. |