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 <tqapplication.h>
00030 #include <network/tdesocketaddress.h>
00031 #include <kurl.h>
00032 #include <unistd.h>
00033 #ifdef HAVE_DNSSD
00034 #include <avahi-client/client.h>
00035 #ifdef AVAHI_API_0_6
00036 #include <avahi-client/publish.h>
00037 #endif
00038 #include <avahi-common/alternative.h>
00039 #include <avahi-common/strlst.h>
00040 #endif
00041 #include "sdevent.h"
00042 #include "responder.h"
00043 #include "servicebrowser.h"
00044 #include "settings.h"
00045
00046 namespace DNSSD
00047 {
00048 static unsigned long publicIP();
00049
00050 #ifdef HAVE_DNSSD
00051 void publish_callback (AvahiEntryGroup*, AvahiEntryGroupState s, void *context);
00052 #endif
00053
00054 class PublicServicePrivate
00055 {
00056 public:
00057 PublicServicePrivate() : m_published(false), m_running(false), m_collision(false)
00058 #ifdef HAVE_DNSSD
00059 , m_group(false)
00060 #endif
00061 {}
00062 bool m_published;
00063 bool m_running;
00064 bool m_collision;
00065 #ifdef HAVE_DNSSD
00066 AvahiEntryGroup* m_group;
00067 #endif
00068 void commit()
00069 {
00070 #ifdef HAVE_DNSSD
00071 if (!m_collision) avahi_entry_group_commit(m_group);
00072 #endif
00073 }
00074
00075 };
00076
00077 PublicService::PublicService(const TQString& name, const TQString& type, unsigned int port,
00078 const TQString& domain)
00079 : TQObject(), ServiceBase(name, type, TQString::null, domain, port)
00080 {
00081 d = new PublicServicePrivate;
00082 #ifdef HAVE_DNSSD
00083 if (Responder::self().client()) {
00084 d->m_group = avahi_entry_group_new(Responder::self().client(), publish_callback,this);
00085 connect(&Responder::self(),TQT_SIGNAL(stateChanged(AvahiClientState)),this,TQT_SLOT(clientState(AvahiClientState)));
00086 }
00087 #endif
00088 if (domain.isNull())
00089 if (Configuration::publishType()==Configuration::EnumPublishType::LAN) m_domain="local.";
00090 else m_domain=Configuration::publishDomain();
00091 }
00092
00093
00094 PublicService::~PublicService()
00095 {
00096 #ifdef HAVE_DNSSD
00097 if (d->m_group) avahi_entry_group_free(d->m_group);
00098 #endif
00099 delete d;
00100 }
00101
00102 void PublicService::tryApply()
00103 {
00104 if (fillEntryGroup()) d->commit();
00105 else {
00106 stop();
00107 emit published(false);
00108 }
00109 }
00110
00111 void PublicService::setServiceName(const TQString& serviceName)
00112 {
00113 m_serviceName = serviceName;
00114 #ifdef HAVE_DNSSD
00115 if (d->m_running) {
00116 avahi_entry_group_reset(d->m_group);
00117 tryApply();
00118 }
00119 #endif
00120 }
00121
00122 void PublicService::setDomain(const TQString& domain)
00123 {
00124 m_domain = domain;
00125 #ifdef HAVE_DNSSD
00126 if (d->m_running) {
00127 avahi_entry_group_reset(d->m_group);
00128 tryApply();
00129 }
00130 #endif
00131 }
00132
00133
00134 void PublicService::setType(const TQString& type)
00135 {
00136 m_type = type;
00137 #ifdef HAVE_DNSSD
00138 if (d->m_running) {
00139 avahi_entry_group_reset(d->m_group);
00140 tryApply();
00141 }
00142 #endif
00143 }
00144
00145 void PublicService::setPort(unsigned short port)
00146 {
00147 m_port = port;
00148 #ifdef HAVE_DNSSD
00149 if (d->m_running) {
00150 avahi_entry_group_reset(d->m_group);
00151 tryApply();
00152 }
00153 #endif
00154 }
00155
00156 void PublicService::setTextData(const TQMap<TQString,TQString>& textData)
00157 {
00158 m_textData = textData;
00159 #ifdef HAVE_DNSSD
00160 if (d->m_running) {
00161 avahi_entry_group_reset(d->m_group);
00162 tryApply();
00163 }
00164 #endif
00165 }
00166
00167 bool PublicService::isPublished() const
00168 {
00169 return d->m_published;
00170 }
00171
00172 bool PublicService::publish()
00173 {
00174 publishAsync();
00175 while (d->m_running && !d->m_published) Responder::self().process();
00176 return d->m_published;
00177 }
00178
00179 void PublicService::stop()
00180 {
00181 #ifdef HAVE_DNSSD
00182 if (d->m_group) avahi_entry_group_reset(d->m_group);
00183 #endif
00184 d->m_published = false;
00185 }
00186 bool PublicService::fillEntryGroup()
00187 {
00188 #ifdef HAVE_DNSSD
00189 AvahiStringList *s=0;
00190 TQMap<TQString,TQString>::ConstIterator itEnd = m_textData.end();
00191 for (TQMap<TQString,TQString>::ConstIterator it = m_textData.begin(); it!=itEnd ; ++it)
00192 s = avahi_string_list_add_pair(s, it.key().utf8(),it.data().utf8());
00193 #ifdef AVAHI_API_0_6
00194 bool res = (!avahi_entry_group_add_service_strlst(d->m_group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, (AvahiPublishFlags)0,
00195 m_serviceName.isNull() ? avahi_client_get_host_name(Responder::self().client()) : m_serviceName.utf8().data(),
00196 m_type.ascii(),domainToDNS(m_domain),m_hostName.utf8(),m_port,s));
00197 #else
00198 bool res = (!avahi_entry_group_add_service_strlst(d->m_group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
00199 m_serviceName.isNull() ? avahi_client_get_host_name(Responder::self().client()) : m_serviceName.utf8().data(),
00200 m_type.ascii(),m_domain.utf8(),m_hostName.utf8(),m_port,s));
00201 #endif
00202 avahi_string_list_free(s);
00203 return res;
00204 #else
00205 return FALSE;
00206 #endif
00207 }
00208
00209 void PublicService::clientState(AvahiClientState s)
00210 {
00211 if (!d->m_running) return;
00212 #ifdef HAVE_DNSSD
00213 switch (s) {
00214 #ifdef AVAHI_API_0_6
00215 case AVAHI_CLIENT_FAILURE:
00216 #else
00217 case AVAHI_CLIENT_S_INVALID:
00218 case AVAHI_CLIENT_DISCONNECTED:
00219 #endif
00220 stop();
00221 emit published(false);
00222 break;
00223 case AVAHI_CLIENT_S_REGISTERING:
00224 case AVAHI_CLIENT_S_COLLISION:
00225 avahi_entry_group_reset(d->m_group);
00226 d->m_collision=true;
00227 break;
00228 case AVAHI_CLIENT_S_RUNNING:
00229 if (d->m_collision) {
00230 d->m_collision=false;
00231 tryApply();
00232 }
00233 }
00234 #endif
00235 }
00236
00237 void PublicService::publishAsync()
00238 {
00239 if (d->m_running) stop();
00240
00241 #ifdef HAVE_DNSSD
00242 if (!d->m_group) {
00243 emit published(false);
00244 return;
00245 }
00246 AvahiClientState s=Responder::self().state();
00247 #endif
00248 d->m_running=true;
00249 d->m_collision=true;
00250 #ifdef HAVE_DNSSD
00251 clientState(s);
00252 #endif
00253 }
00254
00255 #ifdef HAVE_DNSSD
00256 void publish_callback (AvahiEntryGroup*, AvahiEntryGroupState s, void *context)
00257 {
00258 TQObject *obj = reinterpret_cast<TQObject*>(context);
00259 if (s!=AVAHI_ENTRY_GROUP_ESTABLISHED && s!=AVAHI_ENTRY_GROUP_COLLISION) return;
00260 PublishEvent* pev=new PublishEvent(s==AVAHI_ENTRY_GROUP_ESTABLISHED);
00261 TQApplication::postEvent(obj, pev);
00262 }
00263 #endif
00264
00265 const KURL PublicService::toInvitation(const TQString& host)
00266 {
00267 KURL url;
00268 url.setProtocol("invitation");
00269 if (host.isEmpty()) {
00270 unsigned long s_address = publicIP();
00271 if (!s_address) return KURL();
00272 KNetwork::KIpAddress addr(s_address);
00273 url.setHost(addr.toString());
00274 } else url.setHost(host);
00275
00276 url.setPort(m_port);
00277 url.setPath("/"+m_type+"/"+KURL::encode_string(m_serviceName));
00278 TQString query;
00279 TQMap<TQString,TQString>::ConstIterator itEnd = m_textData.end();
00280 for (TQMap<TQString,TQString>::ConstIterator it = m_textData.begin(); it!=itEnd ; ++it)
00281 url.addQueryItem(it.key(),it.data());;
00282 return url;
00283 }
00284
00285 void PublicService::customEvent(TQCustomEvent* event)
00286 {
00287 #ifdef HAVE_DNSSD
00288 if (event->type()==TQEvent::User+SD_PUBLISH) {
00289 if (!static_cast<PublishEvent*>(event)->m_ok) {
00290 setServiceName(TQString::fromUtf8(avahi_alternative_service_name(m_serviceName.utf8())));
00291 return;
00292 }
00293 d->m_published=true;
00294 emit published(true);
00295 }
00296 #endif
00297 }
00298
00299 void PublicService::virtual_hook(int, void*)
00300 {
00301 }
00302
00303 static unsigned long publicIP()
00304 {
00305 struct sockaddr_in addr;
00306 socklen_t len = sizeof(addr);
00307 int sock = socket(AF_INET,SOCK_DGRAM,0);
00308 if (sock == -1) return 0;
00309 addr.sin_family = AF_INET;
00310 addr.sin_port = 1;
00311 addr.sin_addr.s_addr = 0x11111111;
00312 if ((connect(sock,(const struct sockaddr*)&addr,sizeof(addr))) == -1) { close(sock); return 0; }
00313 if ((getsockname(sock,(struct sockaddr*)&addr, &len)) == -1) { close(sock); return 0; }
00314 ::close(sock);
00315 return addr.sin_addr.s_addr;
00316 }
00317
00318
00319 }
00320
00321 #include "publicservice.moc"