• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • dcop
 

dcop

  • dcop
dcopserver.cpp
1 /*****************************************************************
2 
3 #include "dcopserver.h"
4 
5 Copyright (c) 1999,2000 Preston Brown <pbrown@kde.org>
6 Copyright (c) 1999,2000 Matthias Ettrich <ettrich@kde.org>
7 Copyright (c) 1999,2001 Waldo Bastian <bastian@kde.org>
8 
9 Permission is hereby granted, free of charge, to any person obtaining a copy
10 of this software and associated documentation files (the "Software"), to deal
11 in the Software without restriction, including without limitation the rights
12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 copies of the Software, and to permit persons to whom the Software is
14 furnished to do so, subject to the following conditions:
15 
16 The above copyright notice and this permission notice shall be included in
17 all copies or substantial portions of the Software.
18 
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 
26 ******************************************************************/
27 
28 #include <config.h>
29 
30 #include <sys/types.h>
31 #ifdef HAVE_SYS_STAT_H
32 #include <sys/stat.h>
33 #endif
34 #ifdef HAVE_SYS_PARAM_H
35 #include <sys/param.h>
36 #endif
37 #include <sys/resource.h>
38 #include <sys/socket.h>
39 
40 #include <unistd.h>
41 #include <stdlib.h>
42 #include <signal.h>
43 #include <unistd.h>
44 #include <fcntl.h>
45 #include <errno.h>
46 #ifdef HAVE_LIMITS_H
47 #include <limits.h>
48 #endif
49 
50 #define QT_CLEAN_NAMESPACE 1
51 #include <tqfile.h>
52 #include <tqtextstream.h>
53 #include <tqdatastream.h>
54 #include <tqptrstack.h>
55 #include <tqtimer.h>
56 
57 #include "dcopserver.h"
58 
59 #include <dcopsignals.h>
60 #include <dcopclient.h>
61 #include <dcopglobal.h>
62 #include "dcop-path.h"
63 
64 #ifdef DCOP_LOG
65 #undef Unsorted
66 #include <tqdir.h>
67 #include <string.h>
68 #endif
69 
70 // #define DCOP_DEBUG
71 
72 DCOPServer* the_server;
73 
74 template class TQDict<DCOPConnection>;
75 template class TQPtrDict<DCOPConnection>;
76 template class TQPtrList<DCOPListener>;
77 
78 #define _DCOPIceSendBegin(x) \
79  int fd = IceConnectionNumber( x ); \
80  long fd_fl = fcntl(fd, F_GETFL, 0); \
81  fcntl(fd, F_SETFL, fd_fl | O_NDELAY);
82 #define _DCOPIceSendEnd() \
83  fcntl(fd, F_SETFL, fd_fl);
84 
85 static TQCString findDcopserverShutdown()
86 {
87 #ifdef Q_OS_WIN32
88  char szPath[512];
89  char *pszFilePart;
90  int ret;
91  ret = SearchPathA(NULL,"dcopserver_shutdown","exe",sizeof(szPath)/sizeof(szPath[0]),szPath,&pszFilePart);
92  if(ret != 0)
93  return TQCString(szPath);
94 #else
95  TQCString path = getenv("PATH");
96  char *dir = strtok(path.data(), ":");
97  while (dir)
98  {
99  TQCString file = dir;
100  file += "/dcopserver_shutdown";
101  if (access(file.data(), X_OK) == 0)
102  return file;
103  dir = strtok(NULL, ":");
104  }
105  TQCString file = DCOP_PATH;
106  file += "/dcopserver_shutdown";
107  if (access(file.data(), X_OK) == 0)
108  return file;
109 #endif
110  return TQCString("dcopserver_shutdown");
111 }
112 
113 static Bool HostBasedAuthProc ( char* /*hostname*/)
114 {
115  return false; // no host based authentication
116 }
117 
118 extern "C" {
119 extern IceWriteHandler _kde_IceWriteHandler;
120 extern IceIOErrorHandler _kde_IceIOErrorHandler;
121 void DCOPIceWriteChar(IceConn iceConn, unsigned long nbytes, char *ptr);
122 }
123 
124 static TQCString readQCString(TQDataStream &ds)
125 {
126  TQCString result;
127  TQ_UINT32 len;
128  ds >> len;
129  TQIODevice *device = ds.device();
130  int bytesLeft = device->size()-device->at();
131  if ((bytesLeft < 0 ) || (len > (uint) bytesLeft))
132  {
133  tqWarning("[dcopserver] Corrupt data!");
134  printf("[dcopserver] bytesLeft: %d, len: %d", bytesLeft, len);
135  return result;
136  }
137  result.TQByteArray::resize( (uint)len );
138  if (len > 0)
139  ds.readRawBytes( result.data(), (uint)len);
140  return result;
141 }
142 
143 static TQByteArray readQByteArray(TQDataStream &ds)
144 {
145  TQByteArray result;
146  TQ_UINT32 len;
147  ds >> len;
148  TQIODevice *device = ds.device();
149  int bytesLeft = device->size()-device->at();
150  if ((bytesLeft < 0 ) || (len > (uint) bytesLeft))
151  {
152  tqWarning("[dcopserver] Corrupt data!");
153  return result;
154  }
155  result.resize( (uint)len );
156  if (len > 0)
157  ds.readRawBytes( result.data(), (uint)len);
158  return result;
159 }
160 
161 
162 extern "C" {
163 extern int _kde_IceTransWrite (void * ciptr, char *buf, int size);
164 }
165 
166 static unsigned long writeIceData(IceConn iceConn, unsigned long nbytes, char *ptr)
167 {
168  int fd = IceConnectionNumber(iceConn);
169  unsigned long nleft = nbytes;
170  while (nleft > 0)
171  {
172  int nwritten;
173 
174  if (iceConn->io_ok)
175  {
176  nwritten = send(fd, ptr, (int) nleft, 0);
177  }
178  else
179  return 0;
180 
181  if (nwritten <= 0)
182  {
183  if (errno == EINTR)
184  continue;
185 
186  if (errno == EAGAIN)
187  return nleft;
188 
189  /*
190  * Fatal IO error. First notify each protocol's IceIOErrorProc
191  * callback, then invoke the application IO error handler.
192  */
193 
194  iceConn->io_ok = False;
195 
196  if (iceConn->connection_status == IceConnectPending)
197  {
198  /*
199  * Don't invoke IO error handler if we are in the
200  * middle of a connection setup.
201  */
202 
203  return 0;
204  }
205 
206  if (iceConn->process_msg_info)
207  {
208  int i;
209 
210  for (i = iceConn->his_min_opcode;
211  i <= iceConn->his_max_opcode; i++)
212  {
213  _IceProcessMsgInfo *process;
214 
215  process = &iceConn->process_msg_info[
216  i - iceConn->his_min_opcode];
217 
218  if (process->in_use)
219  {
220  IceIOErrorProc IOErrProc = process->accept_flag ?
221  process->protocol->accept_client->io_error_proc :
222  process->protocol->orig_client->io_error_proc;
223 
224  if (IOErrProc)
225  (*IOErrProc) (iceConn);
226  }
227  }
228  }
229 
230  (*_kde_IceIOErrorHandler) (iceConn);
231  return 0;
232  }
233 
234  nleft -= nwritten;
235  ptr += nwritten;
236  }
237  return 0;
238 }
239 
240 void DCOPIceWriteChar(IceConn iceConn, unsigned long nbytes, char *ptr)
241 {
242  DCOPConnection* conn = the_server->findConn( iceConn );
243 #ifdef DCOP_DEBUG
244 tqWarning("[dcopserver] DCOPIceWriteChar() Writing %d bytes [%s]", nbytes, conn ? conn->appId.data() : "<unknown>");
245 #endif
246 
247  if (conn)
248  {
249  if (conn->outputBlocked)
250  {
251  TQByteArray _data(nbytes);
252  memcpy(_data.data(), ptr, nbytes);
253 #ifdef DCOP_DEBUG
254 tqWarning("[dcopserver] _IceWrite() outputBlocked. Queuing %d bytes.", _data.size());
255 #endif
256  conn->outputBuffer.append(_data);
257  return;
258  }
259  // assert(conn->outputBuffer.isEmpty());
260  }
261 
262  unsigned long nleft = writeIceData(iceConn, nbytes, ptr);
263  if ((nleft > 0) && conn)
264  {
265  TQByteArray _data(nleft);
266  memcpy(_data.data(), ptr, nleft);
267  conn->waitForOutputReady(_data, 0);
268  return;
269  }
270 }
271 
272 static void DCOPIceWrite(IceConn iceConn, const TQByteArray &_data)
273 {
274  DCOPConnection* conn = the_server->findConn( iceConn );
275 #ifdef DCOP_DEBUG
276 tqWarning("[dcopserver] DCOPIceWrite() Writing %d bytes [%s]", _data.size(), conn ? conn->appId.data() : "<unknown>");
277 #endif
278  if (conn)
279  {
280  if (conn->outputBlocked)
281  {
282 #ifdef DCOP_DEBUG
283 tqWarning("[dcopserver] DCOPIceWrite() outputBlocked. Queuing %d bytes.", _data.size());
284 #endif
285  conn->outputBuffer.append(_data);
286  return;
287  }
288  // assert(conn->outputBuffer.isEmpty());
289  }
290 
291  unsigned long nleft = writeIceData(iceConn, _data.size(), const_cast<TQByteArray&>(_data).data());
292  if ((nleft > 0) && conn)
293  {
294  conn->waitForOutputReady(_data, _data.size() - nleft);
295  return;
296  }
297 }
298 
299 void DCOPConnection::waitForOutputReady(const TQByteArray &_data, int start)
300 {
301 #ifdef DCOP_DEBUG
302 tqWarning("[dcopserver] waitForOutputReady fd = %d datasize = %d start = %d", socket(), _data.size(), start);
303 #endif
304  outputBlocked = true;
305  outputBuffer.append(_data);
306  outputBufferStart = start;
307  if (!outputBufferNotifier)
308  {
309  outputBufferNotifier = new TQSocketNotifier(socket(), Write);
310  connect(outputBufferNotifier, TQT_SIGNAL(activated(int)),
311  the_server, TQT_SLOT(slotOutputReady(int)));
312  }
313  outputBufferNotifier->setEnabled(true);
314  return;
315 }
316 
317 void DCOPServer::slotOutputReady(int socket)
318 {
319 #ifdef DCOP_DEBUG
320 tqWarning("[dcopserver] slotOutputReady fd = %d", socket);
321 #endif
322  // Find out connection.
323  DCOPConnection *conn = fd_clients.find(socket);
324  //assert(conn);
325  //assert(conn->outputBlocked);
326  //assert(conn->socket() == socket);
327  // Forward
328  conn->slotOutputReady();
329 }
330 
331 
332 void DCOPConnection::slotOutputReady()
333 {
334  //assert(outputBlocked);
335  //assert(!outputBuffer.isEmpty());
336 
337  TQByteArray data = outputBuffer.first();
338 
339  int fd = socket();
340 
341  long fd_fl = fcntl(fd, F_GETFL, 0);
342  fcntl(fd, F_SETFL, fd_fl | O_NDELAY);
343  /*
344  Use special write handling on windows platform. The write function from
345  the runtime library (on MSVC) does not allow to write on sockets.
346  */
347  int nwritten;
348  nwritten = ::send(fd,data.data()+outputBufferStart,data.size()-outputBufferStart,0);
349 
350  int e = errno;
351  fcntl(fd, F_SETFL, fd_fl);
352 
353 #ifdef DCOP_DEBUG
354 tqWarning("[dcopserver] slotOutputReady() %d bytes written", nwritten);
355 #endif
356 
357  if (nwritten < 0)
358  {
359  if ((e == EINTR) || (e == EAGAIN))
360  return;
361  (*_kde_IceIOErrorHandler) (iceConn);
362  return;
363  }
364  outputBufferStart += nwritten;
365 
366  if (outputBufferStart == data.size())
367  {
368  outputBufferStart = 0;
369  outputBuffer.remove(outputBuffer.begin());
370  if (outputBuffer.isEmpty())
371  {
372 #ifdef DCOP_DEBUG
373 tqWarning("[dcopserver] slotOutputRead() all data transmitted.");
374 #endif
375  outputBlocked = false;
376  outputBufferNotifier->setEnabled(false);
377  }
378 #ifdef DCOP_DEBUG
379 else
380 {
381 tqWarning("[dcopserver] slotOutputRead() more data to send.");
382 }
383 #endif
384  }
385 }
386 
387 static void DCOPIceSendData(IceConn _iceConn,
388  const TQByteArray &_data)
389 {
390  if (_iceConn->outbufptr > _iceConn->outbuf)
391  {
392 #ifdef DCOP_DEBUG
393 tqWarning("[dcopserver] Flushing data, fd = %d", IceConnectionNumber(_iceConn));
394 #endif
395  IceFlush( _iceConn );
396  }
397  DCOPIceWrite(_iceConn, _data);
398 }
399 
400 class DCOPListener : public TQSocketNotifier
401 {
402 public:
403  DCOPListener( IceListenObj obj )
404  : TQSocketNotifier( IceGetListenConnectionNumber( obj ),
405  TQSocketNotifier::Read, 0, 0)
406 {
407  listenObj = obj;
408 }
409 
410  IceListenObj listenObj;
411 };
412 
413 DCOPConnection::DCOPConnection( IceConn conn )
414  : TQSocketNotifier( IceConnectionNumber( conn ),
415  TQSocketNotifier::Read, 0, 0 )
416 {
417  iceConn = conn;
418  notifyRegister = 0;
419  _signalConnectionList = 0;
420  daemon = false;
421  outputBlocked = false;
422  outputBufferNotifier = 0;
423  outputBufferStart = 0;
424 }
425 
426 DCOPConnection::~DCOPConnection()
427 {
428  delete _signalConnectionList;
429  delete outputBufferNotifier;
430 }
431 
432 DCOPSignalConnectionList *
433 DCOPConnection::signalConnectionList()
434 {
435  if (!_signalConnectionList)
436  _signalConnectionList = new DCOPSignalConnectionList;
437  return _signalConnectionList;
438 }
439 
440 static IceAuthDataEntry *authDataEntries;
441 static char *addAuthFile;
442 
443 static IceListenObj *listenObjs;
444 static int numTransports;
445 static int ready[2];
446 
447 
448 /* for printing hex digits */
449 static void fprintfhex (FILE *fp, unsigned int len, char *cp)
450 {
451  static char hexchars[] = "0123456789abcdef";
452 
453  for (; len > 0; len--, cp++) {
454  unsigned char s = *cp;
455  putc(hexchars[s >> 4], fp);
456  putc(hexchars[s & 0x0f], fp);
457  }
458 }
459 
460 /*
461  * We use temporary files which contain commands to add entries to
462  * the .ICEauthority file.
463  */
464 static void
465 write_iceauth (FILE *addfp, IceAuthDataEntry *entry)
466 {
467  fprintf (addfp,
468  "add %s \"\" %s %s ",
469  entry->protocol_name,
470  entry->network_id,
471  entry->auth_name);
472  fprintfhex (addfp, entry->auth_data_length, entry->auth_data);
473  fprintf (addfp, "\n");
474 }
475 
476 #ifndef HAVE_MKSTEMPS
477 #include <string.h>
478 #include <strings.h>
479 
480 /* this is based on code taken from the GNU libc, distributed under the LGPL license */
481 
482 /* Generate a unique temporary file name from TEMPLATE.
483 
484  TEMPLATE has the form:
485 
486  <path>/ccXXXXXX<suffix>
487 
488  SUFFIX_LEN tells us how long <suffix> is (it can be zero length).
489 
490  The last six characters of TEMPLATE before <suffix> must be "XXXXXX";
491  they are replaced with a string that makes the filename unique.
492 
493  Returns a file descriptor open on the file for reading and writing. */
494 
495 int mkstemps (char* _template, int suffix_len)
496 {
497  static const char letters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
498  char *XXXXXX;
499  int len;
500  int count;
501  int value;
502 
503  len = strlen (_template);
504 
505  if ((int) len < 6 + suffix_len || strncmp (&_template[len - 6 - suffix_len], "XXXXXX", 6))
506  return -1;
507 
508  XXXXXX = &_template[len - 6 - suffix_len];
509 
510  value = rand();
511  for (count = 0; count < 256; ++count)
512  {
513  int v = value;
514  int fd;
515 
516  /* Fill in the random bits. */
517  XXXXXX[0] = letters[v % 62];
518  v /= 62;
519  XXXXXX[1] = letters[v % 62];
520  v /= 62;
521  XXXXXX[2] = letters[v % 62];
522  v /= 62;
523  XXXXXX[3] = letters[v % 62];
524  v /= 62;
525  XXXXXX[4] = letters[v % 62];
526  v /= 62;
527  XXXXXX[5] = letters[v % 62];
528 
529  fd = open (_template, O_RDWR|O_CREAT|O_EXCL, 0600);
530  if (fd >= 0)
531  /* The file does not exist. */
532  return fd;
533 
534  /* This is a random value. It is only necessary that the next
535  TMP_MAX values generated by adding 7777 to VALUE are different
536  with (module 2^32). */
537  value += 7777;
538  }
539  /* We return the null string if we can't find a unique file name. */
540  _template[0] = '\0';
541  return -1;
542 }
543 
544 #endif
545 
546 static char *unique_filename (const char *path, const char *prefix, int *pFd)
547 {
548  char tempFile[PATH_MAX];
549  char *ptr;
550 
551 #ifdef Q_OS_WIN
552  snprintf (tempFile, PATH_MAX, "%s\\%sXXXXXX", path, prefix);
553 #else
554  snprintf (tempFile, PATH_MAX, "%s/%sXXXXXX", path, prefix);
555 #endif
556  ptr = static_cast<char *>(malloc(strlen(tempFile) + 1));
557  if (ptr != NULL)
558  {
559  int fd = mkstemps(tempFile, 0);
560  if(fd >= 0)
561  {
562  *pFd = fd;
563  strcpy(ptr, tempFile);
564  }
565  else
566  {
567  free(ptr);
568  ptr = NULL;
569  }
570  }
571  return ptr;
572 }
573 
574 #define MAGIC_COOKIE_LEN 16
575 
576 Status
577 SetAuthentication (int count, IceListenObj *_listenObjs,
578  IceAuthDataEntry **_authDataEntries)
579 {
580  FILE *addfp = NULL;
581  const char *path;
582  int original_umask;
583  int i;
584  TQCString command;
585  int fd;
586 
587  original_umask = umask (0077); /* disallow non-owner access */
588 
589 #ifdef Q_OS_WIN
590  char temppath[512];
591  DWORD dw = GetTempPathA(sizeof(temppath),temppath);
592  if(dw != 0)
593  {
594  temppath[dw - 1] = 0;
595  path = temppath;
596  }
597  else
598  path = ".";
599 #else
600  path = getenv ("DCOP_SAVE_DIR");
601  if (!path)
602  path = "/tmp";
603 #endif
604  if ((addAuthFile = unique_filename (path, "dcop", &fd)) == NULL)
605  goto bad;
606 
607  if (!(addfp = fdopen(fd, "wb")))
608  goto bad;
609 
610  if ((*_authDataEntries = static_cast<IceAuthDataEntry *>(malloc (count * 2 * sizeof (IceAuthDataEntry)))) == NULL)
611  goto bad;
612 
613  for (i = 0; i < numTransports * 2; i += 2) {
614  (*_authDataEntries)[i].network_id =
615  IceGetListenConnectionString (_listenObjs[i/2]);
616  (*_authDataEntries)[i].protocol_name = const_cast<char *>("ICE");
617  (*_authDataEntries)[i].auth_name = const_cast<char *>("MIT-MAGIC-COOKIE-1");
618 
619  (*_authDataEntries)[i].auth_data =
620  IceGenerateMagicCookie (MAGIC_COOKIE_LEN);
621  (*_authDataEntries)[i].auth_data_length = MAGIC_COOKIE_LEN;
622 
623  (*_authDataEntries)[i+1].network_id =
624  IceGetListenConnectionString (_listenObjs[i/2]);
625  (*_authDataEntries)[i+1].protocol_name = const_cast<char *>("DCOP");
626  (*_authDataEntries)[i+1].auth_name = const_cast<char *>("MIT-MAGIC-COOKIE-1");
627 
628  (*_authDataEntries)[i+1].auth_data =
629  IceGenerateMagicCookie (MAGIC_COOKIE_LEN);
630  (*_authDataEntries)[i+1].auth_data_length = MAGIC_COOKIE_LEN;
631 
632  write_iceauth (addfp, &(*_authDataEntries)[i]);
633  write_iceauth (addfp, &(*_authDataEntries)[i+1]);
634 
635  IceSetPaAuthData (2, &(*_authDataEntries)[i]);
636 
637  IceSetHostBasedAuthProc (_listenObjs[i/2], HostBasedAuthProc);
638  }
639 
640  fclose (addfp);
641 
642  umask (original_umask);
643 
644  command = DCOPClient::iceauthPath();
645 
646  if (command.isEmpty())
647  {
648  fprintf( stderr, "[dcopserver] 'iceauth' not found in path, aborting." );
649  exit(1);
650  }
651 
652  command += " source ";
653  command += addAuthFile;
654  system (command);
655 
656  unlink(addAuthFile);
657 
658  return (1);
659 
660  bad:
661 
662  if (addfp)
663  fclose (addfp);
664 
665  if (addAuthFile) {
666  unlink(addAuthFile);
667  free(addAuthFile);
668  }
669 
670  umask (original_umask);
671 
672  return (0);
673 }
674 
675 /*
676  * Free up authentication data.
677  */
678 void
679 FreeAuthenticationData(int count, IceAuthDataEntry *_authDataEntries)
680 {
681  /* Each transport has entries for ICE and XSMP */
682  int i;
683 
684  for (i = 0; i < count * 2; i++) {
685  free (_authDataEntries[i].network_id);
686  free (_authDataEntries[i].auth_data);
687  }
688 
689  free(_authDataEntries);
690  free(addAuthFile);
691 }
692 
693 void DCOPWatchProc ( IceConn iceConn, IcePointer client_data, Bool opening, IcePointer* watch_data)
694 {
695  DCOPServer* ds = static_cast<DCOPServer*>(client_data);
696 
697  if (opening) {
698  *watch_data = static_cast<IcePointer>(ds->watchConnection( iceConn ));
699  }
700  else {
701  ds->removeConnection( static_cast<void*>(*watch_data) );
702  }
703 }
704 
705 void DCOPProcessMessage( IceConn iceConn, IcePointer /*clientData*/,
706  int opcode, unsigned long length, Bool swap)
707 {
708  the_server->processMessage( iceConn, opcode, length, swap );
709 }
710 
711 void DCOPServer::processMessage( IceConn iceConn, int opcode,
712  unsigned long length, Bool /*swap*/)
713 {
714  DCOPConnection* conn = clients.find( iceConn );
715  if ( !conn ) {
716  tqWarning("[dcopserver] DCOPServer::processMessage message from unknown connection. [opcode = %d]", opcode);
717  return;
718  }
719  switch( opcode ) {
720  case DCOPSend:
721  case DCOPReplyDelayed:
722  {
723  DCOPMsg *pMsg = 0;
724  IceReadMessageHeader(iceConn, sizeof(DCOPMsg), DCOPMsg, pMsg);
725  CARD32 key = pMsg->key;
726  TQByteArray ba( length );
727  IceReadData(iceConn, length, ba.data() );
728  TQDataStream ds( ba, IO_ReadOnly );
729  TQCString fromApp = readQCString(ds);
730  TQCString toApp = readQCString(ds);
731 
732  DCOPConnection* target = findApp( toApp );
733  int datalen = ba.size();
734  if ( opcode == DCOPReplyDelayed ) {
735  if ( !target )
736  tqWarning("[dcopserver] DCOPServer::DCOPReplyDelayed for unknown connection.");
737  else if ( !conn )
738  tqWarning("[dcopserver] DCOPServer::DCOPReplyDelayed from unknown connection.");
739  else if (!conn->waitingForDelayedReply.removeRef( target->iceConn ))
740  tqWarning("[dcopserver] DCOPServer::DCOPReplyDelayed from/to does not match. (#2)");
741  else if (!target->waitingOnReply.removeRef(iceConn))
742  tqWarning("[dcopserver] DCOPServer::DCOPReplyDelayed for client who wasn't waiting on one!");
743  }
744  if ( target ) {
745 #ifdef DCOP_DEBUG
746 if (opcode == DCOPSend)
747 {
748  TQCString obj = readQCString(ds);
749  TQCString fun = readQCString(ds);
750  tqWarning("[dcopserver] Sending %d bytes from %s to %s. DCOPSend %s", length, fromApp.data(), toApp.data(), fun.data());
751 }
752 #endif
753  IceGetHeader( target->iceConn, majorOpcode, opcode,
754  sizeof(DCOPMsg), DCOPMsg, pMsg );
755  pMsg->key = key;
756  pMsg->length += datalen;
757  _DCOPIceSendBegin( target->iceConn );
758  DCOPIceSendData(target->iceConn, ba);
759  _DCOPIceSendEnd();
760  } else if ( toApp == "DCOPServer" ) {
761  TQCString obj = readQCString(ds);
762  TQCString fun = readQCString(ds);
763  TQByteArray data = readQByteArray(ds);
764 
765  TQCString replyType;
766  TQByteArray replyData;
767  if ( !receive( toApp, obj, fun, data, replyType, replyData, iceConn ) ) {
768  tqWarning("[dcopserver] %s failure: object '%s' has no function '%s'", toApp.data(), obj.data(), fun.data() );
769  }
770  } else if ( toApp[toApp.length()-1] == '*') {
771 #ifdef DCOP_DEBUG
772 if (opcode == DCOPSend)
773 {
774  TQCString obj = readQCString(ds);
775  TQCString fun = readQCString(ds);
776  tqWarning("[dcopserver] Sending %d bytes from %s to %s. DCOPSend %s", length, fromApp.data(), toApp.data(), fun.data());
777 }
778 #endif
779  // handle a multicast.
780  TQAsciiDictIterator<DCOPConnection> aIt(appIds);
781  int l = toApp.length()-1;
782  for ( ; aIt.current(); ++aIt) {
783  DCOPConnection *client = aIt.current();
784  if (!l || (strncmp(client->appId.data(), toApp.data(), l) == 0))
785  {
786  IceGetHeader(client->iceConn, majorOpcode, DCOPSend,
787  sizeof(DCOPMsg), DCOPMsg, pMsg);
788  pMsg->key = key;
789  pMsg->length += datalen;
790  _DCOPIceSendBegin( client->iceConn );
791  DCOPIceSendData(client->iceConn, ba);
792  _DCOPIceSendEnd();
793  }
794  }
795  }
796  }
797  break;
798  case DCOPCall:
799  case DCOPFind:
800  {
801  DCOPMsg *pMsg = 0;
802  IceReadMessageHeader(iceConn, sizeof(DCOPMsg), DCOPMsg, pMsg);
803  CARD32 key = pMsg->key;
804  TQByteArray ba( length );
805  IceReadData(iceConn, length, ba.data() );
806  TQDataStream ds( ba, IO_ReadOnly );
807  TQCString fromApp = readQCString(ds);
808  TQCString toApp = readQCString(ds);
809  DCOPConnection* target = findApp( toApp );
810  int datalen = ba.size();
811 
812  if ( target ) {
813 #ifdef DCOP_DEBUG
814 if (opcode == DCOPCall)
815 {
816  TQCString obj = readQCString(ds);
817  TQCString fun = readQCString(ds);
818  tqWarning("[dcopserver] Sending %d bytes from %s to %s. DCOPCall %s", length, fromApp.data(), toApp.data(), fun.data());
819 }
820 #endif
821  target->waitingForReply.append( iceConn );
822  conn->waitingOnReply.append( target->iceConn);
823 
824  IceGetHeader( target->iceConn, majorOpcode, opcode,
825  sizeof(DCOPMsg), DCOPMsg, pMsg );
826  pMsg->key = key;
827  pMsg->length += datalen;
828  _DCOPIceSendBegin( target->iceConn );
829  DCOPIceSendData(target->iceConn, ba);
830  _DCOPIceSendEnd();
831  } else {
832  TQCString replyType;
833  TQByteArray replyData;
834  bool b = false;
835  // DCOPServer itself does not do DCOPFind.
836  if ( (opcode == DCOPCall) && (toApp == "DCOPServer") ) {
837  TQCString obj = readQCString(ds);
838  TQCString fun = readQCString(ds);
839  TQByteArray data = readQByteArray(ds);
840  b = receive( toApp, obj, fun, data, replyType, replyData, iceConn );
841  if ( !b )
842  tqWarning("[dcopserver] %s failure: object '%s' has no function '%s'", toApp.data(), obj.data(), fun.data() );
843  }
844 
845  if (b) {
846  TQByteArray reply;
847  TQDataStream replyStream( reply, IO_WriteOnly );
848  replyStream << toApp << fromApp << replyType << replyData.size();
849  int replylen = reply.size() + replyData.size();
850  IceGetHeader( iceConn, majorOpcode, DCOPReply,
851  sizeof(DCOPMsg), DCOPMsg, pMsg );
852  if ( key != 0 )
853  pMsg->key = key;
854  else
855  pMsg->key = serverKey++;
856  pMsg->length += replylen;
857  _DCOPIceSendBegin( iceConn );
858  DCOPIceSendData( iceConn, reply);
859  DCOPIceSendData( iceConn, replyData);
860  _DCOPIceSendEnd();
861  } else {
862  TQByteArray reply;
863  TQDataStream replyStream( reply, IO_WriteOnly );
864  replyStream << toApp << fromApp;
865  IceGetHeader( iceConn, majorOpcode, DCOPReplyFailed,
866  sizeof(DCOPMsg), DCOPMsg, pMsg );
867  if ( key != 0 )
868  pMsg->key = key;
869  else
870  pMsg->key = serverKey++;
871  pMsg->length += reply.size();
872  _DCOPIceSendBegin( iceConn );
873  DCOPIceSendData( iceConn, reply );
874  _DCOPIceSendEnd();
875  }
876  }
877  }
878  break;
879  case DCOPReply:
880  case DCOPReplyFailed:
881  case DCOPReplyWait:
882  {
883  DCOPMsg *pMsg = 0;
884  IceReadMessageHeader(iceConn, sizeof(DCOPMsg), DCOPMsg, pMsg);
885  CARD32 key = pMsg->key;
886  TQByteArray ba( length );
887  IceReadData(iceConn, length, ba.data() );
888  TQDataStream ds( ba, IO_ReadOnly );
889  TQCString fromApp = readQCString(ds);
890  TQCString toApp = readQCString(ds);
891 
892  DCOPConnection* connreply = findApp( toApp );
893  int datalen = ba.size();
894 
895  if ( !connreply )
896  tqWarning("[dcopserver] DCOPServer::DCOPReply for unknown connection.");
897  else {
898  conn->waitingForReply.removeRef( connreply->iceConn );
899  if ( opcode == DCOPReplyWait )
900  {
901  conn->waitingForDelayedReply.append( connreply->iceConn );
902  }
903  else
904  { // DCOPReply or DCOPReplyFailed
905  if (!connreply->waitingOnReply.removeRef(iceConn))
906  tqWarning("[dcopserver] DCOPReply from %s to %s who wasn't waiting on one!",
907  fromApp.data(), toApp.data());
908  }
909  IceGetHeader( connreply->iceConn, majorOpcode, opcode,
910  sizeof(DCOPMsg), DCOPMsg, pMsg );
911  pMsg->key = key;
912  pMsg->length += datalen;
913  _DCOPIceSendBegin( connreply->iceConn );
914  DCOPIceSendData(connreply->iceConn, ba);
915  _DCOPIceSendEnd();
916  }
917  }
918  break;
919  default:
920  tqWarning("[dcopserver] DCOPServer::processMessage unknown message");
921  }
922 }
923 
924 static const IcePaVersionRec DCOPServerVersions[] = {
925  { DCOPVersionMajor, DCOPVersionMinor, DCOPProcessMessage }
926 };
927 
928 static const IcePoVersionRec DUMMYVersions[] = {
929  { DCOPVersionMajor, DCOPVersionMinor, 0 }
930 };
931 
932 static Status DCOPServerProtocolSetupProc ( IceConn /*iceConn*/,
933  int majorVersion, int minorVersion,
934  char* vendor, char* release,
935  IcePointer *clientDataRet,
936  char ** /*failureReasonRet*/)
937 {
938  /*
939  * vendor/release are undefined for ProtocolSetup in DCOP
940  */
941 
942  if (vendor)
943  free (vendor);
944  if (release)
945  free (release);
946 
947  *clientDataRet = 0;
948 
949  return (majorVersion == DCOPVersionMajor && minorVersion == DCOPVersionMinor);
950 }
951 
952 #ifndef Q_OS_WIN
953 static int pipeOfDeath[2];
954 
955 static void sighandler(int sig)
956 {
957  if (sig == SIGHUP) {
958  signal(SIGHUP, sighandler);
959  return;
960  }
961 
962  write(pipeOfDeath[1], "x", 1);
963 }
964 #endif
965 
966 extern "C"
967 {
968  extern int _kde_IceLastMajorOpcode; // from libICE
969 }
970 
971 DCOPServer::DCOPServer(bool _suicide)
972  : TQObject(0,0), currentClientNumber(0), appIds(263), clients(263)
973 {
974  serverKey = 42;
975 
976  suicide = _suicide;
977  shutdown = false;
978 
979  dcopSignals = new DCOPSignals;
980 
981  if (_kde_IceLastMajorOpcode < 1 )
982  IceRegisterForProtocolSetup(const_cast<char *>("DUMMY"),
983  const_cast<char *>("DUMMY"),
984  const_cast<char *>("DUMMY"),
985  1, const_cast<IcePoVersionRec *>(DUMMYVersions),
986  DCOPAuthCount, const_cast<char **>(DCOPAuthNames),
987  DCOPClientAuthProcs, 0);
988  if (_kde_IceLastMajorOpcode < 1 )
989  tqWarning("[dcopserver] DCOPServer Error: incorrect major opcode!");
990 
991  the_server = this;
992  if (( majorOpcode = IceRegisterForProtocolReply (const_cast<char *>("DCOP"),
993  const_cast<char *>(DCOPVendorString),
994  const_cast<char *>(DCOPReleaseString),
995  1, const_cast<IcePaVersionRec *>(DCOPServerVersions),
996  1, const_cast<char **>(DCOPAuthNames),
997  DCOPServerAuthProcs,
998  HostBasedAuthProc,
999  DCOPServerProtocolSetupProc,
1000  NULL, /* IceProtocolActivateProc - we don't care about
1001  when the Protocol Reply is sent, because the
1002  session manager can not immediately send a
1003  message - it must wait for RegisterClient. */
1004  NULL /* IceIOErrorProc */
1005  )) < 0)
1006  {
1007  tqWarning("[dcopserver] Could not register DCOP protocol with ICE");
1008  }
1009 
1010  char errormsg[256];
1011  int orig_umask = umask(077); /*old libICE's don't reset the umask() they set */
1012  if (!IceListenForConnections (&numTransports, &listenObjs,
1013  256, errormsg))
1014  {
1015  fprintf (stderr, "[dcopserver] %s", errormsg);
1016  exit (1);
1017  } else {
1018  (void) umask(orig_umask);
1019  // publish available transports.
1020  TQCString fName = DCOPClient::dcopServerFile();
1021  FILE *f;
1022  if(!(f = ::fopen(fName.data(), "w+"))) {
1023  fprintf (stderr, "[dcopserver] Can not create file %s: %s",
1024  fName.data(), ::strerror(errno));
1025  exit(1);
1026  }
1027  char *idlist = IceComposeNetworkIdList(numTransports, listenObjs);
1028  if (idlist != 0) {
1029  fprintf(f, "%s", idlist);
1030  free(idlist);
1031  }
1032  fprintf(f, "\n%i\n", getpid());
1033  fclose(f);
1034 #ifndef Q_OS_WIN32
1035  if (TQCString(getenv("DCOPAUTHORITY")).isEmpty())
1036  {
1037  // Create a link named like the old-style (KDE 2.x) naming
1038  TQCString compatName = DCOPClient::dcopServerFileOld();
1039  ::symlink(fName,compatName);
1040  }
1041 #endif // Q_OS_WIN32
1042  }
1043 
1044 #if 0
1045  if (!SetAuthentication_local(numTransports, listenObjs))
1046  tqFatal("DCOPSERVER: authentication setup failed.");
1047 #endif
1048  if (!SetAuthentication(numTransports, listenObjs, &authDataEntries))
1049  tqFatal("DCOPSERVER: authentication setup failed.");
1050 
1051  IceAddConnectionWatch (DCOPWatchProc, static_cast<IcePointer>(this));
1052  _IceWriteHandler = DCOPIceWriteChar;
1053 
1054  listener.setAutoDelete( true );
1055  DCOPListener* con;
1056  for ( int i = 0; i < numTransports; i++) {
1057  con = new DCOPListener( listenObjs[i] );
1058  listener.append( con );
1059  connect( con, TQT_SIGNAL( activated(int) ), this, TQT_SLOT( newClient(int) ) );
1060  }
1061  char c = 0;
1062  write(ready[1], &c, 1); // dcopserver is started
1063  close(ready[1]);
1064 
1065  m_timer = new TQTimer(this);
1066  connect( m_timer, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotTerminate()) );
1067  m_deadConnectionTimer = new TQTimer(this);
1068  connect( m_deadConnectionTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotCleanDeadConnections()) );
1069 
1070 #ifdef Q_OS_WIN
1071  char szEventName[256];
1072  sprintf(szEventName,"dcopserver%i",GetCurrentProcessId());
1073  m_evTerminate = CreateEventA(NULL,TRUE,FALSE,(LPCSTR)szEventName);
1074  ResetEvent(m_evTerminate);
1075  m_hTerminateThread = CreateThread(NULL,0,TerminatorThread,this,0,&m_dwTerminateThreadId);
1076  if(m_hTerminateThread)
1077  CloseHandle(m_hTerminateThread);
1078 #endif
1079 
1080 #ifdef DCOP_LOG
1081  char hostname_buffer[256];
1082  memset( hostname_buffer, 0, sizeof( hostname_buffer ) );
1083  if ( gethostname( hostname_buffer, 255 ) < 0 )
1084  hostname_buffer[0] = '\0';
1085  m_logger = new TQFile( TQString( "%1/.dcop-%2.log" ).arg( TQDir::homeDirPath() ).arg( hostname_buffer ) );
1086  if ( m_logger->open( IO_WriteOnly ) ) {
1087  m_stream = new TQTextStream( m_logger );
1088  }
1089 #endif
1090 }
1091 
1092 DCOPServer::~DCOPServer()
1093 {
1094  system(findDcopserverShutdown()+" --nokill");
1095  IceFreeListenObjs(numTransports, listenObjs);
1096  FreeAuthenticationData(numTransports, authDataEntries);
1097  delete dcopSignals;
1098 #ifdef DCOP_LOG
1099  delete m_stream;
1100  m_logger->close();
1101  delete m_logger;
1102 #endif
1103 #ifdef Q_OS_WIN
1104  SetEvent(m_evTerminate);
1105  CloseHandle(m_evTerminate);
1106 #endif
1107 }
1108 
1109 DCOPConnection* DCOPServer::findApp( const TQCString& appId )
1110 {
1111  if ( appId.isNull() )
1112  return 0;
1113  DCOPConnection* conn = appIds.find( appId );
1114  return conn;
1115 }
1116 
1120 void DCOPServer::slotCleanDeadConnections()
1121 {
1122 tqWarning("[dcopserver] DCOP Cleaning up dead connections.");
1123  while(!deadConnections.isEmpty())
1124  {
1125  IceConn iceConn = deadConnections.take(0);
1126  IceSetShutdownNegotiation (iceConn, False);
1127  (void) IceCloseConnection( iceConn );
1128  }
1129 }
1130 
1134 void DCOPServer::ioError( IceConn iceConn )
1135 {
1136  deadConnections.removeRef(iceConn);
1137  deadConnections.prepend(iceConn);
1138  m_deadConnectionTimer->start(0, true);
1139 }
1140 
1141 
1142 void DCOPServer::processData( int /*socket*/ )
1143 {
1144  IceConn iceConn = static_cast<const DCOPConnection*>(sender())->iceConn;
1145  IceProcessMessagesStatus status = IceProcessMessages( iceConn, 0, 0 );
1146  if ( status == IceProcessMessagesIOError ) {
1147  deadConnections.removeRef(iceConn);
1148  if (deadConnections.isEmpty())
1149  m_deadConnectionTimer->stop();
1150  IceSetShutdownNegotiation (iceConn, False);
1151  (void) IceCloseConnection( iceConn );
1152  }
1153 }
1154 
1155 void DCOPServer::newClient( int /*socket*/ )
1156 {
1157  IceAcceptStatus status;
1158  IceConn iceConn = IceAcceptConnection( static_cast<const DCOPListener*>(sender())->listenObj, &status);
1159  if (!iceConn) {
1160  if (status == IceAcceptBadMalloc)
1161  tqWarning("[dcopserver] Failed to alloc connection object!");
1162  else // IceAcceptFailure
1163  tqWarning("[dcopserver] Failed to accept ICE connection!");
1164  return;
1165  }
1166 
1167  IceSetShutdownNegotiation( iceConn, False );
1168 
1169  IceConnectStatus cstatus;
1170  while ((cstatus = IceConnectionStatus (iceConn))==IceConnectPending) {
1171  (void) IceProcessMessages( iceConn, 0, 0 );
1172  }
1173 
1174  if (cstatus != IceConnectAccepted) {
1175  if (cstatus == IceConnectIOError)
1176  tqWarning ("[dcopserver] IO error opening ICE Connection!");
1177  else
1178  tqWarning ("[dcopserver] ICE Connection rejected!");
1179  deadConnections.removeRef(iceConn);
1180  (void) IceCloseConnection (iceConn);
1181  }
1182 }
1183 
1184 void* DCOPServer::watchConnection( IceConn iceConn )
1185 {
1186  DCOPConnection* con = new DCOPConnection( iceConn );
1187  connect( con, TQT_SIGNAL( activated(int) ), this, TQT_SLOT( processData(int) ) );
1188 
1189  clients.insert(iceConn, con );
1190  fd_clients.insert( IceConnectionNumber(iceConn), con);
1191 
1192  return static_cast<void*>(con);
1193 }
1194 
1195 void DCOPServer::removeConnection( void* data )
1196 {
1197  DCOPConnection* conn = static_cast<DCOPConnection*>(data);
1198 
1199  dcopSignals->removeConnections(conn);
1200 
1201  clients.remove(conn->iceConn );
1202  fd_clients.remove( IceConnectionNumber(conn->iceConn) );
1203 
1204  // Send DCOPReplyFailed to all in conn->waitingForReply
1205  while (!conn->waitingForReply.isEmpty()) {
1206  IceConn iceConn = conn->waitingForReply.take(0);
1207  if (iceConn) {
1208  DCOPConnection* target = clients.find( iceConn );
1209  tqWarning("[dcopserver] DCOP aborting call from '%s' to '%s'", target ? target->appId.data() : "<unknown>" , conn->appId.data() );
1210  TQByteArray reply;
1211  DCOPMsg *pMsg;
1212  IceGetHeader( iceConn, majorOpcode, DCOPReplyFailed,
1213  sizeof(DCOPMsg), DCOPMsg, pMsg );
1214  pMsg->key = 1;
1215  pMsg->length += reply.size();
1216  _DCOPIceSendBegin( iceConn );
1217  DCOPIceSendData(iceConn, reply);
1218  _DCOPIceSendEnd();
1219  if (!target)
1220  tqWarning("[dcopserver] Unknown target in waitingForReply");
1221  else if (!target->waitingOnReply.removeRef(conn->iceConn))
1222  tqWarning("[dcopserver] Client in waitingForReply wasn't waiting on reply");
1223  }
1224  }
1225 
1226  // Send DCOPReplyFailed to all in conn->waitingForDelayedReply
1227  while (!conn->waitingForDelayedReply.isEmpty()) {
1228  IceConn iceConn = conn->waitingForDelayedReply.take(0);
1229  if (iceConn) {
1230  DCOPConnection* target = clients.find( iceConn );
1231  tqWarning("[dcopserver] DCOP aborting (delayed) call from '%s' to '%s'", target ? target->appId.data() : "<unknown>", conn->appId.data() );
1232  TQByteArray reply;
1233  DCOPMsg *pMsg;
1234  IceGetHeader( iceConn, majorOpcode, DCOPReplyFailed,
1235  sizeof(DCOPMsg), DCOPMsg, pMsg );
1236  pMsg->key = 1;
1237  pMsg->length += reply.size();
1238  _DCOPIceSendBegin( iceConn );
1239  DCOPIceSendData( iceConn, reply );
1240  _DCOPIceSendEnd();
1241  if (!target)
1242  tqWarning("[dcopserver] Unknown target in waitingForDelayedReply");
1243  else if (!target->waitingOnReply.removeRef(conn->iceConn))
1244  tqWarning("[dcopserver] Client in waitingForDelayedReply wasn't waiting on reply");
1245  }
1246  }
1247  while (!conn->waitingOnReply.isEmpty())
1248  {
1249  IceConn iceConn = conn->waitingOnReply.take(0);
1250  if (iceConn) {
1251  DCOPConnection* target = clients.find( iceConn );
1252  if (!target)
1253  {
1254  tqWarning("[dcopserver] Still waiting for answer from non-existing client.");
1255  continue;
1256  }
1257  tqWarning("[dcopserver] DCOP aborting while waiting for answer from '%s'", target->appId.data());
1258  if (!target->waitingForReply.removeRef(conn->iceConn) &&
1259  !target->waitingForDelayedReply.removeRef(conn->iceConn))
1260  tqWarning("[dcopserver] Called client has forgotten about caller");
1261  }
1262  }
1263 
1264  if ( !conn->appId.isNull() ) {
1265 #ifndef NDEBUG
1266  tqDebug("DCOP: unregister '%s'", conn->appId.data() );
1267 #endif
1268  if ( !conn->daemon )
1269  {
1270  currentClientNumber--;
1271  }
1272 
1273  appIds.remove( conn->appId );
1274 
1275  broadcastApplicationRegistration( conn, "applicationRemoved(TQCString)", conn->appId );
1276  }
1277 
1278  delete conn;
1279 
1280  if ( suicide && (currentClientNumber == 0) )
1281  {
1282  m_timer->start( 10000 ); // if within 10 seconds nothing happens, we'll terminate
1283  }
1284  if ( shutdown && appIds.isEmpty())
1285  {
1286  m_timer->start( 10 ); // Exit now
1287  }
1288 }
1289 
1290 void DCOPServer::slotTerminate()
1291 {
1292 #ifndef NDEBUG
1293  fprintf( stderr, "[dcopserver] slotTerminate() -> sending terminateTDE signal." );
1294 #endif
1295  TQByteArray data;
1296  dcopSignals->emitSignal(0L /* dcopserver */, "terminateTDE()", data, false);
1297  disconnect( m_timer, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotTerminate()) );
1298  connect( m_timer, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotSuicide()) );
1299  system(findDcopserverShutdown()+" --nokill");
1300 }
1301 
1302 void DCOPServer::slotSuicide()
1303 {
1304 #ifndef NDEBUG
1305  fprintf( stderr, "[dcopserver] slotSuicide() -> exit." );
1306 #endif
1307  exit(0);
1308 }
1309 
1310 void DCOPServer::slotShutdown()
1311 {
1312 #ifndef NDEBUG
1313  fprintf( stderr, "[dcopserver] slotShutdown() -> waiting for clients to disconnect." );
1314 #endif
1315  char c;
1316 #ifndef Q_OS_WIN
1317  read(pipeOfDeath[0], &c, 1);
1318 #endif
1319  if (!shutdown)
1320  {
1321  shutdown = true;
1322  TQByteArray data;
1323  dcopSignals->emitSignal(0L /* dcopserver */, "terminateTDE()", data, false);
1324  m_timer->start( 10000 ); // if within 10 seconds nothing happens, we'll terminate
1325  disconnect( m_timer, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotTerminate()) );
1326  connect( m_timer, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotExit()) );
1327  if (appIds.isEmpty())
1328  slotExit(); // Exit now
1329  }
1330 }
1331 
1332 void DCOPServer::slotExit()
1333 {
1334 #ifndef NDEBUG
1335  fprintf( stderr, "[dcopserver] slotExit() -> exit." );
1336 #endif
1337 #ifdef Q_OS_WIN
1338  SetEvent(m_evTerminate);
1339  if(m_dwTerminateThreadId != GetCurrentThreadId())
1340  WaitForSingleObject(m_hTerminateThread,INFINITE);
1341  CloseHandle(m_hTerminateThread);
1342 #endif
1343  exit(0);
1344 }
1345 
1346 bool DCOPServer::receive(const TQCString &/*app*/, const TQCString &obj,
1347  const TQCString &fun, const TQByteArray& data,
1348  TQCString& replyType, TQByteArray &replyData,
1349  IceConn iceConn)
1350 {
1351 #ifdef DCOP_LOG
1352  (*m_stream) << "Received a message: obj =\""
1353  << obj << "\", fun =\""
1354  << fun << "\", replyType =\""
1355  << replyType << "\", data.size() =\""
1356  << data.size() << "\", replyData.size() ="
1357  << replyData.size() << "";
1358  m_logger->flush();
1359 #endif
1360 
1361  if ( obj == "emit")
1362  {
1363  DCOPConnection* conn = clients.find( iceConn );
1364  if (conn) {
1365  //tqDebug("DCOPServer: %s emits %s", conn->appId.data(), fun.data());
1366  dcopSignals->emitSignal(conn, fun, data, false);
1367  }
1368  replyType = "void";
1369  return true;
1370  }
1371  if ( fun == "setDaemonMode(bool)" ) {
1372  TQDataStream args( data, IO_ReadOnly );
1373  if ( !args.atEnd() ) {
1374  TQ_INT8 iDaemon;
1375  bool daemon;
1376  args >> iDaemon;
1377 
1378  daemon = static_cast<bool>( iDaemon );
1379 
1380  DCOPConnection* conn = clients.find( iceConn );
1381  if ( conn && !conn->appId.isNull() ) {
1382  if ( daemon ) {
1383  if ( !conn->daemon )
1384  {
1385  conn->daemon = true;
1386 
1387 #ifndef NDEBUG
1388  tqDebug( "DCOP: new daemon %s", conn->appId.data() );
1389 #endif
1390 
1391  currentClientNumber--;
1392 
1393 // David says it's safer not to do this :-)
1394 // if ( currentClientNumber == 0 )
1395 // m_timer->start( 10000 );
1396  }
1397  } else
1398  {
1399  if ( conn->daemon ) {
1400  conn->daemon = false;
1401 
1402  currentClientNumber++;
1403 
1404  m_timer->stop();
1405  }
1406  }
1407  }
1408 
1409  replyType = "void";
1410  return true;
1411  }
1412  }
1413  if ( fun == "registerAs(TQCString)" ) {
1414  TQDataStream args( data, IO_ReadOnly );
1415  if (!args.atEnd()) {
1416  TQCString app2 = readQCString(args);
1417  TQDataStream reply( replyData, IO_WriteOnly );
1418  DCOPConnection* conn = clients.find( iceConn );
1419  if ( conn && !app2.isEmpty() ) {
1420  if ( !conn->appId.isNull() &&
1421  appIds.find( conn->appId ) == conn ) {
1422  appIds.remove( conn->appId );
1423 
1424  }
1425 
1426  TQCString oldAppId;
1427  if ( conn->appId.isNull() )
1428  {
1429  currentClientNumber++;
1430  m_timer->stop(); // abort termination if we were planning one
1431 #ifndef NDEBUG
1432  tqDebug("DCOP: register '%s' -> number of clients is now %d", app2.data(), currentClientNumber );
1433 #endif
1434  }
1435 #ifndef NDEBUG
1436  else
1437  {
1438  oldAppId = conn->appId;
1439  tqDebug("DCOP: '%s' now known as '%s'", conn->appId.data(), app2.data() );
1440  }
1441 #endif
1442 
1443  conn->appId = app2;
1444  if ( appIds.find( app2 ) != 0 ) {
1445  // we already have this application, unify
1446  int n = 1;
1447  TQCString tmp;
1448  do {
1449  n++;
1450  tmp.setNum( n );
1451  tmp.prepend("-");
1452  tmp.prepend( app2 );
1453  } while ( appIds.find( tmp ) != 0 );
1454  conn->appId = tmp;
1455  }
1456  appIds.insert( conn->appId, conn );
1457 
1458  int c = conn->appId.find( '-' );
1459  if ( c > 0 )
1460  conn->plainAppId = conn->appId.left( c );
1461  else
1462  conn->plainAppId = conn->appId;
1463 
1464  if( !oldAppId.isEmpty())
1465  broadcastApplicationRegistration( conn,
1466  "applicationRemoved(TQCString)", oldAppId );
1467  broadcastApplicationRegistration( conn, "applicationRegistered(TQCString)", conn->appId );
1468  }
1469  replyType = "TQCString";
1470  reply << conn->appId;
1471  return true;
1472  }
1473  }
1474  else if ( fun == "registeredApplications()" ) {
1475  TQDataStream reply( replyData, IO_WriteOnly );
1476  QCStringList applications;
1477  TQAsciiDictIterator<DCOPConnection> it( appIds );
1478  while ( it.current() ) {
1479  applications << it.currentKey();
1480  ++it;
1481  }
1482  replyType = "QCStringList";
1483  reply << applications;
1484  return true;
1485  } else if ( fun == "isApplicationRegistered(TQCString)" ) {
1486  TQDataStream args( data, IO_ReadOnly );
1487  if (!args.atEnd()) {
1488  TQCString s = readQCString(args);
1489  TQDataStream reply( replyData, IO_WriteOnly );
1490  int b = ( findApp( s ) != 0 );
1491  replyType = "bool";
1492  reply << b;
1493  return true;
1494  }
1495  } else if ( fun == "setNotifications(bool)" ) {
1496  TQDataStream args( data, IO_ReadOnly );
1497  if (!args.atEnd()) {
1498  TQ_INT8 notifyActive;
1499  args >> notifyActive;
1500  DCOPConnection* conn = clients.find( iceConn );
1501  if ( conn ) {
1502  if ( notifyActive )
1503  conn->notifyRegister++;
1504  else if ( conn->notifyRegister > 0 )
1505  conn->notifyRegister--;
1506  }
1507  replyType = "void";
1508  return true;
1509  }
1510  } else if ( fun == "connectSignal(TQCString,TQCString,TQCString,TQCString,TQCString,bool)") {
1511  DCOPConnection* conn = clients.find( iceConn );
1512  if (!conn) return false;
1513  TQDataStream args(data, IO_ReadOnly );
1514  if (args.atEnd()) return false;
1515  TQCString sender = readQCString(args);
1516  TQCString senderObj = readQCString(args);
1517  TQCString signal = readQCString(args);
1518  TQCString receiverObj = readQCString(args);
1519  TQCString slot = readQCString(args);
1520  TQ_INT8 Volatile;
1521  args >> Volatile;
1522 #ifdef DCOP_DEBUG
1523  tqDebug("DCOPServer: connectSignal(sender = %s senderObj = %s signal = %s recvObj = %s slot = %s)", sender.data(), senderObj.data(), signal.data(), receiverObj.data(), slot.data());
1524 #endif
1525  bool b = dcopSignals->connectSignal(sender, senderObj, signal, conn, receiverObj, slot, (Volatile != 0));
1526  replyType = "bool";
1527  TQDataStream reply( replyData, IO_WriteOnly );
1528  reply << (TQ_INT8) (b?1:0);
1529  return true;
1530  } else if ( fun == "disconnectSignal(TQCString,TQCString,TQCString,TQCString,TQCString)") {
1531  DCOPConnection* conn = clients.find( iceConn );
1532  if (!conn) return false;
1533  TQDataStream args(data, IO_ReadOnly );
1534  if (args.atEnd()) return false;
1535  TQCString sender = readQCString(args);
1536  TQCString senderObj = readQCString(args);
1537  TQCString signal = readQCString(args);
1538  TQCString receiverObj = readQCString(args);
1539  TQCString slot = readQCString(args);
1540 #ifdef DCOP_DEBUG
1541  tqDebug("DCOPServer: disconnectSignal(sender = %s senderObj = %s signal = %s recvObj = %s slot = %s)", sender.data(), senderObj.data(), signal.data(), receiverObj.data(), slot.data());
1542 #endif
1543  bool b = dcopSignals->disconnectSignal(sender, senderObj, signal, conn, receiverObj, slot);
1544  replyType = "bool";
1545  TQDataStream reply( replyData, IO_WriteOnly );
1546  reply << (TQ_INT8) (b?1:0);
1547  return true;
1548  }
1549 
1550  return false;
1551 }
1552 
1553 void DCOPServer::broadcastApplicationRegistration( DCOPConnection* conn, const TQCString type,
1554  const TQCString& appId )
1555 {
1556  TQByteArray data;
1557  TQDataStream datas( data, IO_WriteOnly );
1558  datas << appId;
1559  TQPtrDictIterator<DCOPConnection> it( clients );
1560  TQByteArray ba;
1561  TQDataStream ds( ba, IO_WriteOnly );
1562  ds <<TQCString("DCOPServer") << TQCString("") << TQCString("")
1563  << type << data;
1564  int datalen = ba.size();
1565  DCOPMsg *pMsg = 0;
1566  while ( it.current() ) {
1567  DCOPConnection* c = it.current();
1568  ++it;
1569  if ( c->notifyRegister && (c != conn) ) {
1570  IceGetHeader( c->iceConn, majorOpcode, DCOPSend,
1571  sizeof(DCOPMsg), DCOPMsg, pMsg );
1572  pMsg->key = 1;
1573  pMsg->length += datalen;
1574  _DCOPIceSendBegin(c->iceConn);
1575  DCOPIceSendData( c->iceConn, ba );
1576  _DCOPIceSendEnd();
1577  }
1578  }
1579 }
1580 
1581 void
1582 DCOPServer::sendMessage(DCOPConnection *conn, const TQCString &sApp,
1583  const TQCString &rApp, const TQCString &rObj,
1584  const TQCString &rFun, const TQByteArray &data)
1585 {
1586  TQByteArray ba;
1587  TQDataStream ds( ba, IO_WriteOnly );
1588  ds << sApp << rApp << rObj << rFun << data;
1589  int datalen = ba.size();
1590  DCOPMsg *pMsg = 0;
1591 
1592  IceGetHeader( conn->iceConn, majorOpcode, DCOPSend,
1593  sizeof(DCOPMsg), DCOPMsg, pMsg );
1594  pMsg->length += datalen;
1595  pMsg->key = 1; // important!
1596 
1597 #ifdef DCOP_LOG
1598  (*m_stream) << "Sending a message: sApp =\""
1599  << sApp << "\", rApp =\""
1600  << rApp << "\", rObj =\""
1601  << rObj << "\", rFun =\""
1602  << rFun << "\", datalen ="
1603  << datalen << "\n";
1604  m_logger->flush();
1605 #endif
1606 
1607  _DCOPIceSendBegin( conn->iceConn );
1608  DCOPIceSendData(conn->iceConn, ba);
1609  _DCOPIceSendEnd();
1610 }
1611 
1612 void IoErrorHandler ( IceConn iceConn)
1613 {
1614  the_server->ioError( iceConn );
1615 }
1616 
1617 static bool isRunning(const TQCString &fName, bool printNetworkId = false)
1618 {
1619  if (::access(fName.data(), R_OK) == 0) {
1620  TQFile f(fName);
1621  f.open(IO_ReadOnly);
1622  int size = TQMIN( (qint64)1024, f.size() ); // protection against a huge file
1623  TQCString contents( size+1 );
1624  bool ok = f.readBlock( contents.data(), size ) == size;
1625  contents[size] = '\0';
1626  int pos = contents.find('\n');
1627  ok = ok && ( pos != -1 );
1628  pid_t pid = ok ? contents.mid(pos+1).toUInt(&ok) : 0;
1629  f.close();
1630  if (ok && pid && (kill(pid, SIGHUP) == 0)) {
1631  if (printNetworkId)
1632  tqWarning("[dcopserver] %s", contents.left(pos).data());
1633  else
1634  tqWarning( "---------------------------------\n"
1635  "[dcopserver] It looks like dcopserver is already running. If you are sure\n"
1636  "that it is not already running, remove %s\n"
1637  "and start dcopserver again.\n"
1638  "---------------------------------",
1639  fName.data() );
1640 
1641  // lock file present, die silently.
1642  return true;
1643  } else {
1644  // either we couldn't read the PID or kill returned an error.
1645  // remove lockfile and continue
1646  unlink(fName.data());
1647  }
1648  } else if (errno != ENOENT) {
1649  // remove lockfile and continue
1650  unlink(fName.data());
1651  }
1652  return false;
1653 }
1654 
1655 const char* const ABOUT =
1656 "Usage: dcopserver [--nofork] [--nosid] [--help]\n"
1657 " dcopserver --serverid\n"
1658 "\n"
1659 "DCOP is TDE's Desktop Communications Protocol. It is a lightweight IPC/RPC\n"
1660 "mechanism built on top of the X Consortium's Inter Client Exchange protocol.\n"
1661 "It enables desktop applications to communicate reliably with low overhead.\n"
1662 "\n"
1663 "Copyright (C) 1999-2001, The KDE Developers <http://www.kde.org>\n"
1664 ;
1665 
1666 extern "C" DCOP_EXPORT int kdemain( int argc, char* argv[] )
1667 {
1668  bool serverid = false;
1669  bool nofork = false;
1670  bool nosid = false;
1671  bool suicide = false;
1672  for(int i = 1; i < argc; i++) {
1673  if (strcmp(argv[i], "--nofork") == 0)
1674  nofork = true;
1675  else if (strcmp(argv[i], "--nosid") == 0)
1676  nosid = true;
1677  else if (strcmp(argv[i], "--nolocal") == 0)
1678  ; // Ignore
1679  else if (strcmp(argv[i], "--suicide") == 0)
1680  suicide = true;
1681  else if (strcmp(argv[i], "--serverid") == 0)
1682  serverid = true;
1683  else {
1684  fprintf(stdout, "%s", ABOUT );
1685  return 0;
1686  }
1687  }
1688 
1689  if (serverid)
1690  {
1691  if (isRunning(DCOPClient::dcopServerFile(), true))
1692  return 0;
1693  return 1;
1694  }
1695 
1696  // check if we are already running
1697  if (isRunning(DCOPClient::dcopServerFile()))
1698  return 0;
1699 #ifndef Q_OS_WIN32
1700  if (TQCString(getenv("DCOPAUTHORITY")).isEmpty() &&
1701  isRunning(DCOPClient::dcopServerFileOld()))
1702  {
1703  // Make symlink for compatibility
1704  TQCString oldFile = DCOPClient::dcopServerFileOld();
1705  TQCString newFile = DCOPClient::dcopServerFile();
1706  symlink(oldFile.data(), newFile.data());
1707  return 0;
1708  }
1709 
1710  struct rlimit limits;
1711 
1712  int retcode = getrlimit(RLIMIT_NOFILE, &limits);
1713  if (!retcode) {
1714  if (limits.rlim_max > 512 && limits.rlim_cur < 512)
1715  {
1716  int cur_limit = limits.rlim_cur;
1717  limits.rlim_cur = 512;
1718  retcode = setrlimit(RLIMIT_NOFILE, &limits);
1719 
1720  if (retcode != 0)
1721  {
1722  tqWarning("[dcopserver] Could not raise limit on number of open files.");
1723  tqWarning("[dcopserver] Current limit = %d", cur_limit);
1724  }
1725  }
1726  }
1727 #endif
1728  pipe(ready);
1729 
1730 #ifndef Q_OS_WIN32
1731  if (!nofork) {
1732  pid_t pid = fork();
1733  if (pid > 0) {
1734  char c = 1;
1735  close(ready[1]);
1736  read(ready[0], &c, 1); // Wait till dcopserver is started
1737  close(ready[0]);
1738  // I am the parent
1739  if (c == 0)
1740  {
1741  // Test whether we are functional.
1742  DCOPClient client;
1743  if (client.attach())
1744  return 0;
1745  }
1746  tqWarning("[dcopserver] DCOPServer self-test failed.");
1747  system(findDcopserverShutdown()+" --kill");
1748  return 1;
1749  }
1750  close(ready[0]);
1751 
1752  if (!nosid)
1753  setsid();
1754 
1755  if (fork() > 0)
1756  return 0; // get rid of controlling terminal
1757  }
1758 
1759  pipe(pipeOfDeath);
1760 
1761  signal(SIGHUP, sighandler);
1762  signal(SIGTERM, sighandler);
1763  signal(SIGPIPE, SIG_IGN);
1764 #else
1765  {
1766  char c = 1;
1767  close(ready[1]);
1768  read(ready[0], &c, 1); // Wait till dcopserver is started
1769  close(ready[0]);
1770  }
1771 #endif
1772  putenv(strdup("SESSION_MANAGER="));
1773 
1774  TQApplication a( argc, argv, false );
1775 
1776  IceSetIOErrorHandler (IoErrorHandler );
1777  DCOPServer *server = new DCOPServer(suicide); // this sets the_server
1778 
1779 #ifdef Q_OS_WIN
1780  SetConsoleCtrlHandler(DCOPServer::dcopServerConsoleProc,TRUE);
1781 #else
1782  TQSocketNotifier DEATH(pipeOfDeath[0], TQSocketNotifier::Read, 0, 0);
1783  server->connect(&DEATH, TQT_SIGNAL(activated(int)), TQT_SLOT(slotShutdown()));
1784 #endif
1785 
1786  int ret = a.exec();
1787  delete server;
1788  return ret;
1789 }
1790 
1791 #ifdef Q_OS_WIN
1792 #include "dcopserver_win.cpp"
1793 #endif
1794 
1795 #include "dcopserver.moc"
DCOPClient::iceauthPath
static TQCString iceauthPath()
Return the path of iceauth or an empty string if not found.
Definition: dcopclient.cpp:214
TDEStdAccel::key
int key(StdAccel) KDE_DEPRECATED
DCOPClient::attach
bool attach()
Attaches to the DCOP server.
Definition: dcopclient.cpp:679
TDEStdAccel::open
const TDEShortcut & open()
DCOPClient
Inter-process communication and remote procedure calls for KDE applications.
Definition: dcopclient.h:68
TDEStdAccel::close
const TDEShortcut & close()
DCOPClient::dcopServerFile
static TQCString dcopServerFile(const TQCString &hostname=0)
File with information how to reach the dcopserver.
Definition: dcopclient.cpp:316
DCOPReply
Represents the return value of a DCOPRef:call() or DCOPRef:send() invocation.
Definition: dcopref.h:44
DCOPClient::dcopServerFileOld
static TQCString dcopServerFileOld(const TQCString &hostname=0) KDE_DEPRECATED
Definition: dcopclient.cpp:323

dcop

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

dcop

Skip menu "dcop"
  • 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 dcop by doxygen 1.8.8
This website is maintained by Timothy Pearson.