00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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
00066
00067
00068
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
00117 emit error(ERR_SLAVE_DIED, arg);
00118
00119 emit slaveDied(this);
00120
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
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
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
00230 emit error(ERR_SLAVE_DIED, arg);
00231
00232 emit slaveDied(this);
00233
00234 }
00235 deref();
00236 }
00237
00238 void Slave::kill()
00239 {
00240 dead = true;
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
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
00297
00298
00299
00300
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
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"