• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

kio

slavebase.cpp

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

kio

Skip menu "kio"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal