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/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
00067
00068
00069
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;
00084
00085
00086 SlavePrivate(
bool derived) : derived(derived) {}
00087 };
00088 }
00089
00090
void Slave::accept(
KSocket *socket)
00091 {
00092 slaveconn.init(socket);
00093
delete serv;
00094 serv = 0;
00095 slaveconn.connect(
this, SLOT(gotInput()));
00096 unlinkSocket();
00097 }
00098
00099
void Slave::unlinkSocket()
00100 {
00101
if (m_socket.isEmpty())
return;
00102
QCString filename =
QFile::encodeName(m_socket);
00103 unlink(filename.data());
00104 m_socket = QString::null;
00105 }
00106
00107
void Slave::timeout()
00108 {
00109
if (!serv)
return;
00110
kdDebug(7002) <<
"slave failed to connect to application pid=" << m_pid <<
" protocol=" << m_protocol <<
endl;
00111
if (m_pid && (::kill(m_pid, 0) == 0))
00112 {
00113
int delta_t = (
int) difftime(time(0), contact_started);
00114
kdDebug(7002) <<
"slave is slow... pid=" << m_pid <<
" t=" << delta_t <<
endl;
00115
if (delta_t < SLAVE_CONNECTION_TIMEOUT_MAX)
00116 {
00117
QTimer::singleShot(1000*SLAVE_CONNECTION_TIMEOUT_MIN,
this, SLOT(timeout()));
00118
return;
00119 }
00120 }
00121
kdDebug(7002) <<
"Houston, we lost our slave, pid=" << m_pid <<
endl;
00122
delete serv;
00123 serv = 0;
00124 unlinkSocket();
00125 dead =
true;
00126
QString arg = m_protocol;
00127
if (!m_host.isEmpty())
00128 arg +=
"://"+m_host;
00129
kdDebug(7002) <<
"slave died pid = " << m_pid <<
endl;
00130 ref();
00131
00132 emit error(ERR_SLAVE_DIED, arg);
00133
00134 emit slaveDied(
this);
00135
00136 deref();
00137 }
00138
00139 Slave::Slave(
KServerSocket *socket,
const QString &protocol,
const QString &socketname)
00140 :
SlaveInterface(&slaveconn), serv(socket), contacted(false),
00141 d(new SlavePrivate(false))
00142 {
00143 m_refCount = 1;
00144 m_protocol = protocol;
00145 m_slaveProtocol = protocol;
00146 m_socket = socketname;
00147 dead =
false;
00148 contact_started = time(0);
00149 idle_since = contact_started;
00150 m_pid = 0;
00151 m_port = 0;
00152
connect(serv, SIGNAL(accepted(
KSocket* )),
00153 SLOT(accept(
KSocket*) ) );
00154 }
00155
00156 Slave::Slave(
bool ,
KServerSocket *socket,
const QString &protocol,
00157
const QString &socketname)
00158 :
SlaveInterface(&slaveconn), serv(socket), contacted(false),
00159 d(new SlavePrivate(true))
00160 {
00161
00162 m_refCount = 1;
00163 m_protocol = protocol;
00164 m_slaveProtocol = protocol;
00165 m_socket = socketname;
00166 dead =
false;
00167 contact_started = time(0);
00168 idle_since = contact_started;
00169 m_pid = 0;
00170 m_port = 0;
00171
if (serv != 0) {
00172
connect(serv, SIGNAL(accepted(
KSocket* )),
00173 SLOT(accept(
KSocket*) ) );
00174 }
00175 }
00176
00177 Slave::~Slave()
00178 {
00179
00180
if (serv != 0) {
00181
delete serv;
00182 serv = 0;
00183 }
00184 unlinkSocket();
00185 m_pid = 99999;
00186
delete d;
00187 d = 0;
00188 }
00189
00190
void Slave::setProtocol(
const QString & protocol)
00191 {
00192 m_protocol = protocol;
00193 }
00194
00195
void Slave::setIdle()
00196 {
00197 idle_since = time(0);
00198 }
00199
00200 time_t Slave::idleTime()
00201 {
00202
return (time_t) difftime(time(0), idle_since);
00203 }
00204
00205
void Slave::setPID(pid_t pid)
00206 {
00207 m_pid = pid;
00208 }
00209
00210
void Slave::hold(
const KURL &url)
00211 {
00212
if (d->derived) {
00213 HoldParams params;
00214 params.url = &url;
00215
virtual_hook(VIRTUAL_HOLD, ¶ms);
00216
return;
00217 }
00218
00219 ref();
00220 {
00221
QByteArray data;
00222
QDataStream stream( data, IO_WriteOnly );
00223 stream << url;
00224 slaveconn.send( CMD_SLAVE_HOLD, data );
00225 slaveconn.close();
00226 dead =
true;
00227 emit slaveDied(
this);
00228 }
00229 deref();
00230
00231 {
00232
DCOPClient *client = kapp->dcopClient();
00233
if (!client->
isAttached())
00234 client->
attach();
00235
00236
QByteArray params, reply;
00237
QCString replyType;
00238
QDataStream stream(params, IO_WriteOnly);
00239 pid_t pid = m_pid;
00240 stream << pid;
00241
00242
QCString launcher =
KApplication::launcher();
00243 client->
call(launcher, launcher,
"waitForSlave(pid_t)",
00244 params, replyType, reply);
00245 }
00246 }
00247
00248
void Slave::suspend()
00249 {
00250
if (d->derived) {
00251
virtual_hook(VIRTUAL_SUSPEND, 0);
00252
return;
00253 }
00254
00255 slaveconn.suspend();
00256 }
00257
00258
void Slave::resume()
00259 {
00260
if (d->derived) {
00261
virtual_hook(VIRTUAL_RESUME, 0);
00262
return;
00263 }
00264
00265 slaveconn.resume();
00266 }
00267
00268
bool Slave::suspended()
00269 {
00270
if (d->derived) {
00271 SuspendedParams params;
00272
virtual_hook(VIRTUAL_SUSPENDED, ¶ms);
00273
return params.retval;
00274 }
00275
00276
return slaveconn.suspended();
00277 }
00278
00279
void Slave::send(
int cmd,
const QByteArray &arr) {
00280
if (d->derived) {
00281 SendParams params;
00282 params.cmd = cmd;
00283 params.arr = &arr;
00284
virtual_hook(VIRTUAL_SEND, ¶ms);
00285
return;
00286 }
00287
00288 slaveconn.send(cmd, arr);
00289 }
00290
00291
void Slave::gotInput()
00292 {
00293 ref();
00294
if (!dispatch())
00295 {
00296 slaveconn.close();
00297 dead =
true;
00298
QString arg = m_protocol;
00299
if (!m_host.isEmpty())
00300 arg +=
"://"+m_host;
00301
kdDebug(7002) <<
"slave died pid = " << m_pid <<
endl;
00302
00303 emit error(ERR_SLAVE_DIED, arg);
00304
00305 emit slaveDied(
this);
00306
00307 }
00308 deref();
00309 }
00310
00311
void Slave::kill()
00312 {
00313 dead =
true;
00314
kdDebug(7002) <<
"killing slave pid=" << m_pid <<
" (" << m_protocol <<
"://"
00315 << m_host <<
")" <<
endl;
00316
if (m_pid)
00317 {
00318 ::kill(m_pid, SIGTERM);
00319 }
00320 }
00321
00322
void Slave::setHost(
const QString &host,
int port,
00323
const QString &user,
const QString &passwd)
00324 {
00325 m_host = host;
00326 m_port = port;
00327 m_user = user;
00328 m_passwd = passwd;
00329
00330
QByteArray data;
00331
QDataStream stream( data, IO_WriteOnly );
00332 stream << m_host << m_port << m_user << m_passwd;
00333 slaveconn.send( CMD_HOST, data );
00334 }
00335
00336
void Slave::resetHost()
00337 {
00338 m_host =
"<reset>";
00339 }
00340
00341
void Slave::setConfig(
const MetaData &config)
00342 {
00343
QByteArray data;
00344
QDataStream stream( data, IO_WriteOnly );
00345 stream << config;
00346 slaveconn.send( CMD_CONFIG, data );
00347 }
00348
00349 Slave* Slave::createSlave(
const QString &protocol,
const KURL& url,
int& error,
QString& error_text )
00350 {
00351
00352
00353
if (protocol ==
"data")
00354
return new DataProtocol();
00355
00356
DCOPClient *client = kapp->dcopClient();
00357
if (!client->
isAttached())
00358 client->
attach();
00359
00360
QString prefix =
locateLocal(
"socket", KGlobal::instance()->instanceName());
00361
KTempFile socketfile(prefix, QString::fromLatin1(
".slave-socket"));
00362
if ( socketfile.status() != 0 )
00363 {
00364 error_text = i18n(
"Unable to create io-slave: %1").
arg(strerror(errno));
00365 error = KIO::ERR_CANNOT_LAUNCH_PROCESS;
00366
return 0;
00367 }
00368
KServerSocket *kss =
new KServerSocket(QFile::encodeName(socketfile.name()));
00369
00370 Slave *slave =
new Slave(kss, protocol, socketfile.name());
00371
00372
00373
00374
00375
00376
00377
00378
00379
static bool bForkSlaves = !
QCString(getenv(
"KDE_FORK_SLAVES")).isEmpty();
00380
00381
if (bForkSlaves || !client->
isAttached() || client->
isAttachedToForeignServer())
00382 {
00383
QString _name =
KProtocolInfo::exec(protocol);
00384
if (_name.
isEmpty())
00385 {
00386 error_text = i18n(
"Unknown protocol '%1'.\n").
arg(protocol);
00387 error = KIO::ERR_CANNOT_LAUNCH_PROCESS;
00388
delete slave;
00389
return 0;
00390 }
00391
QString lib_path =
KLibLoader::findLibrary(_name.
latin1());
00392
if (lib_path.
isEmpty())
00393 {
00394 error_text = i18n(
"Can not find io-slave for protocol '%1'.").
arg(protocol);
00395 error = KIO::ERR_CANNOT_LAUNCH_PROCESS;
00396
return 0;
00397 }
00398
00399
KProcess proc;
00400
00401 proc <<
locate(
"exe",
"kioslave") << lib_path << protocol <<
"" << socketfile.name();
00402
kdDebug(7002) <<
"kioslave" <<
", " << lib_path <<
", " << protocol <<
", " << QString::null <<
", " << socketfile.name() <<
endl;
00403
00404 proc.
start(KProcess::DontCare);
00405
00406 slave->setPID(proc.
pid());
00407
QTimer::singleShot(1000*SLAVE_CONNECTION_TIMEOUT_MIN, slave, SLOT(timeout()));
00408
return slave;
00409 }
00410
00411
00412
QByteArray params, reply;
00413
QCString replyType;
00414
QDataStream stream(params, IO_WriteOnly);
00415 stream << protocol << url.
host() << socketfile.name();
00416
00417
QCString launcher =
KApplication::launcher();
00418
if (!client->
call(launcher, launcher,
"requestSlave(QString,QString,QString)",
00419 params, replyType, reply)) {
00420 error_text = i18n(
"Can't talk to klauncher");
00421 error = KIO::ERR_CANNOT_LAUNCH_PROCESS;
00422
delete slave;
00423
return 0;
00424 }
00425
QDataStream stream2(reply, IO_ReadOnly);
00426
QString errorStr;
00427 pid_t pid;
00428 stream2 >> pid >> errorStr;
00429
if (!pid)
00430 {
00431 error_text = i18n(
"Unable to create io-slave:\nklauncher said: %1").
arg(errorStr);
00432 error = KIO::ERR_CANNOT_LAUNCH_PROCESS;
00433
delete slave;
00434
return 0;
00435 }
00436 slave->setPID(pid);
00437
QTimer::singleShot(1000*SLAVE_CONNECTION_TIMEOUT_MIN, slave, SLOT(timeout()));
00438
00439
return slave;
00440 }
00441
00442 Slave* Slave::holdSlave(
const QString &protocol,
const KURL& url )
00443 {
00444
00445
00446
if (protocol ==
"data")
00447
return new DataProtocol();
00448
00449
DCOPClient *client = kapp->dcopClient();
00450
if (!client->
isAttached())
00451 client->
attach();
00452
00453
QString prefix =
locateLocal(
"socket", KGlobal::instance()->instanceName());
00454
KTempFile socketfile(prefix, QString::fromLatin1(
".slave-socket"));
00455
if ( socketfile.status() != 0 )
00456
return 0;
00457
00458
KServerSocket *kss =
new KServerSocket(QFile::encodeName(socketfile.name()));
00459
00460 Slave *slave =
new Slave(kss, protocol, socketfile.name());
00461
00462
QByteArray params, reply;
00463
QCString replyType;
00464
QDataStream stream(params, IO_WriteOnly);
00465 stream << url << socketfile.name();
00466
00467
QCString launcher =
KApplication::launcher();
00468
if (!client->
call(launcher, launcher,
"requestHoldSlave(KURL,QString)",
00469 params, replyType, reply)) {
00470
delete slave;
00471
return 0;
00472 }
00473
QDataStream stream2(reply, IO_ReadOnly);
00474 pid_t pid;
00475 stream2 >> pid;
00476
if (!pid)
00477 {
00478
delete slave;
00479
return 0;
00480 }
00481 slave->setPID(pid);
00482
QTimer::singleShot(1000*SLAVE_CONNECTION_TIMEOUT_MIN, slave, SLOT(timeout()));
00483
00484
return slave;
00485 }
00486
00487
void Slave::virtual_hook(
int id,
void* data ) {
00488 KIO::SlaveInterface::virtual_hook(
id, data );
00489 }
00490
00491
#include "slave.moc"