# kio Library API Documentation

Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Source Files

# slave.cpp

    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,v 1.56 2002/06/19 17:46:02 domi Exp $
    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., 59 Temple Place - Suite 330,
    00020  *  Boston, MA 02111-1307, 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/slave.h"
    00048 #include "kio/kservice.h"
    00049 #include <kio/global.h>
    00050 #include <kprotocolmanager.h>
    00051 #include <kprotocolinfo.h>
    00052
    00053 #ifdef HAVE_PATHS_H
    00054 #include <paths.h>
    00055 #endif
    00056
    00057 #ifndef _PATH_TMP
    00058 #define _PATH_TMP "/tmp"
    00059 #endif
    00060
    00061 using namespace KIO;
    00062
    00063 #define SLAVE_CONNECTION_TIMEOUT_MIN       2
    00064
    00065 // Without debug info we consider it an error if the slave doesn't connect
    00066 // within 10 seconds.
    00067 // With debug info we give the slave an hour so that developers have a chance
    00068 // to debug their slave.
    00069 #ifdef NDEBUG
    00070 #define SLAVE_CONNECTION_TIMEOUT_MAX      10
    00071 #else
    00072 #define SLAVE_CONNECTION_TIMEOUT_MAX    3600
    00073 #endif
    00074
    00075 void Slave::accept(KSocket *socket)
    00076 {
    00077     slaveconn.init(socket);
    00078     delete serv;
    00079     serv = 0;
    00080     slaveconn.connect(this, SLOT(gotInput()));
    00081     unlinkSocket();
    00082 }
    00083
    00084 void Slave::unlinkSocket()
    00085 {
    00086     if (m_socket.isEmpty()) return;
    00087     QCString filename = QFile::encodeName(m_socket);
    00088     unlink(filename.data());
    00089     m_socket = QString::null;
    00090 }
    00091
    00092 void Slave::timeout()
    00093 {
    00094    if (!serv) return;
    00095    kdDebug(7002) << "slave failed to connect to application pid=" << m_pid << " protocol=" << m_protocol << endl;
    00096    if (m_pid && (::kill(m_pid, 0) == 0))
    00097    {
    00098       int delta_t = (int) difftime(time(0), contact_started);
    00099       kdDebug(7002) << "slave is slow... pid=" << m_pid << " t=" << delta_t << endl;
    00100       if (delta_t < SLAVE_CONNECTION_TIMEOUT_MAX)
    00101       {
    00102          QTimer::singleShot(1000*SLAVE_CONNECTION_TIMEOUT_MIN, this, SLOT(timeout()));
    00103          return;
    00104       }
    00105    }
    00106    kdDebug(7002) << "Houston, we lost our slave, pid=" << m_pid << endl;
    00107    delete serv;
    00108    serv = 0;
    00109    unlinkSocket();
    00110    dead = true;
    00111    QString arg = m_protocol;
    00112    if (!m_host.isEmpty())
    00113       arg += "://"+m_host;
    00114    kdDebug(7002) << "slave died pid = " << m_pid << endl;
    00115    ref();
    00116    // Tell the job about the problem.
    00117    emit error(ERR_SLAVE_DIED, arg);
    00118    // Tell the scheduler about the problem.
    00119    emit slaveDied(this);
    00120    // After the above signal we're dead!!
    00121    deref();
    00122 }
    00123
    00124 Slave::Slave(KServerSocket *socket, const QString &protocol, const QString &socketname)
    00125   : SlaveInterface(&slaveconn), serv(socket), contacted(false)
    00126 {
    00127     m_refCount = 1;
    00128     m_protocol = protocol;
    00129     m_slaveProtocol = protocol;
    00130     m_socket = socketname;
    00131     dead = false;
    00132     contact_started = time(0);
    00133     idle_since = contact_started;
    00134     m_pid = 0;
    00135     m_port = 0;
    00136     connect(serv, SIGNAL(accepted( KSocket* )),
    00137             SLOT(accept(KSocket*) ) );
    00138 }
    00139
    00140 Slave::~Slave()
    00141 {
    00142     // kdDebug(7002) << "destructing slave object pid = " << m_pid << endl;
    00143     if (serv != 0) {
    00144         delete serv;
    00145         serv = 0;
    00146     }
    00147     unlinkSocket();
    00148     m_pid = 99999;
    00149 }
    00150
    00151 void Slave::setProtocol(const QString & protocol)
    00152 {
    00153     m_protocol = protocol;
    00154 }
    00155
    00156 void Slave::setIdle()
    00157 {
    00158     idle_since = time(0);
    00159 }
    00160
    00161 time_t Slave::idleTime()
    00162 {
    00163     return (time_t) difftime(time(0), idle_since);
    00164 }
    00165
    00166 void Slave::setPID(pid_t pid)
    00167 {
    00168     m_pid = pid;
    00169 }
    00170
    00171 void Slave::hold(const KURL &url)
    00172 {
    00173    ref();
    00174    {
    00175       QByteArray data;
    00176       QDataStream stream( data, IO_WriteOnly );
    00177       stream << url;
    00178       slaveconn.send( CMD_SLAVE_HOLD, data );
    00179       slaveconn.close();
    00180       dead = true;
    00181       emit slaveDied(this);
    00182    }
    00183    deref();
    00184    // Call KLauncher::waitForSlave(pid);
    00185    {
    00186       DCOPClient *client = kapp->dcopClient();
    00187       if (!client->isAttached())
    00188          client->attach();
    00189
    00190       QByteArray params, reply;
    00191       QCString replyType;
    00192       QDataStream stream(params, IO_WriteOnly);
    00193       pid_t pid = m_pid;
    00194       stream << pid;
    00195
    00196       QCString launcher = KApplication::launcher();
    00197       client->call(launcher, launcher, "waitForSlave(pid_t)",
    00198             params, replyType, reply);
    00199    }
    00200 }
    00201
    00202 void Slave::suspend()
    00203 {
    00204    slaveconn.suspend();
    00205 }
    00206
    00207 void Slave::resume()
    00208 {
    00209    slaveconn.resume();
    00210 }
    00211
    00212 bool Slave::suspended()
    00213 {
    00214    return slaveconn.suspended();
    00215 }
    00216
    00217
    00218 void Slave::gotInput()
    00219 {
    00220     ref();
    00221     if (!dispatch())
    00222     {
    00223         slaveconn.close();
    00224         dead = true;
    00225         QString arg = m_protocol;
    00226         if (!m_host.isEmpty())
    00227             arg += "://"+m_host;
    00228         kdDebug(7002) << "slave died pid = " << m_pid << endl;
    00229         // Tell the job about the problem.
    00230         emit error(ERR_SLAVE_DIED, arg);
    00231         // Tell the scheduler about the problem.
    00232         emit slaveDied(this);
    00233         // After the above signal we're dead!!
    00234     }
    00235     deref();
    00236 }
    00237
    00238 void Slave::kill()
    00239 {
    00240     dead = true; // OO can be such simple.
    00241     kdDebug(7002) << "killing slave pid=" << m_pid << " (" << m_protocol << "://"
    00242                   << m_host << ")" << endl;
    00243     if (m_pid)
    00244     {
    00245        ::kill(m_pid, SIGTERM);
    00246     }
    00247 }
    00248
    00249 void Slave::setHost( const QString &host, int port,
    00250                      const QString &user, const QString &passwd)
    00251 {
    00252     m_host = host;
    00253     m_port = port;
    00254     m_user = user;
    00255     m_passwd = passwd;
    00256
    00257     QByteArray data;
    00258     QDataStream stream( data, IO_WriteOnly );
    00259     stream << m_host << m_port << m_user << m_passwd;
    00260     slaveconn.send( CMD_HOST, data );
    00261 }
    00262
    00263 void Slave::resetHost()
    00264 {
    00265     m_host = "<reset>";
    00266 }
    00267
    00268 void Slave::setConfig(const MetaData &config)
    00269 {
    00270     QByteArray data;
    00271     QDataStream stream( data, IO_WriteOnly );
    00272     stream << config;
    00273     slaveconn.send( CMD_CONFIG, data );
    00274 }
    00275
    00276 Slave* Slave::createSlave( const QString &protocol, const KURL& url, int& error, QString& error_text )
    00277 {
    00278     //kdDebug(7002) << "createSlave '" << protocol << "' for " << url.prettyURL() << endl;
    00279
    00280     DCOPClient *client = kapp->dcopClient();
    00281     if (!client->isAttached())
    00282         client->attach();
    00283
    00284     QString prefix = locateLocal("socket", KGlobal::instance()->instanceName());
    00285     KTempFile socketfile(prefix, QString::fromLatin1(".slave-socket"));
    00286     if ( socketfile.status() != 0 )
    00287     {
    00288         error_text = i18n("Unable to create io-slave: %1").arg(strerror(errno));
    00289         error = KIO::ERR_CANNOT_LAUNCH_PROCESS;
    00290         return 0;
    00291     }
    00292     KServerSocket *kss = new KServerSocket(QFile::encodeName(socketfile.name()));
    00293
    00294     Slave *slave = new Slave(kss, protocol, socketfile.name());
    00295
    00296     // WABA: if the dcopserver is running under another uid we don't ask
    00297     // klauncher for a slave, because the slave might have that other uid
    00298     // as well, which might either be a) undesired or b) make it impossible
    00299     // for the slave to connect to the application.
    00300     // In such case we start the slave via KProcess.
    00301     if (!client->isAttached() || client->isAttachedToForeignServer())
    00302     {
    00303        QString _name = KProtocolInfo::exec(protocol);
    00304        if (_name.isEmpty())
    00305        {
    00306           error_text = i18n("Unknown protocol '%1'.\n").arg(protocol);
    00307           error = KIO::ERR_CANNOT_LAUNCH_PROCESS;
    00308           delete slave;
    00309           return 0;
    00310        }
    00311        QString lib_path = KLibLoader::findLibrary(_name.latin1());
    00312        if (lib_path.isEmpty())
    00313        {
    00314           error_text = i18n("Can not find io-slave for protocol '%1'.").arg(protocol);
    00315           error = KIO::ERR_CANNOT_LAUNCH_PROCESS;
    00316           return 0;
    00317        }
    00318
    00319        KProcess proc;
    00320
    00321        proc << "kioslave" << lib_path << protocol << "" << socketfile.name();
    00322        kdDebug(7002) << "kioslave" << ", " << lib_path << ", " << protocol << ", " << QString::null << ", " << socketfile.name() << endl;
    00323
    00324        proc.start(KProcess::DontCare);
    00325
    00326        slave->setPID(proc.pid());
    00327        QTimer::singleShot(1000*SLAVE_CONNECTION_TIMEOUT_MIN, slave, SLOT(timeout()));
    00328        return slave;
    00329     }
    00330
    00331
    00332     QByteArray params, reply;
    00333     QCString replyType;
    00334     QDataStream stream(params, IO_WriteOnly);
    00335     stream << protocol << url.host() << socketfile.name();
    00336
    00337     QCString launcher = KApplication::launcher();
    00338     if (!client->call(launcher, launcher, "requestSlave(QString,QString,QString)",
    00339             params, replyType, reply)) {
    00340         error_text = i18n("Can't talk to klauncher");
    00341         error = KIO::ERR_CANNOT_LAUNCH_PROCESS;
    00342         delete slave;
    00343         return 0;
    00344     }
    00345     QDataStream stream2(reply, IO_ReadOnly);
    00346     QString errorStr;
    00347     pid_t pid;
    00348     stream2 >> pid >> errorStr;
    00349     if (!pid)
    00350     {
    00351         error_text = i18n("Unable to create io-slave:\nklauncher said: %1").arg(errorStr);
    00352         error = KIO::ERR_CANNOT_LAUNCH_PROCESS;
    00353         delete slave;
    00354         return 0;
    00355     }
    00356     slave->setPID(pid);
    00357     QTimer::singleShot(1000*SLAVE_CONNECTION_TIMEOUT_MIN, slave, SLOT(timeout()));
    00358
    00359     return slave;
    00360 }
    00361
    00362 Slave* Slave::holdSlave( const QString &protocol, const KURL& url )
    00363 {
    00364     //kdDebug(7002) << "holdSlave '" << protocol << "' for " << url.prettyURL() << endl;
    00365
    00366     DCOPClient *client = kapp->dcopClient();
    00367     if (!client->isAttached())
    00368         client->attach();
    00369
    00370     QString prefix = locateLocal("socket", KGlobal::instance()->instanceName());
    00371     KTempFile socketfile(prefix, QString::fromLatin1(".slave-socket"));
    00372     if ( socketfile.status() != 0 )
    00373         return 0;
    00374
    00375     KServerSocket *kss = new KServerSocket(QFile::encodeName(socketfile.name()));
    00376
    00377     Slave *slave = new Slave(kss, protocol, socketfile.name());
    00378
    00379     QByteArray params, reply;
    00380     QCString replyType;
    00381     QDataStream stream(params, IO_WriteOnly);
    00382     stream << url << socketfile.name();
    00383
    00384     QCString launcher = KApplication::launcher();
    00385     if (!client->call(launcher, launcher, "requestHoldSlave(KURL,QString)",
    00386             params, replyType, reply)) {
    00387         delete slave;
    00388         return 0;
    00389     }
    00390     QDataStream stream2(reply, IO_ReadOnly);
    00391     pid_t pid;
    00392     stream2 >> pid;
    00393     if (!pid)
    00394     {
    00395         delete slave;
    00396         return 0;
    00397     }
    00398     slave->setPID(pid);
    00399     QTimer::singleShot(1000*SLAVE_CONNECTION_TIMEOUT_MIN, slave, SLOT(timeout()));
    00400
    00401     return slave;
    00402 }
    00403
    00404 void Slave::virtual_hook( int id, void* data )
    00405 { KIO::SlaveInterface::virtual_hook( id, data ); }
    00406
    00407 #include "slave.moc"

This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 13:14:38 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001