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