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