• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • kio/kio
 

kio/kio

  • kio
  • kio
slavebase.cpp
1 /*
2  *
3  * This file is part of the KDE libraries
4  * Copyright (c) 2000 Waldo Bastian <bastian@kde.org>
5  * Copyright (c) 2000 David Faure <faure@kde.org>
6  * Copyright (c) 2000 Stephan Kulow <coolo@kde.org>
7  *
8  * $Id$
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Library General Public
12  * License version 2 as published by the Free Software Foundation.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public License
20  * along with this library; see the file COPYING.LIB. If not, write to
21  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  * Boston, MA 02110-1301, USA.
23  *
24  **/
25 
26 #include "slavebase.h"
27 
28 #include <config.h>
29 
30 #include <sys/time.h>
31 #ifdef HAVE_SYS_SELECT_H
32 #include <sys/select.h> // Needed on some systems.
33 #endif
34 
35 #include <assert.h>
36 #include <kdebug.h>
37 #include <stdlib.h>
38 #include <errno.h>
39 #include <unistd.h>
40 #include <signal.h>
41 #include <time.h>
42 
43 #include <tqfile.h>
44 
45 #include <dcopclient.h>
46 
47 #include <kapplication.h>
48 #include <ksock.h>
49 #include <kcrash.h>
50 #include <kdesu/client.h>
51 #include <klocale.h>
52 #include <ksocks.h>
53 
54 #include "kremoteencoding.h"
55 
56 #include "kio/slavebase.h"
57 #include "kio/connection.h"
58 #include "kio/ioslave_defaults.h"
59 #include "kio/slaveinterface.h"
60 
61 #include "uiserver_stub.h"
62 
63 #ifndef NDEBUG
64 #ifdef HAVE_BACKTRACE
65 #include <execinfo.h>
66 #endif
67 #endif
68 
69 using namespace KIO;
70 
71 template class TQPtrList<TQValueList<UDSAtom> >;
72 typedef TQValueList<TQCString> AuthKeysList;
73 typedef TQMap<TQString,TQCString> AuthKeysMap;
74 #define KIO_DATA TQByteArray data; TQDataStream stream( data, IO_WriteOnly ); stream
75 #define KIO_FILESIZE_T(x) (unsigned long)(x & 0xffffffff) << (unsigned long)(x >> 32)
76 
77 namespace KIO {
78 
79 class SlaveBaseConfig : public KConfigBase
80 {
81 public:
82  SlaveBaseConfig(SlaveBase *_slave)
83  : slave(_slave) { }
84 
85  bool internalHasGroup(const TQCString &) const { qWarning("hasGroup(const TQCString &)");
86 return false; }
87 
88  TQStringList groupList() const { return TQStringList(); }
89 
90  TQMap<TQString,TQString> entryMap(const TQString &group) const
91  { Q_UNUSED(group); return TQMap<TQString,TQString>(); }
92 
93  void reparseConfiguration() { }
94 
95  KEntryMap internalEntryMap( const TQString &pGroup) const { Q_UNUSED(pGroup); return KEntryMap(); }
96 
97  KEntryMap internalEntryMap() const { return KEntryMap(); }
98 
99  void putData(const KEntryKey &_key, const KEntry&_data, bool _checkGroup)
100  { Q_UNUSED(_key); Q_UNUSED(_data); Q_UNUSED(_checkGroup); }
101 
102  KEntry lookupData(const KEntryKey &_key) const
103  {
104  KEntry entry;
105  TQString value = slave->metaData(_key.c_key);
106  if (!value.isNull())
107  entry.mValue = value.utf8();
108  return entry;
109  }
110 protected:
111  SlaveBase *slave;
112 };
113 
114 
115 class SlaveBasePrivate {
116 public:
117  TQString slaveid;
118  bool resume:1;
119  bool needSendCanResume:1;
120  bool onHold:1;
121  bool wasKilled:1;
122  MetaData configData;
123  SlaveBaseConfig *config;
124  KURL onHoldUrl;
125 
126  struct timeval last_tv;
127  KIO::filesize_t totalSize;
128  KIO::filesize_t sentListEntries;
129  DCOPClient *dcopClient;
130  KRemoteEncoding *remotefile;
131  time_t timeout;
132  TQByteArray timeoutData;
133 };
134 
135 }
136 
137 static SlaveBase *globalSlave;
138 long SlaveBase::s_seqNr;
139 
140 static volatile bool slaveWriteError = false;
141 
142 static const char *s_protocol;
143 
144 #ifdef Q_OS_UNIX
145 static void genericsig_handler(int sigNumber)
146 {
147  signal(sigNumber,SIG_IGN);
148  //WABA: Don't do anything that requires malloc, we can deadlock on it since
149  //a SIGTERM signal can come in while we are in malloc/free.
150  //kdDebug()<<"kioslave : exiting due to signal "<<sigNumber<<endl;
151  //set the flag which will be checked in dispatchLoop() and which *should* be checked
152  //in lengthy operations in the various slaves
153  if (globalSlave!=0)
154  globalSlave->setKillFlag();
155  signal(SIGALRM,SIG_DFL);
156  alarm(5); //generate an alarm signal in 5 seconds, in this time the slave has to exit
157 }
158 #endif
159 
161 
162 SlaveBase::SlaveBase( const TQCString &protocol,
163  const TQCString &pool_socket,
164  const TQCString &app_socket )
165  : mProtocol(protocol), m_pConnection(0),
166  mPoolSocket( TQFile::decodeName(pool_socket)),
167  mAppSocket( TQFile::decodeName(app_socket))
168 {
169  s_protocol = protocol.data();
170 #ifdef Q_OS_UNIX
171  if (!getenv("KDE_DEBUG"))
172  {
173  KCrash::setCrashHandler( sigsegv_handler );
174  signal(SIGILL,&sigsegv_handler);
175  signal(SIGTRAP,&sigsegv_handler);
176  signal(SIGABRT,&sigsegv_handler);
177  signal(SIGBUS,&sigsegv_handler);
178  signal(SIGALRM,&sigsegv_handler);
179  signal(SIGFPE,&sigsegv_handler);
180 #ifdef SIGPOLL
181  signal(SIGPOLL, &sigsegv_handler);
182 #endif
183 #ifdef SIGSYS
184  signal(SIGSYS, &sigsegv_handler);
185 #endif
186 #ifdef SIGVTALRM
187  signal(SIGVTALRM, &sigsegv_handler);
188 #endif
189 #ifdef SIGXCPU
190  signal(SIGXCPU, &sigsegv_handler);
191 #endif
192 #ifdef SIGXFSZ
193  signal(SIGXFSZ, &sigsegv_handler);
194 #endif
195  }
196 
197  struct sigaction act;
198  act.sa_handler = sigpipe_handler;
199  sigemptyset( &act.sa_mask );
200  act.sa_flags = 0;
201  sigaction( SIGPIPE, &act, 0 );
202 
203  signal(SIGINT,&genericsig_handler);
204  signal(SIGQUIT,&genericsig_handler);
205  signal(SIGTERM,&genericsig_handler);
206 #endif
207 
208  globalSlave=this;
209 
210  appconn = new Connection();
211  listEntryCurrentSize = 100;
212  struct timeval tp;
213  gettimeofday(&tp, 0);
214  listEntry_sec = tp.tv_sec;
215  listEntry_usec = tp.tv_usec;
216  mConnectedToApp = true;
217 
218  d = new SlaveBasePrivate;
219  // by kahl for netmgr (need a way to identify slaves)
220  d->slaveid = protocol;
221  d->slaveid += TQString::number(getpid());
222  d->resume = false;
223  d->needSendCanResume = false;
224  d->config = new SlaveBaseConfig(this);
225  d->onHold = false;
226  d->wasKilled=false;
227  d->last_tv.tv_sec = 0;
228  d->last_tv.tv_usec = 0;
229 // d->processed_size = 0;
230  d->totalSize=0;
231  d->sentListEntries=0;
232  d->timeout = 0;
233  connectSlave(mAppSocket);
234 
235  d->dcopClient = 0;
236  d->remotefile = 0;
237 }
238 
239 SlaveBase::~SlaveBase()
240 {
241  delete d;
242  s_protocol = "";
243 }
244 
245 DCOPClient *SlaveBase::dcopClient()
246 {
247  if (!d->dcopClient)
248  {
249  d->dcopClient = KApplication::dcopClient();
250  if (!d->dcopClient->isAttached())
251  d->dcopClient->attach();
252  d->dcopClient->setDaemonMode( true );
253  }
254  return d->dcopClient;
255 }
256 
257 void SlaveBase::dispatchLoop()
258 {
259 #ifdef Q_OS_UNIX //TODO: WIN32
260  fd_set rfds;
261  int retval;
262 
263  while (true)
264  {
265  if (d->timeout && (d->timeout < time(0)))
266  {
267  TQByteArray data = d->timeoutData;
268  d->timeout = 0;
269  d->timeoutData = TQByteArray();
270  special(data);
271  }
272  FD_ZERO(&rfds);
273 
274  assert(appconn->inited());
275  int maxfd = appconn->fd_from();
276  FD_SET(appconn->fd_from(), &rfds);
277  if( d->dcopClient )
278  {
279  FD_SET( d->dcopClient->socket(), &rfds );
280  if( d->dcopClient->socket() > maxfd )
281  maxfd = d->dcopClient->socket();
282  }
283 
284  if (!d->timeout) // we can wait forever
285  {
286  retval = select( maxfd + 1, &rfds, NULL, NULL, NULL);
287  }
288  else
289  {
290  struct timeval tv;
291  tv.tv_sec = kMax(d->timeout-time(0),(time_t) 1);
292  tv.tv_usec = 0;
293  retval = select( maxfd + 1, &rfds, NULL, NULL, &tv);
294  }
295  if ((retval>0) && FD_ISSET(appconn->fd_from(), &rfds))
296  { // dispatch application messages
297  int cmd;
298  TQByteArray data;
299  if ( appconn->read(&cmd, data) != -1 )
300  {
301  dispatch(cmd, data);
302  }
303  else // some error occurred, perhaps no more application
304  {
305  // When the app exits, should the slave be put back in the pool ?
306  if (mConnectedToApp && !mPoolSocket.isEmpty())
307  {
308  disconnectSlave();
309  mConnectedToApp = false;
310  closeConnection();
311  connectSlave(mPoolSocket);
312  }
313  else
314  {
315  return;
316  }
317  }
318  }
319  if( retval > 0 && d->dcopClient && FD_ISSET( d->dcopClient->socket(), &rfds ))
320  {
321  d->dcopClient->processSocketData( d->dcopClient->socket());
322  }
323  if ((retval<0) && (errno != EINTR))
324  {
325  kdDebug(7019) << "dispatchLoop(): select returned " << retval << " "
326  << (errno==EBADF?"EBADF":errno==EINTR?"EINTR":errno==EINVAL?"EINVAL":errno==ENOMEM?"ENOMEM":"unknown")
327  << " (" << errno << ")" << endl;
328  return;
329  }
330  //I think we get here when we were killed in dispatch() and not in select()
331  if (wasKilled())
332  {
333  kdDebug(7019)<<" dispatchLoop() slave was killed, returning"<<endl;
334  return;
335  }
336  }
337 #else
338 #error The KIO slave system only works under UNIX
339 #endif
340 }
341 
342 void SlaveBase::connectSlave(const TQString& path)
343 {
344 #ifdef Q_OS_UNIX //TODO: KSocket not yet available on WIN32
345  appconn->init(new KSocket(TQFile::encodeName(path).data()));
346  if (!appconn->inited())
347  {
348  kdDebug(7019) << "SlaveBase: failed to connect to " << path << endl;
349  exit();
350  }
351 
352  setConnection(appconn);
353 #endif
354 }
355 
356 void SlaveBase::disconnectSlave()
357 {
358  appconn->close();
359 }
360 
361 void SlaveBase::setMetaData(const TQString &key, const TQString &value)
362 {
363  mOutgoingMetaData.replace(key, value);
364 }
365 
366 TQString SlaveBase::metaData(const TQString &key) const
367 {
368  if (mIncomingMetaData.contains(key))
369  return mIncomingMetaData[key];
370  if (d->configData.contains(key))
371  return d->configData[key];
372  return TQString::null;
373 }
374 
375 bool SlaveBase::hasMetaData(const TQString &key) const
376 {
377  if (mIncomingMetaData.contains(key))
378  return true;
379  if (d->configData.contains(key))
380  return true;
381  return false;
382 }
383 
384 // ### remove the next two methods for KDE4 (they miss the const)
385 TQString SlaveBase::metaData(const TQString &key) {
386  return const_cast<const SlaveBase*>(this)->metaData( key );
387 }
388 bool SlaveBase::hasMetaData(const TQString &key) {
389  return const_cast<const SlaveBase*>(this)->hasMetaData( key );
390 }
391 
392 KConfigBase *SlaveBase::config()
393 {
394  return d->config;
395 }
396 
397 void SlaveBase::sendMetaData()
398 {
399  KIO_DATA << mOutgoingMetaData;
400 
401  slaveWriteError = false;
402  m_pConnection->send( INF_META_DATA, data );
403  if (slaveWriteError) exit();
404  mOutgoingMetaData.clear(); // Clear
405 }
406 
407 KRemoteEncoding *SlaveBase::remoteEncoding()
408 {
409  if (d->remotefile != 0)
410  return d->remotefile;
411 
412  return d->remotefile = new KRemoteEncoding(metaData("Charset").latin1());
413 }
414 
415 void SlaveBase::data( const TQByteArray &data )
416 {
417  if (!mOutgoingMetaData.isEmpty())
418  sendMetaData();
419  slaveWriteError = false;
420  m_pConnection->send( MSG_DATA, data );
421  if (slaveWriteError) exit();
422 }
423 
424 void SlaveBase::dataReq( )
425 {
426 /*
427  if (!mOutgoingMetaData.isEmpty())
428  sendMetaData();
429 */
430  if (d->needSendCanResume)
431  canResume(0);
432  m_pConnection->send( MSG_DATA_REQ );
433 }
434 
435 void SlaveBase::error( int _errid, const TQString &_text )
436 {
437  mIncomingMetaData.clear(); // Clear meta data
438  mOutgoingMetaData.clear();
439  KIO_DATA << (TQ_INT32) _errid << _text;
440 
441  m_pConnection->send( MSG_ERROR, data );
442  //reset
443  listEntryCurrentSize = 100;
444  d->sentListEntries=0;
445  d->totalSize=0;
446 }
447 
448 void SlaveBase::connected()
449 {
450  slaveWriteError = false;
451  m_pConnection->send( MSG_CONNECTED );
452  if (slaveWriteError) exit();
453 }
454 
455 void SlaveBase::finished()
456 {
457  mIncomingMetaData.clear(); // Clear meta data
458  if (!mOutgoingMetaData.isEmpty())
459  sendMetaData();
460  m_pConnection->send( MSG_FINISHED );
461 
462  // reset
463  listEntryCurrentSize = 100;
464  d->sentListEntries=0;
465  d->totalSize=0;
466 }
467 
468 void SlaveBase::needSubURLData()
469 {
470  m_pConnection->send( MSG_NEED_SUBURL_DATA );
471 }
472 
473 void SlaveBase::slaveStatus( const TQString &host, bool connected )
474 {
475  pid_t pid = getpid();
476  TQ_INT8 b = connected ? 1 : 0;
477  KIO_DATA << pid << mProtocol << host << b;
478  if (d->onHold)
479  stream << d->onHoldUrl;
480  m_pConnection->send( MSG_SLAVE_STATUS, data );
481 }
482 
483 void SlaveBase::canResume()
484 {
485  m_pConnection->send( MSG_CANRESUME );
486 }
487 
488 void SlaveBase::totalSize( KIO::filesize_t _bytes )
489 {
490  KIO_DATA << KIO_FILESIZE_T(_bytes);
491  slaveWriteError = false;
492  m_pConnection->send( INF_TOTAL_SIZE, data );
493  if (slaveWriteError) exit();
494 
495  //this one is usually called before the first item is listed in listDir()
496  struct timeval tp;
497  gettimeofday(&tp, 0);
498  listEntry_sec = tp.tv_sec;
499  listEntry_usec = tp.tv_usec;
500  d->totalSize=_bytes;
501  d->sentListEntries=0;
502 }
503 
504 void SlaveBase::processedSize( KIO::filesize_t _bytes )
505 {
506  bool emitSignal=false;
507  struct timeval tv;
508  int gettimeofday_res=gettimeofday( &tv, 0L );
509 
510  if( _bytes == d->totalSize )
511  emitSignal=true;
512  else if ( gettimeofday_res == 0 ) {
513  time_t msecdiff = 2000;
514  if (d->last_tv.tv_sec) {
515  // Compute difference, in ms
516  msecdiff = 1000 * ( tv.tv_sec - d->last_tv.tv_sec );
517  time_t usecdiff = tv.tv_usec - d->last_tv.tv_usec;
518  if ( usecdiff < 0 ) {
519  msecdiff--;
520  msecdiff += 1000;
521  }
522  msecdiff += usecdiff / 1000;
523  }
524  emitSignal=msecdiff >= 100; // emit size 10 times a second
525  }
526 
527  if( emitSignal ) {
528  KIO_DATA << KIO_FILESIZE_T(_bytes);
529  slaveWriteError = false;
530  m_pConnection->send( INF_PROCESSED_SIZE, data );
531  if (slaveWriteError) exit();
532  if ( gettimeofday_res == 0 ) {
533  d->last_tv.tv_sec = tv.tv_sec;
534  d->last_tv.tv_usec = tv.tv_usec;
535  }
536  }
537 // d->processed_size = _bytes;
538 }
539 
540 void SlaveBase::processedPercent( float /* percent */ )
541 {
542  kdDebug(7019) << "SlaveBase::processedPercent: STUB" << endl;
543 }
544 
545 
546 void SlaveBase::speed( unsigned long _bytes_per_second )
547 {
548  KIO_DATA << (TQ_UINT32) _bytes_per_second;
549  slaveWriteError = false;
550  m_pConnection->send( INF_SPEED, data );
551  if (slaveWriteError) exit();
552 }
553 
554 void SlaveBase::redirection( const KURL& _url )
555 {
556  KIO_DATA << _url;
557  m_pConnection->send( INF_REDIRECTION, data );
558 }
559 
560 void SlaveBase::errorPage()
561 {
562  m_pConnection->send( INF_ERROR_PAGE );
563 }
564 
565 static bool isSubCommand(int cmd)
566 {
567  return ( (cmd == CMD_REPARSECONFIGURATION) ||
568  (cmd == CMD_META_DATA) ||
569  (cmd == CMD_CONFIG) ||
570  (cmd == CMD_SUBURL) ||
571  (cmd == CMD_SLAVE_STATUS) ||
572  (cmd == CMD_SLAVE_CONNECT) ||
573  (cmd == CMD_SLAVE_HOLD) ||
574  (cmd == CMD_MULTI_GET));
575 }
576 
577 void SlaveBase::mimeType( const TQString &_type)
578 {
579  // kdDebug(7019) << "(" << getpid() << ") SlaveBase::mimeType '" << _type << "'" << endl;
580  int cmd;
581  do
582  {
583  // Send the meta-data each time we send the mime-type.
584  if (!mOutgoingMetaData.isEmpty())
585  {
586  // kdDebug(7019) << "(" << getpid() << ") mimeType: emitting meta data" << endl;
587  KIO_DATA << mOutgoingMetaData;
588  m_pConnection->send( INF_META_DATA, data );
589  }
590  KIO_DATA << _type;
591  m_pConnection->send( INF_MIME_TYPE, data );
592  while(true)
593  {
594  cmd = 0;
595  if ( m_pConnection->read( &cmd, data ) == -1 ) {
596  kdDebug(7019) << "SlaveBase: mimetype: read error" << endl;
597  exit();
598  }
599  // kdDebug(7019) << "(" << getpid() << ") Slavebase: mimetype got " << cmd << endl;
600  if ( cmd == CMD_HOST) // Ignore.
601  continue;
602  if ( isSubCommand(cmd) )
603  {
604  dispatch( cmd, data );
605  continue; // Disguised goto
606  }
607  break;
608  }
609  }
610  while (cmd != CMD_NONE);
611  mOutgoingMetaData.clear();
612 }
613 
614 void SlaveBase::exit()
615 {
616  this->~SlaveBase();
617  ::exit(255);
618 }
619 
620 void SlaveBase::warning( const TQString &_msg)
621 {
622  KIO_DATA << _msg;
623  m_pConnection->send( INF_WARNING, data );
624 }
625 
626 void SlaveBase::infoMessage( const TQString &_msg)
627 {
628  KIO_DATA << _msg;
629  m_pConnection->send( INF_INFOMESSAGE, data );
630 }
631 
632 bool SlaveBase::requestNetwork(const TQString& host)
633 {
634  KIO_DATA << host << d->slaveid;
635  m_pConnection->send( MSG_NET_REQUEST, data );
636 
637  if ( waitForAnswer( INF_NETWORK_STATUS, 0, data ) != -1 )
638  {
639  bool status;
640  TQDataStream stream( data, IO_ReadOnly );
641  stream >> status;
642  return status;
643  } else
644  return false;
645 }
646 
647 void SlaveBase::dropNetwork(const TQString& host)
648 {
649  KIO_DATA << host << d->slaveid;
650  m_pConnection->send( MSG_NET_DROP, data );
651 }
652 
653 void SlaveBase::statEntry( const UDSEntry& entry )
654 {
655  KIO_DATA << entry;
656  slaveWriteError = false;
657  m_pConnection->send( MSG_STAT_ENTRY, data );
658  if (slaveWriteError) exit();
659 }
660 
661 void SlaveBase::listEntry( const UDSEntry& entry, bool _ready )
662 {
663  static struct timeval tp;
664  static const int maximum_updatetime = 300;
665  static const int minimum_updatetime = 100;
666 
667  if (!_ready) {
668  pendingListEntries.append(entry);
669 
670  if (pendingListEntries.count() > listEntryCurrentSize) {
671  gettimeofday(&tp, 0);
672 
673  long diff = ((tp.tv_sec - listEntry_sec) * 1000000 +
674  tp.tv_usec - listEntry_usec) / 1000;
675  if (diff==0) diff=1;
676 
677  if (diff > maximum_updatetime) {
678  listEntryCurrentSize = listEntryCurrentSize * 3 / 4;
679  _ready = true;
680  }
681 //if we can send all list entries of this dir which have not yet been sent
682 //within maximum_updatetime, then make listEntryCurrentSize big enough for all of them
683  else if (((pendingListEntries.count()*maximum_updatetime)/diff) > (d->totalSize-d->sentListEntries))
684  listEntryCurrentSize=d->totalSize-d->sentListEntries+1;
685 //if we are below minimum_updatetime, estimate how much we will get within
686 //maximum_updatetime
687  else if (diff < minimum_updatetime)
688  listEntryCurrentSize = (pendingListEntries.count() * maximum_updatetime) / diff;
689  else
690  _ready=true;
691  }
692  }
693  if (_ready) { // may happen when we started with !ready
694  listEntries( pendingListEntries );
695  pendingListEntries.clear();
696 
697  gettimeofday(&tp, 0);
698  listEntry_sec = tp.tv_sec;
699  listEntry_usec = tp.tv_usec;
700  }
701 }
702 
703 void SlaveBase::listEntries( const UDSEntryList& list )
704 {
705  KIO_DATA << (TQ_UINT32)list.count();
706  UDSEntryListConstIterator it = list.begin();
707  UDSEntryListConstIterator end = list.end();
708  for (; it != end; ++it)
709  stream << *it;
710  slaveWriteError = false;
711  m_pConnection->send( MSG_LIST_ENTRIES, data);
712  if (slaveWriteError) exit();
713  d->sentListEntries+=(uint)list.count();
714 }
715 
716 void SlaveBase::sendAuthenticationKey( const TQCString& key,
717  const TQCString& group,
718  bool keepPass )
719 {
720  KIO_DATA << key << group << keepPass;
721  m_pConnection->send( MSG_AUTH_KEY, data );
722 }
723 
724 void SlaveBase::delCachedAuthentication( const TQString& key )
725 {
726  KIO_DATA << key.utf8() ;
727  m_pConnection->send( MSG_DEL_AUTH_KEY, data );
728 }
729 
730 void SlaveBase::sigsegv_handler(int sig)
731 {
732 #ifdef Q_OS_UNIX
733  signal(sig,SIG_DFL); // Next one kills
734 
735  //Kill us if we deadlock
736  signal(SIGALRM,SIG_DFL);
737  alarm(5); //generate an alarm signal in 5 seconds, in this time the slave has to exit
738 
739  // Debug and printf should be avoided because they might
740  // call malloc.. and get in a nice recursive malloc loop
741  char buffer[120];
742  snprintf(buffer, sizeof(buffer), "kioslave: ####### CRASH ###### protocol = %s pid = %d signal = %d\n", s_protocol, getpid(), sig);
743  write(2, buffer, strlen(buffer));
744 #ifndef NDEBUG
745 #ifdef HAVE_BACKTRACE
746  void* trace[256];
747  int n = backtrace(trace, 256);
748  if (n)
749  backtrace_symbols_fd(trace, n, 2);
750 #endif
751 #endif
752  ::exit(1);
753 #endif
754 }
755 
756 void SlaveBase::sigpipe_handler (int)
757 {
758  // We ignore a SIGPIPE in slaves.
759  // A SIGPIPE can happen in two cases:
760  // 1) Communication error with application.
761  // 2) Communication error with network.
762  slaveWriteError = true;
763 
764  // Don't add anything else here, especially no debug output
765 }
766 
767 void SlaveBase::setHost(TQString const &, int, TQString const &, TQString const &)
768 {
769 }
770 
771 void SlaveBase::openConnection(void)
772 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_CONNECT)); }
773 void SlaveBase::closeConnection(void)
774 { } // No response!
775 void SlaveBase::stat(KURL const &)
776 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_STAT)); }
777 void SlaveBase::put(KURL const &, int, bool, bool)
778 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_PUT)); }
779 void SlaveBase::special(const TQByteArray &)
780 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_SPECIAL)); }
781 void SlaveBase::listDir(KURL const &)
782 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_LISTDIR)); }
783 void SlaveBase::get(KURL const & )
784 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_GET)); }
785 void SlaveBase::mimetype(KURL const &url)
786 { get(url); }
787 void SlaveBase::rename(KURL const &, KURL const &, bool)
788 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_RENAME)); }
789 void SlaveBase::symlink(TQString const &, KURL const &, bool)
790 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_SYMLINK)); }
791 void SlaveBase::copy(KURL const &, KURL const &, int, bool)
792 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_COPY)); }
793 void SlaveBase::del(KURL const &, bool)
794 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_DEL)); }
795 void SlaveBase::mkdir(KURL const &, int)
796 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_MKDIR)); }
797 void SlaveBase::chmod(KURL const &, int)
798 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_CHMOD)); }
799 void SlaveBase::setSubURL(KURL const &)
800 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_SUBURL)); }
801 void SlaveBase::multiGet(const TQByteArray &)
802 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_MULTI_GET)); }
803 
804 
805 void SlaveBase::slave_status()
806 { slaveStatus( TQString::null, false ); }
807 
808 void SlaveBase::reparseConfiguration()
809 {
810 }
811 
812 bool SlaveBase::dispatch()
813 {
814  assert( m_pConnection );
815 
816  int cmd;
817  TQByteArray data;
818  if ( m_pConnection->read( &cmd, data ) == -1 )
819  {
820  kdDebug(7019) << "SlaveBase::dispatch() has read error." << endl;
821  return false;
822  }
823 
824  dispatch( cmd, data );
825  return true;
826 }
827 
828 bool SlaveBase::openPassDlg( AuthInfo& info )
829 {
830  return openPassDlg(info, TQString::null);
831 }
832 
833 bool SlaveBase::openPassDlg( AuthInfo& info, const TQString &errorMsg )
834 {
835  TQCString replyType;
836  TQByteArray params;
837  TQByteArray reply;
838  AuthInfo authResult;
839  long windowId = metaData("window-id").toLong();
840  long progressId = metaData("progress-id").toLong();
841  unsigned long userTimestamp = metaData("user-timestamp").toULong();
842 
843  kdDebug(7019) << "SlaveBase::openPassDlg window-id=" << windowId << " progress-id=" << progressId << endl;
844 
845  (void) dcopClient(); // Make sure to have a dcop client.
846 
847  UIServer_stub uiserver( "kio_uiserver", "UIServer" );
848  if (progressId)
849  uiserver.setJobVisible( progressId, false );
850 
851  TQDataStream stream(params, IO_WriteOnly);
852 
853  if (metaData("no-auth-prompt").lower() == "true")
854  stream << info << TQString("<NoAuthPrompt>") << windowId << s_seqNr << userTimestamp;
855  else
856  stream << info << errorMsg << windowId << s_seqNr << userTimestamp;
857 
858  bool callOK = d->dcopClient->call( "kded", "kpasswdserver", "queryAuthInfo(KIO::AuthInfo, TQString, long int, long int, unsigned long int)",
859  params, replyType, reply );
860 
861  if (progressId)
862  uiserver.setJobVisible( progressId, true );
863 
864  if (!callOK)
865  {
866  kdWarning(7019) << "Can't communicate with kded_kpasswdserver!" << endl;
867  return false;
868  }
869 
870  if ( replyType == "KIO::AuthInfo" )
871  {
872  TQDataStream stream2( reply, IO_ReadOnly );
873  stream2 >> authResult >> s_seqNr;
874  }
875  else
876  {
877  kdError(7019) << "DCOP function queryAuthInfo(...) returns "
878  << replyType << ", expected KIO::AuthInfo" << endl;
879  return false;
880  }
881 
882  if (!authResult.isModified())
883  return false;
884 
885  info = authResult;
886 
887  kdDebug(7019) << "SlaveBase::openPassDlg: username=" << info.username << endl;
888  kdDebug(7019) << "SlaveBase::openPassDlg: password=[hidden]" << endl;
889 
890  return true;
891 }
892 
893 int SlaveBase::messageBox( MessageBoxType type, const TQString &text, const TQString &caption,
894  const TQString &buttonYes, const TQString &buttonNo )
895 {
896  return messageBox( text, type, caption, buttonYes, buttonNo, TQString::null );
897 }
898 
899 int SlaveBase::messageBox( const TQString &text, MessageBoxType type, const TQString &caption,
900  const TQString &buttonYes, const TQString &buttonNo, const TQString &dontAskAgainName )
901 {
902  kdDebug(7019) << "messageBox " << type << " " << text << " - " << caption << buttonYes << buttonNo << endl;
903  KIO_DATA << (TQ_INT32)type << text << caption << buttonYes << buttonNo << dontAskAgainName;
904  m_pConnection->send( INF_MESSAGEBOX, data );
905  if ( waitForAnswer( CMD_MESSAGEBOXANSWER, 0, data ) != -1 )
906  {
907  TQDataStream stream( data, IO_ReadOnly );
908  int answer;
909  stream >> answer;
910  kdDebug(7019) << "got messagebox answer" << answer << endl;
911  return answer;
912  } else
913  return 0; // communication failure
914 }
915 
916 bool SlaveBase::canResume( KIO::filesize_t offset )
917 {
918  kdDebug(7019) << "SlaveBase::canResume offset=" << KIO::number(offset) << endl;
919  d->needSendCanResume = false;
920  KIO_DATA << KIO_FILESIZE_T(offset);
921  m_pConnection->send( MSG_RESUME, data );
922  if ( offset )
923  {
924  int cmd;
925  if ( waitForAnswer( CMD_RESUMEANSWER, CMD_NONE, data, &cmd ) != -1 )
926  {
927  kdDebug(7019) << "SlaveBase::canResume returning " << (cmd == CMD_RESUMEANSWER) << endl;
928  return cmd == CMD_RESUMEANSWER;
929  } else
930  return false;
931  }
932  else // No resuming possible -> no answer to wait for
933  return true;
934 }
935 
936 
937 
938 int SlaveBase::waitForAnswer( int expected1, int expected2, TQByteArray & data, int *pCmd )
939 {
940  int cmd, result;
941  for (;;)
942  {
943  result = m_pConnection->read( &cmd, data );
944  if ( result == -1 )
945  {
946  kdDebug(7019) << "SlaveBase::waitForAnswer has read error." << endl;
947  return -1;
948  }
949  if ( cmd == expected1 || cmd == expected2 )
950  {
951  if ( pCmd ) *pCmd = cmd;
952  return result;
953  }
954  if ( isSubCommand(cmd) )
955  {
956  dispatch( cmd, data );
957  }
958  else
959  {
960  kdWarning() << "Got cmd " << cmd << " while waiting for an answer!" << endl;
961  }
962  }
963 }
964 
965 
966 int SlaveBase::readData( TQByteArray &buffer)
967 {
968  int result = waitForAnswer( MSG_DATA, 0, buffer );
969  //kdDebug(7019) << "readData: length = " << result << " " << endl;
970  return result;
971 }
972 
973 void SlaveBase::setTimeoutSpecialCommand(int timeout, const TQByteArray &data)
974 {
975  if (timeout > 0)
976  d->timeout = time(0)+(time_t)timeout;
977  else if (timeout == 0)
978  d->timeout = 1; // Immediate timeout
979  else
980  d->timeout = 0; // Canceled
981 
982  d->timeoutData = data;
983 }
984 
985 void SlaveBase::dispatch( int command, const TQByteArray &data )
986 {
987  TQDataStream stream( data, IO_ReadOnly );
988 
989  KURL url;
990  int i;
991 
992  switch( command ) {
993  case CMD_HOST: {
994  // Reset s_seqNr, see kpasswdserver/DESIGN
995  s_seqNr = 0;
996  TQString passwd;
997  TQString host, user;
998  stream >> host >> i >> user >> passwd;
999  setHost( host, i, user, passwd );
1000  }
1001  break;
1002  case CMD_CONNECT:
1003  openConnection( );
1004  break;
1005  case CMD_DISCONNECT:
1006  closeConnection( );
1007  break;
1008  case CMD_SLAVE_STATUS:
1009  slave_status();
1010  break;
1011  case CMD_SLAVE_CONNECT:
1012  {
1013  d->onHold = false;
1014  TQString app_socket;
1015  TQDataStream stream( data, IO_ReadOnly);
1016  stream >> app_socket;
1017  appconn->send( MSG_SLAVE_ACK );
1018  disconnectSlave();
1019  mConnectedToApp = true;
1020  connectSlave(app_socket);
1021  } break;
1022  case CMD_SLAVE_HOLD:
1023  {
1024  KURL url;
1025  TQDataStream stream( data, IO_ReadOnly);
1026  stream >> url;
1027  d->onHoldUrl = url;
1028  d->onHold = true;
1029  disconnectSlave();
1030  mConnectedToApp = false;
1031  // Do not close connection!
1032  connectSlave(mPoolSocket);
1033  } break;
1034  case CMD_REPARSECONFIGURATION:
1035  reparseConfiguration();
1036  break;
1037  case CMD_CONFIG:
1038  stream >> d->configData;
1039 #ifdef Q_OS_UNIX //TODO: not yet available on WIN32
1040  KSocks::setConfig(d->config);
1041 #endif
1042  delete d->remotefile;
1043  d->remotefile = 0;
1044  break;
1045  case CMD_GET:
1046  {
1047  stream >> url;
1048  get( url );
1049  } break;
1050  case CMD_PUT:
1051  {
1052  int permissions;
1053  TQ_INT8 iOverwrite, iResume;
1054  stream >> url >> iOverwrite >> iResume >> permissions;
1055  bool overwrite = ( iOverwrite != 0 );
1056  bool resume = ( iResume != 0 );
1057 
1058  // Remember that we need to send canResume(), TransferJob is expecting
1059  // it. Well, in theory this shouldn't be done if resume is true.
1060  // (the resume bool is currently unused)
1061  d->needSendCanResume = true /* !resume */;
1062 
1063  put( url, permissions, overwrite, resume);
1064  } break;
1065  case CMD_STAT:
1066  stream >> url;
1067  stat( url );
1068  break;
1069  case CMD_MIMETYPE:
1070  stream >> url;
1071  mimetype( url );
1072  break;
1073  case CMD_LISTDIR:
1074  stream >> url;
1075  listDir( url );
1076  break;
1077  case CMD_MKDIR:
1078  stream >> url >> i;
1079  mkdir( url, i );
1080  break;
1081  case CMD_RENAME:
1082  {
1083  TQ_INT8 iOverwrite;
1084  KURL url2;
1085  stream >> url >> url2 >> iOverwrite;
1086  bool overwrite = (iOverwrite != 0);
1087  rename( url, url2, overwrite );
1088  } break;
1089  case CMD_SYMLINK:
1090  {
1091  TQ_INT8 iOverwrite;
1092  TQString target;
1093  stream >> target >> url >> iOverwrite;
1094  bool overwrite = (iOverwrite != 0);
1095  symlink( target, url, overwrite );
1096  } break;
1097  case CMD_COPY:
1098  {
1099  int permissions;
1100  TQ_INT8 iOverwrite;
1101  KURL url2;
1102  stream >> url >> url2 >> permissions >> iOverwrite;
1103  bool overwrite = (iOverwrite != 0);
1104  copy( url, url2, permissions, overwrite );
1105  } break;
1106  case CMD_DEL:
1107  {
1108  TQ_INT8 isFile;
1109  stream >> url >> isFile;
1110  del( url, isFile != 0);
1111  } break;
1112  case CMD_CHMOD:
1113  stream >> url >> i;
1114  chmod( url, i);
1115  break;
1116  case CMD_SPECIAL:
1117  special( data );
1118  break;
1119  case CMD_META_DATA:
1120  //kdDebug(7019) << "(" << getpid() << ") Incoming meta-data..." << endl;
1121  stream >> mIncomingMetaData;
1122  break;
1123  case CMD_SUBURL:
1124  stream >> url;
1125  setSubURL(url);
1126  break;
1127  case CMD_NONE:
1128  fprintf(stderr, "Got unexpected CMD_NONE!\n");
1129  break;
1130  case CMD_MULTI_GET:
1131  multiGet( data );
1132  break;
1133  default:
1134  // Some command we don't understand.
1135  // Just ignore it, it may come from some future version of KDE.
1136  break;
1137  }
1138 }
1139 
1140 TQString SlaveBase::createAuthCacheKey( const KURL& url )
1141 {
1142  if( !url.isValid() )
1143  return TQString::null;
1144 
1145  // Generate the basic key sequence.
1146  TQString key = url.protocol();
1147  key += '-';
1148  key += url.host();
1149  int port = url.port();
1150  if( port )
1151  {
1152  key += ':';
1153  key += TQString::number(port);
1154  }
1155 
1156  return key;
1157 }
1158 
1159 bool SlaveBase::pingCacheDaemon() const
1160 {
1161 #ifdef Q_OS_UNIX
1162  // TODO: Ping kded / kpasswdserver
1163  KDEsuClient client;
1164  int success = client.ping();
1165  if( success == -1 )
1166  {
1167  success = client.startServer();
1168  if( success == -1 )
1169  {
1170  kdDebug(7019) << "Cannot start a new deamon!!" << endl;
1171  return false;
1172  }
1173  kdDebug(7019) << "Sucessfully started new cache deamon!!" << endl;
1174  }
1175  return true;
1176 #else
1177  return false;
1178 #endif
1179 }
1180 
1181 bool SlaveBase::checkCachedAuthentication( AuthInfo& info )
1182 {
1183  TQCString replyType;
1184  TQByteArray params;
1185  TQByteArray reply;
1186  AuthInfo authResult;
1187  long windowId = metaData("window-id").toLong();
1188  unsigned long userTimestamp = metaData("user-timestamp").toULong();
1189 
1190  kdDebug(7019) << "SlaveBase::checkCachedAuthInfo window = " << windowId << " url = " << info.url.url() << endl;
1191 
1192  (void) dcopClient(); // Make sure to have a dcop client.
1193 
1194  TQDataStream stream(params, IO_WriteOnly);
1195  stream << info << windowId << userTimestamp;
1196 
1197  if ( !d->dcopClient->call( "kded", "kpasswdserver", "checkAuthInfo(KIO::AuthInfo, long int, unsigned long int)",
1198  params, replyType, reply ) )
1199  {
1200  kdWarning(7019) << "Can't communicate with kded_kpasswdserver!" << endl;
1201  return false;
1202  }
1203 
1204  if ( replyType == "KIO::AuthInfo" )
1205  {
1206  TQDataStream stream2( reply, IO_ReadOnly );
1207  stream2 >> authResult;
1208  }
1209  else
1210  {
1211  kdError(7019) << "DCOP function checkAuthInfo(...) returns "
1212  << replyType << ", expected KIO::AuthInfo" << endl;
1213  return false;
1214  }
1215  if (!authResult.isModified())
1216  {
1217  return false;
1218  }
1219 
1220  info = authResult;
1221  return true;
1222 }
1223 
1224 bool SlaveBase::cacheAuthentication( const AuthInfo& info )
1225 {
1226  TQByteArray params;
1227  long windowId = metaData("window-id").toLong();
1228 
1229  (void) dcopClient(); // Make sure to have a dcop client.
1230 
1231  TQDataStream stream(params, IO_WriteOnly);
1232  stream << info << windowId;
1233 
1234  d->dcopClient->send( "kded", "kpasswdserver", "addAuthInfo(KIO::AuthInfo, long int)", params );
1235 
1236  return true;
1237 }
1238 
1239 int SlaveBase::connectTimeout()
1240 {
1241  bool ok;
1242  TQString tmp = metaData("ConnectTimeout");
1243  int result = tmp.toInt(&ok);
1244  if (ok)
1245  return result;
1246  return DEFAULT_CONNECT_TIMEOUT;
1247 }
1248 
1249 int SlaveBase::proxyConnectTimeout()
1250 {
1251  bool ok;
1252  TQString tmp = metaData("ProxyConnectTimeout");
1253  int result = tmp.toInt(&ok);
1254  if (ok)
1255  return result;
1256  return DEFAULT_PROXY_CONNECT_TIMEOUT;
1257 }
1258 
1259 
1260 int SlaveBase::responseTimeout()
1261 {
1262  bool ok;
1263  TQString tmp = metaData("ResponseTimeout");
1264  int result = tmp.toInt(&ok);
1265  if (ok)
1266  return result;
1267  return DEFAULT_RESPONSE_TIMEOUT;
1268 }
1269 
1270 
1271 int SlaveBase::readTimeout()
1272 {
1273  bool ok;
1274  TQString tmp = metaData("ReadTimeout");
1275  int result = tmp.toInt(&ok);
1276  if (ok)
1277  return result;
1278  return DEFAULT_READ_TIMEOUT;
1279 }
1280 
1281 bool SlaveBase::wasKilled() const
1282 {
1283  return d->wasKilled;
1284 }
1285 
1286 void SlaveBase::setKillFlag()
1287 {
1288  d->wasKilled=true;
1289 }
1290 
1291 void SlaveBase::virtual_hook( int, void* )
1292 { /*BASE::virtual_hook( id, data );*/ }
1293 

kio/kio

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

kio/kio

Skip menu "kio/kio"
  • arts
  • dcop
  • dnssd
  • interfaces
  •     interface
  •     library
  •   kspeech
  •   ktexteditor
  • kabc
  • kate
  • kcmshell
  • kdecore
  • kded
  • kdefx
  • kdeprint
  • kdesu
  • kdeui
  • kdoctools
  • khtml
  • kimgio
  • kinit
  • kio
  •   bookmarks
  •   httpfilter
  •   kfile
  •   kio
  •   kioexec
  •   kpasswdserver
  •   kssl
  • kioslave
  •   http
  • kjs
  • kmdi
  •   kmdi
  • knewstuff
  • kparts
  • krandr
  • kresources
  • kspell2
  • kunittest
  • kutils
  • kwallet
  • libkmid
  • libkscreensaver
Generated for kio/kio by doxygen 1.8.3.1
This website is maintained by Timothy Pearson.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. |