• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • 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  * $Id: slave.cpp 467686 2005-10-05 23:00:10Z dfaure $
00007  *
00008  *  This library is free software; you can redistribute it and/or
00009  *  modify it under the terms of the GNU Library General Public
00010  *  License version 2 as published by the Free Software Foundation.
00011  *
00012  *  This library is distributed in the hope that it will be useful,
00013  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  *  Library General Public License for more details.
00016  *
00017  *  You should have received a copy of the GNU Library General Public License
00018  *  along with this library; see the file COPYING.LIB.  If not, write to
00019  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00020  *  Boston, MA 02110-1301, USA.
00021  **/
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 <qfile.h>
00034 #include <qtimer.h>
00035 
00036 #include <dcopclient.h>
00037 #include <kdebug.h>
00038 #include <klocale.h>
00039 #include <kglobal.h>
00040 #include <kstandarddirs.h>
00041 #include <kapplication.h>
00042 #include <ktempfile.h>
00043 #include <ksock.h>
00044 #include <kprocess.h>
00045 #include <klibloader.h>
00046 
00047 #include "kio/dataprotocol.h"
00048 #include "kio/slave.h"
00049 #include "kio/kservice.h"
00050 #include <kio/global.h>
00051 #include <kprotocolmanager.h>
00052 #include <kprotocolinfo.h>
00053 
00054 #ifdef HAVE_PATHS_H
00055 #include <paths.h>
00056 #endif
00057 
00058 #ifndef _PATH_TMP
00059 #define _PATH_TMP "/tmp"
00060 #endif
00061 
00062 using namespace KIO;
00063 
00064 #define SLAVE_CONNECTION_TIMEOUT_MIN       2
00065 
00066 // Without debug info we consider it an error if the slave doesn't connect
00067 // within 10 seconds.
00068 // With debug info we give the slave an hour so that developers have a chance
00069 // to debug their slave.
00070 #ifdef NDEBUG
00071 #define SLAVE_CONNECTION_TIMEOUT_MAX      10
00072 #else
00073 #define SLAVE_CONNECTION_TIMEOUT_MAX    3600
00074 #endif
00075 
00076 namespace KIO {
00077 
00081   class SlavePrivate {
00082   public:
00083     bool derived;   // true if this instance of Slave is actually an
00084                 // instance of a derived class.
00085 
00086     SlavePrivate(bool derived) : derived(derived) {}
00087   };
00088 }
00089 
00090 void Slave::accept(KSocket *socket)
00091 {
00092 #ifndef Q_WS_WIN
00093     slaveconn.init(socket);
00094 #endif
00095     delete serv;
00096     serv = 0;
00097     slaveconn.connect(this, SLOT(gotInput()));
00098     unlinkSocket();
00099 }
00100 
00101 void Slave::unlinkSocket()
00102 {
00103     if (m_socket.isEmpty()) return;
00104     QCString filename = QFile::encodeName(m_socket);
00105     unlink(filename.data());
00106     m_socket = QString::null;
00107 }
00108 
00109 void Slave::timeout()
00110 {
00111    if (!serv) return;
00112    kdDebug(7002) << "slave failed to connect to application pid=" << m_pid << " protocol=" << m_protocol << endl;
00113    if (m_pid && (::kill(m_pid, 0) == 0))
00114    {
00115       int delta_t = (int) difftime(time(0), contact_started);
00116       kdDebug(7002) << "slave is slow... pid=" << m_pid << " t=" << delta_t << endl;
00117       if (delta_t < SLAVE_CONNECTION_TIMEOUT_MAX)
00118       {
00119          QTimer::singleShot(1000*SLAVE_CONNECTION_TIMEOUT_MIN, this, SLOT(timeout()));
00120          return;
00121       }
00122    }
00123    kdDebug(7002) << "Houston, we lost our slave, pid=" << m_pid << endl;
00124    delete serv;
00125    serv = 0;
00126    unlinkSocket();
00127    dead = true;
00128    QString arg = m_protocol;
00129    if (!m_host.isEmpty())
00130       arg += "://"+m_host;
00131    kdDebug(7002) << "slave died pid = " << m_pid << endl;
00132    ref();
00133    // Tell the job about the problem.
00134    emit error(ERR_SLAVE_DIED, arg);
00135    // Tell the scheduler about the problem.
00136    emit slaveDied(this);
00137    // After the above signal we're dead!!
00138    deref();
00139 }
00140 
00141 Slave::Slave(KServerSocket *socket, const QString &protocol, const QString &socketname)
00142   : SlaveInterface(&slaveconn), serv(socket), contacted(false),
00143     d(new SlavePrivate(false))
00144 {
00145     m_refCount = 1;
00146     m_protocol = protocol;
00147     m_slaveProtocol = protocol;
00148     m_socket = socketname;
00149     dead = false;
00150     contact_started = time(0);
00151     idle_since = contact_started;
00152     m_pid = 0;
00153     m_port = 0;
00154 #ifndef Q_WS_WIN
00155     connect(serv, SIGNAL(accepted( KSocket* )),
00156         SLOT(accept(KSocket*) ) );
00157 #endif
00158 }
00159 
00160 Slave::Slave(bool /*derived*/, KServerSocket *socket, const QString &protocol,
00161     const QString &socketname)
00162   : SlaveInterface(&slaveconn), serv(socket), contacted(false),
00163     d(new SlavePrivate(true))
00164 {
00165     // FIXME: hmm, duplicating code here from public ctor, no good (LS)
00166     m_refCount = 1;
00167     m_protocol = protocol;
00168     m_slaveProtocol = protocol;
00169     m_socket = socketname;
00170     dead = false;
00171     contact_started = time(0);
00172     idle_since = contact_started;
00173     m_pid = 0;
00174     m_port = 0;
00175     if (serv != 0) {
00176 #ifndef Q_WS_WIN
00177       connect(serv, SIGNAL(accepted( KSocket* )),
00178         SLOT(accept(KSocket*) ) );
00179 #endif
00180     }
00181 }
00182 
00183 Slave::~Slave()
00184 {
00185     // kdDebug(7002) << "destructing slave object pid = " << m_pid << endl;
00186     if (serv != 0) {
00187         delete serv;
00188         serv = 0;
00189     }
00190     unlinkSocket();
00191     m_pid = 99999;
00192     delete d;
00193     d = 0;
00194 }
00195 
00196 void Slave::setProtocol(const QString & protocol)
00197 {
00198     m_protocol = protocol;
00199 }
00200 
00201 void Slave::setIdle()
00202 {
00203     idle_since = time(0);
00204 }
00205 
00206 time_t Slave::idleTime()
00207 {
00208     return (time_t) difftime(time(0), idle_since);
00209 }
00210 
00211 void Slave::setPID(pid_t pid)
00212 {
00213     m_pid = pid;
00214 }
00215 
00216 void Slave::hold(const KURL &url)
00217 {
00218    if (d->derived) {        // TODO: clean up before KDE 4
00219      HoldParams params;
00220      params.url = &url;
00221      virtual_hook(VIRTUAL_HOLD, &params);
00222      return;
00223    }/*end if*/
00224 
00225    ref();
00226    {
00227       QByteArray data;
00228       QDataStream stream( data, IO_WriteOnly );
00229       stream << url;
00230       slaveconn.send( CMD_SLAVE_HOLD, data );
00231       slaveconn.close();
00232       dead = true;
00233       emit slaveDied(this);
00234    }
00235    deref();
00236    // Call KLauncher::waitForSlave(pid);
00237    {
00238       DCOPClient *client = kapp->dcopClient();
00239       if (!client->isAttached())
00240          client->attach();
00241 
00242       QByteArray params, reply;
00243       QCString replyType;
00244       QDataStream stream(params, IO_WriteOnly);
00245       pid_t pid = m_pid;
00246       stream << pid;
00247 
00248       QCString launcher = KApplication::launcher();
00249       client->call(launcher, launcher, "waitForSlave(pid_t)",
00250         params, replyType, reply);
00251    }
00252 }
00253 
00254 void Slave::suspend()
00255 {
00256    if (d->derived) {        // TODO: clean up before KDE 4
00257      virtual_hook(VIRTUAL_SUSPEND, 0);
00258      return;
00259    }/*end if*/
00260 
00261    slaveconn.suspend();
00262 }
00263 
00264 void Slave::resume()
00265 {
00266    if (d->derived) {        // TODO: clean up before KDE 4
00267      virtual_hook(VIRTUAL_RESUME, 0);
00268      return;
00269    }/*end if*/
00270 
00271    slaveconn.resume();
00272 }
00273 
00274 bool Slave::suspended()
00275 {
00276    if (d->derived) {        // TODO: clean up before KDE 4
00277      SuspendedParams params;
00278      virtual_hook(VIRTUAL_SUSPENDED, &params);
00279      return params.retval;
00280    }/*end if*/
00281 
00282    return slaveconn.suspended();
00283 }
00284 
00285 void Slave::send(int cmd, const QByteArray &arr) {
00286    if (d->derived) {        // TODO: clean up before KDE 4
00287      SendParams params;
00288      params.cmd = cmd;
00289      params.arr = &arr;
00290      virtual_hook(VIRTUAL_SEND, &params);
00291      return;
00292    }/*end if*/
00293 
00294    slaveconn.send(cmd, arr);
00295 }
00296 
00297 void Slave::gotInput()
00298 {
00299     ref();
00300     if (!dispatch())
00301     {
00302         slaveconn.close();
00303         dead = true;
00304         QString arg = m_protocol;
00305         if (!m_host.isEmpty())
00306             arg += "://"+m_host;
00307         kdDebug(7002) << "slave died pid = " << m_pid << endl;
00308         // Tell the job about the problem.
00309         emit error(ERR_SLAVE_DIED, arg);
00310         // Tell the scheduler about the problem.
00311         emit slaveDied(this);
00312     }
00313     deref();
00314     // Here we might be dead!!
00315 }
00316 
00317 void Slave::kill()
00318 {
00319     dead = true; // OO can be such simple.
00320     kdDebug(7002) << "killing slave pid=" << m_pid << " (" << m_protocol << "://"
00321           << m_host << ")" << endl;
00322     if (m_pid)
00323     {
00324        ::kill(m_pid, SIGTERM);
00325     }
00326 }
00327 
00328 void Slave::setHost( const QString &host, int port,
00329                      const QString &user, const QString &passwd)
00330 {
00331     m_host = host;
00332     m_port = port;
00333     m_user = user;
00334     m_passwd = passwd;
00335 
00336     QByteArray data;
00337     QDataStream stream( data, IO_WriteOnly );
00338     stream << m_host << m_port << m_user << m_passwd;
00339     slaveconn.send( CMD_HOST, data );
00340 }
00341 
00342 void Slave::resetHost()
00343 {
00344     m_host = "<reset>";
00345 }
00346 
00347 void Slave::setConfig(const MetaData &config)
00348 {
00349     QByteArray data;
00350     QDataStream stream( data, IO_WriteOnly );
00351     stream << config;
00352     slaveconn.send( CMD_CONFIG, data );
00353 }
00354 
00355 Slave* Slave::createSlave( const QString &protocol, const KURL& url, int& error, QString& error_text )
00356 {
00357     //kdDebug(7002) << "createSlave '" << protocol << "' for " << url.prettyURL() << endl;
00358     // Firstly take into account all special slaves
00359     if (protocol == "data")
00360         return new DataProtocol();
00361 
00362     DCOPClient *client = kapp->dcopClient();
00363     if (!client->isAttached())
00364     client->attach();
00365 
00366     QString prefix = locateLocal("socket", KGlobal::instance()->instanceName());
00367     KTempFile socketfile(prefix, QString::fromLatin1(".slave-socket"));
00368     if ( socketfile.status() != 0 )
00369     {
00370     error_text = i18n("Unable to create io-slave: %1").arg(strerror(errno));
00371     error = KIO::ERR_CANNOT_LAUNCH_PROCESS;
00372     return 0;
00373     }
00374 
00375 #ifdef __CYGWIN__
00376    socketfile.close();
00377 #endif
00378     
00379 #ifndef Q_WS_WIN
00380     KServerSocket *kss = new KServerSocket(QFile::encodeName(socketfile.name()));
00381 
00382     Slave *slave = new Slave(kss, protocol, socketfile.name());
00383 #else
00384     Slave *slave = 0;
00385 #endif
00386 
00387     // WABA: if the dcopserver is running under another uid we don't ask
00388     // klauncher for a slave, because the slave might have that other uid
00389     // as well, which might either be a) undesired or b) make it impossible
00390     // for the slave to connect to the application.
00391     // In such case we start the slave via KProcess.
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 = !QCString(getenv("KDE_FORK_SLAVES")).isEmpty();
00395     
00396     if (bForkSlaves || !client->isAttached() || client->isAttachedToForeignServer())
00397     {
00398        QString _name = KProtocolInfo::exec(protocol);
00399        if (_name.isEmpty())
00400        {
00401           error_text = i18n("Unknown protocol '%1'.").arg(protocol);
00402           error = KIO::ERR_CANNOT_LAUNCH_PROCESS;
00403           delete slave;
00404           return 0;
00405        }
00406        QString lib_path = KLibLoader::findLibrary(_name.latin1());
00407        if (lib_path.isEmpty())
00408        {
00409           error_text = i18n("Can not find io-slave for protocol '%1'.").arg(protocol);
00410           error = KIO::ERR_CANNOT_LAUNCH_PROCESS;
00411           return 0;
00412        }
00413 
00414        KProcess proc;
00415 
00416        proc << locate("exe", "kioslave") << lib_path << protocol << "" << socketfile.name();
00417        kdDebug(7002) << "kioslave" << ", " << lib_path << ", " << protocol << ", " << QString::null << ", " << socketfile.name() << endl;
00418 
00419        proc.start(KProcess::DontCare);
00420 
00421 #ifndef Q_WS_WIN
00422        slave->setPID(proc.pid());
00423        QTimer::singleShot(1000*SLAVE_CONNECTION_TIMEOUT_MIN, slave, SLOT(timeout()));
00424 #endif
00425        return slave;
00426     }
00427 
00428 
00429     QByteArray params, reply;
00430     QCString replyType;
00431     QDataStream stream(params, IO_WriteOnly);
00432     stream << protocol << url.host() << socketfile.name();
00433 
00434     QCString launcher = KApplication::launcher();
00435     if (!client->call(launcher, launcher, "requestSlave(QString,QString,QString)",
00436         params, replyType, reply)) {
00437     error_text = i18n("Cannot talk to klauncher");
00438     error = KIO::ERR_SLAVE_DEFINED;
00439         delete slave;
00440         return 0;
00441     }
00442     QDataStream stream2(reply, IO_ReadOnly);
00443     QString errorStr;
00444     pid_t pid;
00445     stream2 >> pid >> errorStr;
00446     if (!pid)
00447     {
00448         error_text = i18n("Unable to create io-slave:\nklauncher said: %1").arg(errorStr);
00449         error = KIO::ERR_CANNOT_LAUNCH_PROCESS;
00450         delete slave;
00451         return 0;
00452     }
00453 #ifndef Q_WS_WIN
00454     slave->setPID(pid);
00455     QTimer::singleShot(1000*SLAVE_CONNECTION_TIMEOUT_MIN, slave, SLOT(timeout()));
00456 #endif
00457     return slave;
00458 }
00459 
00460 Slave* Slave::holdSlave( const QString &protocol, const KURL& url )
00461 {
00462     //kdDebug(7002) << "holdSlave '" << protocol << "' for " << url.prettyURL() << endl;
00463     // Firstly take into account all special slaves
00464     if (protocol == "data")
00465         return 0;
00466 
00467     DCOPClient *client = kapp->dcopClient();
00468     if (!client->isAttached())
00469     client->attach();
00470 
00471     QString prefix = locateLocal("socket", KGlobal::instance()->instanceName());
00472     KTempFile socketfile(prefix, QString::fromLatin1(".slave-socket"));
00473     if ( socketfile.status() != 0 )
00474     return 0;
00475 
00476 #ifdef __CYGWIN__
00477    socketfile.close();
00478    socketfile.unlink();
00479 #endif
00480 
00481 #ifndef Q_WS_WIN
00482     KServerSocket *kss = new KServerSocket(QFile::encodeName(socketfile.name()));
00483 
00484     Slave *slave = new Slave(kss, protocol, socketfile.name());
00485 #else
00486     Slave *slave = 0;
00487 #endif
00488 
00489     QByteArray params, reply;
00490     QCString replyType;
00491     QDataStream stream(params, IO_WriteOnly);
00492     stream << url << socketfile.name();
00493 
00494     QCString launcher = KApplication::launcher();
00495     if (!client->call(launcher, launcher, "requestHoldSlave(KURL,QString)",
00496         params, replyType, reply)) {
00497         delete slave;
00498         return 0;
00499     }
00500     QDataStream stream2(reply, IO_ReadOnly);
00501     pid_t pid;
00502     stream2 >> pid;
00503     if (!pid)
00504     {
00505         delete slave;
00506         return 0;
00507     }
00508 #ifndef Q_WS_WIN
00509     slave->setPID(pid);
00510     QTimer::singleShot(1000*SLAVE_CONNECTION_TIMEOUT_MIN, slave, SLOT(timeout()));
00511 #endif
00512     return slave;
00513 }
00514 
00515 void Slave::virtual_hook( int id, void* data ) {
00516   KIO::SlaveInterface::virtual_hook( id, data );
00517 }
00518 
00519 #include "slave.moc"

kio

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

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
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