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 Wed Aug 4 05:25:38 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2003