remoteservice.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 <qeventloop.h> 00024 #include <qapplication.h> 00025 #include <kurl.h> 00026 #ifdef HAVE_SYS_TYPES_H 00027 #include <sys/types.h> 00028 #endif 00029 #include <netinet/in.h> 00030 #include <avahi-client/client.h> 00031 #include <avahi-common/strlst.h> 00032 #ifdef AVAHI_API_0_6 00033 #include <avahi-client/lookup.h> 00034 #endif 00035 #include "remoteservice.h" 00036 #include "responder.h" 00037 #include "sdevent.h" 00038 #include <kdebug.h> 00039 00040 namespace DNSSD 00041 { 00042 #ifdef AVAHI_API_0_6 00043 void resolve_callback(AvahiServiceResolver*, AvahiIfIndex, AvahiProtocol proto, AvahiResolverEvent e, 00044 const char* name, const char* type, const char* domain, const char* hostname, const AvahiAddress* a, 00045 uint16_t port, AvahiStringList* txt, AvahiLookupResultFlags, void* context); 00046 #else 00047 void resolve_callback(AvahiServiceResolver*, AvahiIfIndex, AvahiProtocol proto, AvahiResolverEvent e, 00048 const char* name, const char* type, const char* domain, const char* hostname, const AvahiAddress* a, 00049 uint16_t port, AvahiStringList* txt, void* context); 00050 #endif 00051 00052 class RemoteServicePrivate : public Responder 00053 { 00054 public: 00055 RemoteServicePrivate() : m_resolved(false), m_running(false), m_resolver(0) {} 00056 bool m_resolved; 00057 bool m_running; 00058 AvahiServiceResolver* m_resolver; 00059 void stop() { 00060 m_running = false; 00061 if (m_resolver) avahi_service_resolver_free(m_resolver); 00062 m_resolver=0; 00063 } 00064 }; 00065 00066 RemoteService::RemoteService(const QString& label) 00067 { 00068 decode(label); 00069 d = new RemoteServicePrivate(); 00070 } 00071 RemoteService::RemoteService(const QString& name,const QString& type,const QString& domain) 00072 : ServiceBase(name, type, domain) 00073 { 00074 d = new RemoteServicePrivate(); 00075 } 00076 00077 RemoteService::RemoteService(const KURL& url) 00078 { 00079 d = new RemoteServicePrivate(); 00080 if (!url.isValid()) return; 00081 if (url.protocol()!="invitation") return; 00082 if (!url.hasPath()) return; 00083 m_hostName = url.host(); 00084 m_port = url.port(); 00085 m_type = url.path().section('/',1,1); 00086 m_serviceName = url.path().section('/',2); 00087 m_textData = url.queryItems(); 00088 d->m_resolved=true; 00089 } 00090 00091 RemoteService::~RemoteService() 00092 { 00093 if (d->m_resolver) avahi_service_resolver_free(d->m_resolver); 00094 delete d; 00095 } 00096 00097 bool RemoteService::resolve() 00098 { 00099 resolveAsync(); 00100 while (d->m_running && !d->m_resolved) Responder::self().process(); 00101 d->stop(); 00102 return d->m_resolved; 00103 } 00104 00105 void RemoteService::resolveAsync() 00106 { 00107 if (d->m_running) return; 00108 d->m_resolved = false; 00109 // FIXME: first protocol should be set? 00110 #ifdef AVAHI_API_0_6 00111 d->m_resolver = avahi_service_resolver_new(Responder::self().client(),AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 00112 m_serviceName.utf8(), m_type.ascii(), domainToDNS(m_domain), AVAHI_PROTO_UNSPEC, AVAHI_LOOKUP_NO_ADDRESS, 00113 resolve_callback, this); 00114 #else 00115 d->m_resolver = avahi_service_resolver_new(Responder::self().client(),AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 00116 m_serviceName.utf8(), m_type.ascii(), m_domain.utf8(), AVAHI_PROTO_UNSPEC, resolve_callback, this); 00117 #endif 00118 if (d->m_resolver) d->m_running=true; 00119 else emit resolved(false); 00120 } 00121 00122 bool RemoteService::isResolved() const 00123 { 00124 return d->m_resolved; 00125 } 00126 00127 void RemoteService::customEvent(QCustomEvent* event) 00128 { 00129 if (event->type() == QEvent::User+SD_ERROR) { 00130 d->stop(); 00131 d->m_resolved=false; 00132 emit resolved(false); 00133 } 00134 if (event->type() == QEvent::User+SD_RESOLVE) { 00135 ResolveEvent* rev = static_cast<ResolveEvent*>(event); 00136 m_hostName = rev->m_hostname; 00137 m_port = rev->m_port; 00138 m_textData = rev->m_txtdata; 00139 d->m_resolved = true; 00140 emit resolved(true); 00141 } 00142 } 00143 00144 void RemoteService::virtual_hook(int, void*) 00145 { 00146 // BASE::virtual_hook(int, void*); 00147 } 00148 00149 QDataStream & operator<< (QDataStream & s, const RemoteService & a) 00150 { 00151 s << (static_cast<ServiceBase>(a)); 00152 Q_INT8 resolved = a.d->m_resolved ? 1:0; 00153 s << resolved; 00154 return s; 00155 } 00156 00157 QDataStream & operator>> (QDataStream & s, RemoteService & a) 00158 { 00159 // stop any possible resolve going on 00160 a.d->stop(); 00161 Q_INT8 resolved; 00162 operator>>(s,(static_cast<ServiceBase&>(a))); 00163 s >> resolved; 00164 a.d->m_resolved = (resolved == 1); 00165 return s; 00166 } 00167 00168 00169 #ifdef AVAHI_API_0_6 00170 void resolve_callback(AvahiServiceResolver*, AvahiIfIndex, AvahiProtocol, AvahiResolverEvent e, 00171 const char*, const char*, const char*, const char* hostname, const AvahiAddress*, 00172 uint16_t port, AvahiStringList* txt, AvahiLookupResultFlags, void* context) 00173 #else 00174 void resolve_callback(AvahiServiceResolver*, AvahiIfIndex, AvahiProtocol, AvahiResolverEvent e, 00175 const char*, const char*, const char*, const char* hostname, const AvahiAddress*, 00176 uint16_t port, AvahiStringList* txt, void* context) 00177 #endif 00178 { 00179 QObject *obj = reinterpret_cast<QObject*>(context); 00180 if (e != AVAHI_RESOLVER_FOUND) { 00181 ErrorEvent err; 00182 QApplication::sendEvent(obj, &err); 00183 return; 00184 } 00185 QMap<QString,QString> map; 00186 const void *voidValue = 0; 00187 while (txt) { 00188 char *key, *value; 00189 size_t size; 00190 if (avahi_string_list_get_pair(txt,&key,&value,&size)) break; 00191 map[QString::fromUtf8(key)]=(value) ? QString::fromUtf8(value) : QString::null; 00192 txt = txt->next; 00193 } 00194 ResolveEvent rev(DNSToDomain(hostname),port,map); 00195 QApplication::sendEvent(obj, &rev); 00196 } 00197 00198 00199 } 00200 00201 #include "remoteservice.moc"