• Skip to content
  • Skip to link menu
KDE 4.7 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • 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 <time.h>
00024 #include <errno.h>
00025 #include <unistd.h>
00026 #include <stdlib.h>
00027 #include <stdio.h>
00028 #include <signal.h>
00029 #include <sys/types.h>
00030 
00031 #include <QtCore/QFile>
00032 #include <QtCore/QTimer>
00033 #include <QtDBus/QtDBus>
00034 #include <QtCore/QProcess>
00035 
00036 #include <kdebug.h>
00037 #include <klocale.h>
00038 #include <kglobal.h>
00039 #include <kstandarddirs.h>
00040 #include <ktoolinvocation.h>
00041 #include <klauncher_iface.h>
00042 #include <klibrary.h>
00043 
00044 #include "dataprotocol.h"
00045 #include "kservice.h"
00046 #include <kio/global.h>
00047 #include "kio/connection.h"
00048 #include <kprotocolinfo.h>
00049 
00050 #include "slaveinterface_p.h"
00051 
00052 using namespace KIO;
00053 
00054 #define SLAVE_CONNECTION_TIMEOUT_MIN       2
00055 
00056 // Without debug info we consider it an error if the slave doesn't connect
00057 // within 10 seconds.
00058 // With debug info we give the slave an hour so that developers have a chance
00059 // to debug their slave.
00060 #ifdef NDEBUG
00061 #define SLAVE_CONNECTION_TIMEOUT_MAX      10
00062 #else
00063 #define SLAVE_CONNECTION_TIMEOUT_MAX    3600
00064 #endif
00065 
00066 namespace KIO {
00067 
00071     class SlavePrivate: public SlaveInterfacePrivate
00072     {
00073     public:
00074         SlavePrivate(const QString &protocol) :
00075             m_protocol(protocol),
00076             m_slaveProtocol(protocol),
00077             slaveconnserver(new KIO::ConnectionServer),
00078             m_job(0),
00079             m_pid(0),
00080             m_port(0),
00081             contacted(false),
00082             dead(false),
00083             contact_started(time(0)),
00084             m_idleSince(0),
00085             m_refCount(1)
00086         {
00087             slaveconnserver->listenForRemote();
00088             if ( !slaveconnserver->isListening() )
00089                 kWarning() << "Connection server not listening, could not connect";
00090         }
00091         ~SlavePrivate()
00092         {
00093             delete slaveconnserver;
00094         }
00095 
00096         QString m_protocol;
00097         QString m_slaveProtocol;
00098         QString m_host;
00099         QString m_user;
00100         QString m_passwd;
00101         KIO::ConnectionServer *slaveconnserver;
00102         KIO::SimpleJob *m_job;
00103         pid_t m_pid;
00104         quint16 m_port;
00105         bool contacted;
00106         bool dead;
00107         time_t contact_started;
00108         time_t m_idleSince;
00109         int m_refCount;
00110   };
00111 }
00112 
00113 void Slave::accept()
00114 {
00115     Q_D(Slave);
00116     d->slaveconnserver->setNextPendingConnection(d->connection);
00117     d->slaveconnserver->deleteLater();
00118     d->slaveconnserver = 0;
00119 
00120     connect(d->connection, SIGNAL(readyRead()), SLOT(gotInput()));
00121 }
00122 
00123 void Slave::timeout()
00124 {
00125     Q_D(Slave);
00126    if (d->dead) //already dead? then slaveDied was emitted and we are done
00127       return;
00128    if (d->connection->isConnected())
00129       return;
00130 
00131    kDebug(7002) << "slave failed to connect to application pid=" << d->m_pid
00132                 << " 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 
00151    ref();
00152    // Tell the job about the problem.
00153    emit error(ERR_SLAVE_DIED, arg);
00154    // Tell the scheduler about the problem.
00155    emit slaveDied(this);
00156    // After the above signal we're dead!!
00157    deref();
00158 }
00159 
00160 Slave::Slave(const QString &protocol, QObject *parent)
00161     : SlaveInterface(*new SlavePrivate(protocol), parent)
00162 {
00163     Q_D(Slave);
00164     d->slaveconnserver->setParent(this);
00165     d->connection = new Connection(this);
00166     connect(d->slaveconnserver, SIGNAL(newConnection()), SLOT(accept()));
00167 }
00168 
00169 Slave::~Slave()
00170 {
00171     // kDebug(7002) << "destructing slave object pid = " << d->m_pid;
00172     //delete d;
00173 }
00174 
00175 QString Slave::protocol()
00176 {
00177     Q_D(Slave);
00178     return d->m_protocol;
00179 }
00180 
00181 void Slave::setProtocol(const QString & protocol)
00182 {
00183     Q_D(Slave);
00184     d->m_protocol = protocol;
00185 }
00186 
00187 QString Slave::slaveProtocol()
00188 {
00189     Q_D(Slave);
00190     return d->m_slaveProtocol;
00191 }
00192 
00193 QString Slave::host()
00194 {
00195     Q_D(Slave);
00196     return d->m_host;
00197 }
00198 
00199 quint16 Slave::port()
00200 {
00201     Q_D(Slave);
00202     return d->m_port;
00203 }
00204 
00205 QString Slave::user()
00206 {
00207     Q_D(Slave);
00208     return d->m_user;
00209 }
00210 
00211 QString Slave::passwd()
00212 {
00213     Q_D(Slave);
00214     return d->m_passwd;
00215 }
00216 
00217 void Slave::setIdle()
00218 {
00219     Q_D(Slave);
00220     d->m_idleSince = time(0);
00221 }
00222 
00223 bool Slave::isConnected()
00224 {
00225     Q_D(Slave);
00226     return d->contacted;
00227 }
00228 
00229 void Slave::setConnected(bool c)
00230 {
00231     Q_D(Slave);
00232     d->contacted = c;
00233 }
00234 
00235 void Slave::ref()
00236 {
00237     Q_D(Slave);
00238     d->m_refCount++;
00239 }
00240 
00241 void Slave::deref()
00242 {
00243     Q_D(Slave);
00244     d->m_refCount--;
00245     if (!d->m_refCount) {
00246         d->connection->disconnect(this);
00247         this->disconnect();
00248         deleteLater();
00249     }
00250 }
00251 
00252 time_t Slave::idleTime()
00253 {
00254     Q_D(Slave);
00255     if (!d->m_idleSince) {
00256         return time_t(0);
00257     }
00258     return time_t(difftime(time(0), d->m_idleSince));
00259 }
00260 
00261 void Slave::setPID(pid_t pid)
00262 {
00263     Q_D(Slave);
00264     d->m_pid = pid;
00265 }
00266 
00267 int Slave::slave_pid()
00268 {
00269     Q_D(Slave);
00270     return d->m_pid;
00271 }
00272 
00273 void Slave::setJob(KIO::SimpleJob *job)
00274 {
00275     Q_D(Slave);
00276     if (!d->sslMetaData.isEmpty()) {
00277         emit metaData(d->sslMetaData);
00278     }
00279     d->m_job = job;
00280 }
00281 
00282 KIO::SimpleJob *Slave::job() const
00283 {
00284     Q_D(const Slave);
00285     return d->m_job;
00286 }
00287 
00288 bool Slave::isAlive()
00289 {
00290     Q_D(Slave);
00291     return !d->dead;
00292 }
00293 
00294 void Slave::hold(const KUrl &url)
00295 {
00296     Q_D(Slave);
00297     ref();
00298     {
00299         QByteArray data;
00300         QDataStream stream( &data, QIODevice::WriteOnly );
00301         stream << url;
00302         d->connection->send( CMD_SLAVE_HOLD, data );
00303         d->connection->close();
00304         d->dead = true;
00305         emit slaveDied(this);
00306     }
00307     deref();
00308     // Call KLauncher::waitForSlave(pid);
00309     {
00310         KToolInvocation::klauncher()->waitForSlave(d->m_pid);
00311     }
00312 }
00313 
00314 void Slave::suspend()
00315 {
00316     Q_D(Slave);
00317     d->connection->suspend();
00318 }
00319 
00320 void Slave::resume()
00321 {
00322     Q_D(Slave);
00323     d->connection->resume();
00324 }
00325 
00326 bool Slave::suspended()
00327 {
00328     Q_D(Slave);
00329     return d->connection->suspended();
00330 }
00331 
00332 void Slave::send(int cmd, const QByteArray &arr)
00333 {
00334     Q_D(Slave);
00335     d->connection->send(cmd, arr);
00336 }
00337 
00338 void Slave::gotInput()
00339 {
00340     Q_D(Slave);
00341     if (d->dead) //already dead? then slaveDied was emitted and we are done
00342         return;
00343     ref();
00344     if (!dispatch())
00345     {
00346         d->connection->close();
00347         d->dead = true;
00348         QString arg = d->m_protocol;
00349         if (!d->m_host.isEmpty())
00350             arg += "://"+d->m_host;
00351         kDebug(7002) << "slave died pid = " << d->m_pid;
00352         // Tell the job about the problem.
00353         emit error(ERR_SLAVE_DIED, arg);
00354         // Tell the scheduler about the problem.
00355         emit slaveDied(this);
00356     }
00357     deref();
00358     // Here we might be dead!!
00359 }
00360 
00361 void Slave::kill()
00362 {
00363     Q_D(Slave);
00364     d->dead = true; // OO can be such simple.
00365     kDebug(7002) << "killing slave pid" << d->m_pid
00366                  << "(" << QString(d->m_protocol) + "://" + d->m_host << ")";
00367     if (d->m_pid)
00368     {
00369 #ifndef _WIN32_WCE
00370        ::kill(d->m_pid, SIGTERM);
00371 #else
00372         ::kill(d->m_pid, SIGKILL);
00373 #endif
00374        d->m_pid = 0;
00375     }
00376 }
00377 
00378 void Slave::setHost( const QString &host, quint16 port,
00379                      const QString &user, const QString &passwd)
00380 {
00381     Q_D(Slave);
00382     d->m_host = host;
00383     d->m_port = port;
00384     d->m_user = user;
00385     d->m_passwd = passwd;
00386     d->sslMetaData.clear();
00387 
00388     QByteArray data;
00389     QDataStream stream( &data, QIODevice::WriteOnly );
00390     stream << d->m_host << d->m_port << d->m_user << d->m_passwd;
00391     d->connection->send( CMD_HOST, data );
00392 }
00393 
00394 void Slave::resetHost()
00395 {
00396     Q_D(Slave);
00397     d->sslMetaData.clear();
00398     d->m_host = "<reset>";
00399 }
00400 
00401 void Slave::setConfig(const MetaData &config)
00402 {
00403     Q_D(Slave);
00404     QByteArray data;
00405     QDataStream stream( &data, QIODevice::WriteOnly );
00406     stream << config;
00407     d->connection->send( CMD_CONFIG, data );
00408 }
00409 
00410 Slave* Slave::createSlave( const QString &protocol, const KUrl& url, int& error, QString& error_text )
00411 {
00412     kDebug(7002) << "createSlave" << protocol << "for" << url;
00413     // Firstly take into account all special slaves
00414     if (protocol == "data")
00415         return new DataProtocol();
00416     Slave *slave = new Slave(protocol);
00417     QString slaveAddress = slave->d_func()->slaveconnserver->address();
00418 
00419 #ifdef Q_OS_UNIX
00420     // In such case we start the slave via QProcess.
00421     // It's possible to force this by setting the env. variable
00422     // KDE_FORK_SLAVES, Clearcase seems to require this.
00423     static bool bForkSlaves = !qgetenv("KDE_FORK_SLAVES").isEmpty();
00424 
00425     if (!bForkSlaves)
00426     {
00427        // check the UID of klauncher
00428        QDBusReply<uint> reply = QDBusConnection::sessionBus().interface()->serviceUid(KToolInvocation::klauncher()->service());
00429        if (reply.isValid() && getuid() != reply)
00430           bForkSlaves = true;
00431     }
00432 
00433     if (bForkSlaves)
00434     {
00435        QString _name = KProtocolInfo::exec(protocol);
00436        if (_name.isEmpty())
00437        {
00438           error_text = i18n("Unknown protocol '%1'.", protocol);
00439           error = KIO::ERR_CANNOT_LAUNCH_PROCESS;
00440           delete slave;
00441           return 0;
00442        }
00443        KLibrary lib(_name, KGlobal::mainComponent());
00444        QString lib_path = lib.fileName();
00445        if (lib_path.isEmpty())
00446        {
00447           error_text = i18n("Can not find io-slave for protocol '%1'.", protocol);
00448           error = KIO::ERR_CANNOT_LAUNCH_PROCESS;
00449           delete slave;
00450           return 0;
00451        }
00452 
00453        const QStringList args = QStringList() << lib_path << protocol << "" << slaveAddress;
00454        kDebug() << "kioslave" << ", " << lib_path << ", " << protocol << ", " << QString() << ", " << slaveAddress;
00455 
00456        QProcess::startDetached( KStandardDirs::locate("exe", "kioslave"), args );
00457 
00458        return slave;
00459     }
00460 #endif
00461 
00462     org::kde::KLauncher* klauncher = KToolInvocation::klauncher();
00463     QString errorStr;
00464     QDBusReply<int> reply = klauncher->requestSlave(protocol, url.host(), slaveAddress, errorStr);
00465     if (!reply.isValid()) {
00466     error_text = i18n("Cannot talk to klauncher: %1", klauncher->lastError().message() );
00467     error = KIO::ERR_CANNOT_LAUNCH_PROCESS;
00468         delete slave;
00469         return 0;
00470     }
00471     pid_t pid = reply;
00472     if (!pid)
00473     {
00474         error_text = i18n("Unable to create io-slave:\nklauncher said: %1", errorStr);
00475         error = KIO::ERR_CANNOT_LAUNCH_PROCESS;
00476         delete slave;
00477         return 0;
00478     }
00479     slave->setPID(pid);
00480     QTimer::singleShot(1000*SLAVE_CONNECTION_TIMEOUT_MIN, slave, SLOT(timeout()));
00481     return slave;
00482 }
00483 
00484 Slave* Slave::holdSlave( const QString &protocol, const KUrl& url )
00485 {
00486     //kDebug(7002) << "holdSlave" << protocol << "for" << url;
00487     // Firstly take into account all special slaves
00488     if (protocol == "data")
00489         return 0;
00490     Slave *slave = new Slave(protocol);
00491     QString slaveAddress = slave->d_func()->slaveconnserver->address();
00492     QDBusReply<int> reply = KToolInvocation::klauncher()->requestHoldSlave(url.url(), slaveAddress);
00493     if (!reply.isValid()) {
00494         delete slave;
00495         return 0;
00496     }
00497     pid_t pid = reply;
00498     if (!pid)
00499     {
00500         delete slave;
00501         return 0;
00502     }
00503     slave->setPID(pid);
00504     QTimer::singleShot(1000*SLAVE_CONNECTION_TIMEOUT_MIN, slave, SLOT(timeout()));
00505     return slave;
00506 }
00507 
00508 bool Slave::checkForHeldSlave(const KUrl &url)
00509 {
00510     return KToolInvocation::klauncher()->checkForHeldSlave(url.url());
00511 }
00512 
00513 #include "slave.moc"

KIO

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

kdelibs

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