kio Library API Documentation

slavebase.cpp

00001 /* 00002 * 00003 * This file is part of the KDE libraries 00004 * Copyright (c) 2000 Waldo Bastian <bastian@kde.org> 00005 * Copyright (c) 2000 David Faure <faure@kde.org> 00006 * Copyright (c) 2000 Stephan Kulow <coolo@kde.org> 00007 * 00008 * $Id: slavebase.cpp,v 1.159 2004/06/27 10:43:57 binner Exp $ 00009 * 00010 * This library is free software; you can redistribute it and/or 00011 * modify it under the terms of the GNU Library General Public 00012 * License version 2 as published by the Free Software Foundation. 00013 * 00014 * This library is distributed in the hope that it will be useful, 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00017 * Library General Public License for more details. 00018 * 00019 * You should have received a copy of the GNU Library General Public License 00020 * along with this library; see the file COPYING.LIB. If not, write to 00021 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00022 * Boston, MA 02111-1307, USA. 00023 * 00024 **/ 00025 00026 #include <config.h> 00027 00028 #include <sys/time.h> 00029 #ifdef HAVE_SYS_SELECT_H 00030 #include <sys/select.h> // Needed on some systems. 00031 #endif 00032 00033 #include <assert.h> 00034 #include <kdebug.h> 00035 #include <stdlib.h> 00036 #include <errno.h> 00037 #include <unistd.h> 00038 #include <signal.h> 00039 #include <time.h> 00040 00041 #include <qfile.h> 00042 00043 #include <dcopclient.h> 00044 00045 #include <kapplication.h> 00046 #include <ksock.h> 00047 #include <kcrash.h> 00048 #include <kdesu/client.h> 00049 #include <klocale.h> 00050 00051 #include <ksocks.h> 00052 00053 #include "slavebase.h" 00054 #include "kremoteencoding.h" 00055 00056 #include "kio/slavebase.h" 00057 #include "kio/connection.h" 00058 #include "kio/ioslave_defaults.h" 00059 #include "kio/slaveinterface.h" 00060 00061 #ifndef NDEBUG 00062 #ifdef HAVE_BACKTRACE 00063 #include <execinfo.h> 00064 #endif 00065 #endif 00066 00067 using namespace KIO; 00068 00069 template class QPtrList<QValueList<UDSAtom> >; 00070 typedef QValueList<QCString> AuthKeysList; 00071 typedef QMap<QString,QCString> AuthKeysMap; 00072 #define KIO_DATA QByteArray data; QDataStream stream( data, IO_WriteOnly ); stream 00073 #define KIO_FILESIZE_T(x) (unsigned long)(x & 0xffffffff) << (unsigned long)(x >> 32) 00074 00075 namespace KIO { 00076 00077 class SlaveBaseConfig : public KConfigBase 00078 { 00079 public: 00080 SlaveBaseConfig(SlaveBase *_slave) 00081 : slave(_slave) { } 00082 00083 bool internalHasGroup(const QCString &) const { qWarning("hasGroup(const QCString &)"); 00084 return false; } 00085 00086 QStringList groupList() const { return QStringList(); } 00087 00088 QMap<QString,QString> entryMap(const QString &) const 00089 { return QMap<QString,QString>(); } 00090 00091 void reparseConfiguration() { } 00092 00093 KEntryMap internalEntryMap( const QString &) const { return KEntryMap(); } 00094 00095 KEntryMap internalEntryMap() const { return KEntryMap(); } 00096 00097 void putData(const KEntryKey &, const KEntry&, bool) { } 00098 00099 KEntry lookupData(const KEntryKey &key) const 00100 { 00101 KEntry entry; 00102 QString value = slave->metaData(key.c_key); 00103 if (!value.isNull()) 00104 entry.mValue = value.utf8(); 00105 return entry; 00106 } 00107 protected: 00108 SlaveBase *slave; 00109 }; 00110 00111 00112 class SlaveBasePrivate { 00113 public: 00114 QString slaveid; 00115 bool resume:1; 00116 bool needSendCanResume:1; 00117 bool onHold:1; 00118 bool wasKilled:1; 00119 MetaData configData; 00120 SlaveBaseConfig *config; 00121 KURL onHoldUrl; 00122 00123 struct timeval last_tv; 00124 KIO::filesize_t totalSize; 00125 KIO::filesize_t sentListEntries; 00126 DCOPClient *dcopClient; 00127 KRemoteEncoding *remotefile; 00128 time_t timeout; 00129 QByteArray timeoutData; 00130 }; 00131 00132 } 00133 00134 static SlaveBase *globalSlave; 00135 long SlaveBase::s_seqNr; 00136 00137 static volatile bool slaveWriteError = false; 00138 00139 static const char *s_protocol; 00140 00141 static void genericsig_handler(int sigNumber) 00142 { 00143 signal(sigNumber,SIG_IGN); 00144 //WABA: Don't do anything that requires malloc, we can deadlock on it since 00145 //a SIGTERM signal can come in while we are in malloc/free. 00146 //kdDebug()<<"kioslave : exiting due to signal "<<sigNumber<<endl; 00147 //set the flag which will be checked in dispatchLoop() and which *should* be checked 00148 //in lengthy operations in the various slaves 00149 if (globalSlave!=0) 00150 globalSlave->setKillFlag(); 00151 signal(SIGALRM,SIG_DFL); 00152 alarm(5); //generate an alarm signal in 5 seconds, in this time the slave has to exit 00153 } 00154 00156 00157 SlaveBase::SlaveBase( const QCString &protocol, 00158 const QCString &pool_socket, 00159 const QCString &app_socket ) 00160 : mProtocol(protocol), m_pConnection(0), 00161 mPoolSocket( QFile::decodeName(pool_socket)), 00162 mAppSocket( QFile::decodeName(app_socket)) 00163 { 00164 s_protocol = protocol.data(); 00165 if (!getenv("KDE_DEBUG")) 00166 { 00167 KCrash::setCrashHandler( sigsegv_handler ); 00168 signal(SIGILL,&sigsegv_handler); 00169 signal(SIGTRAP,&sigsegv_handler); 00170 signal(SIGABRT,&sigsegv_handler); 00171 signal(SIGBUS,&sigsegv_handler); 00172 signal(SIGALRM,&sigsegv_handler); 00173 signal(SIGFPE,&sigsegv_handler); 00174 #ifdef SIGPOLL 00175 signal(SIGPOLL, &sigsegv_handler); 00176 #endif 00177 #ifdef SIGSYS 00178 signal(SIGSYS, &sigsegv_handler); 00179 #endif 00180 #ifdef SIGVTALRM 00181 signal(SIGVTALRM, &sigsegv_handler); 00182 #endif 00183 #ifdef SIGXCPU 00184 signal(SIGXCPU, &sigsegv_handler); 00185 #endif 00186 #ifdef SIGXFSZ 00187 signal(SIGXFSZ, &sigsegv_handler); 00188 #endif 00189 } 00190 00191 struct sigaction act; 00192 act.sa_handler = sigpipe_handler; 00193 sigemptyset( &act.sa_mask ); 00194 act.sa_flags = 0; 00195 sigaction( SIGPIPE, &act, 0 ); 00196 00197 signal(SIGINT,&genericsig_handler); 00198 signal(SIGQUIT,&genericsig_handler); 00199 signal(SIGTERM,&genericsig_handler); 00200 00201 globalSlave=this; 00202 00203 appconn = new Connection(); 00204 listEntryCurrentSize = 100; 00205 struct timeval tp; 00206 gettimeofday(&tp, 0); 00207 listEntry_sec = tp.tv_sec; 00208 listEntry_usec = tp.tv_usec; 00209 mConnectedToApp = true; 00210 00211 d = new SlaveBasePrivate; 00212 // by kahl for netmgr (need a way to identify slaves) 00213 d->slaveid = protocol; 00214 d->slaveid += QString::number(getpid()); 00215 d->resume = false; 00216 d->needSendCanResume = false; 00217 d->config = new SlaveBaseConfig(this); 00218 d->onHold = false; 00219 d->wasKilled=false; 00220 d->last_tv.tv_sec = 0; 00221 d->last_tv.tv_usec = 0; 00222 // d->processed_size = 0; 00223 d->totalSize=0; 00224 d->sentListEntries=0; 00225 d->timeout = 0; 00226 connectSlave(mAppSocket); 00227 00228 d->dcopClient = 0; 00229 d->remotefile = 0; 00230 } 00231 00232 SlaveBase::~SlaveBase() 00233 { 00234 delete d; 00235 s_protocol = ""; 00236 } 00237 00238 DCOPClient *SlaveBase::dcopClient() 00239 { 00240 if (!d->dcopClient) 00241 { 00242 d->dcopClient = new DCOPClient(); 00243 d->dcopClient->attach(); 00244 } 00245 return d->dcopClient; 00246 } 00247 00248 void SlaveBase::dispatchLoop() 00249 { 00250 fd_set rfds; 00251 int retval; 00252 00253 while (true) 00254 { 00255 if (d->timeout && (d->timeout < time(0))) 00256 { 00257 QByteArray data = d->timeoutData; 00258 d->timeout = 0; 00259 d->timeoutData = QByteArray(); 00260 special(data); 00261 } 00262 FD_ZERO(&rfds); 00263 00264 assert(appconn->inited()); 00265 FD_SET(appconn->fd_from(), &rfds); 00266 00267 if (!d->timeout) // we can wait forever 00268 { 00269 retval = select(appconn->fd_from()+ 1, &rfds, NULL, NULL, NULL); 00270 } 00271 else 00272 { 00273 struct timeval tv; 00274 tv.tv_sec = kMax(d->timeout-time(0),(time_t) 1); 00275 tv.tv_usec = 0; 00276 retval = select(appconn->fd_from()+ 1, &rfds, NULL, NULL, &tv); 00277 } 00278 if ((retval>0) && FD_ISSET(appconn->fd_from(), &rfds)) 00279 { // dispatch application messages 00280 int cmd; 00281 QByteArray data; 00282 if ( appconn->read(&cmd, data) != -1 ) 00283 { 00284 dispatch(cmd, data); 00285 } 00286 else // some error occurred, perhaps no more application 00287 { 00288 // When the app exits, should the slave be put back in the pool ? 00289 if (mConnectedToApp && !mPoolSocket.isEmpty()) 00290 { 00291 disconnectSlave(); 00292 mConnectedToApp = false; 00293 closeConnection(); 00294 connectSlave(mPoolSocket); 00295 } 00296 else 00297 { 00298 return; 00299 } 00300 } 00301 } 00302 else if ((retval<0) && (errno != EINTR)) 00303 { 00304 kdDebug(7019) << "dispatchLoop(): select returned " << retval << " " 00305 << (errno==EBADF?"EBADF":errno==EINTR?"EINTR":errno==EINVAL?"EINVAL":errno==ENOMEM?"ENOMEM":"unknown") 00306 << " (" << errno << ")" << endl; 00307 return; 00308 } 00309 //I think we get here when we were killed in dispatch() and not in select() 00310 if (wasKilled()) 00311 { 00312 kdDebug(7019)<<" dispatchLoop() slave was killed, returning"<<endl; 00313 return; 00314 } 00315 } 00316 } 00317 00318 void SlaveBase::connectSlave(const QString& path) 00319 { 00320 appconn->init(new KSocket(QFile::encodeName(path))); 00321 if (!appconn->inited()) 00322 { 00323 kdDebug(7019) << "SlaveBase: failed to connect to " << path << endl; 00324 exit(); 00325 } 00326 00327 setConnection(appconn); 00328 } 00329 00330 void SlaveBase::disconnectSlave() 00331 { 00332 appconn->close(); 00333 } 00334 00335 void SlaveBase::setMetaData(const QString &key, const QString &value) 00336 { 00337 mOutgoingMetaData.replace(key, value); 00338 } 00339 00340 QString SlaveBase::metaData(const QString &key) const 00341 { 00342 if (mIncomingMetaData.contains(key)) 00343 return mIncomingMetaData[key]; 00344 if (d->configData.contains(key)) 00345 return d->configData[key]; 00346 return QString::null; 00347 } 00348 00349 bool SlaveBase::hasMetaData(const QString &key) const 00350 { 00351 if (mIncomingMetaData.contains(key)) 00352 return true; 00353 if (d->configData.contains(key)) 00354 return true; 00355 return false; 00356 } 00357 00358 // ### remove the next two methods for KDE4 (they miss the const) 00359 QString SlaveBase::metaData(const QString &key) { 00360 return const_cast<const SlaveBase*>(this)->metaData( key ); 00361 } 00362 bool SlaveBase::hasMetaData(const QString &key) { 00363 return const_cast<const SlaveBase*>(this)->hasMetaData( key ); 00364 } 00365 00366 KConfigBase *SlaveBase::config() 00367 { 00368 return d->config; 00369 } 00370 00371 void SlaveBase::sendMetaData() 00372 { 00373 KIO_DATA << mOutgoingMetaData; 00374 00375 slaveWriteError = false; 00376 m_pConnection->send( INF_META_DATA, data ); 00377 if (slaveWriteError) exit(); 00378 mOutgoingMetaData.clear(); // Clear 00379 } 00380 00381 KRemoteEncoding *SlaveBase::remoteEncoding() 00382 { 00383 if (d->remotefile != 0) 00384 return d->remotefile; 00385 00386 return d->remotefile = new KRemoteEncoding(metaData("Charset").latin1()); 00387 } 00388 00389 void SlaveBase::data( const QByteArray &data ) 00390 { 00391 if (!mOutgoingMetaData.isEmpty()) 00392 sendMetaData(); 00393 slaveWriteError = false; 00394 m_pConnection->send( MSG_DATA, data ); 00395 if (slaveWriteError) exit(); 00396 } 00397 00398 void SlaveBase::dataReq( ) 00399 { 00400 /* 00401 if (!mOutgoingMetaData.isEmpty()) 00402 sendMetaData(); 00403 */ 00404 if (d->needSendCanResume) 00405 canResume(0); 00406 m_pConnection->send( MSG_DATA_REQ ); 00407 } 00408 00409 void SlaveBase::error( int _errid, const QString &_text ) 00410 { 00411 mIncomingMetaData.clear(); // Clear meta data 00412 mOutgoingMetaData.clear(); 00413 KIO_DATA << _errid << _text; 00414 00415 m_pConnection->send( MSG_ERROR, data ); 00416 //reset 00417 listEntryCurrentSize = 100; 00418 d->sentListEntries=0; 00419 d->totalSize=0; 00420 } 00421 00422 void SlaveBase::connected() 00423 { 00424 slaveWriteError = false; 00425 m_pConnection->send( MSG_CONNECTED ); 00426 if (slaveWriteError) exit(); 00427 } 00428 00429 void SlaveBase::finished() 00430 { 00431 mIncomingMetaData.clear(); // Clear meta data 00432 if (!mOutgoingMetaData.isEmpty()) 00433 sendMetaData(); 00434 m_pConnection->send( MSG_FINISHED ); 00435 00436 // reset 00437 listEntryCurrentSize = 100; 00438 d->sentListEntries=0; 00439 d->totalSize=0; 00440 } 00441 00442 void SlaveBase::needSubURLData() 00443 { 00444 m_pConnection->send( MSG_NEED_SUBURL_DATA ); 00445 } 00446 00447 void SlaveBase::slaveStatus( const QString &host, bool connected ) 00448 { 00449 pid_t pid = getpid(); 00450 Q_INT8 b = connected ? 1 : 0; 00451 KIO_DATA << pid << mProtocol << host << b; 00452 if (d->onHold) 00453 stream << d->onHoldUrl; 00454 m_pConnection->send( MSG_SLAVE_STATUS, data ); 00455 } 00456 00457 void SlaveBase::canResume() 00458 { 00459 m_pConnection->send( MSG_CANRESUME ); 00460 } 00461 00462 void SlaveBase::totalSize( KIO::filesize_t _bytes ) 00463 { 00464 KIO_DATA << KIO_FILESIZE_T(_bytes); 00465 slaveWriteError = false; 00466 m_pConnection->send( INF_TOTAL_SIZE, data ); 00467 if (slaveWriteError) exit(); 00468 00469 //this one is usually called before the first item is listed in listDir() 00470 struct timeval tp; 00471 gettimeofday(&tp, 0); 00472 listEntry_sec = tp.tv_sec; 00473 listEntry_usec = tp.tv_usec; 00474 d->totalSize=_bytes; 00475 d->sentListEntries=0; 00476 } 00477 00478 void SlaveBase::processedSize( KIO::filesize_t _bytes ) 00479 { 00480 struct timeval tv; 00481 if ( gettimeofday( &tv, 0L ) == 0 ) { 00482 time_t msecdiff = 2000; 00483 if (d->last_tv.tv_sec) { 00484 // Compute difference, in ms 00485 msecdiff = 1000 * ( tv.tv_sec - d->last_tv.tv_sec ); 00486 time_t usecdiff = tv.tv_usec - d->last_tv.tv_usec; 00487 if ( usecdiff < 0 ) { 00488 msecdiff--; 00489 msecdiff += 1000; 00490 } 00491 msecdiff += usecdiff / 1000; 00492 } 00493 if ( msecdiff >= 100 ) { // emit size 10 times a second 00494 KIO_DATA << KIO_FILESIZE_T(_bytes); 00495 slaveWriteError = false; 00496 m_pConnection->send( INF_PROCESSED_SIZE, data ); 00497 if (slaveWriteError) exit(); 00498 d->last_tv.tv_sec = tv.tv_sec; 00499 d->last_tv.tv_usec = tv.tv_usec; 00500 } 00501 } 00502 // d->processed_size = _bytes; 00503 } 00504 00505 void SlaveBase::processedPercent( float /* percent */ ) 00506 { 00507 kdDebug(7019) << "SlaveBase::processedPercent: STUB" << endl; 00508 } 00509 00510 00511 void SlaveBase::speed( unsigned long _bytes_per_second ) 00512 { 00513 KIO_DATA << _bytes_per_second; 00514 slaveWriteError = false; 00515 m_pConnection->send( INF_SPEED, data ); 00516 if (slaveWriteError) exit(); 00517 } 00518 00519 void SlaveBase::redirection( const KURL& _url ) 00520 { 00521 KIO_DATA << _url; 00522 m_pConnection->send( INF_REDIRECTION, data ); 00523 } 00524 00525 void SlaveBase::errorPage() 00526 { 00527 m_pConnection->send( INF_ERROR_PAGE ); 00528 } 00529 00530 static bool isSubCommand(int cmd) 00531 { 00532 return ( (cmd == CMD_REPARSECONFIGURATION) || 00533 (cmd == CMD_META_DATA) || 00534 (cmd == CMD_CONFIG) || 00535 (cmd == CMD_SUBURL) || 00536 (cmd == CMD_SLAVE_STATUS) || 00537 (cmd == CMD_SLAVE_CONNECT) || 00538 (cmd == CMD_SLAVE_HOLD) || 00539 (cmd == CMD_MULTI_GET)); 00540 } 00541 00542 void SlaveBase::mimeType( const QString &_type) 00543 { 00544 // kdDebug(7019) << "(" << getpid() << ") SlaveBase::mimeType '" << _type << "'" << endl; 00545 int cmd; 00546 do 00547 { 00548 // Send the meta-data each time we send the mime-type. 00549 if (!mOutgoingMetaData.isEmpty()) 00550 { 00551 // kdDebug(7019) << "(" << getpid() << ") mimeType: emitting meta data" << endl; 00552 KIO_DATA << mOutgoingMetaData; 00553 m_pConnection->send( INF_META_DATA, data ); 00554 } 00555 KIO_DATA << _type; 00556 m_pConnection->send( INF_MIME_TYPE, data ); 00557 while(true) 00558 { 00559 cmd = 0; 00560 if ( m_pConnection->read( &cmd, data ) == -1 ) { 00561 kdDebug(7019) << "SlaveBase: mimetype: read error" << endl; 00562 exit(); 00563 } 00564 // kdDebug(7019) << "(" << getpid() << ") Slavebase: mimetype got " << cmd << endl; 00565 if ( cmd == CMD_HOST) // Ignore. 00566 continue; 00567 if ( isSubCommand(cmd) ) 00568 { 00569 dispatch( cmd, data ); 00570 continue; // Disguised goto 00571 } 00572 break; 00573 } 00574 } 00575 while (cmd != CMD_NONE); 00576 mOutgoingMetaData.clear(); 00577 } 00578 00579 void SlaveBase::exit() 00580 { 00581 this->~SlaveBase(); 00582 ::exit(255); 00583 } 00584 00585 void SlaveBase::warning( const QString &_msg) 00586 { 00587 KIO_DATA << _msg; 00588 m_pConnection->send( INF_WARNING, data ); 00589 } 00590 00591 void SlaveBase::infoMessage( const QString &_msg) 00592 { 00593 KIO_DATA << _msg; 00594 m_pConnection->send( INF_INFOMESSAGE, data ); 00595 } 00596 00597 bool SlaveBase::requestNetwork(const QString& host) 00598 { 00599 KIO_DATA << host << d->slaveid; 00600 m_pConnection->send( MSG_NET_REQUEST, data ); 00601 00602 if ( waitForAnswer( INF_NETWORK_STATUS, 0, data ) != -1 ) 00603 { 00604 bool status; 00605 QDataStream stream( data, IO_ReadOnly ); 00606 stream >> status; 00607 return status; 00608 } else 00609 return false; 00610 } 00611 00612 void SlaveBase::dropNetwork(const QString& host) 00613 { 00614 KIO_DATA << host << d->slaveid; 00615 m_pConnection->send( MSG_NET_DROP, data ); 00616 } 00617 00618 void SlaveBase::statEntry( const UDSEntry& entry ) 00619 { 00620 KIO_DATA << entry; 00621 slaveWriteError = false; 00622 m_pConnection->send( MSG_STAT_ENTRY, data ); 00623 if (slaveWriteError) exit(); 00624 } 00625 00626 void SlaveBase::listEntry( const UDSEntry& entry, bool _ready ) 00627 { 00628 static struct timeval tp; 00629 static const int maximum_updatetime = 300; 00630 static const int minimum_updatetime = 100; 00631 00632 if (!_ready) { 00633 pendingListEntries.append(entry); 00634 00635 if (pendingListEntries.count() > listEntryCurrentSize) { 00636 gettimeofday(&tp, 0); 00637 00638 long diff = ((tp.tv_sec - listEntry_sec) * 1000000 + 00639 tp.tv_usec - listEntry_usec) / 1000; 00640 if (diff==0) diff=1; 00641 00642 if (diff > maximum_updatetime) { 00643 listEntryCurrentSize = listEntryCurrentSize * 3 / 4; 00644 _ready = true; 00645 } 00646 //if we can send all list entries of this dir which have not yet been sent 00647 //within maximum_updatetime, then make listEntryCurrentSize big enough for all of them 00648 else if (((pendingListEntries.count()*maximum_updatetime)/diff) > (d->totalSize-d->sentListEntries)) 00649 listEntryCurrentSize=d->totalSize-d->sentListEntries+1; 00650 //if we are below minimum_updatetime, estimate how much we will get within 00651 //maximum_updatetime 00652 else if (diff < minimum_updatetime) 00653 listEntryCurrentSize = (pendingListEntries.count() * maximum_updatetime) / diff; 00654 else 00655 _ready=true; 00656 } 00657 } 00658 if (_ready) { // may happen when we started with !ready 00659 listEntries( pendingListEntries ); 00660 pendingListEntries.clear(); 00661 00662 gettimeofday(&tp, 0); 00663 listEntry_sec = tp.tv_sec; 00664 listEntry_usec = tp.tv_usec; 00665 } 00666 } 00667 00668 void SlaveBase::listEntries( const UDSEntryList& list ) 00669 { 00670 KIO_DATA << (uint)list.count(); 00671 UDSEntryListConstIterator it = list.begin(); 00672 UDSEntryListConstIterator end = list.end(); 00673 for (; it != end; ++it) 00674 stream << *it; 00675 slaveWriteError = false; 00676 m_pConnection->send( MSG_LIST_ENTRIES, data); 00677 if (slaveWriteError) exit(); 00678 d->sentListEntries+=(uint)list.count(); 00679 } 00680 00681 void SlaveBase::sendAuthenticationKey( const QCString& key, 00682 const QCString& group, 00683 bool keepPass ) 00684 { 00685 KIO_DATA << key << group << keepPass; 00686 m_pConnection->send( MSG_AUTH_KEY, data ); 00687 } 00688 00689 void SlaveBase::delCachedAuthentication( const QString& key ) 00690 { 00691 KIO_DATA << key.utf8() ; 00692 m_pConnection->send( MSG_DEL_AUTH_KEY, data ); 00693 } 00694 00695 void SlaveBase::sigsegv_handler(int sig) 00696 { 00697 signal(sig,SIG_DFL); // Next one kills 00698 00699 //Kill us if we deadlock 00700 signal(SIGALRM,SIG_DFL); 00701 alarm(5); //generate an alarm signal in 5 seconds, in this time the slave has to exit 00702 00703 // Debug and printf should be avoided because they might 00704 // call malloc.. and get in a nice recursive malloc loop 00705 char buffer[120]; 00706 snprintf(buffer, sizeof(buffer), "kioslave: ####### CRASH ###### protocol = %s pid = %d signal = %d\n", s_protocol, getpid(), sig); 00707 write(2, buffer, strlen(buffer)); 00708 #ifndef NDEBUG 00709 #ifdef HAVE_BACKTRACE 00710 void* trace[256]; 00711 int n = backtrace(trace, 256); 00712 if (n) 00713 backtrace_symbols_fd(trace, n, 2); 00714 #endif 00715 #endif 00716 ::exit(1); 00717 } 00718 00719 void SlaveBase::sigpipe_handler (int) 00720 { 00721 // We ignore a SIGPIPE in slaves. 00722 // A SIGPIPE can happen in two cases: 00723 // 1) Communication error with application. 00724 // 2) Communication error with network. 00725 slaveWriteError = true; 00726 00727 // Don't add anything else here, especially no debug output 00728 } 00729 00730 void SlaveBase::setHost(QString const &, int, QString const &, QString const &) 00731 { 00732 } 00733 00734 void SlaveBase::openConnection(void) 00735 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_CONNECT)); } 00736 void SlaveBase::closeConnection(void) 00737 { } // No response! 00738 void SlaveBase::stat(KURL const &) 00739 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_STAT)); } 00740 void SlaveBase::put(KURL const &, int, bool, bool) 00741 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_PUT)); } 00742 void SlaveBase::special(const QByteArray &) 00743 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_SPECIAL)); } 00744 void SlaveBase::listDir(KURL const &) 00745 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_LISTDIR)); } 00746 void SlaveBase::get(KURL const & ) 00747 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_GET)); } 00748 void SlaveBase::mimetype(KURL const &url) 00749 { get(url); } 00750 void SlaveBase::rename(KURL const &, KURL const &, bool) 00751 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_RENAME)); } 00752 void SlaveBase::symlink(QString const &, KURL const &, bool) 00753 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_SYMLINK)); } 00754 void SlaveBase::copy(KURL const &, KURL const &, int, bool) 00755 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_COPY)); } 00756 void SlaveBase::del(KURL const &, bool) 00757 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_DEL)); } 00758 void SlaveBase::mkdir(KURL const &, int) 00759 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_MKDIR)); } 00760 void SlaveBase::chmod(KURL const &, int) 00761 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_CHMOD)); } 00762 void SlaveBase::setSubURL(KURL const &) 00763 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_SUBURL)); } 00764 void SlaveBase::multiGet(const QByteArray &) 00765 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_MULTI_GET)); } 00766 00767 00768 void SlaveBase::slave_status() 00769 { slaveStatus( QString::null, false ); } 00770 00771 void SlaveBase::reparseConfiguration() 00772 { 00773 } 00774 00775 bool SlaveBase::dispatch() 00776 { 00777 assert( m_pConnection ); 00778 00779 int cmd; 00780 QByteArray data; 00781 if ( m_pConnection->read( &cmd, data ) == -1 ) 00782 { 00783 kdDebug(7019) << "SlaveBase::dispatch() has read error." << endl; 00784 return false; 00785 } 00786 00787 dispatch( cmd, data ); 00788 return true; 00789 } 00790 00791 bool SlaveBase::openPassDlg( AuthInfo& info ) 00792 { 00793 return openPassDlg(info, QString::null); 00794 } 00795 00796 bool SlaveBase::openPassDlg( AuthInfo& info, const QString &errorMsg ) 00797 { 00798 QCString replyType; 00799 QByteArray params; 00800 QByteArray reply; 00801 AuthInfo authResult; 00802 long windowId = metaData("window-id").toLong(); 00803 00804 kdDebug(7019) << "SlaveBase::openPassDlg window-id=" << windowId << endl; 00805 00806 (void) dcopClient(); // Make sure to have a dcop client. 00807 00808 QDataStream stream(params, IO_WriteOnly); 00809 00810 if (metaData("no-auth-prompt").lower() == "true") 00811 stream << info << QString("<NoAuthPrompt>") << windowId << s_seqNr; 00812 else 00813 stream << info << errorMsg << windowId << s_seqNr; 00814 00815 if (!d->dcopClient->call( "kded", "kpasswdserver", "queryAuthInfo(KIO::AuthInfo, QString, long int, long int)", 00816 params, replyType, reply ) ) 00817 { 00818 kdWarning(7019) << "Can't communicate with kded_kpasswdserver!" << endl; 00819 return false; 00820 } 00821 00822 if ( replyType == "KIO::AuthInfo" ) 00823 { 00824 QDataStream stream2( reply, IO_ReadOnly ); 00825 stream2 >> authResult >> s_seqNr; 00826 } 00827 else 00828 { 00829 kdError(7019) << "DCOP function queryAuthInfo(...) returns " 00830 << replyType << ", expected KIO::AuthInfo" << endl; 00831 return false; 00832 } 00833 00834 if (!authResult.isModified()) 00835 return false; 00836 00837 info = authResult; 00838 00839 kdDebug(7019) << "SlaveBase::openPassDlg: username=" << info.username << endl; 00840 kdDebug(7019) << "SlaveBase::openPassDlg: password=[hidden]" << endl; 00841 00842 return true; 00843 } 00844 00845 int SlaveBase::messageBox( MessageBoxType type, const QString &text, const QString &caption, 00846 const QString &buttonYes, const QString &buttonNo ) 00847 { 00848 return messageBox( text, type, caption, buttonYes, buttonNo, QString::null ); 00849 } 00850 00851 int SlaveBase::messageBox( const QString &text, MessageBoxType type, const QString &caption, 00852 const QString &buttonYes, const QString &buttonNo, const QString &dontAskAgainName ) 00853 { 00854 kdDebug(7019) << "messageBox " << type << " " << text << " - " << caption << buttonYes << buttonNo << endl; 00855 KIO_DATA << (int)type << text << caption << buttonYes << buttonNo << dontAskAgainName; 00856 m_pConnection->send( INF_MESSAGEBOX, data ); 00857 if ( waitForAnswer( CMD_MESSAGEBOXANSWER, 0, data ) != -1 ) 00858 { 00859 QDataStream stream( data, IO_ReadOnly ); 00860 int answer; 00861 stream >> answer; 00862 kdDebug(7019) << "got messagebox answer" << answer << endl; 00863 return answer; 00864 } else 00865 return 0; // communication failure 00866 } 00867 00868 bool SlaveBase::canResume( KIO::filesize_t offset ) 00869 { 00870 kdDebug(7019) << "SlaveBase::canResume offset=" << KIO::number(offset) << endl; 00871 d->needSendCanResume = false; 00872 KIO_DATA << KIO_FILESIZE_T(offset); 00873 m_pConnection->send( MSG_RESUME, data ); 00874 if ( offset ) 00875 { 00876 int cmd; 00877 if ( waitForAnswer( CMD_RESUMEANSWER, CMD_NONE, data, &cmd ) != -1 ) 00878 { 00879 kdDebug(7019) << "SlaveBase::canResume returning " << (cmd == CMD_RESUMEANSWER) << endl; 00880 return cmd == CMD_RESUMEANSWER; 00881 } else 00882 return false; 00883 } 00884 else // No resuming possible -> no answer to wait for 00885 return true; 00886 } 00887 00888 00889 00890 int SlaveBase::waitForAnswer( int expected1, int expected2, QByteArray & data, int *pCmd ) 00891 { 00892 int cmd, result; 00893 for (;;) 00894 { 00895 result = m_pConnection->read( &cmd, data ); 00896 if ( result == -1 ) 00897 { 00898 kdDebug(7019) << "SlaveBase::waitForAnswer has read error." << endl; 00899 return -1; 00900 } 00901 if ( cmd == expected1 || cmd == expected2 ) 00902 { 00903 if ( pCmd ) *pCmd = cmd; 00904 return result; 00905 } 00906 if ( isSubCommand(cmd) ) 00907 { 00908 dispatch( cmd, data ); 00909 } 00910 else 00911 { 00912 kdWarning() << "Got cmd " << cmd << " while waiting for an answer!" << endl; 00913 } 00914 } 00915 } 00916 00917 00918 int SlaveBase::readData( QByteArray &buffer) 00919 { 00920 int result = waitForAnswer( MSG_DATA, 0, buffer ); 00921 //kdDebug(7019) << "readData: length = " << result << " " << endl; 00922 return result; 00923 } 00924 00925 void SlaveBase::setTimeoutSpecialCommand(int timeout, const QByteArray &data) 00926 { 00927 if (timeout > 0) 00928 d->timeout = time(0)+(time_t)timeout; 00929 else if (timeout == 0) 00930 d->timeout = 1; // Immediate timeout 00931 else 00932 d->timeout = 0; // Canceled 00933 00934 d->timeoutData = data; 00935 } 00936 00937 void SlaveBase::dispatch( int command, const QByteArray &data ) 00938 { 00939 QDataStream stream( data, IO_ReadOnly ); 00940 00941 KURL url; 00942 int i; 00943 00944 switch( command ) { 00945 case CMD_HOST: { 00946 // Reset s_seqNr, see kpasswdserver/DESIGN 00947 s_seqNr = 0; 00948 QString passwd; 00949 QString host, user; 00950 stream >> host >> i >> user >> passwd; 00951 setHost( host, i, user, passwd ); 00952 } 00953 break; 00954 case CMD_CONNECT: 00955 openConnection( ); 00956 break; 00957 case CMD_DISCONNECT: 00958 closeConnection( ); 00959 break; 00960 case CMD_SLAVE_STATUS: 00961 slave_status(); 00962 break; 00963 case CMD_SLAVE_CONNECT: 00964 { 00965 d->onHold = false; 00966 QString app_socket; 00967 QDataStream stream( data, IO_ReadOnly); 00968 stream >> app_socket; 00969 appconn->send( MSG_SLAVE_ACK ); 00970 disconnectSlave(); 00971 mConnectedToApp = true; 00972 connectSlave(app_socket); 00973 } break; 00974 case CMD_SLAVE_HOLD: 00975 { 00976 KURL url; 00977 QDataStream stream( data, IO_ReadOnly); 00978 stream >> url; 00979 d->onHoldUrl = url; 00980 d->onHold = true; 00981 disconnectSlave(); 00982 mConnectedToApp = false; 00983 // Do not close connection! 00984 connectSlave(mPoolSocket); 00985 } break; 00986 case CMD_REPARSECONFIGURATION: 00987 reparseConfiguration(); 00988 break; 00989 case CMD_CONFIG: 00990 stream >> d->configData; 00991 KSocks::setConfig(d->config); 00992 delete d->remotefile; 00993 d->remotefile = 0; 00994 break; 00995 case CMD_GET: 00996 { 00997 stream >> url; 00998 get( url ); 00999 } break; 01000 case CMD_PUT: 01001 { 01002 int permissions; 01003 Q_INT8 iOverwrite, iResume; 01004 stream >> url >> iOverwrite >> iResume >> permissions; 01005 bool overwrite = ( iOverwrite != 0 ); 01006 bool resume = ( iResume != 0 ); 01007 01008 // Remember that we need to send canResume(), TransferJob is expecting 01009 // it. Well, in theory this shouldn't be done if resume is true. 01010 // (the resume bool is currently unused) 01011 d->needSendCanResume = true /* !resume */; 01012 01013 put( url, permissions, overwrite, resume); 01014 } break; 01015 case CMD_STAT: 01016 stream >> url; 01017 stat( url ); 01018 break; 01019 case CMD_MIMETYPE: 01020 stream >> url; 01021 mimetype( url ); 01022 break; 01023 case CMD_LISTDIR: 01024 stream >> url; 01025 listDir( url ); 01026 break; 01027 case CMD_MKDIR: 01028 stream >> url >> i; 01029 mkdir( url, i ); 01030 break; 01031 case CMD_RENAME: 01032 { 01033 Q_INT8 iOverwrite; 01034 KURL url2; 01035 stream >> url >> url2 >> iOverwrite; 01036 bool overwrite = (iOverwrite != 0); 01037 rename( url, url2, overwrite ); 01038 } break; 01039 case CMD_SYMLINK: 01040 { 01041 Q_INT8 iOverwrite; 01042 QString target; 01043 stream >> target >> url >> iOverwrite; 01044 bool overwrite = (iOverwrite != 0); 01045 symlink( target, url, overwrite ); 01046 } break; 01047 case CMD_COPY: 01048 { 01049 int permissions; 01050 Q_INT8 iOverwrite; 01051 KURL url2; 01052 stream >> url >> url2 >> permissions >> iOverwrite; 01053 bool overwrite = (iOverwrite != 0); 01054 copy( url, url2, permissions, overwrite ); 01055 } break; 01056 case CMD_DEL: 01057 { 01058 Q_INT8 isFile; 01059 stream >> url >> isFile; 01060 del( url, isFile != 0); 01061 } break; 01062 case CMD_CHMOD: 01063 stream >> url >> i; 01064 chmod( url, i); 01065 break; 01066 case CMD_SPECIAL: 01067 special( data ); 01068 break; 01069 case CMD_META_DATA: 01070 //kdDebug(7019) << "(" << getpid() << ") Incoming meta-data..." << endl; 01071 stream >> mIncomingMetaData; 01072 break; 01073 case CMD_SUBURL: 01074 stream >> url; 01075 setSubURL(url); 01076 break; 01077 case CMD_NONE: 01078 fprintf(stderr, "Got unexpected CMD_NONE!\n"); 01079 break; 01080 case CMD_MULTI_GET: 01081 multiGet( data ); 01082 break; 01083 default: 01084 // Some command we don't understand. 01085 // Just ignore it, it may come from some future version of KDE. 01086 break; 01087 } 01088 } 01089 01090 QString SlaveBase::createAuthCacheKey( const KURL& url ) 01091 { 01092 if( !url.isValid() ) 01093 return QString::null; 01094 01095 // Generate the basic key sequence. 01096 QString key = url.protocol(); 01097 key += '-'; 01098 key += url.host(); 01099 int port = url.port(); 01100 if( port ) 01101 { 01102 key += ':'; 01103 key += QString::number(port); 01104 } 01105 01106 return key; 01107 } 01108 01109 bool SlaveBase::pingCacheDaemon() const 01110 { 01111 // TODO: Ping kded / kpasswdserver 01112 KDEsuClient client; 01113 int success = client.ping(); 01114 if( success == -1 ) 01115 { 01116 success = client.startServer(); 01117 if( success == -1 ) 01118 { 01119 kdDebug(7019) << "Cannot start a new deamon!!" << endl; 01120 return false; 01121 } 01122 kdDebug(7019) << "Sucessfully started new cache deamon!!" << endl; 01123 } 01124 return true; 01125 } 01126 01127 bool SlaveBase::checkCachedAuthentication( AuthInfo& info ) 01128 { 01129 QCString replyType; 01130 QByteArray params; 01131 QByteArray reply; 01132 AuthInfo authResult; 01133 long windowId = metaData("window-id").toLong(); 01134 01135 kdDebug(7019) << "SlaveBase::checkCachedAuthInfo window = " << windowId << " url = " << info.url.url() << endl; 01136 01137 (void) dcopClient(); // Make sure to have a dcop client. 01138 01139 QDataStream stream(params, IO_WriteOnly); 01140 stream << info << windowId; 01141 01142 if ( !d->dcopClient->call( "kded", "kpasswdserver", "checkAuthInfo(KIO::AuthInfo, long int)", 01143 params, replyType, reply ) ) 01144 { 01145 kdWarning(7019) << "Can't communicate with kded_kpasswdserver!" << endl; 01146 return false; 01147 } 01148 01149 if ( replyType == "KIO::AuthInfo" ) 01150 { 01151 QDataStream stream2( reply, IO_ReadOnly ); 01152 stream2 >> authResult; 01153 } 01154 else 01155 { 01156 kdError(7019) << "DCOP function checkAuthInfo(...) returns " 01157 << replyType << ", expected KIO::AuthInfo" << endl; 01158 return false; 01159 } 01160 if (!authResult.isModified()) 01161 { 01162 return false; 01163 } 01164 01165 info = authResult; 01166 return true; 01167 } 01168 01169 bool SlaveBase::cacheAuthentication( const AuthInfo& info ) 01170 { 01171 QByteArray params; 01172 long windowId = metaData("window-id").toLong(); 01173 01174 (void) dcopClient(); // Make sure to have a dcop client. 01175 01176 QDataStream stream(params, IO_WriteOnly); 01177 stream << info << windowId; 01178 01179 d->dcopClient->send( "kded", "kpasswdserver", "addAuthInfo(KIO::AuthInfo, long int)", params ); 01180 01181 return true; 01182 } 01183 01184 int SlaveBase::connectTimeout() 01185 { 01186 bool ok; 01187 QString tmp = metaData("ConnectTimeout"); 01188 int result = tmp.toInt(&ok); 01189 if (ok) 01190 return result; 01191 return DEFAULT_CONNECT_TIMEOUT; 01192 } 01193 01194 int SlaveBase::proxyConnectTimeout() 01195 { 01196 bool ok; 01197 QString tmp = metaData("ProxyConnectTimeout"); 01198 int result = tmp.toInt(&ok); 01199 if (ok) 01200 return result; 01201 return DEFAULT_PROXY_CONNECT_TIMEOUT; 01202 } 01203 01204 01205 int SlaveBase::responseTimeout() 01206 { 01207 bool ok; 01208 QString tmp = metaData("ResponseTimeout"); 01209 int result = tmp.toInt(&ok); 01210 if (ok) 01211 return result; 01212 return DEFAULT_RESPONSE_TIMEOUT; 01213 } 01214 01215 01216 int SlaveBase::readTimeout() 01217 { 01218 bool ok; 01219 QString tmp = metaData("ReadTimeout"); 01220 int result = tmp.toInt(&ok); 01221 if (ok) 01222 return result; 01223 return DEFAULT_READ_TIMEOUT; 01224 } 01225 01226 bool SlaveBase::wasKilled() const 01227 { 01228 return d->wasKilled; 01229 } 01230 01231 void SlaveBase::setKillFlag() 01232 { 01233 d->wasKilled=true; 01234 } 01235 01236 void SlaveBase::virtual_hook( int, void* ) 01237 { /*BASE::virtual_hook( id, data );*/ } 01238
KDE Logo
This file is part of the documentation for kio Library Version 3.3.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Sep 29 09:41:08 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003