• Skip to content
  • Skip to link menu
KDE 4.2 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         d->connection->disconnect(this);
00245         this->disconnect();
00246         deleteLater();
00247     }
00248 }
00249 
00250 time_t Slave::idleTime()
00251 {
00252     Q_D(Slave);
00253     return (time_t) difftime(time(0), d->idle_since);
00254 }
00255 
00256 void Slave::setPID(pid_t pid)
00257 {
00258     Q_D(Slave);
00259     d->m_pid = pid;
00260 }
00261 
00262 int Slave::slave_pid()
00263 {
00264     Q_D(Slave);
00265     return d->m_pid;
00266 }
00267 
00268 bool Slave::isAlive()
00269 {
00270     Q_D(Slave);
00271     return !d->dead;
00272 }
00273 
00274 void Slave::hold(const KUrl &url)
00275 {
00276     Q_D(Slave);
00277     ref();
00278     {
00279         QByteArray data;
00280         QDataStream stream( &data, QIODevice::WriteOnly );
00281         stream << url;
00282         d->connection->send( CMD_SLAVE_HOLD, data );
00283         d->connection->close();
00284         d->dead = true;
00285         emit slaveDied(this);
00286     }
00287     deref();
00288     // Call KLauncher::waitForSlave(pid);
00289     {
00290         KToolInvocation::klauncher()->waitForSlave(d->m_pid);
00291     }
00292 }
00293 
00294 void Slave::suspend()
00295 {
00296     Q_D(Slave);
00297     d->connection->suspend();
00298 }
00299 
00300 void Slave::resume()
00301 {
00302     Q_D(Slave);
00303     d->connection->resume();
00304 }
00305 
00306 bool Slave::suspended()
00307 {
00308     Q_D(Slave);
00309     return d->connection->suspended();
00310 }
00311 
00312 void Slave::send(int cmd, const QByteArray &arr)
00313 {
00314     Q_D(Slave);
00315     d->connection->send(cmd, arr);
00316 }
00317 
00318 void Slave::gotInput()
00319 {
00320     Q_D(Slave);
00321     ref();
00322     if (!dispatch())
00323     {
00324         d->connection->close();
00325         d->dead = true;
00326         QString arg = d->m_protocol;
00327         if (!d->m_host.isEmpty())
00328             arg += "://"+d->m_host;
00329         kDebug(7002) << "slave died pid = " << d->m_pid;
00330         // Tell the job about the problem.
00331         emit error(ERR_SLAVE_DIED, arg);
00332         // Tell the scheduler about the problem.
00333         emit slaveDied(this);
00334     }
00335     deref();
00336     // Here we might be dead!!
00337 }
00338 
00339 void Slave::kill()
00340 {
00341     Q_D(Slave);
00342     d->dead = true; // OO can be such simple.
00343     kDebug(7002) << "killing slave pid" << d->m_pid
00344                  << "(" << QString(d->m_protocol) + "://" + d->m_host << ")";
00345     if (d->m_pid)
00346     {
00347        ::kill(d->m_pid, SIGTERM);
00348     }
00349 }
00350 
00351 void Slave::setHost( const QString &host, quint16 port,
00352                      const QString &user, const QString &passwd)
00353 {
00354     Q_D(Slave);
00355     d->m_host = host;
00356     d->m_port = port;
00357     d->m_user = user;
00358     d->m_passwd = passwd;
00359 
00360     QByteArray data;
00361     QDataStream stream( &data, QIODevice::WriteOnly );
00362     stream << d->m_host << d->m_port << d->m_user << d->m_passwd;
00363     d->connection->send( CMD_HOST, data );
00364 }
00365 
00366 void Slave::resetHost()
00367 {
00368     Q_D(Slave);
00369     d->m_host = "<reset>";
00370 }
00371 
00372 void Slave::setConfig(const MetaData &config)
00373 {
00374     Q_D(Slave);
00375     QByteArray data;
00376     QDataStream stream( &data, QIODevice::WriteOnly );
00377     stream << config;
00378     d->connection->send( CMD_CONFIG, data );
00379 }
00380 
00381 Slave* Slave::createSlave( const QString &protocol, const KUrl& url, int& error, QString& error_text )
00382 {
00383     kDebug(7002) << "createSlave" << protocol << "for" << url;
00384     // Firstly take into account all special slaves
00385     if (protocol == "data")
00386         return new DataProtocol();
00387     Slave *slave = new Slave(protocol);
00388     QString slaveAddress = slave->d_func()->slaveconnserver->address();
00389 
00390 #ifdef Q_OS_UNIX
00391     // In such case we start the slave via QProcess.
00392     // It's possible to force this by setting the env. variable
00393     // KDE_FORK_SLAVES, Clearcase seems to require this.
00394     static bool bForkSlaves = !qgetenv("KDE_FORK_SLAVES").isEmpty();
00395 
00396     if (!bForkSlaves)
00397     {
00398        // check the UID of klauncher
00399        QDBusReply<uint> reply = QDBusConnection::sessionBus().interface()->serviceUid(KToolInvocation::klauncher()->service());
00400        if (reply.isValid() && getuid() != reply)
00401           bForkSlaves = true;
00402     }
00403 
00404     if (bForkSlaves)
00405     {
00406        QString _name = KProtocolInfo::exec(protocol);
00407        if (_name.isEmpty())
00408        {
00409           error_text = i18n("Unknown protocol '%1'.", protocol);
00410           error = KIO::ERR_CANNOT_LAUNCH_PROCESS;
00411           delete slave;
00412           return 0;
00413        }
00414        QString lib_path = KLibLoader::findLibrary(QFile::encodeName(_name));
00415        if (lib_path.isEmpty())
00416        {
00417           error_text = i18n("Can not find io-slave for protocol '%1'.", protocol);
00418           error = KIO::ERR_CANNOT_LAUNCH_PROCESS;
00419           delete slave;
00420           return 0;
00421        }
00422 
00423        QStringList args = QStringList() << lib_path << protocol << "" << slaveAddress;
00424        kDebug() << "kioslave" << ", " << lib_path << ", " << protocol << ", " << QString() << ", " << slaveAddress;
00425 
00426        QProcess::startDetached( KStandardDirs::locate("exe", "kioslave"), args );
00427 
00428        return slave;
00429     }
00430 #endif
00431 
00432     org::kde::KLauncher* klauncher = KToolInvocation::klauncher();
00433     QString errorStr;
00434     QDBusReply<int> reply = klauncher->requestSlave(protocol, url.host(), slaveAddress, errorStr);
00435     if (!reply.isValid()) {
00436     error_text = i18n("Cannot talk to klauncher: %1", klauncher->lastError().message() );
00437     error = KIO::ERR_CANNOT_LAUNCH_PROCESS;
00438         delete slave;
00439         return 0;
00440     }
00441     pid_t pid = reply;
00442     if (!pid)
00443     {
00444         error_text = i18n("Unable to create io-slave:\nklauncher said: %1", errorStr);
00445         error = KIO::ERR_CANNOT_LAUNCH_PROCESS;
00446         delete slave;
00447         return 0;
00448     }
00449     slave->setPID(pid);
00450     QTimer::singleShot(1000*SLAVE_CONNECTION_TIMEOUT_MIN, slave, SLOT(timeout()));
00451     return slave;
00452 }
00453 
00454 Slave* Slave::holdSlave( const QString &protocol, const KUrl& url )
00455 {
00456     //kDebug(7002) << "holdSlave" << protocol << "for" << url;
00457     // Firstly take into account all special slaves
00458     if (protocol == "data")
00459         return 0;
00460     Slave *slave = new Slave(protocol);
00461     QString slaveAddress = slave->d_func()->slaveconnserver->address();
00462     QDBusReply<int> reply = KToolInvocation::klauncher()->requestHoldSlave(url.url(), slaveAddress);
00463     if (!reply.isValid()) {
00464         delete slave;
00465         return 0;
00466     }
00467     pid_t pid = reply;
00468     if (!pid)
00469     {
00470         delete slave;
00471         return 0;
00472     }
00473     slave->setPID(pid);
00474     QTimer::singleShot(1000*SLAVE_CONNECTION_TIMEOUT_MIN, slave, SLOT(timeout()));
00475     return slave;
00476 }
00477 
00478 #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
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.7
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