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