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