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