• Skip to content
  • Skip to link menu
KDE 4.1 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->connection->isConnected())
00129       return;
00130 
00131    kDebug(7002) << "slave failed to connect to application pid=" << d->m_pid << " protocol=" << d->m_protocol;
00132    if (d->m_pid && (::kill(d->m_pid, 0) == 0))
00133    {
00134       int delta_t = (int) difftime(time(0), d->contact_started);
00135       kDebug(7002) << "slave is slow... pid=" << d->m_pid << " t=" << delta_t;
00136       if (delta_t < SLAVE_CONNECTION_TIMEOUT_MAX)
00137       {
00138          QTimer::singleShot(1000*SLAVE_CONNECTION_TIMEOUT_MIN, this, SLOT(timeout()));
00139          return;
00140       }
00141    }
00142    kDebug(7002) << "Houston, we lost our slave, pid=" << d->m_pid;
00143    d->connection->close();
00144    d->dead = true;
00145    QString arg = d->m_protocol;
00146    if (!d->m_host.isEmpty())
00147       arg += "://"+d->m_host;
00148    kDebug(7002) << "slave died pid = " << d->m_pid;
00149    ref();
00150    // Tell the job about the problem.
00151    emit error(ERR_SLAVE_DIED, arg);
00152    // Tell the scheduler about the problem.
00153    emit slaveDied(this);
00154    // After the above signal we're dead!!
00155    deref();
00156 }
00157 
00158 Slave::Slave(const QString &protocol, QObject *parent)
00159     : SlaveInterface(*new SlavePrivate(protocol), parent)
00160 {
00161     Q_D(Slave);
00162     d->slaveconnserver->setParent(this);
00163     d->connection = new Connection(this);
00164     connect(d->slaveconnserver, SIGNAL(newConnection()), SLOT(accept()));
00165 }
00166 
00167 Slave::~Slave()
00168 {
00169     // kDebug(7002) << "destructing slave object pid = " << d->m_pid;
00170     //delete d;
00171 }
00172 
00173 QString Slave::protocol()
00174 {
00175     Q_D(Slave);
00176     return d->m_protocol;
00177 }
00178 
00179 void Slave::setProtocol(const QString & protocol)
00180 {
00181     Q_D(Slave);
00182     d->m_protocol = protocol;
00183 }
00184 
00185 QString Slave::slaveProtocol()
00186 {
00187     Q_D(Slave);
00188     return d->m_slaveProtocol;
00189 }
00190 
00191 QString Slave::host()
00192 {
00193     Q_D(Slave);
00194     return d->m_host;
00195 }
00196 
00197 quint16 Slave::port()
00198 {
00199     Q_D(Slave);
00200     return d->m_port;
00201 }
00202 
00203 QString Slave::user()
00204 {
00205     Q_D(Slave);
00206     return d->m_user;
00207 }
00208 
00209 QString Slave::passwd()
00210 {
00211     Q_D(Slave);
00212     return d->m_passwd;
00213 }
00214 
00215 void Slave::setIdle()
00216 {
00217     Q_D(Slave);
00218     d->idle_since = time(0);
00219 }
00220 
00221 bool Slave::isConnected()
00222 {
00223     Q_D(Slave);
00224     return d->contacted;
00225 }
00226 
00227 void Slave::setConnected(bool c)
00228 {
00229     Q_D(Slave);
00230     d->contacted = c;
00231 }
00232 
00233 void Slave::ref()
00234 {
00235     Q_D(Slave);
00236     d->m_refCount++;
00237 }
00238 
00239 void Slave::deref()
00240 {
00241     Q_D(Slave);
00242     d->m_refCount--;
00243     if (!d->m_refCount)
00244         deleteLater();
00245 }
00246 
00247 time_t Slave::idleTime()
00248 {
00249     Q_D(Slave);
00250     return (time_t) difftime(time(0), d->idle_since);
00251 }
00252 
00253 void Slave::setPID(pid_t pid)
00254 {
00255     Q_D(Slave);
00256     d->m_pid = pid;
00257 }
00258 
00259 int Slave::slave_pid()
00260 {
00261     Q_D(Slave);
00262     return d->m_pid;
00263 }
00264 
00265 bool Slave::isAlive()
00266 {
00267     Q_D(Slave);
00268     return !d->dead;
00269 }
00270 
00271 void Slave::hold(const KUrl &url)
00272 {
00273     Q_D(Slave);
00274     ref();
00275     {
00276         QByteArray data;
00277         QDataStream stream( &data, QIODevice::WriteOnly );
00278         stream << url;
00279         d->connection->send( CMD_SLAVE_HOLD, data );
00280         d->connection->close();
00281         d->dead = true;
00282         emit slaveDied(this);
00283     }
00284     deref();
00285     // Call KLauncher::waitForSlave(pid);
00286     {
00287         KToolInvocation::klauncher()->waitForSlave(d->m_pid);
00288     }
00289 }
00290 
00291 void Slave::suspend()
00292 {
00293     Q_D(Slave);
00294     d->connection->suspend();
00295 }
00296 
00297 void Slave::resume()
00298 {
00299     Q_D(Slave);
00300     d->connection->resume();
00301 }
00302 
00303 bool Slave::suspended()
00304 {
00305     Q_D(Slave);
00306     return d->connection->suspended();
00307 }
00308 
00309 void Slave::send(int cmd, const QByteArray &arr)
00310 {
00311     Q_D(Slave);
00312     d->connection->send(cmd, arr);
00313 }
00314 
00315 void Slave::gotInput()
00316 {
00317     Q_D(Slave);
00318     ref();
00319     if (!dispatch())
00320     {
00321         d->connection->close();
00322         d->dead = true;
00323         QString arg = d->m_protocol;
00324         if (!d->m_host.isEmpty())
00325             arg += "://"+d->m_host;
00326         kDebug(7002) << "slave died pid = " << d->m_pid;
00327         // Tell the job about the problem.
00328         emit error(ERR_SLAVE_DIED, arg);
00329         // Tell the scheduler about the problem.
00330         emit slaveDied(this);
00331     }
00332     deref();
00333     // Here we might be dead!!
00334 }
00335 
00336 void Slave::kill()
00337 {
00338     Q_D(Slave);
00339     d->dead = true; // OO can be such simple.
00340     kDebug(7002) << "killing slave pid=" << d->m_pid << " (" << d->m_protocol << "://"
00341           << d->m_host << ")";
00342     if (d->m_pid)
00343     {
00344        ::kill(d->m_pid, SIGTERM);
00345     }
00346 }
00347 
00348 void Slave::setHost( const QString &host, quint16 port,
00349                      const QString &user, const QString &passwd)
00350 {
00351     Q_D(Slave);
00352     d->m_host = host;
00353     d->m_port = port;
00354     d->m_user = user;
00355     d->m_passwd = passwd;
00356 
00357     QByteArray data;
00358     QDataStream stream( &data, QIODevice::WriteOnly );
00359     stream << d->m_host << d->m_port << d->m_user << d->m_passwd;
00360     d->connection->send( CMD_HOST, data );
00361 }
00362 
00363 void Slave::resetHost()
00364 {
00365     Q_D(Slave);
00366     d->m_host = "<reset>";
00367 }
00368 
00369 void Slave::setConfig(const MetaData &config)
00370 {
00371     Q_D(Slave);
00372     QByteArray data;
00373     QDataStream stream( &data, QIODevice::WriteOnly );
00374     stream << config;
00375     d->connection->send( CMD_CONFIG, data );
00376 }
00377 
00378 Slave* Slave::createSlave( const QString &protocol, const KUrl& url, int& error, QString& error_text )
00379 {
00380     kDebug(7002) << "createSlave" << protocol << "for" << url;
00381     // Firstly take into account all special slaves
00382     if (protocol == "data")
00383         return new DataProtocol();
00384     Slave *slave = new Slave(protocol);
00385     QString slaveAddress = slave->d_func()->slaveconnserver->address();
00386 
00387 #ifdef Q_OS_UNIX
00388     // In such case we start the slave via QProcess.
00389     // It's possible to force this by setting the env. variable
00390     // KDE_FORK_SLAVES, Clearcase seems to require this.
00391     static bool bForkSlaves = !qgetenv("KDE_FORK_SLAVES").isEmpty();
00392 
00393     if (!bForkSlaves)
00394     {
00395        // check the UID of klauncher
00396        QDBusReply<uint> reply = QDBusConnection::sessionBus().interface()->serviceUid(KToolInvocation::klauncher()->service());
00397        if (reply.isValid() && getuid() != reply)
00398           bForkSlaves = true;
00399     }
00400 
00401     if (bForkSlaves)
00402     {
00403        QString _name = KProtocolInfo::exec(protocol);
00404        if (_name.isEmpty())
00405        {
00406           error_text = i18n("Unknown protocol '%1'.", protocol);
00407           error = KIO::ERR_CANNOT_LAUNCH_PROCESS;
00408           delete slave;
00409           return 0;
00410        }
00411        QString lib_path = KLibLoader::findLibrary(QFile::encodeName(_name));
00412        if (lib_path.isEmpty())
00413        {
00414           error_text = i18n("Can not find io-slave for protocol '%1'.", protocol);
00415           error = KIO::ERR_CANNOT_LAUNCH_PROCESS;
00416           return 0;
00417        }
00418 
00419        QStringList args = QStringList() << lib_path << protocol << "" << slaveAddress;
00420        kDebug() << "kioslave" << ", " << lib_path << ", " << protocol << ", " << QString() << ", " << slaveAddress;
00421 
00422        QProcess::startDetached( KStandardDirs::locate("exe", "kioslave"), args );
00423 
00424        return slave;
00425     }
00426 #endif
00427 
00428     org::kde::KLauncher* klauncher = KToolInvocation::klauncher();
00429     QString errorStr;
00430     QDBusReply<int> reply = klauncher->requestSlave(protocol, url.host(), slaveAddress, errorStr);
00431     if (!reply.isValid()) {
00432     error_text = i18n("Cannot talk to klauncher: %1", klauncher->lastError().message() );
00433     error = KIO::ERR_CANNOT_LAUNCH_PROCESS;
00434         delete slave;
00435         return 0;
00436     }
00437     pid_t pid = reply;
00438     if (!pid)
00439     {
00440         error_text = i18n("Unable to create io-slave:\nklauncher said: %1", errorStr);
00441         error = KIO::ERR_CANNOT_LAUNCH_PROCESS;
00442         delete slave;
00443         return 0;
00444     }
00445     slave->setPID(pid);
00446     QTimer::singleShot(1000*SLAVE_CONNECTION_TIMEOUT_MIN, slave, SLOT(timeout()));
00447     return slave;
00448 }
00449 
00450 Slave* Slave::holdSlave( const QString &protocol, const KUrl& url )
00451 {
00452     //kDebug(7002) << "holdSlave" << protocol << "for" << url;
00453     // Firstly take into account all special slaves
00454     if (protocol == "data")
00455         return 0;
00456     Slave *slave = new Slave(protocol);
00457     QString slaveAddress = slave->d_func()->slaveconnserver->address();
00458     QDBusReply<int> reply = KToolInvocation::klauncher()->requestHoldSlave(url.url(), slaveAddress);
00459     if (!reply.isValid()) {
00460         delete slave;
00461         return 0;
00462     }
00463     pid_t pid = reply;
00464     if (!pid)
00465     {
00466         delete slave;
00467         return 0;
00468     }
00469     slave->setPID(pid);
00470     QTimer::singleShot(1000*SLAVE_CONNECTION_TIMEOUT_MIN, slave, SLOT(timeout()));
00471     return slave;
00472 }
00473 
00474 #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
  • Kross
  • KUtils
  • Nepomuk
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs 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