kio Library API Documentation

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.63 2004/09/08 12:39:04 tilladam 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/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 // After the above signal we're dead!! 00313 } 00314 deref(); 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 #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 // WABA: if the dcopserver is running under another uid we don't ask 00383 // klauncher for a slave, because the slave might have that other uid 00384 // as well, which might either be a) undesired or b) make it impossible 00385 // for the slave to connect to the application. 00386 // In such case we start the slave via KProcess. 00387 // It's possible to force this by setting the env. variable 00388 // KDE_FORK_SLAVES, Clearcase seems to require this. 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 //kdDebug(7002) << "holdSlave '" << protocol << "' for " << url.prettyURL() << endl; 00458 // Firstly take into account all special slaves 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"
KDE Logo
This file is part of the documentation for kio Library Version 3.4.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Apr 12 23:09:32 2005 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003