# kio Library API Documentation

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

This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 13:14:39 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001