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