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
#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
00134 emit error(ERR_SLAVE_DIED, arg);
00135
00136 emit slaveDied(
this);
00137
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 , KServerSocket *socket,
const QString &protocol,
00161
const QString &socketname)
00162 :
SlaveInterface(&slaveconn), serv(socket), contacted(false),
00163 d(new SlavePrivate(true))
00164 {
00165
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
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) {
00219 HoldParams params;
00220 params.url = &url;
00221 virtual_hook(VIRTUAL_HOLD, ¶ms);
00222
return;
00223 }
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
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) {
00257 virtual_hook(VIRTUAL_SUSPEND, 0);
00258
return;
00259 }
00260
00261 slaveconn.suspend();
00262 }
00263
00264
void Slave::resume()
00265 {
00266
if (d->derived) {
00267 virtual_hook(VIRTUAL_RESUME, 0);
00268
return;
00269 }
00270
00271 slaveconn.resume();
00272 }
00273
00274
bool Slave::suspended()
00275 {
00276
if (d->derived) {
00277 SuspendedParams params;
00278 virtual_hook(VIRTUAL_SUSPENDED, ¶ms);
00279
return params.retval;
00280 }
00281
00282
return slaveconn.suspended();
00283 }
00284
00285
void Slave::send(
int cmd,
const QByteArray &arr) {
00286
if (d->derived) {
00287 SendParams params;
00288 params.cmd = cmd;
00289 params.arr = &arr;
00290 virtual_hook(VIRTUAL_SEND, ¶ms);
00291
return;
00292 }
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
00309 emit error(ERR_SLAVE_DIED, arg);
00310
00311 emit slaveDied(
this);
00312
00313 }
00314 deref();
00315 }
00316
00317
void Slave::kill()
00318 {
00319 dead =
true;
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
00358
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
#ifndef Q_WS_WIN
00375
KServerSocket *kss =
new KServerSocket(QFile::encodeName(socketfile.
name()));
00376
00377 Slave *slave =
new Slave(kss, protocol, socketfile.
name());
00378
#else
00379
Slave *slave = 0;
00380
#endif
00381
00382
00383
00384
00385
00386
00387
00388
00389
static bool bForkSlaves = !
QCString(getenv(
"KDE_FORK_SLAVES")).isEmpty();
00390
00391
if (bForkSlaves || !client->
isAttached() || client->
isAttachedToForeignServer())
00392 {
00393
QString _name =
KProtocolInfo::exec(protocol);
00394
if (_name.isEmpty())
00395 {
00396 error_text = i18n(
"Unknown protocol '%1'.").arg(protocol);
00397 error = KIO::ERR_CANNOT_LAUNCH_PROCESS;
00398
delete slave;
00399
return 0;
00400 }
00401
QString lib_path =
KLibLoader::findLibrary(_name.latin1());
00402
if (lib_path.isEmpty())
00403 {
00404 error_text = i18n(
"Can not find io-slave for protocol '%1'.").arg(protocol);
00405 error = KIO::ERR_CANNOT_LAUNCH_PROCESS;
00406
return 0;
00407 }
00408
00409
KProcess proc;
00410
00411 proc <<
locate(
"exe",
"kioslave") << lib_path << protocol <<
"" << socketfile.
name();
00412
kdDebug(7002) <<
"kioslave" <<
", " << lib_path <<
", " << protocol <<
", " << QString::null <<
", " << socketfile.
name() <<
endl;
00413
00414 proc.
start(KProcess::DontCare);
00415
00416
#ifndef Q_WS_WIN
00417
slave->setPID(proc.
pid());
00418 QTimer::singleShot(1000*SLAVE_CONNECTION_TIMEOUT_MIN, slave, SLOT(timeout()));
00419
#endif
00420
return slave;
00421 }
00422
00423
00424
QByteArray params, reply;
00425
QCString replyType;
00426
QDataStream stream(params, IO_WriteOnly);
00427 stream << protocol << url.
host() << socketfile.
name();
00428
00429
QCString launcher =
KApplication::launcher();
00430
if (!client->
call(launcher, launcher,
"requestSlave(QString,QString,QString)",
00431 params, replyType, reply)) {
00432 error_text = i18n(
"Cannot talk to klauncher");
00433 error = KIO::ERR_CANNOT_LAUNCH_PROCESS;
00434
delete slave;
00435
return 0;
00436 }
00437
QDataStream stream2(reply, IO_ReadOnly);
00438
QString errorStr;
00439 pid_t pid;
00440 stream2 >> pid >> errorStr;
00441
if (!pid)
00442 {
00443 error_text = i18n(
"Unable to create io-slave:\nklauncher said: %1").arg(errorStr);
00444 error = KIO::ERR_CANNOT_LAUNCH_PROCESS;
00445
delete slave;
00446
return 0;
00447 }
00448
#ifndef Q_WS_WIN
00449
slave->setPID(pid);
00450 QTimer::singleShot(1000*SLAVE_CONNECTION_TIMEOUT_MIN, slave, SLOT(timeout()));
00451
#endif
00452
return slave;
00453 }
00454
00455 Slave* Slave::holdSlave(
const QString &protocol,
const KURL& url )
00456 {
00457
00458
00459
if (protocol ==
"data")
00460
return 0;
00461
00462
DCOPClient *client = kapp->dcopClient();
00463
if (!client->
isAttached())
00464 client->
attach();
00465
00466
QString prefix =
locateLocal(
"socket", KGlobal::instance()->instanceName());
00467
KTempFile socketfile(prefix, QString::fromLatin1(
".slave-socket"));
00468
if ( socketfile.
status() != 0 )
00469
return 0;
00470
00471
#ifndef Q_WS_WIN
00472
KServerSocket *kss =
new KServerSocket(QFile::encodeName(socketfile.
name()));
00473
00474 Slave *slave =
new Slave(kss, protocol, socketfile.
name());
00475
#else
00476
Slave *slave = 0;
00477
#endif
00478
00479
QByteArray params, reply;
00480
QCString replyType;
00481
QDataStream stream(params, IO_WriteOnly);
00482 stream << url << socketfile.
name();
00483
00484
QCString launcher =
KApplication::launcher();
00485
if (!client->
call(launcher, launcher,
"requestHoldSlave(KURL,QString)",
00486 params, replyType, reply)) {
00487
delete slave;
00488
return 0;
00489 }
00490
QDataStream stream2(reply, IO_ReadOnly);
00491 pid_t pid;
00492 stream2 >> pid;
00493
if (!pid)
00494 {
00495
delete slave;
00496
return 0;
00497 }
00498
#ifndef Q_WS_WIN
00499
slave->setPID(pid);
00500 QTimer::singleShot(1000*SLAVE_CONNECTION_TIMEOUT_MIN, slave, SLOT(timeout()));
00501
#endif
00502
return slave;
00503 }
00504
00505
void Slave::virtual_hook(
int id,
void* data ) {
00506 KIO::SlaveInterface::virtual_hook(
id, data );
00507 }
00508
00509
#include "slave.moc"