kio Library: slavebase.cpp Source File (kio Library)

| # kio Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Namespaces | Source Files

# 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 416248 2005-05-20 22:15:55Z craig $
    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     bool           emitSignal=false;
    00490     struct timeval tv;
    00491     int            gettimeofday_res=gettimeofday( &tv, 0L );
    00492
    00493     if( _bytes == d->totalSize )
    00494         emitSignal=true;
    00495     else if ( gettimeofday_res == 0 ) {
    00496         time_t msecdiff = 2000;
    00497         if (d->last_tv.tv_sec) {
    00498             // Compute difference, in ms
    00499             msecdiff = 1000 * ( tv.tv_sec - d->last_tv.tv_sec );
    00500             time_t usecdiff = tv.tv_usec - d->last_tv.tv_usec;
    00501             if ( usecdiff < 0 ) {
    00502                 msecdiff--;
    00503                 msecdiff += 1000;
    00504             }
    00505             msecdiff += usecdiff / 1000;
    00506         }
    00507         emitSignal=msecdiff >= 100; // emit size 10 times a second
    00508     }
    00509
    00510     if( emitSignal ) {
    00511         KIO_DATA << KIO_FILESIZE_T(_bytes);
    00512         slaveWriteError = false;
    00513         m_pConnection->send( INF_PROCESSED_SIZE, data );
    00514             if (slaveWriteError) exit();
    00515         if ( gettimeofday_res == 0 ) {
    00516             d->last_tv.tv_sec = tv.tv_sec;
    00517             d->last_tv.tv_usec = tv.tv_usec;
    00518         }
    00519     }
    00520 //    d->processed_size = _bytes;
    00521 }
    00522
    00523 void SlaveBase::processedPercent( float /* percent */ )
    00524 {
    00525   kdDebug(7019) << "SlaveBase::processedPercent: STUB" << endl;
    00526 }
    00527
    00528
    00529 void SlaveBase::speed( unsigned long _bytes_per_second )
    00530 {
    00531     KIO_DATA << (Q_UINT32) _bytes_per_second;
    00532     slaveWriteError = false;
    00533     m_pConnection->send( INF_SPEED, data );
    00534     if (slaveWriteError) exit();
    00535 }
    00536
    00537 void SlaveBase::redirection( const KURL& _url )
    00538 {
    00539     KIO_DATA << _url;
    00540     m_pConnection->send( INF_REDIRECTION, data );
    00541 }
    00542
    00543 void SlaveBase::errorPage()
    00544 {
    00545     m_pConnection->send( INF_ERROR_PAGE );
    00546 }
    00547
    00548 static bool isSubCommand(int cmd)
    00549 {
    00550    return ( (cmd == CMD_REPARSECONFIGURATION) ||
    00551             (cmd == CMD_META_DATA) ||
    00552             (cmd == CMD_CONFIG) ||
    00553             (cmd == CMD_SUBURL) ||
    00554             (cmd == CMD_SLAVE_STATUS) ||
    00555             (cmd == CMD_SLAVE_CONNECT) ||
    00556             (cmd == CMD_SLAVE_HOLD) ||
    00557             (cmd == CMD_MULTI_GET));
    00558 }
    00559
    00560 void SlaveBase::mimeType( const QString &_type)
    00561 {
    00562   // kdDebug(7019) << "(" << getpid() << ") SlaveBase::mimeType '" << _type << "'" << endl;
    00563   int cmd;
    00564   do
    00565   {
    00566     // Send the meta-data each time we send the mime-type.
    00567     if (!mOutgoingMetaData.isEmpty())
    00568     {
    00569       // kdDebug(7019) << "(" << getpid() << ") mimeType: emitting meta data" << endl;
    00570       KIO_DATA << mOutgoingMetaData;
    00571       m_pConnection->send( INF_META_DATA, data );
    00572     }
    00573     KIO_DATA << _type;
    00574     m_pConnection->send( INF_MIME_TYPE, data );
    00575     while(true)
    00576     {
    00577        cmd = 0;
    00578        if ( m_pConnection->read( &cmd, data ) == -1 ) {
    00579            kdDebug(7019) << "SlaveBase: mimetype: read error" << endl;
    00580            exit();
    00581        }
    00582        // kdDebug(7019) << "(" << getpid() << ") Slavebase: mimetype got " << cmd << endl;
    00583        if ( cmd == CMD_HOST) // Ignore.
    00584           continue;
    00585        if ( isSubCommand(cmd) )
    00586        {
    00587           dispatch( cmd, data );
    00588           continue; // Disguised goto
    00589        }
    00590        break;
    00591     }
    00592   }
    00593   while (cmd != CMD_NONE);
    00594   mOutgoingMetaData.clear();
    00595 }
    00596
    00597 void SlaveBase::exit()
    00598 {
    00599     this->~SlaveBase();
    00600     ::exit(255);
    00601 }
    00602
    00603 void SlaveBase::warning( const QString &_msg)
    00604 {
    00605     KIO_DATA << _msg;
    00606     m_pConnection->send( INF_WARNING, data );
    00607 }
    00608
    00609 void SlaveBase::infoMessage( const QString &_msg)
    00610 {
    00611     KIO_DATA << _msg;
    00612     m_pConnection->send( INF_INFOMESSAGE, data );
    00613 }
    00614
    00615 bool SlaveBase::requestNetwork(const QString& host)
    00616 {
    00617     KIO_DATA << host << d->slaveid;
    00618     m_pConnection->send( MSG_NET_REQUEST, data );
    00619
    00620     if ( waitForAnswer( INF_NETWORK_STATUS, 0, data ) != -1 )
    00621     {
    00622         bool status;
    00623         QDataStream stream( data, IO_ReadOnly );
    00624         stream >> status;
    00625         return status;
    00626     } else
    00627         return false;
    00628 }
    00629
    00630 void SlaveBase::dropNetwork(const QString& host)
    00631 {
    00632     KIO_DATA << host << d->slaveid;
    00633     m_pConnection->send( MSG_NET_DROP, data );
    00634 }
    00635
    00636 void SlaveBase::statEntry( const UDSEntry& entry )
    00637 {
    00638     KIO_DATA << entry;
    00639     slaveWriteError = false;
    00640     m_pConnection->send( MSG_STAT_ENTRY, data );
    00641     if (slaveWriteError) exit();
    00642 }
    00643
    00644 void SlaveBase::listEntry( const UDSEntry& entry, bool _ready )
    00645 {
    00646    static struct timeval tp;
    00647    static const int maximum_updatetime = 300;
    00648    static const int minimum_updatetime = 100;
    00649
    00650    if (!_ready) {
    00651       pendingListEntries.append(entry);
    00652
    00653       if (pendingListEntries.count() > listEntryCurrentSize) {
    00654          gettimeofday(&tp, 0);
    00655
    00656          long diff = ((tp.tv_sec - listEntry_sec) * 1000000 +
    00657                       tp.tv_usec - listEntry_usec) / 1000;
    00658          if (diff==0) diff=1;
    00659
    00660          if (diff > maximum_updatetime) {
    00661             listEntryCurrentSize = listEntryCurrentSize * 3 / 4;
    00662             _ready = true;
    00663          }
    00664 //if we can send all list entries of this dir which have not yet been sent
    00665 //within maximum_updatetime, then make listEntryCurrentSize big enough for all of them
    00666          else if (((pendingListEntries.count()*maximum_updatetime)/diff) > (d->totalSize-d->sentListEntries))
    00667             listEntryCurrentSize=d->totalSize-d->sentListEntries+1;
    00668 //if we are below minimum_updatetime, estimate how much we will get within
    00669 //maximum_updatetime
    00670          else if (diff < minimum_updatetime)
    00671             listEntryCurrentSize = (pendingListEntries.count() * maximum_updatetime) / diff;
    00672          else
    00673             _ready=true;
    00674       }
    00675    }
    00676    if (_ready) { // may happen when we started with !ready
    00677       listEntries( pendingListEntries );
    00678       pendingListEntries.clear();
    00679
    00680       gettimeofday(&tp, 0);
    00681       listEntry_sec = tp.tv_sec;
    00682       listEntry_usec = tp.tv_usec;
    00683    }
    00684 }
    00685
    00686 void SlaveBase::listEntries( const UDSEntryList& list )
    00687 {
    00688     KIO_DATA << (Q_UINT32)list.count();
    00689     UDSEntryListConstIterator it = list.begin();
    00690     UDSEntryListConstIterator end = list.end();
    00691     for (; it != end; ++it)
    00692       stream << *it;
    00693     slaveWriteError = false;
    00694     m_pConnection->send( MSG_LIST_ENTRIES, data);
    00695     if (slaveWriteError) exit();
    00696     d->sentListEntries+=(uint)list.count();
    00697 }
    00698
    00699 void SlaveBase::sendAuthenticationKey( const QCString& key,
    00700                                        const QCString& group,
    00701                                        bool keepPass )
    00702 {
    00703     KIO_DATA << key << group << keepPass;
    00704     m_pConnection->send( MSG_AUTH_KEY, data );
    00705 }
    00706
    00707 void SlaveBase::delCachedAuthentication( const QString& key )
    00708 {
    00709     KIO_DATA << key.utf8() ;
    00710     m_pConnection->send( MSG_DEL_AUTH_KEY, data );
    00711 }
    00712
    00713 void SlaveBase::sigsegv_handler(int sig)
    00714 {
    00715 #ifdef Q_OS_UNIX
    00716     signal(sig,SIG_DFL); // Next one kills
    00717
    00718     //Kill us if we deadlock
    00719     signal(SIGALRM,SIG_DFL);
    00720     alarm(5);  //generate an alarm signal in 5 seconds, in this time the slave has to exit
    00721
    00722     // Debug and printf should be avoided because they might
    00723     // call malloc.. and get in a nice recursive malloc loop
    00724     char buffer[120];
    00725     snprintf(buffer, sizeof(buffer), "kioslave: ####### CRASH ###### protocol = %s pid = %d signal = %d\n", s_protocol, getpid(), sig);
    00726     write(2, buffer, strlen(buffer));
    00727 #ifndef NDEBUG
    00728 #ifdef HAVE_BACKTRACE
    00729     void* trace[256];
    00730     int n = backtrace(trace, 256);
    00731     if (n)
    00732       backtrace_symbols_fd(trace, n, 2);
    00733 #endif
    00734 #endif
    00735     ::exit(1);
    00736 #endif
    00737 }
    00738
    00739 void SlaveBase::sigpipe_handler (int)
    00740 {
    00741     // We ignore a SIGPIPE in slaves.
    00742     // A SIGPIPE can happen in two cases:
    00743     // 1) Communication error with application.
    00744     // 2) Communication error with network.
    00745     slaveWriteError = true;
    00746
    00747     // Don't add anything else here, especially no debug output
    00748 }
    00749
    00750 void SlaveBase::setHost(QString const &, int, QString const &, QString const &)
    00751 {
    00752 }
    00753
    00754 void SlaveBase::openConnection(void)
    00755 { error(  ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_CONNECT)); }
    00756 void SlaveBase::closeConnection(void)
    00757 { } // No response!
    00758 void SlaveBase::stat(KURL const &)
    00759 { error(  ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_STAT)); }
    00760 void SlaveBase::put(KURL const &, int, bool, bool)
    00761 { error(  ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_PUT)); }
    00762 void SlaveBase::special(const QByteArray &)
    00763 { error(  ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_SPECIAL)); }
    00764 void SlaveBase::listDir(KURL const &)
    00765 { error(  ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_LISTDIR)); }
    00766 void SlaveBase::get(KURL const & )
    00767 { error(  ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_GET)); }
    00768 void SlaveBase::mimetype(KURL const &url)
    00769 { get(url); }
    00770 void SlaveBase::rename(KURL const &, KURL const &, bool)
    00771 { error(  ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_RENAME)); }
    00772 void SlaveBase::symlink(QString const &, KURL const &, bool)
    00773 { error(  ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_SYMLINK)); }
    00774 void SlaveBase::copy(KURL const &, KURL const &, int, bool)
    00775 { error(  ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_COPY)); }
    00776 void SlaveBase::del(KURL const &, bool)
    00777 { error(  ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_DEL)); }
    00778 void SlaveBase::mkdir(KURL const &, int)
    00779 { error(  ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_MKDIR)); }
    00780 void SlaveBase::chmod(KURL const &, int)
    00781 { error(  ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_CHMOD)); }
    00782 void SlaveBase::setSubURL(KURL const &)
    00783 { error(  ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_SUBURL)); }
    00784 void SlaveBase::multiGet(const QByteArray &)
    00785 { error(  ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_MULTI_GET)); }
    00786
    00787
    00788 void SlaveBase::slave_status()
    00789 { slaveStatus( QString::null, false ); }
    00790
    00791 void SlaveBase::reparseConfiguration()
    00792 {
    00793 }
    00794
    00795 bool SlaveBase::dispatch()
    00796 {
    00797     assert( m_pConnection );
    00798
    00799     int cmd;
    00800     QByteArray data;
    00801     if ( m_pConnection->read( &cmd, data ) == -1 )
    00802     {
    00803         kdDebug(7019) << "SlaveBase::dispatch() has read error." << endl;
    00804         return false;
    00805     }
    00806
    00807     dispatch( cmd, data );
    00808     return true;
    00809 }
    00810
    00811 bool SlaveBase::openPassDlg( AuthInfo& info )
    00812 {
    00813     return openPassDlg(info, QString::null);
    00814 }
    00815
    00816 bool SlaveBase::openPassDlg( AuthInfo& info, const QString &errorMsg )
    00817 {
    00818     QCString replyType;
    00819     QByteArray params;
    00820     QByteArray reply;
    00821     AuthInfo authResult;
    00822     long windowId = metaData("window-id").toLong();
    00823
    00824     kdDebug(7019) << "SlaveBase::openPassDlg window-id=" << windowId << endl;
    00825
    00826     (void) dcopClient(); // Make sure to have a dcop client.
    00827
    00828     QDataStream stream(params, IO_WriteOnly);
    00829
    00830     if (metaData("no-auth-prompt").lower() == "true")
    00831        stream << info << QString("<NoAuthPrompt>") << windowId << s_seqNr;
    00832     else
    00833        stream << info << errorMsg << windowId << s_seqNr;
    00834
    00835     if (!d->dcopClient->call( "kded", "kpasswdserver", "queryAuthInfo(KIO::AuthInfo, QString, long int, long int)",
    00836                                params, replyType, reply ) )
    00837     {
    00838        kdWarning(7019) << "Can't communicate with kded_kpasswdserver!" << endl;
    00839        return false;
    00840     }
    00841
    00842     if ( replyType == "KIO::AuthInfo" )
    00843     {
    00844        QDataStream stream2( reply, IO_ReadOnly );
    00845        stream2 >> authResult >> s_seqNr;
    00846     }
    00847     else
    00848     {
    00849        kdError(7019) << "DCOP function queryAuthInfo(...) returns "
    00850                      << replyType << ", expected KIO::AuthInfo" << endl;
    00851        return false;
    00852     }
    00853
    00854     if (!authResult.isModified())
    00855        return false;
    00856
    00857     info = authResult;
    00858
    00859     kdDebug(7019) << "SlaveBase::openPassDlg: username=" << info.username << endl;
    00860     kdDebug(7019) << "SlaveBase::openPassDlg: password=[hidden]" << endl;
    00861
    00862     return true;
    00863 }
    00864
    00865 int SlaveBase::messageBox( MessageBoxType type, const QString &text, const QString &caption,
    00866                            const QString &buttonYes, const QString &buttonNo )
    00867 {
    00868     return messageBox( text, type, caption, buttonYes, buttonNo, QString::null );
    00869 }
    00870
    00871 int SlaveBase::messageBox( const QString &text, MessageBoxType type, const QString &caption,
    00872                            const QString &buttonYes, const QString &buttonNo, const QString &dontAskAgainName )
    00873 {
    00874     kdDebug(7019) << "messageBox " << type << " " << text << " - " << caption << buttonYes << buttonNo << endl;
    00875     KIO_DATA << (Q_INT32)type << text << caption << buttonYes << buttonNo << dontAskAgainName;
    00876     m_pConnection->send( INF_MESSAGEBOX, data );
    00877     if ( waitForAnswer( CMD_MESSAGEBOXANSWER, 0, data ) != -1 )
    00878     {
    00879         QDataStream stream( data, IO_ReadOnly );
    00880         int answer;
    00881         stream >> answer;
    00882         kdDebug(7019) << "got messagebox answer" << answer << endl;
    00883         return answer;
    00884     } else
    00885         return 0; // communication failure
    00886 }
    00887
    00888 bool SlaveBase::canResume( KIO::filesize_t offset )
    00889 {
    00890     kdDebug(7019) << "SlaveBase::canResume offset=" << KIO::number(offset) << endl;
    00891     d->needSendCanResume = false;
    00892     KIO_DATA << KIO_FILESIZE_T(offset);
    00893     m_pConnection->send( MSG_RESUME, data );
    00894     if ( offset )
    00895     {
    00896         int cmd;
    00897         if ( waitForAnswer( CMD_RESUMEANSWER, CMD_NONE, data, &cmd ) != -1 )
    00898         {
    00899             kdDebug(7019) << "SlaveBase::canResume returning " << (cmd == CMD_RESUMEANSWER) << endl;
    00900             return cmd == CMD_RESUMEANSWER;
    00901         } else
    00902             return false;
    00903     }
    00904     else // No resuming possible -> no answer to wait for
    00905         return true;
    00906 }
    00907
    00908
    00909
    00910 int SlaveBase::waitForAnswer( int expected1, int expected2, QByteArray & data, int *pCmd )
    00911 {
    00912     int cmd, result;
    00913     for (;;)
    00914     {
    00915         result = m_pConnection->read( &cmd, data );
    00916         if ( result == -1 )
    00917         {
    00918             kdDebug(7019) << "SlaveBase::waitForAnswer has read error." << endl;
    00919             return -1;
    00920         }
    00921         if ( cmd == expected1 || cmd == expected2 )
    00922         {
    00923             if ( pCmd ) *pCmd = cmd;
    00924             return result;
    00925         }
    00926         if ( isSubCommand(cmd) )
    00927         {
    00928             dispatch( cmd, data );
    00929         }
    00930         else
    00931         {
    00932             kdWarning() << "Got cmd " << cmd << " while waiting for an answer!" << endl;
    00933         }
    00934     }
    00935 }
    00936
    00937
    00938 int SlaveBase::readData( QByteArray &buffer)
    00939 {
    00940    int result = waitForAnswer( MSG_DATA, 0, buffer );
    00941    //kdDebug(7019) << "readData: length = " << result << " " << endl;
    00942    return result;
    00943 }
    00944
    00945 void SlaveBase::setTimeoutSpecialCommand(int timeout, const QByteArray &data)
    00946 {
    00947    if (timeout > 0)
    00948       d->timeout = time(0)+(time_t)timeout;
    00949    else if (timeout == 0)
    00950       d->timeout = 1; // Immediate timeout
    00951    else
    00952       d->timeout = 0; // Canceled
    00953
    00954    d->timeoutData = data;
    00955 }
    00956
    00957 void SlaveBase::dispatch( int command, const QByteArray &data )
    00958 {
    00959     QDataStream stream( data, IO_ReadOnly );
    00960
    00961     KURL url;
    00962     int i;
    00963
    00964     switch( command ) {
    00965     case CMD_HOST: {
    00966         // Reset s_seqNr, see kpasswdserver/DESIGN
    00967         s_seqNr = 0;
    00968         QString passwd;
    00969         QString host, user;
    00970         stream >> host >> i >> user >> passwd;
    00971         setHost( host, i, user, passwd );
    00972     }
    00973     break;
    00974     case CMD_CONNECT:
    00975         openConnection( );
    00976         break;
    00977     case CMD_DISCONNECT:
    00978         closeConnection( );
    00979         break;
    00980     case CMD_SLAVE_STATUS:
    00981         slave_status();
    00982         break;
    00983     case CMD_SLAVE_CONNECT:
    00984     {
    00985         d->onHold = false;
    00986         QString app_socket;
    00987         QDataStream stream( data, IO_ReadOnly);
    00988         stream >> app_socket;
    00989         appconn->send( MSG_SLAVE_ACK );
    00990         disconnectSlave();
    00991         mConnectedToApp = true;
    00992         connectSlave(app_socket);
    00993     } break;
    00994     case CMD_SLAVE_HOLD:
    00995     {
    00996         KURL url;
    00997         QDataStream stream( data, IO_ReadOnly);
    00998         stream >> url;
    00999         d->onHoldUrl = url;
    01000         d->onHold = true;
    01001         disconnectSlave();
    01002         mConnectedToApp = false;
    01003         // Do not close connection!
    01004         connectSlave(mPoolSocket);
    01005     } break;
    01006     case CMD_REPARSECONFIGURATION:
    01007         reparseConfiguration();
    01008         break;
    01009     case CMD_CONFIG:
    01010         stream >> d->configData;
    01011 #ifdef Q_OS_UNIX //TODO: not yet available on WIN32
    01012         KSocks::setConfig(d->config);
    01013 #endif
    01014     delete d->remotefile;
    01015     d->remotefile = 0;
    01016         break;
    01017     case CMD_GET:
    01018     {
    01019         stream >> url;
    01020         get( url );
    01021     } break;
    01022     case CMD_PUT:
    01023     {
    01024         int permissions;
    01025         Q_INT8 iOverwrite, iResume;
    01026         stream >> url >> iOverwrite >> iResume >> permissions;
    01027         bool overwrite = ( iOverwrite != 0 );
    01028         bool resume = ( iResume != 0 );
    01029
    01030         // Remember that we need to send canResume(), TransferJob is expecting
    01031         // it. Well, in theory this shouldn't be done if resume is true.
    01032         //   (the resume bool is currently unused)
    01033         d->needSendCanResume = true   /* !resume */;
    01034
    01035         put( url, permissions, overwrite, resume);
    01036     } break;
    01037     case CMD_STAT:
    01038         stream >> url;
    01039         stat( url );
    01040         break;
    01041     case CMD_MIMETYPE:
    01042         stream >> url;
    01043         mimetype( url );
    01044         break;
    01045     case CMD_LISTDIR:
    01046         stream >> url;
    01047         listDir( url );
    01048         break;
    01049     case CMD_MKDIR:
    01050         stream >> url >> i;
    01051         mkdir( url, i );
    01052         break;
    01053     case CMD_RENAME:
    01054     {
    01055         Q_INT8 iOverwrite;
    01056         KURL url2;
    01057         stream >> url >> url2 >> iOverwrite;
    01058         bool overwrite = (iOverwrite != 0);
    01059         rename( url, url2, overwrite );
    01060     } break;
    01061     case CMD_SYMLINK:
    01062     {
    01063         Q_INT8 iOverwrite;
    01064         QString target;
    01065         stream >> target >> url >> iOverwrite;
    01066         bool overwrite = (iOverwrite != 0);
    01067         symlink( target, url, overwrite );
    01068     } break;
    01069     case CMD_COPY:
    01070     {
    01071         int permissions;
    01072         Q_INT8 iOverwrite;
    01073         KURL url2;
    01074         stream >> url >> url2 >> permissions >> iOverwrite;
    01075         bool overwrite = (iOverwrite != 0);
    01076         copy( url, url2, permissions, overwrite );
    01077     } break;
    01078     case CMD_DEL:
    01079     {
    01080         Q_INT8 isFile;
    01081         stream >> url >> isFile;
    01082         del( url, isFile != 0);
    01083     } break;
    01084     case CMD_CHMOD:
    01085         stream >> url >> i;
    01086         chmod( url, i);
    01087         break;
    01088     case CMD_SPECIAL:
    01089         special( data );
    01090         break;
    01091     case CMD_META_DATA:
    01092         //kdDebug(7019) << "(" << getpid() << ") Incoming meta-data..." << endl;
    01093         stream >> mIncomingMetaData;
    01094         break;
    01095     case CMD_SUBURL:
    01096         stream >> url;
    01097         setSubURL(url);
    01098         break;
    01099     case CMD_NONE:
    01100         fprintf(stderr, "Got unexpected CMD_NONE!\n");
    01101         break;
    01102     case CMD_MULTI_GET:
    01103         multiGet( data );
    01104         break;
    01105     default:
    01106         // Some command we don't understand.
    01107         // Just ignore it, it may come from some future version of KDE.
    01108         break;
    01109     }
    01110 }
    01111
    01112 QString SlaveBase::createAuthCacheKey( const KURL& url )
    01113 {
    01114     if( !url.isValid() )
    01115         return QString::null;
    01116
    01117     // Generate the basic key sequence.
    01118     QString key = url.protocol();
    01119     key += '-';
    01120     key += url.host();
    01121     int port = url.port();
    01122     if( port )
    01123     {
    01124       key += ':';
    01125       key += QString::number(port);
    01126     }
    01127
    01128     return key;
    01129 }
    01130
    01131 bool SlaveBase::pingCacheDaemon() const
    01132 {
    01133 #ifdef Q_OS_UNIX
    01134     // TODO: Ping kded / kpasswdserver
    01135     KDEsuClient client;
    01136     int success = client.ping();
    01137     if( success == -1 )
    01138     {
    01139         success = client.startServer();
    01140         if( success == -1 )
    01141         {
    01142             kdDebug(7019) << "Cannot start a new deamon!!" << endl;
    01143             return false;
    01144         }
    01145         kdDebug(7019) << "Sucessfully started new cache deamon!!" << endl;
    01146     }
    01147     return true;
    01148 #else
    01149     return false;
    01150 #endif
    01151 }
    01152
    01153 bool SlaveBase::checkCachedAuthentication( AuthInfo& info )
    01154 {
    01155     QCString replyType;
    01156     QByteArray params;
    01157     QByteArray reply;
    01158     AuthInfo authResult;
    01159     long windowId = metaData("window-id").toLong();
    01160
    01161     kdDebug(7019) << "SlaveBase::checkCachedAuthInfo window = " << windowId << " url = " << info.url.url() << endl;
    01162
    01163     (void) dcopClient(); // Make sure to have a dcop client.
    01164
    01165     QDataStream stream(params, IO_WriteOnly);
    01166     stream << info << windowId;
    01167
    01168     if ( !d->dcopClient->call( "kded", "kpasswdserver", "checkAuthInfo(KIO::AuthInfo, long int)",
    01169                                params, replyType, reply ) )
    01170     {
    01171        kdWarning(7019) << "Can't communicate with kded_kpasswdserver!" << endl;
    01172        return false;
    01173     }
    01174
    01175     if ( replyType == "KIO::AuthInfo" )
    01176     {
    01177        QDataStream stream2( reply, IO_ReadOnly );
    01178        stream2 >> authResult;
    01179     }
    01180     else
    01181     {
    01182        kdError(7019) << "DCOP function checkAuthInfo(...) returns "
    01183                      << replyType << ", expected KIO::AuthInfo" << endl;
    01184        return false;
    01185     }
    01186     if (!authResult.isModified())
    01187     {
    01188        return false;
    01189     }
    01190
    01191     info = authResult;
    01192     return true;
    01193 }
    01194
    01195 bool SlaveBase::cacheAuthentication( const AuthInfo& info )
    01196 {
    01197     QByteArray params;
    01198     long windowId = metaData("window-id").toLong();
    01199
    01200     (void) dcopClient(); // Make sure to have a dcop client.
    01201
    01202     QDataStream stream(params, IO_WriteOnly);
    01203     stream << info << windowId;
    01204
    01205     d->dcopClient->send( "kded", "kpasswdserver", "addAuthInfo(KIO::AuthInfo, long int)", params );
    01206
    01207     return true;
    01208 }
    01209
    01210 int SlaveBase::connectTimeout()
    01211 {
    01212     bool ok;
    01213     QString tmp = metaData("ConnectTimeout");
    01214     int result = tmp.toInt(&ok);
    01215     if (ok)
    01216        return result;
    01217     return DEFAULT_CONNECT_TIMEOUT;
    01218 }
    01219
    01220 int SlaveBase::proxyConnectTimeout()
    01221 {
    01222     bool ok;
    01223     QString tmp = metaData("ProxyConnectTimeout");
    01224     int result = tmp.toInt(&ok);
    01225     if (ok)
    01226        return result;
    01227     return DEFAULT_PROXY_CONNECT_TIMEOUT;
    01228 }
    01229
    01230
    01231 int SlaveBase::responseTimeout()
    01232 {
    01233     bool ok;
    01234     QString tmp = metaData("ResponseTimeout");
    01235     int result = tmp.toInt(&ok);
    01236     if (ok)
    01237        return result;
    01238     return DEFAULT_RESPONSE_TIMEOUT;
    01239 }
    01240
    01241
    01242 int SlaveBase::readTimeout()
    01243 {
    01244     bool ok;
    01245     QString tmp = metaData("ReadTimeout");
    01246     int result = tmp.toInt(&ok);
    01247     if (ok)
    01248        return result;
    01249     return DEFAULT_READ_TIMEOUT;
    01250 }
    01251
    01252 bool SlaveBase::wasKilled() const
    01253 {
    01254    return d->wasKilled;
    01255 }
    01256
    01257 void SlaveBase::setKillFlag()
    01258 {
    01259    d->wasKilled=true;
    01260 }
    01261
    01262 void SlaveBase::virtual_hook( int, void* )
    01263 { /*BASE::virtual_hook( id, data );*/ }
    01264

This file is part of the documentation for kio Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:24:07 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003