• Skip to content
  • Skip to link menu
KDE 4.3 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KIO

slave.cpp

Go to the documentation of this file.
00001 /*
00002  *  This file is part of the KDE libraries
00003  *  Copyright (c) 2000 Waldo Bastian <bastian@kde.org>
00004  *                2000 Stephan Kulow <coolo@kde.org>
00005  *
00006  *  This library is free software; you can redistribute it and/or
00007  *  modify it under the terms of the GNU Library General Public
00008  *  License version 2 as published by the Free Software Foundation.
00009  *
00010  *  This library is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  *  Library General Public License for more details.
00014  *
00015  *  You should have received a copy of the GNU Library General Public License
00016  *  along with this library; see the file COPYING.LIB.  If not, write to
00017  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018  *  Boston, MA 02110-1301, USA.
00019  **/
00020 
00021 #include "slave.h"
00022 
00023 #include <config.h>
00024 
00025 #include <time.h>
00026 #include <errno.h>
00027 #include <unistd.h>
00028 #include <stdlib.h>
00029 #include <stdio.h>
00030 #include <signal.h>
00031 #include <sys/types.h>
00032 
00033 #include <QtCore/QBool>
00034 #include <QtCore/QFile>
00035 #include <QtCore/QTimer>
00036 #include <QtDBus/QtDBus>
00037 #include <QtCore/QProcess>
00038 
00039 #include <kdebug.h>
00040 #include <klocale.h>
00041 #include <kglobal.h>
00042 #include <kstandarddirs.h>
00043 #include <kapplication.h>
00044 #include <ktemporaryfile.h>
00045 #include <ktoolinvocation.h>
00046 #include <klauncher_iface.h>
00047 
00048 #include "dataprotocol.h"
00049 #include "kservice.h"
00050 #include <kio/global.h>
00051 #include "kio/connection.h"
00052 #include <kprotocolmanager.h>
00053 #include <kprotocolinfo.h>
00054 
00055 #include "slaveinterface_p.h"
00056 
00057 using namespace KIO;
00058 
00059 #define SLAVE_CONNECTION_TIMEOUT_MIN       2
00060 
00061 // Without debug info we consider it an error if the slave doesn't connect
00062 // within 10 seconds.
00063 // With debug info we give the slave an hour so that developers have a chance
00064 // to debug their slave.
00065 #ifdef NDEBUG
00066 #define SLAVE_CONNECTION_TIMEOUT_MAX      10
00067 #else
00068 #define SLAVE_CONNECTION_TIMEOUT_MAX    3600
00069 #endif
00070 
00071 namespace KIO {
00072 
00076     class SlavePrivate: public SlaveInterfacePrivate
00077     {
00078     public:
00079         SlavePrivate(const QString &protocol) :
00080             m_protocol(protocol),
00081             m_slaveProtocol(protocol),
00082             slaveconnserver(new KIO::ConnectionServer),
00083             m_pid(0),
00084             m_port(0),
00085             contacted(false),
00086             dead(false),
00087             contact_started(time(0)),
00088             m_refCount(1)
00089         {
00090             slaveconnserver->listenForRemote();
00091             if ( !slaveconnserver->isListening() )
00092                 kWarning() << "Connection server not listening, could not connect";
00093         }
00094         ~SlavePrivate()
00095         {
00096             delete slaveconnserver;
00097         }
00098 
00099         QString m_protocol;
00100         QString m_slaveProtocol;
00101         QString m_host;
00102         QString m_user;
00103         QString m_passwd;
00104         KIO::ConnectionServer *slaveconnserver;
00105         pid_t m_pid;
00106         quint16 m_port;
00107         bool contacted;
00108         bool dead;
00109         time_t contact_started;
00110         time_t idle_since;
00111         int m_refCount;
00112   };
00113 }
00114 
00115 void Slave::accept()
00116 {
00117     Q_D(Slave);
00118     d->slaveconnserver->setNextPendingConnection(d->connection);
00119     d->slaveconnserver->deleteLater();
00120     d->slaveconnserver = 0;
00121 
00122     connect(d->connection, SIGNAL(readyRead()), SLOT(gotInput()));
00123 }
00124 
00125 void Slave::timeout()
00126 {
00127     Q_D(Slave);
00128    if (d->dead)
00129       return;
00130    if (d->connection->isConnected())
00131       return;
00132    kDebug(7002) << "slave failed to connect to application pid=" << d->m_pid << " protocol=" << d->m_protocol;
00133    if (d->m_pid && (::kill(d->m_pid, 0) == 0))
00134    {
00135       int delta_t = (int) difftime(time(0), d->contact_started);
00136       kDebug(7002) << "slave is slow... pid=" << d->m_pid << " t=" << delta_t;
00137       if (delta_t < SLAVE_CONNECTION_TIMEOUT_MAX)
00138       {
00139          QTimer::singleShot(1000*SLAVE_CONNECTION_TIMEOUT_MIN, this, SLOT(timeout()));
00140          return;
00141       }
00142    }
00143    kDebug(7002) << "Houston, we lost our slave, pid=" << d->m_pid;
00144    d->connection->close();
00145    d->dead = true;
00146    QString arg = d->m_protocol;
00147    if (!d->m_host.isEmpty())
00148       arg += "://"+d->m_host;
00149    kDebug(7002) << "slave died pid = " << d->m_pid;
00150    ref();
00151    // Tell the job about the problem.
00152    emit error(ERR_SLAVE_DIED, arg);
00153    // Tell the scheduler about the problem.
00154    emit slaveDied(this);
00155    // After the above signal we're dead!!
00156    deref();
00157 }
00158 
00159 Slave::Slave(const QString &protocol, QObject *parent)
00160     : SlaveInterface(*new SlavePrivate(protocol), parent)
00161 {
00162     Q_D(Slave);
00163     d->slaveconnserver->setParent(this);
00164     d->connection = new Connection(this);
00165     connect(d->slaveconnserver, SIGNAL(newConnection()), SLOT(accept()));
00166 }
00167 
00168 Slave::~Slave()
00169 {
00170     // kDebug(7002) << "destructing slave object pid = " << d->m_pid;
00171     //delete d;
00172 }
00173 
00174 QString Slave::protocol()
00175 {
00176     Q_D(Slave);
00177     return d->m_protocol;
00178 }
00179 
00180 void Slave::setProtocol(const QString & protocol)
00181 {
00182     Q_D(Slave);
00183     d->m_protocol = protocol;
00184 }
00185 
00186 QString Slave::slaveProtocol()
00187 {
00188     Q_D(Slave);
00189     return d->m_slaveProtocol;
00190 }
00191 
00192 QString Slave::host()
00193 {
00194     Q_D(Slave);
00195     return d->m_host;
00196 }
00197 
00198 quint16 Slave::port()
00199 {
00200     Q_D(Slave);
00201     return d->m_port;
00202 }
00203 
00204 QString Slave::user()
00205 {
00206     Q_D(Slave);
00207     return d->m_user;
00208 }
00209 
00210 QString Slave::passwd()
00211 {
00212     Q_D(Slave);
00213     return d->m_passwd;
00214 }
00215 
00216 void Slave::setIdle()
00217 {
00218     Q_D(Slave);
00219     d->idle_since = time(0);
00220 }
00221 
00222 bool Slave::isConnected()
00223 {
00224     Q_D(Slave);
00225     return d->contacted;
00226 }
00227 
00228 void Slave::setConnected(bool c)
00229 {
00230     Q_D(Slave);
00231     d->contacted = c;
00232 }
00233 
00234 void Slave::ref()
00235 {
00236     Q_D(Slave);
00237     d->m_refCount++;
00238 }
00239 
00240 void Slave::deref()
00241 {
00242     Q_D(Slave);
00243     d->m_refCount--;
00244     if (!d->m_refCount) {
00245         d->connection->disconnect(this);
00246         this->disconnect();
00247         deleteLater();
00248     }
00249 }
00250 
00251 time_t Slave::idleTime()
00252 {
00253     Q_D(Slave);
00254     return (time_t) difftime(time(0), d->idle_since);
00255 }
00256 
00257 void Slave::setPID(pid_t pid)
00258 {
00259     Q_D(Slave);
00260     d->m_pid = pid;
00261 }
00262 
00263 int Slave::slave_pid()
00264 {
00265     Q_D(Slave);
00266     return d->m_pid;
00267 }
00268 
00269 bool Slave::isAlive()
00270 {
00271     Q_D(Slave);
00272     return !d->dead;
00273 }
00274 
00275 void Slave::hold(const KUrl &url)
00276 {
00277     Q_D(Slave);
00278     ref();
00279     {
00280         QByteArray data;
00281         QDataStream stream( &data, QIODevice::WriteOnly );
00282         stream << url;
00283         d->connection->send( CMD_SLAVE_HOLD, data );
00284         d->connection->close();
00285         d->dead = true;
00286         emit slaveDied(this);
00287     }
00288     deref();
00289     // Call KLauncher::waitForSlave(pid);
00290     {
00291         KToolInvocation::klauncher()->waitForSlave(d->m_pid);
00292     }
00293 }
00294 
00295 void Slave::suspend()
00296 {
00297     Q_D(Slave);
00298     d->connection->suspend();
00299 }
00300 
00301 void Slave::resume()
00302 {
00303     Q_D(Slave);
00304     d->connection->resume();
00305 }
00306 
00307 bool Slave::suspended()
00308 {
00309     Q_D(Slave);
00310     return d->connection->suspended();
00311 }
00312 
00313 void Slave::send(int cmd, const QByteArray &arr)
00314 {
00315     Q_D(Slave);
00316     d->connection->send(cmd, arr);
00317 }
00318 
00319 void Slave::gotInput()
00320 {
00321     Q_D(Slave);
00322     ref();
00323     if (!dispatch())
00324     {
00325         d->connection->close();
00326         d->dead = true;
00327         QString arg = d->m_protocol;
00328         if (!d->m_host.isEmpty())
00329             arg += "://"+d->m_host;
00330         kDebug(7002) << "slave died pid = " << d->m_pid;
00331         // Tell the job about the problem.
00332         emit error(ERR_SLAVE_DIED, arg);
00333         // Tell the scheduler about the problem.
00334         emit slaveDied(this);
00335     }
00336     deref();
00337     // Here we might be dead!!
00338 }
00339 
00340 void Slave::kill()
00341 {
00342     Q_D(Slave);
00343     d->dead = true; // OO can be such simple.
00344     kDebug(7002) << "killing slave pid" << d->m_pid
00345                  << "(" << QString(d->m_protocol) + "://" + d->m_host << ")";
00346     if (d->m_pid)
00347     {
00348        ::kill(d->m_pid, SIGTERM);
00349     }
00350 }
00351 
00352 void Slave::setHost( const QString &host, quint16 port,
00353                      const QString &user, const QString &passwd)
00354 {
00355     Q_D(Slave);
00356     d->m_host = host;
00357     d->m_port = port;
00358     d->m_user = user;
00359     d->m_passwd = passwd;
00360 
00361     QByteArray data;
00362     QDataStream stream( &data, QIODevice::WriteOnly );
00363     stream << d->m_host << d->m_port << d->m_user << d->m_passwd;
00364     d->connection->send( CMD_HOST, data );
00365 }
00366 
00367 void Slave::resetHost()
00368 {
00369     Q_D(Slave);
00370     d->m_host = "<reset>";
00371 }
00372 
00373 void Slave::setConfig(const MetaData &config)
00374 {
00375     Q_D(Slave);
00376     QByteArray data;
00377     QDataStream stream( &data, QIODevice::WriteOnly );
00378     stream << config;
00379     d->connection->send( CMD_CONFIG, data );
00380 }
00381 
00382 Slave* Slave::createSlave( const QString &protocol, const KUrl& url, int& error, QString& error_text )
00383 {
00384     kDebug(7002) << "createSlave" << protocol << "for" << url;
00385     // Firstly take into account all special slaves
00386     if (protocol == "data")
00387         return new DataProtocol();
00388     Slave *slave = new Slave(protocol);
00389     QString slaveAddress = slave->d_func()->slaveconnserver->address();
00390 
00391 #ifdef Q_OS_UNIX
00392     // In such case we start the slave via QProcess.
00393     // It's possible to force this by setting the env. variable
00394     // KDE_FORK_SLAVES, Clearcase seems to require this.
00395     static bool bForkSlaves = !qgetenv("KDE_FORK_SLAVES").isEmpty();
00396 
00397     if (!bForkSlaves)
00398     {
00399        // check the UID of klauncher
00400        QDBusReply<uint> reply = QDBusConnection::sessionBus().interface()->serviceUid(KToolInvocation::klauncher()->service());
00401        if (reply.isValid() && getuid() != reply)
00402           bForkSlaves = true;
00403     }
00404 
00405     if (bForkSlaves)
00406     {
00407        QString _name = KProtocolInfo::exec(protocol);
00408        if (_name.isEmpty())
00409        {
00410           error_text = i18n("Unknown protocol '%1'.", protocol);
00411           error = KIO::ERR_CANNOT_LAUNCH_PROCESS;
00412           delete slave;
00413           return 0;
00414        }
00415        QString lib_path = KLibLoader::findLibrary(_name);
00416        if (lib_path.isEmpty())
00417        {
00418           error_text = i18n("Can not find io-slave for protocol '%1'.", protocol);
00419           error = KIO::ERR_CANNOT_LAUNCH_PROCESS;
00420           delete slave;
00421           return 0;
00422        }
00423 
00424        QStringList args = QStringList() << lib_path << protocol << "" << slaveAddress;
00425        kDebug() << "kioslave" << ", " << lib_path << ", " << protocol << ", " << QString() << ", " << slaveAddress;
00426 
00427        QProcess::startDetached( KStandardDirs::locate("exe", "kioslave"), args );
00428 
00429        return slave;
00430     }
00431 #endif
00432 
00433     org::kde::KLauncher* klauncher = KToolInvocation::klauncher();
00434     QString errorStr;
00435     QDBusReply<int> reply = klauncher->requestSlave(protocol, url.host(), slaveAddress, errorStr);
00436     if (!reply.isValid()) {
00437     error_text = i18n("Cannot talk to klauncher: %1", klauncher->lastError().message() );
00438     error = KIO::ERR_CANNOT_LAUNCH_PROCESS;
00439         delete slave;
00440         return 0;
00441     }
00442     pid_t pid = reply;
00443     if (!pid)
00444     {
00445         error_text = i18n("Unable to create io-slave:\nklauncher said: %1", errorStr);
00446         error = KIO::ERR_CANNOT_LAUNCH_PROCESS;
00447         delete slave;
00448         return 0;
00449     }
00450     slave->setPID(pid);
00451     QTimer::singleShot(1000*SLAVE_CONNECTION_TIMEOUT_MIN, slave, SLOT(timeout()));
00452     return slave;
00453 }
00454 
00455 Slave* Slave::holdSlave( const QString &protocol, const KUrl& url )
00456 {
00457     //kDebug(7002) << "holdSlave" << protocol << "for" << url;
00458     // Firstly take into account all special slaves
00459     if (protocol == "data")
00460         return 0;
00461     Slave *slave = new Slave(protocol);
00462     QString slaveAddress = slave->d_func()->slaveconnserver->address();
00463     QDBusReply<int> reply = KToolInvocation::klauncher()->requestHoldSlave(url.url(), slaveAddress);
00464     if (!reply.isValid()) {
00465         delete slave;
00466         return 0;
00467     }
00468     pid_t pid = reply;
00469     if (!pid)
00470     {
00471         delete slave;
00472         return 0;
00473     }
00474     slave->setPID(pid);
00475     QTimer::singleShot(1000*SLAVE_CONNECTION_TIMEOUT_MIN, slave, SLOT(timeout()));
00476     return slave;
00477 }
00478 
00479 #include "slave.moc"

KIO

Skip menu "KIO"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
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