servicebrowser.cpp
00001 /* This file is part of the KDE project 00002 * 00003 * Copyright (C) 2004 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 <signal.h> 00022 #include <errno.h> 00023 #include <tqstringlist.h> 00024 #include <tqfile.h> 00025 #include "domainbrowser.h" 00026 #include "responder.h" 00027 #include "query.h" 00028 #include "servicebrowser.h" 00029 #ifdef HAVE_DNSSD 00030 #include <avahi-client/client.h> 00031 #endif 00032 #include <config.h> 00033 00034 namespace DNSSD 00035 { 00036 00037 const TQString ServiceBrowser::AllServices = "_services._dns-sd._udp"; 00038 00039 class ServiceBrowserPrivate 00040 { 00041 public: 00042 ServiceBrowserPrivate() : m_running(false) 00043 {} 00044 TQValueList<RemoteService::Ptr> m_services; 00045 TQValueList<RemoteService::Ptr> m_duringResolve; 00046 TQStringList m_types; 00047 DomainBrowser* m_domains; 00048 int m_flags; 00049 bool m_running; 00050 bool m_finished; 00051 TQDict<Query> resolvers; 00052 }; 00053 00054 ServiceBrowser::ServiceBrowser(const TQString& type,DomainBrowser* domains,bool autoResolve) 00055 { 00056 if (domains) init(type,domains,autoResolve ? AutoResolve : 0); 00057 else init(type,new DomainBrowser(this),autoResolve ? AutoResolve|AutoDelete : AutoDelete); 00058 } 00059 ServiceBrowser::ServiceBrowser(const TQStringList& types,DomainBrowser* domains,int flags) 00060 { 00061 if (domains) init(types,domains,flags); 00062 else init(types,new DomainBrowser(this),flags|AutoDelete); 00063 } 00064 00065 void ServiceBrowser::init(const TQStringList& type,DomainBrowser* domains,int flags) 00066 { 00067 d = new ServiceBrowserPrivate(); 00068 d->resolvers.setAutoDelete(true); 00069 d->m_types=type; 00070 d->m_flags=flags; 00071 d->m_domains = domains; 00072 connect(d->m_domains,TQT_SIGNAL(domainAdded(const TQString& )),this,TQT_SLOT(addDomain(const TQString& ))); 00073 connect(d->m_domains,TQT_SIGNAL(domainRemoved(const TQString& )),this, 00074 TQT_SLOT(removeDomain(const TQString& ))); 00075 } 00076 ServiceBrowser::ServiceBrowser(const TQString& type,const TQString& domain,bool autoResolve) 00077 { 00078 init(type,new DomainBrowser(domain,false,this),autoResolve ? AutoResolve|AutoDelete : AutoDelete); 00079 } 00080 ServiceBrowser::ServiceBrowser(const TQString& type,const TQString& domain,int flags) 00081 { 00082 init(type,new DomainBrowser(domain,false,this),flags | AutoDelete); 00083 } 00084 00085 const ServiceBrowser::State ServiceBrowser::isAvailable() 00086 { 00087 #ifdef HAVE_DNSSD 00088 AvahiClientState s = Responder::self().state(); 00089 #ifdef AVAHI_API_0_6 00090 return (s==AVAHI_CLIENT_FAILURE) ? Stopped : Working; 00091 #else 00092 return (s==AVAHI_CLIENT_S_INVALID || s==AVAHI_CLIENT_DISCONNECTED) ? Stopped : Working; 00093 #endif 00094 #else 00095 return Unsupported; 00096 #endif 00097 } 00098 ServiceBrowser::~ ServiceBrowser() 00099 { 00100 if (d->m_flags & AutoDelete) delete d->m_domains; 00101 delete d; 00102 } 00103 00104 const DomainBrowser* ServiceBrowser::browsedDomains() const 00105 { 00106 return d->m_domains; 00107 } 00108 00109 void ServiceBrowser::serviceResolved(bool success) 00110 { 00111 TQObject* sender_obj = const_cast<TQObject*>(TQT_TQOBJECT_CONST(sender())); 00112 RemoteService* svr = static_cast<RemoteService*>(sender_obj); 00113 disconnect(svr,TQT_SIGNAL(resolved(bool)),this,TQT_SLOT(serviceResolved(bool))); 00114 TQValueList<RemoteService::Ptr>::Iterator it = d->m_duringResolve.begin(); 00115 TQValueList<RemoteService::Ptr>::Iterator itEnd = d->m_duringResolve.end(); 00116 while ( it!= itEnd && svr!= (*it)) ++it; 00117 if (it != itEnd) { 00118 if (success) { 00119 d->m_services+=(*it); 00120 emit serviceAdded(svr); 00121 } 00122 d->m_duringResolve.remove(it); 00123 queryFinished(); 00124 } 00125 } 00126 00127 void ServiceBrowser::startBrowse() 00128 { 00129 if (d->m_running) return; 00130 d->m_running=true; 00131 if (isAvailable()!=Working) return; 00132 if (d->m_domains->isRunning()) { 00133 TQStringList::const_iterator itEnd = d->m_domains->domains().end(); 00134 for ( TQStringList::const_iterator it = d->m_domains->domains().begin(); it != itEnd; ++it ) 00135 addDomain(*it); 00136 } else d->m_domains->startBrowse(); 00137 } 00138 00139 void ServiceBrowser::gotNewService(RemoteService::Ptr svr) 00140 { 00141 if (findDuplicate(svr)==(d->m_services.end())) { 00142 if (d->m_flags & AutoResolve) { 00143 connect(svr,TQT_SIGNAL(resolved(bool )),this,TQT_SLOT(serviceResolved(bool ))); 00144 d->m_duringResolve+=svr; 00145 svr->resolveAsync(); 00146 } else { 00147 d->m_services+=svr; 00148 emit serviceAdded(svr); 00149 } 00150 } 00151 } 00152 00153 void ServiceBrowser::gotRemoveService(RemoteService::Ptr svr) 00154 { 00155 TQValueList<RemoteService::Ptr>::Iterator it = findDuplicate(svr); 00156 if (it!=(d->m_services.end())) { 00157 emit serviceRemoved(*it); 00158 d->m_services.remove(it); 00159 } 00160 } 00161 00162 00163 void ServiceBrowser::removeDomain(const TQString& domain) 00164 { 00165 while (d->resolvers[domain]) d->resolvers.remove(domain); 00166 TQValueList<RemoteService::Ptr>::Iterator it = d->m_services.begin(); 00167 while (it!=d->m_services.end()) 00168 // use section to skip possible trailing dot 00169 if ((*it)->domain().section('.',0) == domain.section('.',0)) { 00170 emit serviceRemoved(*it); 00171 it = d->m_services.remove(it); 00172 } else ++it; 00173 } 00174 00175 void ServiceBrowser::addDomain(const TQString& domain) 00176 { 00177 if (!d->m_running) return; 00178 if (!(d->resolvers[domain])) { 00179 TQStringList::ConstIterator itEnd = d->m_types.end(); 00180 for (TQStringList::ConstIterator it=d->m_types.begin(); it!=itEnd; ++it) { 00181 Query* b = new Query((*it),domain); 00182 connect(b,TQT_SIGNAL(serviceAdded(DNSSD::RemoteService::Ptr)),this, 00183 TQT_SLOT(gotNewService(DNSSD::RemoteService::Ptr))); 00184 connect(b,TQT_SIGNAL(serviceRemoved(DNSSD::RemoteService::Ptr )),this, 00185 TQT_SLOT(gotRemoveService(DNSSD::RemoteService::Ptr))); 00186 connect(b,TQT_SIGNAL(finished()),this,TQT_SLOT(queryFinished())); 00187 b->startQuery(); 00188 d->resolvers.insert(domain,b); 00189 } 00190 } 00191 } 00192 00193 void ServiceBrowser::queryFinished() 00194 { 00195 if (allFinished()) emit finished(); 00196 } 00197 00198 bool ServiceBrowser::allFinished() 00199 { 00200 if (d->m_duringResolve.count()) return false; 00201 bool all = true; 00202 TQDictIterator<Query> it(d->resolvers); 00203 for ( ; it.current(); ++it) all&=(*it)->isFinished(); 00204 return all; 00205 } 00206 00207 const TQValueList<RemoteService::Ptr>& ServiceBrowser::services() const 00208 { 00209 return d->m_services; 00210 } 00211 00212 void ServiceBrowser::virtual_hook(int, void*) 00213 {} 00214 00215 TQValueList<RemoteService::Ptr>::Iterator ServiceBrowser::findDuplicate(RemoteService::Ptr src) 00216 { 00217 TQValueList<RemoteService::Ptr>::Iterator itEnd = d->m_services.end(); 00218 for (TQValueList<RemoteService::Ptr>::Iterator it = d->m_services.begin(); it!=itEnd; ++it) 00219 if ((src->type()==(*it)->type()) && (src->serviceName()==(*it)->serviceName()) && 00220 (src->domain() == (*it)->domain())) return it; 00221 return itEnd; 00222 } 00223 00224 00225 } 00226 00227 #include "servicebrowser.moc"