• 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
5Copyright (c) 1999,2000 Preston Brown <pbrown@kde.org>
6Copyright (c) 1999,2000 Matthias Ettrich <ettrich@kde.org>
7Copyright (c) 1999,2001 Waldo Bastian <bastian@kde.org>
8
9Permission is hereby granted, free of charge, to any person obtaining a copy
10of this software and associated documentation files (the "Software"), to deal
11in the Software without restriction, including without limitation the rights
12to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13copies of the Software, and to permit persons to whom the Software is
14furnished to do so, subject to the following conditions:
15
16The above copyright notice and this permission notice shall be included in
17all copies or substantial portions of the Software.
18
19THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24CONNECTION 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
71DCOPServer* the_server;
72
73template class TQDict<DCOPConnection>;
74template class TQPtrDict<DCOPConnection>;
75template 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
84static 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
112static Bool HostBasedAuthProc ( char* /*hostname*/)
113{
114 return false; // no host based authentication
115}
116
117extern "C" {
118extern IceWriteHandler _kde_IceWriteHandler;
119extern IceIOErrorHandler _kde_IceIOErrorHandler;
120void DCOPIceWriteChar(IceConn iceConn, unsigned long nbytes, char *ptr);
121}
122
123static 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
142static 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
161extern "C" {
162extern int _kde_IceTransWrite (void * ciptr, char *buf, int size);
163}
164
165static 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
239void DCOPIceWriteChar(IceConn iceConn, unsigned long nbytes, char *ptr)
240{
241 DCOPConnection* conn = the_server->findConn( iceConn );
242#ifdef DCOP_DEBUG
243tqWarning("[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
253tqWarning("[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
271static void DCOPIceWrite(IceConn iceConn, const TQByteArray &_data)
272{
273 DCOPConnection* conn = the_server->findConn( iceConn );
274#ifdef DCOP_DEBUG
275tqWarning("[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
282tqWarning("[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
298void DCOPConnection::waitForOutputReady(const TQByteArray &_data, int start)
299{
300#ifdef DCOP_DEBUG
301tqWarning("[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
316void DCOPServer::slotOutputReady(int socket)
317{
318#ifdef DCOP_DEBUG
319tqWarning("[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
331void 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
353tqWarning("[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
372tqWarning("[dcopserver] slotOutputRead() all data transmitted.");
373#endif
374 outputBlocked = false;
375 outputBufferNotifier->setEnabled(false);
376 }
377#ifdef DCOP_DEBUG
378else
379{
380tqWarning("[dcopserver] slotOutputRead() more data to send.");
381}
382#endif
383 }
384}
385
386static void DCOPIceSendData(IceConn _iceConn,
387 const TQByteArray &_data)
388{
389 if (_iceConn->outbufptr > _iceConn->outbuf)
390 {
391#ifdef DCOP_DEBUG
392tqWarning("[dcopserver] Flushing data, fd = %d", IceConnectionNumber(_iceConn));
393#endif
394 IceFlush( _iceConn );
395 }
396 DCOPIceWrite(_iceConn, _data);
397}
398
399class DCOPListener : public TQSocketNotifier
400{
401public:
402 DCOPListener( IceListenObj obj )
403 : TQSocketNotifier( IceGetListenConnectionNumber( obj ),
404 TQSocketNotifier::Read, 0, 0)
405{
406 listenObj = obj;
407}
408
409 IceListenObj listenObj;
410};
411
412DCOPConnection::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
425DCOPConnection::~DCOPConnection()
426{
427 delete _signalConnectionList;
428 delete outputBufferNotifier;
429}
430
431DCOPSignalConnectionList *
432DCOPConnection::signalConnectionList()
433{
434 if (!_signalConnectionList)
435 _signalConnectionList = new DCOPSignalConnectionList;
436 return _signalConnectionList;
437}
438
439static IceAuthDataEntry *authDataEntries;
440static char *addAuthFile;
441
442static IceListenObj *listenObjs;
443static int numTransports;
444static int ready[2];
445
446
447/* for printing hex digits */
448static 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 */
463static void
464write_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
494int 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
545static 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
575Status
576SetAuthentication (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 */
677void
678FreeAuthenticationData(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
692void 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
704void DCOPProcessMessage( IceConn iceConn, IcePointer /*clientData*/,
705 int opcode, unsigned long length, Bool swap)
706{
707 the_server->processMessage( iceConn, opcode, length, swap );
708}
709
710void 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
745if (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
771if (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
813if (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
923static const IcePaVersionRec DCOPServerVersions[] = {
924 { DCOPVersionMajor, DCOPVersionMinor, DCOPProcessMessage }
925};
926
927static const IcePoVersionRec DUMMYVersions[] = {
928 { DCOPVersionMajor, DCOPVersionMinor, 0 }
929};
930
931static 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
952static int pipeOfDeath[2];
953
954static 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
965extern "C"
966{
967 extern int _kde_IceLastMajorOpcode; // from libICE
968}
969
970DCOPServer::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
1091DCOPServer::~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
1108DCOPConnection* DCOPServer::findApp( const TQCString& appId )
1109{
1110 if ( appId.isNull() )
1111 return 0;
1112 DCOPConnection* conn = appIds.find( appId );
1113 return conn;
1114}
1115
1119void DCOPServer::slotCleanDeadConnections()
1120{
1121tqWarning("[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
1133void DCOPServer::ioError( IceConn iceConn )
1134{
1135 deadConnections.removeRef(iceConn);
1136 deadConnections.prepend(iceConn);
1137 m_deadConnectionTimer->start(0, true);
1138}
1139
1140
1141void 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
1154void 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
1183void* 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
1194void 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
1289void 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
1301void DCOPServer::slotSuicide()
1302{
1303#ifndef NDEBUG
1304 fprintf( stderr, "[dcopserver] slotSuicide() -> exit." );
1305#endif
1306 exit(0);
1307}
1308
1309void 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
1331void 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
1345bool 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
1552void 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
1580void
1581DCOPServer::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
1611void IoErrorHandler ( IceConn iceConn)
1612{
1613 the_server->ioError( iceConn );
1614}
1615
1616static 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
1654const 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
1665extern "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.4
This website is maintained by Timothy Pearson.