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

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
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for dcop by doxygen 1.9.1
This website is maintained by Timothy Pearson.