30 #include <sys/types.h>
31 #ifdef HAVE_SYS_STAT_H
34 #ifdef HAVE_SYS_PARAM_H
35 #include <sys/param.h>
37 #include <sys/resource.h>
38 #include <sys/socket.h>
51 #include <tqtextstream.h>
52 #include <tqdatastream.h>
53 #include <tqptrstack.h>
56 #include "dcopserver.h"
58 #include <dcopsignals.h>
59 #include <dcopclient.h>
60 #include <dcopglobal.h>
61 #include "dcop-path.h"
71 DCOPServer* the_server;
73 template class TQDict<DCOPConnection>;
74 template class TQPtrDict<DCOPConnection>;
75 template class TQPtrList<DCOPListener>;
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);
84 static TQCString findDcopserverShutdown()
90 ret = SearchPathA(NULL,
"dcopserver_shutdown",
"exe",
sizeof(szPath)/
sizeof(szPath[0]),szPath,&pszFilePart);
92 return TQCString(szPath);
94 TQCString path = getenv(
"PATH");
95 char *dir = strtok(path.data(),
":");
99 file +=
"/dcopserver_shutdown";
100 if (access(file.data(), X_OK) == 0)
102 dir = strtok(NULL,
":");
104 TQCString file = DCOP_PATH;
105 file +=
"/dcopserver_shutdown";
106 if (access(file.data(), X_OK) == 0)
109 return TQCString(
"dcopserver_shutdown");
112 static Bool HostBasedAuthProc (
char* )
118 extern IceWriteHandler _kde_IceWriteHandler;
119 extern IceIOErrorHandler _kde_IceIOErrorHandler;
120 void DCOPIceWriteChar(IceConn iceConn,
unsigned long nbytes,
char *ptr);
123 static TQCString readQCString(TQDataStream &ds)
128 TQIODevice *device = ds.device();
129 int bytesLeft = device->size()-device->at();
130 if ((bytesLeft < 0 ) || (len > (uint) bytesLeft))
132 tqWarning(
"[dcopserver] Corrupt data!");
133 printf(
"[dcopserver] bytesLeft: %d, len: %d", bytesLeft, len);
136 result.TQByteArray::resize( (uint)len );
138 ds.readRawBytes( result.data(), (uint)len);
142 static TQByteArray readQByteArray(TQDataStream &ds)
147 TQIODevice *device = ds.device();
148 int bytesLeft = device->size()-device->at();
149 if ((bytesLeft < 0 ) || (len > (uint) bytesLeft))
151 tqWarning(
"[dcopserver] Corrupt data!");
154 result.resize( (uint)len );
156 ds.readRawBytes( result.data(), (uint)len);
162 extern int _kde_IceTransWrite (
void * ciptr,
char *buf,
int size);
165 static unsigned long writeIceData(IceConn iceConn,
unsigned long nbytes,
char *ptr)
167 int fd = IceConnectionNumber(iceConn);
168 unsigned long nleft = nbytes;
175 nwritten = send(fd, ptr, (
int) nleft, 0);
193 iceConn->io_ok = False;
195 if (iceConn->connection_status == IceConnectPending)
205 if (iceConn->process_msg_info)
209 for (i = iceConn->his_min_opcode;
210 i <= iceConn->his_max_opcode; i++)
212 _IceProcessMsgInfo *process;
214 process = &iceConn->process_msg_info[
215 i - iceConn->his_min_opcode];
219 IceIOErrorProc IOErrProc = process->accept_flag ?
220 process->protocol->accept_client->io_error_proc :
221 process->protocol->orig_client->io_error_proc;
224 (*IOErrProc) (iceConn);
229 (*_kde_IceIOErrorHandler) (iceConn);
239 void DCOPIceWriteChar(IceConn iceConn,
unsigned long nbytes,
char *ptr)
241 DCOPConnection* conn = the_server->findConn( iceConn );
243 tqWarning(
"[dcopserver] DCOPIceWriteChar() Writing %d bytes [%s]", nbytes, conn ? conn->appId.data() :
"<unknown>");
248 if (conn->outputBlocked)
250 TQByteArray _data(nbytes);
251 memcpy(_data.data(), ptr, nbytes);
253 tqWarning(
"[dcopserver] _IceWrite() outputBlocked. Queuing %d bytes.", _data.size());
255 conn->outputBuffer.append(_data);
261 unsigned long nleft = writeIceData(iceConn, nbytes, ptr);
262 if ((nleft > 0) && conn)
264 TQByteArray _data(nleft);
265 memcpy(_data.data(), ptr, nleft);
266 conn->waitForOutputReady(_data, 0);
271 static void DCOPIceWrite(IceConn iceConn,
const TQByteArray &_data)
273 DCOPConnection* conn = the_server->findConn( iceConn );
275 tqWarning(
"[dcopserver] DCOPIceWrite() Writing %d bytes [%s]", _data.size(), conn ? conn->appId.data() :
"<unknown>");
279 if (conn->outputBlocked)
282 tqWarning(
"[dcopserver] DCOPIceWrite() outputBlocked. Queuing %d bytes.", _data.size());
284 conn->outputBuffer.append(_data);
290 unsigned long nleft = writeIceData(iceConn, _data.size(),
const_cast<TQByteArray&
>(_data).data());
291 if ((nleft > 0) && conn)
293 conn->waitForOutputReady(_data, _data.size() - nleft);
298 void DCOPConnection::waitForOutputReady(
const TQByteArray &_data,
int start)
301 tqWarning(
"[dcopserver] waitForOutputReady fd = %d datasize = %d start = %d", socket(), _data.size(), start);
303 outputBlocked =
true;
304 outputBuffer.append(_data);
305 outputBufferStart = start;
306 if (!outputBufferNotifier)
308 outputBufferNotifier =
new TQSocketNotifier(socket(), Write);
309 connect(outputBufferNotifier, TQ_SIGNAL(activated(
int)),
310 the_server, TQ_SLOT(slotOutputReady(
int)));
312 outputBufferNotifier->setEnabled(
true);
316 void DCOPServer::slotOutputReady(
int socket)
319 tqWarning(
"[dcopserver] slotOutputReady fd = %d", socket);
322 DCOPConnection *conn = fd_clients.find(socket);
327 conn->slotOutputReady();
331 void DCOPConnection::slotOutputReady()
336 TQByteArray data = outputBuffer.first();
340 long fd_fl = fcntl(fd, F_GETFL, 0);
341 fcntl(fd, F_SETFL, fd_fl | O_NDELAY);
347 nwritten = ::send(fd,data.data()+outputBufferStart,data.size()-outputBufferStart,0);
350 fcntl(fd, F_SETFL, fd_fl);
353 tqWarning(
"[dcopserver] slotOutputReady() %d bytes written", nwritten);
358 if ((e == EINTR) || (e == EAGAIN))
360 (*_kde_IceIOErrorHandler) (iceConn);
363 outputBufferStart += nwritten;
365 if (outputBufferStart == data.size())
367 outputBufferStart = 0;
368 outputBuffer.remove(outputBuffer.begin());
369 if (outputBuffer.isEmpty())
372 tqWarning(
"[dcopserver] slotOutputRead() all data transmitted.");
374 outputBlocked =
false;
375 outputBufferNotifier->setEnabled(
false);
380 tqWarning(
"[dcopserver] slotOutputRead() more data to send.");
386 static void DCOPIceSendData(IceConn _iceConn,
387 const TQByteArray &_data)
389 if (_iceConn->outbufptr > _iceConn->outbuf)
392 tqWarning(
"[dcopserver] Flushing data, fd = %d", IceConnectionNumber(_iceConn));
394 IceFlush( _iceConn );
396 DCOPIceWrite(_iceConn, _data);
399 class DCOPListener :
public TQSocketNotifier
402 DCOPListener( IceListenObj obj )
403 : TQSocketNotifier( IceGetListenConnectionNumber( obj ),
404 TQSocketNotifier::Read, 0, 0)
409 IceListenObj listenObj;
412 DCOPConnection::DCOPConnection( IceConn conn )
413 : TQSocketNotifier( IceConnectionNumber( conn ),
414 TQSocketNotifier::Read, 0, 0 )
418 _signalConnectionList = 0;
420 outputBlocked =
false;
421 outputBufferNotifier = 0;
422 outputBufferStart = 0;
425 DCOPConnection::~DCOPConnection()
427 delete _signalConnectionList;
428 delete outputBufferNotifier;
431 DCOPSignalConnectionList *
432 DCOPConnection::signalConnectionList()
434 if (!_signalConnectionList)
435 _signalConnectionList =
new DCOPSignalConnectionList;
436 return _signalConnectionList;
439 static IceAuthDataEntry *authDataEntries;
440 static char *addAuthFile;
442 static IceListenObj *listenObjs;
443 static int numTransports;
448 static void fprintfhex (FILE *fp,
unsigned int len,
char *cp)
450 static char hexchars[] =
"0123456789abcdef";
452 for (; len > 0; len--, cp++) {
453 unsigned char s = *cp;
454 putc(hexchars[s >> 4], fp);
455 putc(hexchars[s & 0x0f], fp);
464 write_iceauth (FILE *addfp, IceAuthDataEntry *entry)
467 "add %s \"\" %s %s ",
468 entry->protocol_name,
471 fprintfhex (addfp, entry->auth_data_length, entry->auth_data);
472 fprintf (addfp,
"\n");
475 #ifndef HAVE_MKSTEMPS
494 int mkstemps (
char* _template,
int suffix_len)
496 static const char letters[] =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
502 len = strlen (_template);
504 if ((
int) len < 6 + suffix_len || strncmp (&_template[len - 6 - suffix_len],
"XXXXXX", 6))
507 XXXXXX = &_template[len - 6 - suffix_len];
510 for (count = 0; count < 256; ++count)
516 XXXXXX[0] = letters[v % 62];
518 XXXXXX[1] = letters[v % 62];
520 XXXXXX[2] = letters[v % 62];
522 XXXXXX[3] = letters[v % 62];
524 XXXXXX[4] = letters[v % 62];
526 XXXXXX[5] = letters[v % 62];
528 fd =
open (_template, O_RDWR|O_CREAT|O_EXCL, 0600);
545 static char *unique_filename (
const char *path,
const char *prefix,
int *pFd)
547 char tempFile[PATH_MAX];
551 snprintf (tempFile, PATH_MAX,
"%s\\%sXXXXXX", path, prefix);
553 snprintf (tempFile, PATH_MAX,
"%s/%sXXXXXX", path, prefix);
555 ptr =
static_cast<char *
>(malloc(strlen(tempFile) + 1));
558 int fd = mkstemps(tempFile, 0);
562 strcpy(ptr, tempFile);
573 #define MAGIC_COOKIE_LEN 16
576 SetAuthentication (
int count, IceListenObj *_listenObjs,
577 IceAuthDataEntry **_authDataEntries)
586 original_umask = umask (0077);
590 DWORD dw = GetTempPathA(
sizeof(temppath),temppath);
593 temppath[dw - 1] = 0;
599 path = getenv (
"DCOP_SAVE_DIR");
603 if ((addAuthFile = unique_filename (path,
"dcop", &fd)) == NULL)
606 if (!(addfp = fdopen(fd,
"wb")))
609 if ((*_authDataEntries =
static_cast<IceAuthDataEntry *
>(malloc (count * 2 *
sizeof (IceAuthDataEntry)))) == NULL)
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");
618 (*_authDataEntries)[i].auth_data =
619 IceGenerateMagicCookie (MAGIC_COOKIE_LEN);
620 (*_authDataEntries)[i].auth_data_length = MAGIC_COOKIE_LEN;
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");
627 (*_authDataEntries)[i+1].auth_data =
628 IceGenerateMagicCookie (MAGIC_COOKIE_LEN);
629 (*_authDataEntries)[i+1].auth_data_length = MAGIC_COOKIE_LEN;
631 write_iceauth (addfp, &(*_authDataEntries)[i]);
632 write_iceauth (addfp, &(*_authDataEntries)[i+1]);
634 IceSetPaAuthData (2, &(*_authDataEntries)[i]);
636 IceSetHostBasedAuthProc (_listenObjs[i/2], HostBasedAuthProc);
641 umask (original_umask);
645 if (command.isEmpty())
647 fprintf( stderr,
"[dcopserver] 'iceauth' not found in path, aborting." );
651 command +=
" source ";
652 command += addAuthFile;
669 umask (original_umask);
678 FreeAuthenticationData(
int count, IceAuthDataEntry *_authDataEntries)
683 for (i = 0; i < count * 2; i++) {
684 free (_authDataEntries[i].network_id);
685 free (_authDataEntries[i].auth_data);
688 free(_authDataEntries);
692 void DCOPWatchProc ( IceConn iceConn, IcePointer client_data, Bool opening, IcePointer* watch_data)
694 DCOPServer* ds =
static_cast<DCOPServer*
>(client_data);
697 *watch_data =
static_cast<IcePointer
>(ds->watchConnection( iceConn ));
700 ds->removeConnection(
static_cast<void*
>(*watch_data) );
704 void DCOPProcessMessage( IceConn iceConn, IcePointer ,
705 int opcode,
unsigned long length, Bool swap)
707 the_server->processMessage( iceConn, opcode, length, swap );
710 void DCOPServer::processMessage( IceConn iceConn,
int opcode,
711 unsigned long length, Bool )
713 DCOPConnection* conn = clients.find( iceConn );
715 tqWarning(
"[dcopserver] DCOPServer::processMessage message from unknown connection. [opcode = %d]", opcode);
720 case DCOPReplyDelayed:
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);
731 DCOPConnection* target = findApp( toApp );
732 int datalen = ba.size();
733 if ( opcode == DCOPReplyDelayed ) {
735 tqWarning(
"[dcopserver] DCOPServer::DCOPReplyDelayed for unknown connection.");
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!");
745 if (opcode == DCOPSend)
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());
752 IceGetHeader( target->iceConn, majorOpcode, opcode,
753 sizeof(DCOPMsg), DCOPMsg, pMsg );
755 pMsg->length += datalen;
756 _DCOPIceSendBegin( target->iceConn );
757 DCOPIceSendData(target->iceConn, ba);
759 }
else if ( toApp ==
"DCOPServer" ) {
760 TQCString obj = readQCString(ds);
761 TQCString fun = readQCString(ds);
762 TQByteArray data = readQByteArray(ds);
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() );
769 }
else if ( toApp[toApp.length()-1] ==
'*') {
771 if (opcode == DCOPSend)
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());
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))
785 IceGetHeader(client->iceConn, majorOpcode, DCOPSend,
786 sizeof(DCOPMsg), DCOPMsg, pMsg);
788 pMsg->length += datalen;
789 _DCOPIceSendBegin( client->iceConn );
790 DCOPIceSendData(client->iceConn, ba);
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();
813 if (opcode == DCOPCall)
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());
820 target->waitingForReply.append( iceConn );
821 conn->waitingOnReply.append( target->iceConn);
823 IceGetHeader( target->iceConn, majorOpcode, opcode,
824 sizeof(DCOPMsg), DCOPMsg, pMsg );
826 pMsg->length += datalen;
827 _DCOPIceSendBegin( target->iceConn );
828 DCOPIceSendData(target->iceConn, ba);
832 TQByteArray replyData;
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 );
841 tqWarning(
"[dcopserver] %s failure: object '%s' has no function '%s'", toApp.data(), obj.data(), fun.data() );
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 );
854 pMsg->key = serverKey++;
855 pMsg->length += replylen;
856 _DCOPIceSendBegin( iceConn );
857 DCOPIceSendData( iceConn, reply);
858 DCOPIceSendData( iceConn, replyData);
862 TQDataStream replyStream( reply, IO_WriteOnly );
863 replyStream << toApp << fromApp;
864 IceGetHeader( iceConn, majorOpcode, DCOPReplyFailed,
865 sizeof(DCOPMsg), DCOPMsg, pMsg );
869 pMsg->key = serverKey++;
870 pMsg->length += reply.size();
871 _DCOPIceSendBegin( iceConn );
872 DCOPIceSendData( iceConn, reply );
879 case DCOPReplyFailed:
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);
891 DCOPConnection* connreply = findApp( toApp );
892 int datalen = ba.size();
895 tqWarning(
"[dcopserver] DCOPServer::DCOPReply for unknown connection.");
897 conn->waitingForReply.removeRef( connreply->iceConn );
898 if ( opcode == DCOPReplyWait )
900 conn->waitingForDelayedReply.append( connreply->iceConn );
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());
908 IceGetHeader( connreply->iceConn, majorOpcode, opcode,
909 sizeof(DCOPMsg), DCOPMsg, pMsg );
911 pMsg->length += datalen;
912 _DCOPIceSendBegin( connreply->iceConn );
913 DCOPIceSendData(connreply->iceConn, ba);
919 tqWarning(
"[dcopserver] DCOPServer::processMessage unknown message");
923 static const IcePaVersionRec DCOPServerVersions[] = {
924 { DCOPVersionMajor, DCOPVersionMinor, DCOPProcessMessage }
927 static const IcePoVersionRec DUMMYVersions[] = {
928 { DCOPVersionMajor, DCOPVersionMinor, 0 }
931 static Status DCOPServerProtocolSetupProc ( IceConn ,
932 int majorVersion,
int minorVersion,
933 char* vendor,
char* release,
934 IcePointer *clientDataRet,
948 return (majorVersion == DCOPVersionMajor && minorVersion == DCOPVersionMinor);
952 static int pipeOfDeath[2];
954 static void sighandler(
int sig)
957 signal(SIGHUP, sighandler);
961 write(pipeOfDeath[1],
"x", 1);
967 extern int _kde_IceLastMajorOpcode;
970 DCOPServer::DCOPServer(
bool _suicide)
971 : TQObject(0,0), currentClientNumber(0), appIds(263), clients(263)
978 dcopSignals =
new DCOPSignals;
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!");
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),
998 DCOPServerProtocolSetupProc,
1006 tqWarning(
"[dcopserver] Could not register DCOP protocol with ICE");
1010 int orig_umask = umask(077);
1011 if (!IceListenForConnections (&numTransports, &listenObjs,
1014 fprintf (stderr,
"[dcopserver] %s", errormsg);
1017 (void) umask(orig_umask);
1021 if(!(f = ::fopen(fName.data(),
"w+"))) {
1022 fprintf (stderr,
"[dcopserver] Can not create file %s: %s",
1023 fName.data(), ::strerror(errno));
1026 char *idlist = IceComposeNetworkIdList(numTransports, listenObjs);
1028 fprintf(f,
"%s", idlist);
1031 fprintf(f,
"\n%i\n", getpid());
1034 if (TQCString(getenv(
"DCOPAUTHORITY")).isEmpty())
1038 ::symlink(fName,compatName);
1044 if (!SetAuthentication_local(numTransports, listenObjs))
1045 tqFatal(
"DCOPSERVER: authentication setup failed.");
1047 if (!SetAuthentication(numTransports, listenObjs, &authDataEntries))
1048 tqFatal(
"DCOPSERVER: authentication setup failed.");
1050 IceAddConnectionWatch (DCOPWatchProc,
static_cast<IcePointer
>(
this));
1051 _IceWriteHandler = DCOPIceWriteChar;
1053 listener.setAutoDelete(
true );
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) ) );
1061 write(ready[1], &c, 1);
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()) );
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);
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 );
1091 DCOPServer::~DCOPServer()
1093 system(findDcopserverShutdown()+
" --nokill");
1094 IceFreeListenObjs(numTransports, listenObjs);
1095 FreeAuthenticationData(numTransports, authDataEntries);
1103 SetEvent(m_evTerminate);
1104 CloseHandle(m_evTerminate);
1108 DCOPConnection* DCOPServer::findApp(
const TQCString& appId )
1110 if ( appId.isNull() )
1112 DCOPConnection* conn = appIds.find( appId );
1119 void DCOPServer::slotCleanDeadConnections()
1121 tqWarning(
"[dcopserver] DCOP Cleaning up dead connections.");
1122 while(!deadConnections.isEmpty())
1124 IceConn iceConn = deadConnections.take(0);
1125 IceSetShutdownNegotiation (iceConn, False);
1126 (void) IceCloseConnection( iceConn );
1133 void DCOPServer::ioError( IceConn iceConn )
1135 deadConnections.removeRef(iceConn);
1136 deadConnections.prepend(iceConn);
1137 m_deadConnectionTimer->start(0,
true);
1141 void DCOPServer::processData(
int )
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 );
1154 void DCOPServer::newClient(
int )
1156 IceAcceptStatus status;
1157 IceConn iceConn = IceAcceptConnection(
static_cast<const DCOPListener*
>(sender())->listenObj, &status);
1159 if (status == IceAcceptBadMalloc)
1160 tqWarning(
"[dcopserver] Failed to alloc connection object!");
1162 tqWarning(
"[dcopserver] Failed to accept ICE connection!");
1166 IceSetShutdownNegotiation( iceConn, False );
1168 IceConnectStatus cstatus;
1169 while ((cstatus = IceConnectionStatus (iceConn))==IceConnectPending) {
1170 (void) IceProcessMessages( iceConn, 0, 0 );
1173 if (cstatus != IceConnectAccepted) {
1174 if (cstatus == IceConnectIOError)
1175 tqWarning (
"[dcopserver] IO error opening ICE Connection!");
1177 tqWarning (
"[dcopserver] ICE Connection rejected!");
1178 deadConnections.removeRef(iceConn);
1179 (void) IceCloseConnection (iceConn);
1183 void* DCOPServer::watchConnection( IceConn iceConn )
1185 DCOPConnection* con =
new DCOPConnection( iceConn );
1186 connect( con, TQ_SIGNAL( activated(
int) ),
this, TQ_SLOT( processData(
int) ) );
1188 clients.insert(iceConn, con );
1189 fd_clients.insert( IceConnectionNumber(iceConn), con);
1191 return static_cast<void*
>(con);
1194 void DCOPServer::removeConnection(
void* data )
1196 DCOPConnection* conn =
static_cast<DCOPConnection*
>(data);
1198 dcopSignals->removeConnections(conn);
1200 clients.remove(conn->iceConn );
1201 fd_clients.remove( IceConnectionNumber(conn->iceConn) );
1204 while (!conn->waitingForReply.isEmpty()) {
1205 IceConn iceConn = conn->waitingForReply.take(0);
1207 DCOPConnection* target = clients.find( iceConn );
1208 tqWarning(
"[dcopserver] DCOP aborting call from '%s' to '%s'", target ? target->appId.data() :
"<unknown>" , conn->appId.data() );
1211 IceGetHeader( iceConn, majorOpcode, DCOPReplyFailed,
1212 sizeof(DCOPMsg), DCOPMsg, pMsg );
1214 pMsg->length += reply.size();
1215 _DCOPIceSendBegin( iceConn );
1216 DCOPIceSendData(iceConn, reply);
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");
1226 while (!conn->waitingForDelayedReply.isEmpty()) {
1227 IceConn iceConn = conn->waitingForDelayedReply.take(0);
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() );
1233 IceGetHeader( iceConn, majorOpcode, DCOPReplyFailed,
1234 sizeof(DCOPMsg), DCOPMsg, pMsg );
1236 pMsg->length += reply.size();
1237 _DCOPIceSendBegin( iceConn );
1238 DCOPIceSendData( iceConn, reply );
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");
1246 while (!conn->waitingOnReply.isEmpty())
1248 IceConn iceConn = conn->waitingOnReply.take(0);
1250 DCOPConnection* target = clients.find( iceConn );
1253 tqWarning(
"[dcopserver] Still waiting for answer from non-existing client.");
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");
1263 if ( !conn->appId.isNull() ) {
1265 tqDebug(
"DCOP: unregister '%s'", conn->appId.data() );
1267 if ( !conn->daemon )
1269 currentClientNumber--;
1272 appIds.remove( conn->appId );
1274 broadcastApplicationRegistration( conn,
"applicationRemoved(TQCString)", conn->appId );
1279 if ( suicide && (currentClientNumber == 0) )
1281 m_timer->start( 10000 );
1283 if ( shutdown && appIds.isEmpty())
1285 m_timer->start( 10 );
1289 void DCOPServer::slotTerminate()
1292 fprintf( stderr,
"[dcopserver] slotTerminate() -> sending terminateTDE signal." );
1295 dcopSignals->emitSignal(0L ,
"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");
1301 void DCOPServer::slotSuicide()
1304 fprintf( stderr,
"[dcopserver] slotSuicide() -> exit." );
1309 void DCOPServer::slotShutdown()
1312 fprintf( stderr,
"[dcopserver] slotShutdown() -> waiting for clients to disconnect." );
1316 read(pipeOfDeath[0], &c, 1);
1322 dcopSignals->emitSignal(0L ,
"terminateTDE()", data,
false);
1323 m_timer->start( 10000 );
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())
1331 void DCOPServer::slotExit()
1334 fprintf( stderr,
"[dcopserver] slotExit() -> exit." );
1337 SetEvent(m_evTerminate);
1338 if(m_dwTerminateThreadId != GetCurrentThreadId())
1339 WaitForSingleObject(m_hTerminateThread,INFINITE);
1340 CloseHandle(m_hTerminateThread);
1345 bool DCOPServer::receive(
const TQCString &,
const TQCString &obj,
1346 const TQCString &fun,
const TQByteArray& data,
1347 TQCString& replyType, TQByteArray &replyData,
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() <<
"";
1362 DCOPConnection* conn = clients.find( iceConn );
1365 dcopSignals->emitSignal(conn, fun, data,
false);
1370 if ( fun ==
"setDaemonMode(bool)" ) {
1371 TQDataStream args( data, IO_ReadOnly );
1372 if ( !args.atEnd() ) {
1377 daemon =
static_cast<bool>( iDaemon );
1379 DCOPConnection* conn = clients.find( iceConn );
1380 if ( conn && !conn->appId.isNull() ) {
1382 if ( !conn->daemon )
1384 conn->daemon =
true;
1387 tqDebug(
"DCOP: new daemon %s", conn->appId.data() );
1390 currentClientNumber--;
1398 if ( conn->daemon ) {
1399 conn->daemon =
false;
1401 currentClientNumber++;
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 );
1426 if ( conn->appId.isNull() )
1428 currentClientNumber++;
1431 tqDebug(
"DCOP: register '%s' -> number of clients is now %d", app2.data(), currentClientNumber );
1437 oldAppId = conn->appId;
1438 tqDebug(
"DCOP: '%s' now known as '%s'", conn->appId.data(), app2.data() );
1443 if ( appIds.find( app2 ) != 0 ) {
1451 tmp.prepend( app2 );
1452 }
while ( appIds.find( tmp ) != 0 );
1455 appIds.insert( conn->appId, conn );
1457 int c = conn->appId.find(
'-' );
1459 conn->plainAppId = conn->appId.left( c );
1461 conn->plainAppId = conn->appId;
1463 if( !oldAppId.isEmpty())
1464 broadcastApplicationRegistration( conn,
1465 "applicationRemoved(TQCString)", oldAppId );
1466 broadcastApplicationRegistration( conn,
"applicationRegistered(TQCString)", conn->appId );
1468 replyType =
"TQCString";
1469 reply << conn->appId;
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();
1481 replyType =
"QCStringList";
1482 reply << applications;
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 );
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 );
1502 conn->notifyRegister++;
1503 else if ( conn->notifyRegister > 0 )
1504 conn->notifyRegister--;
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);
1522 tqDebug(
"DCOPServer: connectSignal(sender = %s senderObj = %s signal = %s recvObj = %s slot = %s)", sender.data(), senderObj.data(), signal.data(), receiverObj.data(), slot.data());
1524 bool b = dcopSignals->connectSignal(sender, senderObj, signal, conn, receiverObj, slot, (Volatile != 0));
1526 TQDataStream reply( replyData, IO_WriteOnly );
1527 reply << (TQ_INT8) (b?1:0);
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);
1540 tqDebug(
"DCOPServer: disconnectSignal(sender = %s senderObj = %s signal = %s recvObj = %s slot = %s)", sender.data(), senderObj.data(), signal.data(), receiverObj.data(), slot.data());
1542 bool b = dcopSignals->disconnectSignal(sender, senderObj, signal, conn, receiverObj, slot);
1544 TQDataStream reply( replyData, IO_WriteOnly );
1545 reply << (TQ_INT8) (b?1:0);
1552 void DCOPServer::broadcastApplicationRegistration( DCOPConnection* conn,
const TQCString type,
1553 const TQCString& appId )
1556 TQDataStream datas( data, IO_WriteOnly );
1558 TQPtrDictIterator<DCOPConnection> it( clients );
1560 TQDataStream ds( ba, IO_WriteOnly );
1561 ds <<TQCString(
"DCOPServer") << TQCString(
"") << TQCString(
"")
1563 int datalen = ba.size();
1565 while ( it.current() ) {
1566 DCOPConnection* c = it.current();
1568 if ( c->notifyRegister && (c != conn) ) {
1569 IceGetHeader( c->iceConn, majorOpcode, DCOPSend,
1570 sizeof(DCOPMsg), DCOPMsg, pMsg );
1572 pMsg->length += datalen;
1573 _DCOPIceSendBegin(c->iceConn);
1574 DCOPIceSendData( c->iceConn, ba );
1581 DCOPServer::sendMessage(DCOPConnection *conn,
const TQCString &sApp,
1582 const TQCString &rApp,
const TQCString &rObj,
1583 const TQCString &rFun,
const TQByteArray &data)
1586 TQDataStream ds( ba, IO_WriteOnly );
1587 ds << sApp << rApp << rObj << rFun << data;
1588 int datalen = ba.size();
1591 IceGetHeader( conn->iceConn, majorOpcode, DCOPSend,
1592 sizeof(DCOPMsg), DCOPMsg, pMsg );
1593 pMsg->length += datalen;
1597 (*m_stream) <<
"Sending a message: sApp =\""
1598 << sApp <<
"\", rApp =\""
1599 << rApp <<
"\", rObj =\""
1600 << rObj <<
"\", rFun =\""
1601 << rFun <<
"\", datalen ="
1606 _DCOPIceSendBegin( conn->iceConn );
1607 DCOPIceSendData(conn->iceConn, ba);
1611 void IoErrorHandler ( IceConn iceConn)
1613 the_server->ioError( iceConn );
1616 static bool isRunning(
const TQCString &fName,
bool printNetworkId =
false)
1618 if (::access(fName.data(), R_OK) == 0) {
1620 f.open(IO_ReadOnly);
1621 int size = TQMIN( (
long)1024, f.size() );
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;
1629 if (ok && pid && (kill(pid, SIGHUP) == 0)) {
1631 tqWarning(
"[dcopserver] %s", contents.left(pos).data());
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 "---------------------------------",
1645 unlink(fName.data());
1647 }
else if (errno != ENOENT) {
1649 unlink(fName.data());
1654 const char*
const ABOUT =
1655 "Usage: dcopserver [--nofork] [--nosid] [--help]\n"
1656 " dcopserver --serverid\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"
1662 "Copyright (C) 1999-2001, The KDE Developers <http://www.kde.org>\n"
1665 extern "C" DCOP_EXPORT
int kdemain(
int argc,
char* argv[] )
1667 bool serverid =
false;
1668 bool nofork =
false;
1670 bool suicide =
false;
1671 for(
int i = 1; i < argc; i++) {
1672 if (strcmp(argv[i],
"--nofork") == 0)
1674 else if (strcmp(argv[i],
"--nosid") == 0)
1676 else if (strcmp(argv[i],
"--nolocal") == 0)
1678 else if (strcmp(argv[i],
"--suicide") == 0)
1680 else if (strcmp(argv[i],
"--serverid") == 0)
1683 fprintf(stdout,
"%s", ABOUT );
1699 if (TQCString(getenv(
"DCOPAUTHORITY")).isEmpty() &&
1705 symlink(oldFile.data(), newFile.data());
1709 struct rlimit limits;
1711 int retcode = getrlimit(RLIMIT_NOFILE, &limits);
1713 if (limits.rlim_max > 512 && limits.rlim_cur < 512)
1715 int cur_limit = limits.rlim_cur;
1716 limits.rlim_cur = 512;
1717 retcode = setrlimit(RLIMIT_NOFILE, &limits);
1721 tqWarning(
"[dcopserver] Could not raise limit on number of open files.");
1722 tqWarning(
"[dcopserver] Current limit = %d", cur_limit);
1735 read(ready[0], &c, 1);
1745 tqWarning(
"[dcopserver] DCOPServer self-test failed.");
1746 system(findDcopserverShutdown()+
" --kill");
1760 signal(SIGHUP, sighandler);
1761 signal(SIGTERM, sighandler);
1762 signal(SIGPIPE, SIG_IGN);
1767 read(ready[0], &c, 1);
1771 putenv(strdup(
"SESSION_MANAGER="));
1773 TQApplication a( argc, argv,
false );
1775 IceSetIOErrorHandler (IoErrorHandler );
1776 DCOPServer *server =
new DCOPServer(suicide);
1779 SetConsoleCtrlHandler(DCOPServer::dcopServerConsoleProc,TRUE);
1781 TQSocketNotifier DEATH(pipeOfDeath[0], TQSocketNotifier::Read, 0, 0);
1782 server->connect(&DEATH, TQ_SIGNAL(activated(
int)), TQ_SLOT(slotShutdown()));
1791 #include "dcopserver_win.cpp"
1794 #include "dcopserver.moc"
Inter-process communication and remote procedure calls for KDE applications.
TQCString appId() const
Returns the current app id or a null string if the application hasn't yet been registered.
static TQCString dcopServerFileOld(const TQCString &hostname=0) TDE_DEPRECATED
bool attach()
Attaches to the DCOP server.
static TQCString dcopServerFile(const TQCString &hostname=0)
File with information how to reach the dcopserver.
static TQCString iceauthPath()
Return the path of iceauth or an empty string if not found.
Represents the return value of a DCOPRef:call() or DCOPRef:send() invocation.
const TDEShortcut & close()
const TDEShortcut & open()