00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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 <qapplication.h>
00030 #include <network/ksocketaddress.h>
00031 #include <kurl.h>
00032 #include <unistd.h>
00033 #include "sdevent.h"
00034 #include "responder.h"
00035 #include "servicebrowser.h"
00036 #include "settings.h"
00037
00038 namespace DNSSD
00039 {
00040 static unsigned long publicIP();
00041 #ifdef HAVE_DNSSD
00042 void publish_callback (DNSServiceRef, DNSServiceFlags, DNSServiceErrorType errorCode, const char *name,
00043 const char*, const char*, void *context);
00044 #endif
00045 class PublicServicePrivate : public Responder
00046 {
00047 public:
00048 PublicServicePrivate() : m_published(false)
00049 {}
00050 bool m_published;
00051 };
00052
00053 PublicService::PublicService(const QString& name, const QString& type, unsigned int port,
00054 const QString& domain)
00055 : QObject(), ServiceBase(name, type, QString::null, domain, port)
00056 {
00057 d = new PublicServicePrivate;
00058 if (domain.isNull())
00059 if (Configuration::publishType()==Configuration::EnumPublishType::LAN) m_domain="local.";
00060 else m_domain=Configuration::publishDomain();
00061 }
00062
00063
00064 PublicService::~PublicService()
00065 {
00066 stop();
00067 delete d;
00068 }
00069
00070 void PublicService::setServiceName(const QString& serviceName)
00071 {
00072 m_serviceName = serviceName;
00073 if (d->isRunning()) {
00074 stop();
00075 publishAsync();
00076 }
00077 }
00078
00079 void PublicService::setDomain(const QString& domain)
00080 {
00081 m_domain = domain;
00082 if (d->isRunning()) {
00083 stop();
00084 publishAsync();
00085 }
00086 }
00087
00088
00089 void PublicService::setType(const QString& type)
00090 {
00091 m_type = type;
00092 if (d->isRunning()) {
00093 stop();
00094 publishAsync();
00095 }
00096 }
00097
00098 void PublicService::setPort(unsigned short port)
00099 {
00100 m_port = port;
00101 if (d->isRunning()) {
00102 stop();
00103 publishAsync();
00104 }
00105 }
00106
00107 bool PublicService::isPublished() const
00108 {
00109 return d->m_published;
00110 }
00111
00112 void PublicService::setTextData(const QMap<QString,QString>& textData)
00113 {
00114 m_textData = textData;
00115 if (d->isRunning()) {
00116 stop();
00117 publishAsync();
00118 }
00119 }
00120
00121 bool PublicService::publish()
00122 {
00123 publishAsync();
00124 while (d->isRunning() && !d->m_published) d->process();
00125 return d->m_published;
00126 }
00127
00128 void PublicService::stop()
00129 {
00130 d->stop();
00131 d->m_published = false;
00132 }
00133
00134 void PublicService::publishAsync()
00135 {
00136 if (d->isRunning()) stop();
00137 #ifdef HAVE_DNSSD
00138 if (ServiceBrowser::isAvailable()==ServiceBrowser::Working) {
00139 TXTRecordRef txt;
00140 TXTRecordCreate(&txt,0,0);
00141 QMap<QString,QString>::ConstIterator itEnd = m_textData.end();
00142 for (QMap<QString,QString>::ConstIterator it = m_textData.begin(); it!=itEnd ; ++it) {
00143 QCString value = it.data().utf8();
00144 if (TXTRecordSetValue(&txt,it.key().utf8(),value.length(),value)!=kDNSServiceErr_NoError) {
00145 TXTRecordDeallocate(&txt);
00146 emit published(false);
00147 return;
00148 }
00149 }
00150 DNSServiceRef ref;
00151 if (DNSServiceRegister(&ref,0,0,m_serviceName.utf8(),m_type.ascii(),domainToDNS(m_domain),NULL,
00152 htons(m_port),TXTRecordGetLength(&txt),TXTRecordGetBytesPtr(&txt),publish_callback,
00153 reinterpret_cast<void*>(this)) == kDNSServiceErr_NoError) d->setRef(ref);
00154 TXTRecordDeallocate(&txt);
00155 }
00156 #endif
00157 if (!d->isRunning()) emit published(false);
00158 }
00159
00160 #ifdef HAVE_DNSSD
00161 void publish_callback (DNSServiceRef, DNSServiceFlags, DNSServiceErrorType errorCode, const char *name,
00162 const char*, const char*, void *context)
00163 {
00164 QObject *obj = reinterpret_cast<QObject*>(context);
00165 if (errorCode != kDNSServiceErr_NoError) {
00166 ErrorEvent err;
00167 QApplication::sendEvent(obj, &err);
00168 } else {
00169 PublishEvent pev(QString::fromUtf8(name));
00170 QApplication::sendEvent(obj, &pev);
00171 }
00172 }
00173 #endif
00174
00175 const KURL PublicService::toInvitation(const QString& host)
00176 {
00177 KURL url;
00178 url.setProtocol("invitation");
00179 if (host.isEmpty()) {
00180 unsigned long s_address = publicIP();
00181 if (!s_address) return KURL();
00182 KNetwork::KIpAddress addr(s_address);
00183 url.setHost(addr.toString());
00184 } else url.setHost(host);
00185
00186 url.setPort(m_port);
00187 url.setPath("/"+m_type+"/"+KURL::encode_string(m_serviceName));
00188 QString query;
00189 QMap<QString,QString>::ConstIterator itEnd = m_textData.end();
00190 for (QMap<QString,QString>::ConstIterator it = m_textData.begin(); it!=itEnd ; ++it)
00191 url.addQueryItem(it.key(),it.data());;
00192 return url;
00193 }
00194
00195 void PublicService::customEvent(QCustomEvent* event)
00196 {
00197 if (event->type()==QEvent::User+SD_ERROR) {
00198 stop();
00199 emit published(false);
00200 }
00201 if (event->type()==QEvent::User+SD_PUBLISH) {
00202 d->m_published=true;
00203 emit published(true);
00204 m_serviceName = static_cast<PublishEvent*>(event)->m_name;
00205 }
00206 }
00207
00208 void PublicService::virtual_hook(int, void*)
00209 {
00210 }
00211
00212 static unsigned long publicIP()
00213 {
00214 struct sockaddr_in addr;
00215 socklen_t len = sizeof(addr);
00216 int sock = socket(AF_INET,SOCK_DGRAM,0);
00217 if (sock == -1) return 0;
00218 addr.sin_family = AF_INET;
00219 addr.sin_port = 1;
00220 addr.sin_addr.s_addr = 0x11111111;
00221 if ((connect(sock,(const struct sockaddr*)&addr,sizeof(addr))) == -1) { close(sock); return 0; }
00222 if ((getsockname(sock,(struct sockaddr*)&addr, &len)) == -1) { close(sock); return 0; }
00223 ::close(sock);
00224 return addr.sin_addr.s_addr;
00225 }
00226
00227
00228 }
00229
00230 #include "publicservice.moc"