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

tdeio/tdeio

  • tdeio
  • tdeio
slave.cpp
1 /*
2  * This file is part of the KDE libraries
3  * Copyright (c) 2000 Waldo Bastian <bastian@kde.org>
4  * 2000 Stephan Kulow <coolo@kde.org>
5  *
6  * $Id$
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License version 2 as published by the Free Software Foundation.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public License
18  * along with this library; see the file COPYING.LIB. If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  **/
22 
23 #include <config.h>
24 
25 #include <time.h>
26 #include <errno.h>
27 #include <unistd.h>
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <signal.h>
31 #include <sys/types.h>
32 
33 #include <tqfile.h>
34 #include <tqtimer.h>
35 
36 #include <dcopclient.h>
37 #include <kdebug.h>
38 #include <tdelocale.h>
39 #include <tdeglobal.h>
40 #include <kstandarddirs.h>
41 #include <tdeapplication.h>
42 #include <tdetempfile.h>
43 #include <ksock.h>
44 #include <kprocess.h>
45 #include <klibloader.h>
46 
47 #include "tdeio/dataprotocol.h"
48 #include "tdeio/slave.h"
49 #include "tdeio/kservice.h"
50 #include <tdeio/global.h>
51 #include <tdeprotocolmanager.h>
52 #include <kprotocolinfo.h>
53 
54 #ifdef HAVE_PATHS_H
55 #include <paths.h>
56 #endif
57 
58 #ifndef _PATH_TMP
59 #define _PATH_TMP "/tmp"
60 #endif
61 
62 using namespace TDEIO;
63 
64 #define SLAVE_CONNECTION_TIMEOUT_MIN 2
65 
66 // Without debug info we consider it an error if the slave doesn't connect
67 // within 10 seconds.
68 // With debug info we give the slave an hour so that developers have a chance
69 // to debug their slave.
70 #ifdef NDEBUG
71 #define SLAVE_CONNECTION_TIMEOUT_MAX 10
72 #else
73 #define SLAVE_CONNECTION_TIMEOUT_MAX 3600
74 #endif
75 
76 namespace TDEIO {
77 
81  class SlavePrivate {
82  public:
83  bool derived; // true if this instance of Slave is actually an
84  // instance of a derived class.
85 
86  SlavePrivate(bool derived) : derived(derived) {}
87  };
88 }
89 
90 void Slave::accept(TDESocket *socket)
91 {
92 #ifndef Q_WS_WIN
93  slaveconn.init(socket);
94 #endif
95  delete serv;
96  serv = 0;
97  slaveconn.connect(this, TQT_SLOT(gotInput()));
98  unlinkSocket();
99 }
100 
101 void Slave::unlinkSocket()
102 {
103  if (m_socket.isEmpty()) return;
104  TQCString filename = TQFile::encodeName(m_socket);
105  unlink(filename.data());
106  m_socket = TQString::null;
107 }
108 
109 void Slave::timeout()
110 {
111  if (!serv) return;
112  kdDebug(7002) << "slave failed to connect to application pid=" << m_pid << " protocol=" << m_protocol << endl;
113  if (m_pid && (::kill(m_pid, 0) == 0))
114  {
115  int delta_t = (int) difftime(time(0), contact_started);
116  kdDebug(7002) << "slave is slow... pid=" << m_pid << " t=" << delta_t << endl;
117  if (delta_t < SLAVE_CONNECTION_TIMEOUT_MAX)
118  {
119  TQTimer::singleShot(1000*SLAVE_CONNECTION_TIMEOUT_MIN, this, TQT_SLOT(timeout()));
120  return;
121  }
122  }
123  kdDebug(7002) << "Houston, we lost our slave, pid=" << m_pid << endl;
124  delete serv;
125  serv = 0;
126  unlinkSocket();
127  dead = true;
128  TQString arg = m_protocol;
129  if (!m_host.isEmpty())
130  arg += "://"+m_host;
131  kdDebug(7002) << "slave died pid = " << m_pid << endl;
132  ref();
133  // Tell the job about the problem.
134  emit error(ERR_SLAVE_DIED, arg);
135  // Tell the scheduler about the problem.
136  emit slaveDied(this);
137  // After the above signal we're dead!!
138  deref();
139 }
140 
141 Slave::Slave(TDEServerSocket *socket, const TQString &protocol, const TQString &socketname)
142  : SlaveInterface(&slaveconn), serv(socket), contacted(false),
143  d(new SlavePrivate(false))
144 {
145  m_refCount = 1;
146  m_protocol = protocol;
147  m_slaveProtocol = protocol;
148  m_socket = socketname;
149  dead = false;
150  contact_started = time(0);
151  idle_since = contact_started;
152  m_pid = 0;
153  m_port = 0;
154 #ifndef Q_WS_WIN
155  connect(serv, TQT_SIGNAL(accepted( TDESocket* )),
156  TQT_SLOT(accept(TDESocket*) ) );
157 #endif
158 }
159 
160 Slave::Slave(bool /*derived*/, TDEServerSocket *socket, const TQString &protocol,
161  const TQString &socketname)
162  : SlaveInterface(&slaveconn), serv(socket), contacted(false),
163  d(new SlavePrivate(true))
164 {
165  // FIXME: hmm, duplicating code here from public ctor, no good (LS)
166  m_refCount = 1;
167  m_protocol = protocol;
168  m_slaveProtocol = protocol;
169  m_socket = socketname;
170  dead = false;
171  contact_started = time(0);
172  idle_since = contact_started;
173  m_pid = 0;
174  m_port = 0;
175  if (serv != 0) {
176 #ifndef Q_WS_WIN
177  connect(serv, TQT_SIGNAL(accepted( TDESocket* )),
178  TQT_SLOT(accept(TDESocket*) ) );
179 #endif
180  }
181 }
182 
183 Slave::~Slave()
184 {
185  // kdDebug(7002) << "destructing slave object pid = " << m_pid << endl;
186  if (serv != 0) {
187  delete serv;
188  serv = 0;
189  }
190  unlinkSocket();
191  m_pid = 99999;
192  delete d;
193  d = 0;
194 }
195 
196 void Slave::setProtocol(const TQString & protocol)
197 {
198  m_protocol = protocol;
199 }
200 
201 void Slave::setIdle()
202 {
203  idle_since = time(0);
204 }
205 
206 time_t Slave::idleTime()
207 {
208  return (time_t) difftime(time(0), idle_since);
209 }
210 
211 void Slave::setPID(pid_t pid)
212 {
213  m_pid = pid;
214 }
215 
216 void Slave::hold(const KURL &url)
217 {
218  if (d->derived) { // TODO: clean up before KDE 4
219  HoldParams params;
220  params.url = &url;
221  virtual_hook(VIRTUAL_HOLD, &params);
222  return;
223  }/*end if*/
224 
225  ref();
226  {
227  TQByteArray data;
228  TQDataStream stream( data, IO_WriteOnly );
229  stream << url;
230  slaveconn.send( CMD_SLAVE_HOLD, data );
231  slaveconn.close();
232  dead = true;
233  emit slaveDied(this);
234  }
235  deref();
236  // Call TDELauncher::waitForSlave(pid);
237  {
238  DCOPClient *client = kapp->dcopClient();
239  if (!client->isAttached())
240  client->attach();
241 
242  TQByteArray params, reply;
243  TQCString replyType;
244  TQDataStream stream(params, IO_WriteOnly);
245  pid_t pid = m_pid;
246  stream << pid;
247 
248  TQCString launcher = TDEApplication::launcher();
249  client->call(launcher, launcher, "waitForSlave(pid_t)",
250  params, replyType, reply);
251  }
252 }
253 
254 void Slave::suspend()
255 {
256  if (d->derived) { // TODO: clean up before KDE 4
257  virtual_hook(VIRTUAL_SUSPEND, 0);
258  return;
259  }/*end if*/
260 
261  slaveconn.suspend();
262 }
263 
264 void Slave::resume()
265 {
266  if (d->derived) { // TODO: clean up before KDE 4
267  virtual_hook(VIRTUAL_RESUME, 0);
268  return;
269  }/*end if*/
270 
271  slaveconn.resume();
272 }
273 
274 bool Slave::suspended()
275 {
276  if (d->derived) { // TODO: clean up before KDE 4
277  SuspendedParams params;
278  virtual_hook(VIRTUAL_SUSPENDED, &params);
279  return params.retval;
280  }/*end if*/
281 
282  return slaveconn.suspended();
283 }
284 
285 void Slave::send(int cmd, const TQByteArray &arr) {
286  if (d->derived) { // TODO: clean up before KDE 4
287  SendParams params;
288  params.cmd = cmd;
289  params.arr = &arr;
290  virtual_hook(VIRTUAL_SEND, &params);
291  return;
292  }/*end if*/
293 
294  slaveconn.send(cmd, arr);
295 }
296 
297 void Slave::gotInput()
298 {
299  ref();
300  if (!dispatch())
301  {
302  slaveconn.close();
303  dead = true;
304  TQString arg = m_protocol;
305  if (!m_host.isEmpty())
306  arg += "://"+m_host;
307  kdDebug(7002) << "slave died pid = " << m_pid << endl;
308  // Tell the job about the problem.
309  emit error(ERR_SLAVE_DIED, arg);
310  // Tell the scheduler about the problem.
311  emit slaveDied(this);
312  }
313  deref();
314  // Here we might be dead!!
315 }
316 
317 void Slave::kill()
318 {
319  dead = true; // OO can be such simple.
320  kdDebug(7002) << "killing slave pid=" << m_pid << " (" << m_protocol << "://"
321  << m_host << ")" << endl;
322  if (m_pid)
323  {
324  ::kill(m_pid, SIGTERM);
325  }
326 }
327 
328 void Slave::setHost( const TQString &host, int port,
329  const TQString &user, const TQString &passwd)
330 {
331  m_host = host;
332  m_port = port;
333  m_user = user;
334  m_passwd = passwd;
335 
336  TQByteArray data;
337  TQDataStream stream( data, IO_WriteOnly );
338  stream << m_host << m_port << m_user << m_passwd;
339  slaveconn.send( CMD_HOST, data );
340 }
341 
342 void Slave::resetHost()
343 {
344  m_host = "<reset>";
345 }
346 
347 void Slave::setConfig(const MetaData &config)
348 {
349  TQByteArray data;
350  TQDataStream stream( data, IO_WriteOnly );
351  stream << config;
352  slaveconn.send( CMD_CONFIG, data );
353 }
354 
355 Slave* Slave::createSlave( const TQString &protocol, const KURL& url, int& error, TQString& error_text )
356 {
357  //kdDebug(7002) << "createSlave '" << protocol << "' for " << url.prettyURL() << endl;
358  // Firstly take into account all special slaves
359  if (protocol == "data")
360  return new DataProtocol();
361 
362  DCOPClient *client = kapp->dcopClient();
363  if (!client->isAttached())
364  client->attach();
365 
366  TQString prefix = locateLocal("socket", TDEGlobal::instance()->instanceName());
367  KTempFile socketfile(prefix, TQString::fromLatin1(".slave-socket"));
368  if ( socketfile.status() != 0 )
369  {
370  error_text = i18n("Unable to create io-slave: %1").arg(strerror(errno));
371  error = TDEIO::ERR_CANNOT_LAUNCH_PROCESS;
372  return 0;
373  }
374 
375 #ifdef __CYGWIN__
376  socketfile.close();
377 #endif
378 
379 #ifndef Q_WS_WIN
380  TDEServerSocket *kss = new TDEServerSocket(TQFile::encodeName(socketfile.name()).data());
381 
382  Slave *slave = new Slave(kss, protocol, socketfile.name());
383 #else
384  Slave *slave = 0;
385 #endif
386 
387  // WABA: if the dcopserver is running under another uid we don't ask
388  // tdelauncher for a slave, because the slave might have that other uid
389  // as well, which might either be a) undesired or b) make it impossible
390  // for the slave to connect to the application.
391  // In such case we start the slave via TDEProcess.
392  // It's possible to force this by setting the env. variable
393  // TDE_FORK_SLAVES, Clearcase seems to require this.
394  static bool bForkSlaves = !TQCString(getenv("TDE_FORK_SLAVES")).isEmpty();
395 
396  if (bForkSlaves || !client->isAttached() || client->isAttachedToForeignServer())
397  {
398  TQString _name = KProtocolInfo::exec(protocol);
399  if (_name.isEmpty())
400  {
401  error_text = i18n("Unknown protocol '%1'.").arg(protocol);
402  error = TDEIO::ERR_CANNOT_LAUNCH_PROCESS;
403  delete slave;
404  return 0;
405  }
406  TQString lib_path = KLibLoader::findLibrary(_name.latin1());
407  if (lib_path.isEmpty())
408  {
409  error_text = i18n("Can not find io-slave for protocol '%1'.").arg(protocol);
410  error = TDEIO::ERR_CANNOT_LAUNCH_PROCESS;
411  return 0;
412  }
413 
414  TDEProcess proc;
415 
416  proc << locate("exe", "tdeioslave") << lib_path << protocol << "" << socketfile.name();
417  kdDebug(7002) << "tdeioslave" << ", " << lib_path << ", " << protocol << ", " << TQString::null << ", " << socketfile.name() << endl;
418 
419  proc.start(TDEProcess::DontCare);
420 
421 #ifndef Q_WS_WIN
422  slave->setPID(proc.pid());
423  TQTimer::singleShot(1000*SLAVE_CONNECTION_TIMEOUT_MIN, slave, TQT_SLOT(timeout()));
424 #endif
425  return slave;
426  }
427 
428 
429  TQByteArray params, reply;
430  TQCString replyType;
431  TQDataStream stream(params, IO_WriteOnly);
432  stream << protocol << url.host() << socketfile.name();
433 
434  TQCString launcher = TDEApplication::launcher();
435  if (!client->call(launcher, launcher, "requestSlave(TQString,TQString,TQString)",
436  params, replyType, reply)) {
437  error_text = i18n("Cannot talk to tdelauncher");
438  error = TDEIO::ERR_SLAVE_DEFINED;
439  delete slave;
440  return 0;
441  }
442  TQDataStream stream2(reply, IO_ReadOnly);
443  TQString errorStr;
444  pid_t pid;
445  stream2 >> pid >> errorStr;
446  if (!pid)
447  {
448  error_text = i18n("Unable to create io-slave:\ntdelauncher said: %1").arg(errorStr);
449  error = TDEIO::ERR_CANNOT_LAUNCH_PROCESS;
450  delete slave;
451  return 0;
452  }
453 #ifndef Q_WS_WIN
454  slave->setPID(pid);
455  TQTimer::singleShot(1000*SLAVE_CONNECTION_TIMEOUT_MIN, slave, TQT_SLOT(timeout()));
456 #endif
457  return slave;
458 }
459 
460 Slave* Slave::holdSlave( const TQString &protocol, const KURL& url )
461 {
462  //kdDebug(7002) << "holdSlave '" << protocol << "' for " << url.prettyURL() << endl;
463  // Firstly take into account all special slaves
464  if (protocol == "data")
465  return 0;
466 
467  DCOPClient *client = kapp->dcopClient();
468  if (!client->isAttached())
469  client->attach();
470 
471  TQString prefix = locateLocal("socket", TDEGlobal::instance()->instanceName());
472  KTempFile socketfile(prefix, TQString::fromLatin1(".slave-socket"));
473  if ( socketfile.status() != 0 )
474  return 0;
475 
476 #ifdef __CYGWIN__
477  socketfile.close();
478  socketfile.unlink();
479 #endif
480 
481 #ifndef Q_WS_WIN
482  TDEServerSocket *kss = new TDEServerSocket(TQFile::encodeName(socketfile.name()).data());
483 
484  Slave *slave = new Slave(kss, protocol, socketfile.name());
485 #else
486  Slave *slave = 0;
487 #endif
488 
489  TQByteArray params, reply;
490  TQCString replyType;
491  TQDataStream stream(params, IO_WriteOnly);
492  stream << url << socketfile.name();
493 
494  TQCString launcher = TDEApplication::launcher();
495  if (!client->call(launcher, launcher, "requestHoldSlave(KURL,TQString)",
496  params, replyType, reply)) {
497  delete slave;
498  return 0;
499  }
500  TQDataStream stream2(reply, IO_ReadOnly);
501  pid_t pid;
502  stream2 >> pid;
503  if (!pid)
504  {
505  delete slave;
506  return 0;
507  }
508 #ifndef Q_WS_WIN
509  slave->setPID(pid);
510  TQTimer::singleShot(1000*SLAVE_CONNECTION_TIMEOUT_MIN, slave, TQT_SLOT(timeout()));
511 #endif
512  return slave;
513 }
514 
515 void Slave::virtual_hook( int id, void* data ) {
516  TDEIO::SlaveInterface::virtual_hook( id, data );
517 }
518 
519 #include "slave.moc"
TDEIO::Slave::Slave
Slave(bool derived, TDEServerSocket *unixdomain, const TQString &protocol, const TQString &socketname)
Use this constructor if you derive your own class from Slave derived must be true in any case...
Definition: slave.cpp:160
TDEIO::Slave::resetHost
void resetHost()
Clear host info.
Definition: slave.cpp:342
TDEIO::Connection::close
void close()
Closes the connection.
Definition: connection.cpp:86
TDEIO::Scheduler::connect
static bool connect(const char *signal, const TQObject *receiver, const char *member)
Function to connect signals emitted by the scheduler.
Definition: scheduler.h:258
TDEIO::Slave::suspend
void suspend()
Suspends the operation of the attached tdeioslave.
Definition: slave.cpp:254
TDEIO::DataProtocol
This tdeioslave provides support of data urls as specified by rfc 2397.
Definition: dataprotocol.h:51
TDEIO::Slave::createSlave
static Slave * createSlave(const TQString &protocol, const KURL &url, int &error, TQString &error_text)
Creates a new slave.
Definition: slave.cpp:355
TDEIO::Slave::setIdle
void setIdle()
Marks this slave as idle.
Definition: slave.cpp:201
TDEIO
A namespace for TDEIO globals.
Definition: authinfo.h:29
TDEIO::Connection::suspended
bool suspended() const
Returns status of connection.
Definition: connection.h:134
KProtocolInfo::exec
static TQString exec(const TQString &protocol)
Returns the library / executable to open for the protocol protocol Example : "tdeio_ftp", meaning either the executable "tdeio_ftp" or the library "tdeio_ftp.la" (recommended), whichever is available.
TDEIO::Slave::idleTime
time_t idleTime()
Definition: slave.cpp:206
TDEIO::Slave::user
TQString user()
Definition: slave.h:133
TDEIO::Slave::protocol
TQString protocol()
The protocol this slave handles.
Definition: slave.h:103
TDEIO::Connection::suspend
void suspend()
Don't handle incoming data until resumed.
Definition: connection.cpp:72
TDEIO::Slave::port
int port()
Definition: slave.h:128
TDEIO::Slave::suspended
bool suspended()
Tells wether the tdeioslave is suspended.
Definition: slave.cpp:274
TDEIO::Slave::hold
void hold(const KURL &url)
Puts the tdeioslave associated with url at halt.
Definition: slave.cpp:216
TDEIO::Slave::kill
void kill()
Force termination.
Definition: slave.cpp:317
TDEIO::Slave
Attention developers: If you change the implementation of TDEIO::Slave, do not use connection() or sl...
Definition: slave.h:43
TDEIO::Slave::setHost
void setHost(const TQString &host, int port, const TQString &user, const TQString &passwd)
Set host for url.
Definition: slave.cpp:328
TDEIO::Slave::setConfig
void setConfig(const MetaData &config)
Configure slave.
Definition: slave.cpp:347
TDEIO::SlaveInterface
There are two classes that specifies the protocol between application (TDEIO::Job) and tdeioslave...
Definition: slaveinterface.h:93
TDEIO::Slave::resume
void resume()
Resumes the operation of the attached tdeioslave.
Definition: slave.cpp:264
TDEIO::Slave::passwd
TQString passwd()
Definition: slave.h:138
TDEIO::Connection::send
void send(int cmd, const TQByteArray &arr=TQByteArray())
Sends/queues the given command to be sent.
Definition: connection.cpp:105
TDEIO::Slave::send
void send(int cmd, const TQByteArray &data=TQByteArray())
Sends the given command to the tdeioslave.
Definition: slave.cpp:285
TDEIO::Slave::host
TQString host()
Definition: slave.h:123
TDEIO::Connection::init
void init(TDESocket *sock)
Initialize this connection to use the given socket.
Definition: connection.cpp:131
TDEIO::MetaData
MetaData is a simple map of key/value strings.
Definition: global.h:515
TDEIO::Connection::resume
void resume()
Resume handling of incoming data.
Definition: connection.cpp:79

tdeio/tdeio

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

tdeio/tdeio

Skip menu "tdeio/tdeio"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  •     tdecore
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  • tdeioslave
  •   http
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdeio/tdeio by doxygen 1.8.8
This website is maintained by Timothy Pearson.