• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • kdenetwork
  • Sitemap
  • Contact Us
 

krfb

kinetd.cpp

Go to the documentation of this file.
00001 
00002 /***************************************************************************
00003                                 kinetd.cpp
00004                               --------------
00005     begin                : Mon Feb 11 2002
00006     copyright            : (C) 2002 by Tim Jansen
00007     email                : tim@tjansen.de
00008  ***************************************************************************/
00009 
00010 /***************************************************************************
00011  *                                                                         *
00012  *   This program is free software; you can redistribute it and/or modify  *
00013  *   it under the terms of the GNU General Public License as published by  *
00014  *   the Free Software Foundation; either version 2 of the License, or     *
00015  *   (at your option) any later version.                                   *
00016  *                                                                         *
00017  ***************************************************************************/
00018 
00019 #include "kinetd.h"
00020 #include "kinetd.moc"
00021 #include "kinetinterface.h"
00022 #include "kuser.h"
00023 #include "uuid.h"
00024 #include <qregexp.h>
00025 #include <kservicetype.h>
00026 #include <kdebug.h>
00027 #include <kstandarddirs.h>
00028 #include <kconfig.h>
00029 #include <KNotification>
00030 #include <ksocketaddress.h>
00031 #include <ksocketdevice.h>
00032 #include <klocale.h>
00033 #include <kglobal.h>
00034 
00035 #include <unistd.h>
00036 #include <fcntl.h>
00037 
00038 #include <kpluginfactory.h>
00039 #include <kpluginloader.h>
00040 
00041 K_PLUGIN_FACTORY(KInetDFactory,
00042                  registerPlugin<KInetD>();
00043     )
00044 K_EXPORT_PLUGIN(KInetDFactory("kinetd"))
00045 
00046 PortListener::PortListener(KService::Ptr s,
00047                KConfig *config,
00048                KServiceRegistry *srvreg) :
00049     m_port(-1),
00050     m_serviceRegistered(false),
00051     m_socket(0),
00052     m_config(config),
00053     m_srvreg(srvreg),
00054     m_dnssdreg(0)
00055 {
00056     m_uuid = createUUID();
00057     loadConfig(s);
00058 
00059     if (m_valid && m_enabled)
00060         acquirePort();
00061 }
00062 
00063 bool PortListener::acquirePort() {
00064     if (m_socket) {
00065         if ((m_port >= m_portBase) &&
00066             (m_port < (m_portBase + m_autoPortRange)))
00067             return true;
00068         else
00069             delete m_socket;
00070     }
00071     m_port = m_portBase;
00072     m_socket = new KNetwork::KServerSocket(m_port, false);
00073     while (!m_socket->bindAndListen()) {
00074         m_port++;
00075         if (m_port >= (m_portBase+m_autoPortRange)) {
00076             kDebug() << "Kinetd cannot load service "<<m_serviceName
00077                   <<": unable to get port" << endl;
00078             m_port = -1;
00079             delete m_socket;
00080             m_socket = 0;
00081             return false;
00082         }
00083         delete m_socket;
00084         m_socket = new KNetwork::KServerSocket(m_port, false);
00085     }
00086     connect(m_socket, SIGNAL(accepted(KSocket*)),
00087         SLOT(accepted(KSocket*)));
00088 
00089     bool s = m_registerService;
00090     bool sd =m_dnssdRegister;
00091     setServiceRegistrationEnabledInternal(false);
00092     dnssdRegister(false);
00093     setServiceRegistrationEnabledInternal(s);
00094     dnssdRegister(sd);
00095     return true;
00096 }
00097 
00098 void PortListener::freePort() {
00099     m_port = -1;
00100     delete m_socket;
00101     m_socket = 0;
00102     setServiceRegistrationEnabledInternal(m_registerService);
00103     dnssdRegister(false);
00104 }
00105 
00106 void PortListener::loadConfig(KService::Ptr s) {
00107     m_valid = true;
00108     m_autoPortRange = 0;
00109     m_enabled = true;
00110     m_argument.clear();
00111     m_multiInstance = false;
00112 
00113     QVariant vid, vport, vautoport, venabled, vargument, vmultiInstance, vurl,
00114       vsattributes, vslifetime, vdname, vdtype, vddata;
00115 
00116     m_execPath = s->exec().utf8();
00117     vid = s->property("X-KDE-KINETD-id");
00118     vport = s->property("X-KDE-KINETD-port");
00119     vautoport = s->property("X-KDE-KINETD-autoPortRange");
00120     venabled = s->property("X-KDE-KINETD-enabled");
00121     vargument = s->property("X-KDE-KINETD-argument");
00122     vmultiInstance = s->property("X-KDE-KINETD-multiInstance");
00123     vurl = s->property("X-KDE-KINETD-serviceURL");
00124     vsattributes = s->property("X-KDE-KINETD-serviceAttributes");
00125     vslifetime = s->property("X-KDE-KINETD-serviceLifetime");
00126     vdname = s->property("X-KDE-KINETD-DNSSD-Name");
00127     vdtype = s->property("X-KDE-KINETD-DNSSD-Type");
00128     vddata = s->property("X-KDE-KINETD-DNSSD-Properties");
00129 
00130     if (!vid.isValid()) {
00131         kDebug() << "Kinetd cannot load service "<<m_serviceName
00132               <<": no id set" << endl;
00133         m_valid = false;
00134         return;
00135     }
00136 
00137     if (!vport.isValid()) {
00138         kDebug() << "Kinetd cannot load service "<<m_serviceName
00139               <<": invalid port" << endl;
00140         m_valid = false;
00141         return;
00142     }
00143 
00144     m_serviceName = vid.toString();
00145     m_serviceLifetime = vslifetime.toInt();
00146     if (m_serviceLifetime < 120) // never less than 120 s
00147         m_serviceLifetime = 120;
00148     m_portBase = vport.toInt();
00149     if (vautoport.isValid())
00150         m_autoPortRange = vautoport.toInt();
00151     if (venabled.isValid())
00152         m_enabled = venabled.toBool();
00153     if (vargument.isValid())
00154         m_argument = vargument.toString();
00155     if (vmultiInstance.isValid())
00156         m_multiInstance = vmultiInstance.toBool();
00157     if (vurl.isValid()) {
00158         m_serviceURL = vurl.toString();
00159         m_registerService = true;
00160     }
00161     else {
00162         m_serviceURL.clear();
00163         m_registerService = false;
00164     }
00165     if (vsattributes.isValid()) {
00166         m_serviceAttributes = vsattributes.toString();
00167     }
00168     else
00169         m_serviceAttributes = "";
00170     if (vddata.isValid()) {
00171         QStringList attrs = vddata.toStringList();
00172         for (QStringList::iterator it=attrs.begin();
00173         it!=attrs.end();it++) {
00174             QString key = (*it).section('=',0,0);
00175             QString value =  processServiceTemplate((*it).section('=',1))[0];
00176             if (!key.isEmpty()) m_dnssdData[key]=value;
00177             }
00178     }
00179     if (vdname.isValid() && vdtype.isValid()) {
00180         m_dnssdName = processServiceTemplate(vdname.toString())[0];
00181         m_dnssdType = vdtype.toString();
00182         m_dnssdRegister = true;
00183         kDebug() << "DNS-SD register is enabled\n";
00184     }
00185     else
00186             m_dnssdRegister = false;
00187 
00188 
00189     m_slpLifetimeEnd = QDateTime::currentDateTime().addSecs(m_serviceLifetime);
00190     m_defaultPortBase = m_portBase;
00191     m_defaultAutoPortRange = m_autoPortRange;
00192 
00193     m_config->setGroup("ListenerConfig");
00194     m_enabled = m_config->readEntry("enabled_" + m_serviceName,
00195                         m_enabled);
00196     m_portBase = m_config->readEntry("port_base_" + m_serviceName,
00197                         m_portBase);
00198     m_autoPortRange = m_config->readEntry("auto_port_range_" + m_serviceName,
00199                          m_autoPortRange);
00200     QDateTime nullTime;
00201     m_expirationTime = m_config->readDateTimeEntry("enabled_expiration_"+m_serviceName,
00202                              &nullTime);
00203     if ((!m_expirationTime.isNull()) && (m_expirationTime < QDateTime::currentDateTime()))
00204         m_enabled = false;
00205     m_registerService = m_config->readEntry("enabled_srvreg_"+m_serviceName,
00206                              m_registerService);
00207 }
00208 
00209 void PortListener::accepted(KSocket *sock) {
00210     QString host, port;
00211     KSocketDevice device(sock->socket());
00212     KSocketAddress ksa = device->peerAddress();
00213     if ( ksa.address()) {
00214         delete sock;
00215         return;
00216     }
00217     KExtendedSocket::resolve(ksa, host, port);
00218     KNotification::event("IncomingConnection",
00219         i18n("Connection from %1", host));
00220     delete ksa;
00221 
00222     if ((!m_enabled) ||
00223        ((!m_multiInstance) && m_process.isRunning())) {
00224         delete sock;
00225         return;
00226     }
00227 
00228     // disable CLOEXEC flag, fixes #77412
00229     fcntl(sock->socket(), F_SETFD, fcntl(sock->socket(), F_GETFD) & ~FD_CLOEXEC);
00230 
00231     m_process.clearArguments();
00232     m_process << m_execPath << m_argument << QString::number(sock->socket());
00233     if (!m_process.start(K3Process::DontCare)) {
00234         KNotification::event("ProcessFailed",
00235             i18n("Call \"%1 %2 %3\" failed", m_execPath,
00236                  m_argument,
00237                  sock->socket()));
00238     }
00239 
00240     delete sock;
00241 }
00242 
00243 bool PortListener::isValid() {
00244     return m_valid;
00245 }
00246 
00247 bool PortListener::isEnabled() {
00248     return m_enabled && m_valid;
00249 }
00250 
00251 int PortListener::port() {
00252     return m_port;
00253 }
00254 
00255 QStringList PortListener::processServiceTemplate(const QString &a) {
00256     QStringList l;
00257     QValueVector<KInetInterface> v = KInetInterface::getAllInterfaces(false);
00258     QValueVector<KInetInterface>::Iterator it = v.begin();
00259     while (it != v.end()) {
00260         KInetSocketAddress *address = (*(it++)).address();
00261         if (!address)
00262             continue;
00263         QString hostName = address->nodeName();
00264         KUser u;
00265         QString x = a; // replace does not work in const QString. Why??
00266         l.append(x.replace(QString("%h"), KServiceRegistry::encodeAttributeValue(hostName))
00267              .replace(QString("%p"), QString::number(m_port))
00268              .replace(QString("%u"), KServiceRegistry::encodeAttributeValue(u.loginName()))
00269              .replace(QString("%i"), KServiceRegistry::encodeAttributeValue(m_uuid))
00270              .replace(QString("%f"), KServiceRegistry::encodeAttributeValue(u.fullName())));
00271     }
00272     return l;
00273 }
00274 
00275 bool PortListener::setPort(int port, int autoPortRange) {
00276     if ((port == m_portBase) && (autoPortRange == m_autoPortRange))
00277         return (m_port != -1);
00278 
00279     m_config->setGroup("ListenerConfig");
00280     if (port > 0) {
00281         m_portBase = port;
00282         m_autoPortRange = autoPortRange;
00283 
00284         m_config->writeEntry("port_base_" + m_serviceName, m_portBase);
00285         m_config->writeEntry("auto_port_range_"+m_serviceName, m_autoPortRange);
00286     }
00287     else {
00288         m_portBase = m_defaultPortBase;
00289         m_autoPortRange = m_defaultAutoPortRange;
00290 
00291         m_config->deleteEntry("port_base_" + m_serviceName);
00292         m_config->deleteEntry("auto_port_range_"+m_serviceName);
00293     }
00294 
00295     m_config->sync();
00296     if (m_enabled)
00297         return acquirePort();
00298     else
00299         return false;
00300 }
00301 
00302 void PortListener::setEnabled(bool e) {
00303     setEnabledInternal(e, QDateTime());
00304 }
00305 
00306 void PortListener::setEnabledInternal(bool e, const QDateTime &ex) {
00307     m_config->setGroup("ListenerConfig");
00308     m_config->writeEntry("enabled_" + m_serviceName, e);
00309     m_config->writeEntry("enabled_expiration_"+m_serviceName, ex);
00310     m_config->sync();
00311 
00312     m_expirationTime = ex;
00313 
00314     if (e) {
00315         if (m_port < 0)
00316             acquirePort();
00317         m_enabled = m_port >= 0;
00318 
00319     }
00320     else {
00321         freePort();
00322         m_enabled = false;
00323     }
00324 }
00325 
00326 void PortListener::setEnabled(const QDateTime &ex) {
00327     setEnabledInternal(true, ex);
00328 }
00329 
00330 bool PortListener::isServiceRegistrationEnabled() {
00331     return m_registerService;
00332 }
00333 
00334 void PortListener::setServiceRegistrationEnabled(bool e) {
00335     setServiceRegistrationEnabledInternal(e);
00336     dnssdRegister(e && m_enabled);
00337     m_config->setGroup("ListenerConfig");
00338     m_config->writeEntry("enable_srvreg_" + m_serviceName, e);
00339     m_config->sync();
00340 }
00341 
00342 void PortListener::setServiceRegistrationEnabledInternal(bool e) {
00343     m_registerService = e;
00344 
00345     if ((!m_srvreg) || m_serviceURL.isNull())
00346         return;
00347     if (m_serviceRegistered == (m_enabled && e))
00348         return;
00349 
00350         if (m_enabled && e) {
00351         m_registeredServiceURLs = processServiceTemplate(m_serviceURL);
00352         QStringList attributes = processServiceTemplate(m_serviceAttributes);
00353         QStringList::Iterator it = m_registeredServiceURLs.begin();
00354         QStringList::Iterator it2 = attributes.begin();
00355         while ((it != m_registeredServiceURLs.end()) &&
00356                (it2 != attributes.end())) {
00357              if (!m_srvreg->registerService(
00358                      *(it++),
00359                      *(it2++),
00360                      m_serviceLifetime))
00361                  kDebug(7021) << "Failure registering SLP service (no slpd running?)";
00362         }
00363         m_serviceRegistered = true;
00364         // make lifetime 30s shorter, because the timeout is not precise
00365         m_slpLifetimeEnd = QDateTime::currentDateTime().addSecs(m_serviceLifetime-30);
00366     } else {
00367         QStringList::Iterator it = m_registeredServiceURLs.begin();
00368         while (it != m_registeredServiceURLs.end())
00369             m_srvreg->unregisterService(*(it++));
00370         m_serviceRegistered = false;
00371     }
00372 }
00373 
00374 void PortListener::dnssdRegister(bool e) {
00375     if (m_dnssdName.isNull() || m_dnssdType.isNull())
00376         return;
00377     if (m_dnssdRegistered ==  e)
00378         return;
00379     if (e) {
00380         m_dnssdRegistered=true;
00381         m_dnssdreg = new DNSSD::PublicService(m_dnssdName,m_dnssdType,m_port);
00382         m_dnssdreg->setTextData(m_dnssdData);
00383         m_dnssdreg->publishAsync();
00384     } else {
00385         m_dnssdRegistered=false;
00386         delete m_dnssdreg;
00387         m_dnssdreg=0;
00388     }
00389 }
00390 
00391 void PortListener::refreshRegistration() {
00392     if (m_serviceRegistered && (m_slpLifetimeEnd.addSecs(-90) < QDateTime::currentDateTime())) {
00393         setServiceRegistrationEnabledInternal(false);
00394         setServiceRegistrationEnabledInternal(true);
00395     }
00396 }
00397 
00398 QDateTime PortListener::expiration() {
00399     return m_expirationTime;
00400 }
00401 
00402 QDateTime PortListener::serviceLifetimeEnd() {
00403     if (m_serviceRegistered)
00404         return m_slpLifetimeEnd;
00405     else
00406         return QDateTime();
00407 }
00408 
00409 QString PortListener::name() {
00410     return m_serviceName;
00411 }
00412 
00413 PortListener::~PortListener() {
00414     setServiceRegistrationEnabledInternal(false);
00415     delete m_socket;
00416 }
00417 
00418 
00419 KInetD::KInetD(QObject* parent, const QList<QVariant>&) :
00420     KDEDModule(parent)
00421 {
00422     m_config = new KConfig("kinetdrc");
00423     m_srvreg = new KServiceRegistry();
00424     if (!m_srvreg->available()) {
00425         kDebug(7021) << "SLP not available";
00426         delete m_srvreg;
00427         m_srvreg = 0;
00428     }
00429     m_portListeners.setAutoDelete(true);
00430     connect(&m_expirationTimer, SIGNAL(timeout()), SLOT(setExpirationTimer()));
00431     connect(&m_portRetryTimer, SIGNAL(timeout()), SLOT(portRetryTimer()));
00432     connect(&m_reregistrationTimer, SIGNAL(timeout()), SLOT(reregistrationTimer()));
00433     loadServiceList();
00434 }
00435 
00436 void KInetD::loadServiceList()
00437 {
00438     m_portListeners.clear();
00439 
00440 
00441     KService::List kinetdModules =
00442         KServiceType::offers("KInetDModule");
00443     for(KService::List::ConstIterator it = kinetdModules.begin();
00444         it != kinetdModules.end();
00445         it++) {
00446         KService::Ptr s = *it;
00447         PortListener *pl = new PortListener(s, m_config, m_srvreg);
00448         if (pl->isValid())
00449             m_portListeners.append(pl);
00450         else
00451             delete pl;
00452     }
00453 
00454     setExpirationTimer();
00455     setPortRetryTimer(true);
00456     setReregistrationTimer();
00457 }
00458 
00459 void KInetD::expirationTimer() {
00460     setExpirationTimer();
00461     setReregistrationTimer();
00462 }
00463 
00464 void KInetD::setExpirationTimer() {
00465     QDateTime nextEx = getNextExpirationTime(); // disables expired portlistener!
00466     if (!nextEx.isNull())
00467         m_expirationTimer.start(QDateTime::currentDateTime().secsTo(nextEx)*1000 + 30000,
00468             false);
00469     else
00470         m_expirationTimer.stop();
00471 }
00472 
00473 void KInetD::portRetryTimer() {
00474     setPortRetryTimer(true);
00475     setReregistrationTimer();
00476 }
00477 
00478 void KInetD::setReregistrationTimer() {
00479     QDateTime d;
00480     PortListener *pl = m_portListeners.first();
00481     while (pl) {
00482         QDateTime d2 = pl->serviceLifetimeEnd();
00483         if (!d2.isNull()) {
00484             if (d2 < QDateTime::currentDateTime()) {
00485                 m_reregistrationTimer.start(0, true);
00486                 return;
00487             }
00488             else if (d.isNull() || (d2 < d))
00489                 d = d2;
00490         }
00491         pl = m_portListeners.next();
00492     }
00493 
00494     if (!d.isNull()) {
00495         int s = QDateTime::currentDateTime().secsTo(d);
00496         if (s < 30)
00497             s = 30; // max frequency 30s
00498         m_reregistrationTimer.start(s*1000, true);
00499     }
00500     else
00501         m_reregistrationTimer.stop();
00502 }
00503 
00504 void KInetD::reregistrationTimer() {
00505     PortListener *pl = m_portListeners.first();
00506     while (pl) {
00507         pl->refreshRegistration();
00508         pl = m_portListeners.next();
00509     }
00510     setReregistrationTimer();
00511 }
00512 
00513 void KInetD::setPortRetryTimer(bool retry) {
00514     int unmappedPorts = 0;
00515 
00516     PortListener *pl = m_portListeners.first();
00517     while (pl) {
00518         if (pl->isEnabled() && (pl->port() < 0))
00519             if (retry) {
00520                 if (!pl->acquirePort())
00521                     unmappedPorts++;
00522             }
00523             else if (pl->port() < 0)
00524                 unmappedPorts++;
00525         pl = m_portListeners.next();
00526     }
00527 
00528     if (unmappedPorts > 0)
00529         m_portRetryTimer.start(30000, false);
00530     else
00531         m_portRetryTimer.stop();
00532 }
00533 
00534 PortListener *KInetD::getListenerByName(QString name)
00535 {
00536     PortListener *pl = m_portListeners.first();
00537     while (pl) {
00538         if (pl->name() == name)
00539             return pl;
00540         pl = m_portListeners.next();
00541     }
00542     return pl;
00543 }
00544 
00545 // gets next expiration timer, SIDEEFFECT: disables expired portlisteners while doing this
00546 QDateTime KInetD::getNextExpirationTime()
00547 {
00548     PortListener *pl = m_portListeners.first();
00549     QDateTime d;
00550     while (pl) {
00551         QDateTime d2 = pl->expiration();
00552         if (!d2.isNull()) {
00553             if (d2 < QDateTime::currentDateTime())
00554                 pl->setEnabled(false);
00555             else if (d.isNull() || (d2 < d))
00556                 d = d2;
00557         }
00558         pl = m_portListeners.next();
00559     }
00560     return d;
00561 }
00562 
00563 QStringList KInetD::services()
00564 {
00565     QStringList list;
00566     PortListener *pl = m_portListeners.first();
00567     while (pl) {
00568         list.append(pl->name());
00569         pl = m_portListeners.next();
00570     }
00571     return list;
00572 }
00573 
00574 bool KInetD::isEnabled(QString service)
00575 {
00576     PortListener *pl = getListenerByName(service);
00577     if (!pl)
00578         return false;
00579 
00580     return pl->isEnabled();
00581 }
00582 
00583 int KInetD::port(QString service)
00584 {
00585     PortListener *pl = getListenerByName(service);
00586     if (!pl)
00587         return -1;
00588 
00589     return pl->port();
00590 }
00591 
00592 bool KInetD::setPort(QString service, int port, int autoPortRange)
00593 {
00594     PortListener *pl = getListenerByName(service);
00595     if (!pl)
00596         return false;
00597 
00598     bool s = pl->setPort(port, autoPortRange);
00599     setPortRetryTimer(false);
00600     setReregistrationTimer();
00601     return s;
00602 }
00603 
00604 bool KInetD::isInstalled(QString service)
00605 {
00606     PortListener *pl = getListenerByName(service);
00607     return (pl != 0);
00608 }
00609 
00610 void KInetD::setEnabled(QString service, bool enable)
00611 {
00612     PortListener *pl = getListenerByName(service);
00613     if (!pl)
00614         return;
00615 
00616     pl->setEnabled(enable);
00617     setExpirationTimer();
00618     setReregistrationTimer();
00619 }
00620 
00621 void KInetD::setEnabled(QString service, QDateTime expiration)
00622 {
00623     PortListener *pl = getListenerByName(service);
00624     if (!pl)
00625         return;
00626 
00627     pl->setEnabled(expiration);
00628     setExpirationTimer();
00629     setReregistrationTimer();
00630 }
00631 
00632 void KInetD::setServiceRegistrationEnabled(QString service, bool enable)
00633 {
00634     PortListener *pl = getListenerByName(service);
00635     if (!pl)
00636         return;
00637 
00638     pl->setServiceRegistrationEnabled(enable);
00639     setReregistrationTimer();
00640 }
00641 
00642 bool KInetD::isServiceRegistrationEnabled(QString service)
00643 {
00644     PortListener *pl = getListenerByName(service);
00645     if (!pl)
00646         return false;
00647 
00648     return pl->isServiceRegistrationEnabled();
00649 }
00650 
00651 KInetD::~KInetD() {
00652     m_portListeners.clear();
00653     delete m_config;
00654         delete m_srvreg;
00655 }

krfb

Skip menu "krfb"
  • Main Page
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members

kdenetwork

Skip menu "kdenetwork"
  • kget
  • kopete
  •   kopete
  •   libkopete
  •       libpapillon
  • krfb
Generated for kdenetwork by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal