00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include <config.h>
00029
00030 #include <sys/types.h>
00031 #ifdef HAVE_SYS_STAT_H
00032 #include <sys/stat.h>
00033 #endif
00034 #ifdef HAVE_SYS_PARAM_H
00035 #include <sys/param.h>
00036 #endif
00037 #include <sys/resource.h>
00038 #include <sys/socket.h>
00039
00040 #include <unistd.h>
00041 #include <stdlib.h>
00042 #include <signal.h>
00043 #include <unistd.h>
00044 #include <fcntl.h>
00045 #include <errno.h>
00046 #ifdef HAVE_LIMITS_H
00047 #include <limits.h>
00048 #endif
00049
00050 #define QT_CLEAN_NAMESPACE 1
00051 #include <tqfile.h>
00052 #include <tqtextstream.h>
00053 #include <tqdatastream.h>
00054 #include <tqptrstack.h>
00055 #include <tqtimer.h>
00056
00057 #include "dcopserver.h"
00058
00059 #include <dcopsignals.h>
00060 #include <dcopclient.h>
00061 #include <dcopglobal.h>
00062 #include "dcop-path.h"
00063
00064 #ifdef DCOP_LOG
00065 #undef Unsorted
00066 #include <tqdir.h>
00067 #include <string.h>
00068 #endif
00069
00070
00071
00072 DCOPServer* the_server;
00073
00074 template class TQDict<DCOPConnection>;
00075 template class TQPtrDict<DCOPConnection>;
00076 template class TQPtrList<DCOPListener>;
00077
00078 #define _DCOPIceSendBegin(x) \
00079 int fd = IceConnectionNumber( x ); \
00080 long fd_fl = fcntl(fd, F_GETFL, 0); \
00081 fcntl(fd, F_SETFL, fd_fl | O_NDELAY);
00082 #define _DCOPIceSendEnd() \
00083 fcntl(fd, F_SETFL, fd_fl);
00084
00085 static TQCString findDcopserverShutdown()
00086 {
00087 #ifdef Q_OS_WIN32
00088 char szPath[512];
00089 char *pszFilePart;
00090 int ret;
00091 ret = SearchPathA(NULL,"dcopserver_shutdown","exe",sizeof(szPath)/sizeof(szPath[0]),szPath,&pszFilePart);
00092 if(ret != 0)
00093 return TQCString(szPath);
00094 #else
00095 TQCString path = getenv("PATH");
00096 char *dir = strtok(path.data(), ":");
00097 while (dir)
00098 {
00099 TQCString file = dir;
00100 file += "/dcopserver_shutdown";
00101 if (access(file.data(), X_OK) == 0)
00102 return file;
00103 dir = strtok(NULL, ":");
00104 }
00105 TQCString file = DCOP_PATH;
00106 file += "/dcopserver_shutdown";
00107 if (access(file.data(), X_OK) == 0)
00108 return file;
00109 #endif
00110 return TQCString("dcopserver_shutdown");
00111 }
00112
00113 static Bool HostBasedAuthProc ( char* )
00114 {
00115 return false;
00116 }
00117
00118 extern "C" {
00119 extern IceWriteHandler _kde_IceWriteHandler;
00120 extern IceIOErrorHandler _kde_IceIOErrorHandler;
00121 void DCOPIceWriteChar(register IceConn iceConn, unsigned long nbytes, char *ptr);
00122 }
00123
00124 static TQCString readQCString(TQDataStream &ds)
00125 {
00126 TQCString result;
00127 TQ_UINT32 len;
00128 ds >> len;
00129 TQIODevice *device = ds.device();
00130 int bytesLeft = device->size()-device->at();
00131 if ((bytesLeft < 0 ) || (len > (uint) bytesLeft))
00132 {
00133 tqWarning("[dcopserver] Corrupt data!");
00134 printf("[dcopserver] bytesLeft: %d, len: %d", bytesLeft, len);
00135 return result;
00136 }
00137 result.TQByteArray::resize( (uint)len );
00138 if (len > 0)
00139 ds.readRawBytes( result.data(), (uint)len);
00140 return result;
00141 }
00142
00143 static TQByteArray readQByteArray(TQDataStream &ds)
00144 {
00145 TQByteArray result;
00146 TQ_UINT32 len;
00147 ds >> len;
00148 TQIODevice *device = ds.device();
00149 int bytesLeft = device->size()-device->at();
00150 if ((bytesLeft < 0 ) || (len > (uint) bytesLeft))
00151 {
00152 tqWarning("[dcopserver] Corrupt data!");
00153 return result;
00154 }
00155 result.resize( (uint)len );
00156 if (len > 0)
00157 ds.readRawBytes( result.data(), (uint)len);
00158 return result;
00159 }
00160
00161
00162 extern "C" {
00163 extern int _kde_IceTransWrite (void * ciptr, char *buf, int size);
00164 }
00165
00166 static unsigned long writeIceData(IceConn iceConn, unsigned long nbytes, char *ptr)
00167 {
00168 int fd = IceConnectionNumber(iceConn);
00169 unsigned long nleft = nbytes;
00170 while (nleft > 0)
00171 {
00172 int nwritten;
00173
00174 if (iceConn->io_ok)
00175 {
00176 nwritten = send(fd, ptr, (int) nleft, 0);
00177 }
00178 else
00179 return 0;
00180
00181 if (nwritten <= 0)
00182 {
00183 if (errno == EINTR)
00184 continue;
00185
00186 if (errno == EAGAIN)
00187 return nleft;
00188
00189
00190
00191
00192
00193
00194 iceConn->io_ok = False;
00195
00196 if (iceConn->connection_status == IceConnectPending)
00197 {
00198
00199
00200
00201
00202
00203 return 0;
00204 }
00205
00206 if (iceConn->process_msg_info)
00207 {
00208 int i;
00209
00210 for (i = iceConn->his_min_opcode;
00211 i <= iceConn->his_max_opcode; i++)
00212 {
00213 _IceProcessMsgInfo *process;
00214
00215 process = &iceConn->process_msg_info[
00216 i - iceConn->his_min_opcode];
00217
00218 if (process->in_use)
00219 {
00220 IceIOErrorProc IOErrProc = process->accept_flag ?
00221 process->protocol->accept_client->io_error_proc :
00222 process->protocol->orig_client->io_error_proc;
00223
00224 if (IOErrProc)
00225 (*IOErrProc) (iceConn);
00226 }
00227 }
00228 }
00229
00230 (*_kde_IceIOErrorHandler) (iceConn);
00231 return 0;
00232 }
00233
00234 nleft -= nwritten;
00235 ptr += nwritten;
00236 }
00237 return 0;
00238 }
00239
00240 void DCOPIceWriteChar(register IceConn iceConn, unsigned long nbytes, char *ptr)
00241 {
00242 DCOPConnection* conn = the_server->findConn( iceConn );
00243 #ifdef DCOP_DEBUG
00244 tqWarning("[dcopserver] DCOPIceWriteChar() Writing %d bytes [%s]", nbytes, conn ? conn->appId.data() : "<unknown>");
00245 #endif
00246
00247 if (conn)
00248 {
00249 if (conn->outputBlocked)
00250 {
00251 TQByteArray _data(nbytes);
00252 memcpy(_data.data(), ptr, nbytes);
00253 #ifdef DCOP_DEBUG
00254 tqWarning("[dcopserver] _IceWrite() outputBlocked. Queuing %d bytes.", _data.size());
00255 #endif
00256 conn->outputBuffer.append(_data);
00257 return;
00258 }
00259
00260 }
00261
00262 unsigned long nleft = writeIceData(iceConn, nbytes, ptr);
00263 if ((nleft > 0) && conn)
00264 {
00265 TQByteArray _data(nleft);
00266 memcpy(_data.data(), ptr, nleft);
00267 conn->waitForOutputReady(_data, 0);
00268 return;
00269 }
00270 }
00271
00272 static void DCOPIceWrite(IceConn iceConn, const TQByteArray &_data)
00273 {
00274 DCOPConnection* conn = the_server->findConn( iceConn );
00275 #ifdef DCOP_DEBUG
00276 tqWarning("[dcopserver] DCOPIceWrite() Writing %d bytes [%s]", _data.size(), conn ? conn->appId.data() : "<unknown>");
00277 #endif
00278 if (conn)
00279 {
00280 if (conn->outputBlocked)
00281 {
00282 #ifdef DCOP_DEBUG
00283 tqWarning("[dcopserver] DCOPIceWrite() outputBlocked. Queuing %d bytes.", _data.size());
00284 #endif
00285 conn->outputBuffer.append(_data);
00286 return;
00287 }
00288
00289 }
00290
00291 unsigned long nleft = writeIceData(iceConn, _data.size(), const_cast<TQByteArray&>(_data).data());
00292 if ((nleft > 0) && conn)
00293 {
00294 conn->waitForOutputReady(_data, _data.size() - nleft);
00295 return;
00296 }
00297 }
00298
00299 void DCOPConnection::waitForOutputReady(const TQByteArray &_data, int start)
00300 {
00301 #ifdef DCOP_DEBUG
00302 tqWarning("[dcopserver] waitForOutputReady fd = %d datasize = %d start = %d", socket(), _data.size(), start);
00303 #endif
00304 outputBlocked = true;
00305 outputBuffer.append(_data);
00306 outputBufferStart = start;
00307 if (!outputBufferNotifier)
00308 {
00309 outputBufferNotifier = new TQSocketNotifier(socket(), Write);
00310 connect(outputBufferNotifier, TQT_SIGNAL(activated(int)),
00311 the_server, TQT_SLOT(slotOutputReady(int)));
00312 }
00313 outputBufferNotifier->setEnabled(true);
00314 return;
00315 }
00316
00317 void DCOPServer::slotOutputReady(int socket)
00318 {
00319 #ifdef DCOP_DEBUG
00320 tqWarning("[dcopserver] slotOutputReady fd = %d", socket);
00321 #endif
00322
00323 DCOPConnection *conn = fd_clients.find(socket);
00324
00325
00326
00327
00328 conn->slotOutputReady();
00329 }
00330
00331
00332 void DCOPConnection::slotOutputReady()
00333 {
00334
00335
00336
00337 TQByteArray data = outputBuffer.first();
00338
00339 int fd = socket();
00340
00341 long fd_fl = fcntl(fd, F_GETFL, 0);
00342 fcntl(fd, F_SETFL, fd_fl | O_NDELAY);
00343
00344
00345
00346
00347 int nwritten;
00348 nwritten = ::send(fd,data.data()+outputBufferStart,data.size()-outputBufferStart,0);
00349
00350 int e = errno;
00351 fcntl(fd, F_SETFL, fd_fl);
00352
00353 #ifdef DCOP_DEBUG
00354 tqWarning("[dcopserver] slotOutputReady() %d bytes written", nwritten);
00355 #endif
00356
00357 if (nwritten < 0)
00358 {
00359 if ((e == EINTR) || (e == EAGAIN))
00360 return;
00361 (*_kde_IceIOErrorHandler) (iceConn);
00362 return;
00363 }
00364 outputBufferStart += nwritten;
00365
00366 if (outputBufferStart == data.size())
00367 {
00368 outputBufferStart = 0;
00369 outputBuffer.remove(outputBuffer.begin());
00370 if (outputBuffer.isEmpty())
00371 {
00372 #ifdef DCOP_DEBUG
00373 tqWarning("[dcopserver] slotOutputRead() all data transmitted.");
00374 #endif
00375 outputBlocked = false;
00376 outputBufferNotifier->setEnabled(false);
00377 }
00378 #ifdef DCOP_DEBUG
00379 else
00380 {
00381 tqWarning("[dcopserver] slotOutputRead() more data to send.");
00382 }
00383 #endif
00384 }
00385 }
00386
00387 static void DCOPIceSendData(register IceConn _iceConn,
00388 const TQByteArray &_data)
00389 {
00390 if (_iceConn->outbufptr > _iceConn->outbuf)
00391 {
00392 #ifdef DCOP_DEBUG
00393 tqWarning("[dcopserver] Flushing data, fd = %d", IceConnectionNumber(_iceConn));
00394 #endif
00395 IceFlush( _iceConn );
00396 }
00397 DCOPIceWrite(_iceConn, _data);
00398 }
00399
00400 class DCOPListener : public TQSocketNotifier
00401 {
00402 public:
00403 DCOPListener( IceListenObj obj )
00404 : TQSocketNotifier( IceGetListenConnectionNumber( obj ),
00405 TQSocketNotifier::Read, 0, 0)
00406 {
00407 listenObj = obj;
00408 }
00409
00410 IceListenObj listenObj;
00411 };
00412
00413 DCOPConnection::DCOPConnection( IceConn conn )
00414 : TQSocketNotifier( IceConnectionNumber( conn ),
00415 TQSocketNotifier::Read, 0, 0 )
00416 {
00417 iceConn = conn;
00418 notifyRegister = 0;
00419 _signalConnectionList = 0;
00420 daemon = false;
00421 outputBlocked = false;
00422 outputBufferNotifier = 0;
00423 outputBufferStart = 0;
00424 }
00425
00426 DCOPConnection::~DCOPConnection()
00427 {
00428 delete _signalConnectionList;
00429 delete outputBufferNotifier;
00430 }
00431
00432 DCOPSignalConnectionList *
00433 DCOPConnection::signalConnectionList()
00434 {
00435 if (!_signalConnectionList)
00436 _signalConnectionList = new DCOPSignalConnectionList;
00437 return _signalConnectionList;
00438 }
00439
00440 static IceAuthDataEntry *authDataEntries;
00441 static char *addAuthFile;
00442
00443 static IceListenObj *listenObjs;
00444 static int numTransports;
00445 static int ready[2];
00446
00447
00448
00449 static void fprintfhex (FILE *fp, unsigned int len, char *cp)
00450 {
00451 static char hexchars[] = "0123456789abcdef";
00452
00453 for (; len > 0; len--, cp++) {
00454 unsigned char s = *cp;
00455 putc(hexchars[s >> 4], fp);
00456 putc(hexchars[s & 0x0f], fp);
00457 }
00458 }
00459
00460
00461
00462
00463
00464 static void
00465 write_iceauth (FILE *addfp, IceAuthDataEntry *entry)
00466 {
00467 fprintf (addfp,
00468 "add %s \"\" %s %s ",
00469 entry->protocol_name,
00470 entry->network_id,
00471 entry->auth_name);
00472 fprintfhex (addfp, entry->auth_data_length, entry->auth_data);
00473 fprintf (addfp, "\n");
00474 }
00475
00476 #ifndef HAVE_MKSTEMPS
00477 #include <string.h>
00478 #include <strings.h>
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495 int mkstemps (char* _template, int suffix_len)
00496 {
00497 static const char letters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
00498 char *XXXXXX;
00499 int len;
00500 int count;
00501 int value;
00502
00503 len = strlen (_template);
00504
00505 if ((int) len < 6 + suffix_len || strncmp (&_template[len - 6 - suffix_len], "XXXXXX", 6))
00506 return -1;
00507
00508 XXXXXX = &_template[len - 6 - suffix_len];
00509
00510 value = rand();
00511 for (count = 0; count < 256; ++count)
00512 {
00513 int v = value;
00514 int fd;
00515
00516
00517 XXXXXX[0] = letters[v % 62];
00518 v /= 62;
00519 XXXXXX[1] = letters[v % 62];
00520 v /= 62;
00521 XXXXXX[2] = letters[v % 62];
00522 v /= 62;
00523 XXXXXX[3] = letters[v % 62];
00524 v /= 62;
00525 XXXXXX[4] = letters[v % 62];
00526 v /= 62;
00527 XXXXXX[5] = letters[v % 62];
00528
00529 fd = open (_template, O_RDWR|O_CREAT|O_EXCL, 0600);
00530 if (fd >= 0)
00531
00532 return fd;
00533
00534
00535
00536
00537 value += 7777;
00538 }
00539
00540 _template[0] = '\0';
00541 return -1;
00542 }
00543
00544 #endif
00545
00546 static char *unique_filename (const char *path, const char *prefix, int *pFd)
00547 {
00548 char tempFile[PATH_MAX];
00549 char *ptr;
00550
00551 #ifdef Q_OS_WIN
00552 snprintf (tempFile, PATH_MAX, "%s\\%sXXXXXX", path, prefix);
00553 #else
00554 snprintf (tempFile, PATH_MAX, "%s/%sXXXXXX", path, prefix);
00555 #endif
00556 ptr = static_cast<char *>(malloc(strlen(tempFile) + 1));
00557 if (ptr != NULL)
00558 {
00559 int fd = mkstemps(tempFile, 0);
00560 if(fd >= 0)
00561 {
00562 *pFd = fd;
00563 strcpy(ptr, tempFile);
00564 }
00565 else
00566 {
00567 free(ptr);
00568 ptr = NULL;
00569 }
00570 }
00571 return ptr;
00572 }
00573
00574 #define MAGIC_COOKIE_LEN 16
00575
00576 Status
00577 SetAuthentication (int count, IceListenObj *_listenObjs,
00578 IceAuthDataEntry **_authDataEntries)
00579 {
00580 FILE *addfp = NULL;
00581 const char *path;
00582 int original_umask;
00583 int i;
00584 TQCString command;
00585 int fd;
00586
00587 original_umask = umask (0077);
00588
00589 #ifdef Q_OS_WIN
00590 char temppath[512];
00591 DWORD dw = GetTempPathA(sizeof(temppath),temppath);
00592 if(dw != 0)
00593 {
00594 temppath[dw - 1] = 0;
00595 path = temppath;
00596 }
00597 else
00598 path = ".";
00599 #else
00600 path = getenv ("DCOP_SAVE_DIR");
00601 if (!path)
00602 path = "/tmp";
00603 #endif
00604 if ((addAuthFile = unique_filename (path, "dcop", &fd)) == NULL)
00605 goto bad;
00606
00607 if (!(addfp = fdopen(fd, "wb")))
00608 goto bad;
00609
00610 if ((*_authDataEntries = static_cast<IceAuthDataEntry *>(malloc (count * 2 * sizeof (IceAuthDataEntry)))) == NULL)
00611 goto bad;
00612
00613 for (i = 0; i < numTransports * 2; i += 2) {
00614 (*_authDataEntries)[i].network_id =
00615 IceGetListenConnectionString (_listenObjs[i/2]);
00616 (*_authDataEntries)[i].protocol_name = const_cast<char *>("ICE");
00617 (*_authDataEntries)[i].auth_name = const_cast<char *>("MIT-MAGIC-COOKIE-1");
00618
00619 (*_authDataEntries)[i].auth_data =
00620 IceGenerateMagicCookie (MAGIC_COOKIE_LEN);
00621 (*_authDataEntries)[i].auth_data_length = MAGIC_COOKIE_LEN;
00622
00623 (*_authDataEntries)[i+1].network_id =
00624 IceGetListenConnectionString (_listenObjs[i/2]);
00625 (*_authDataEntries)[i+1].protocol_name = const_cast<char *>("DCOP");
00626 (*_authDataEntries)[i+1].auth_name = const_cast<char *>("MIT-MAGIC-COOKIE-1");
00627
00628 (*_authDataEntries)[i+1].auth_data =
00629 IceGenerateMagicCookie (MAGIC_COOKIE_LEN);
00630 (*_authDataEntries)[i+1].auth_data_length = MAGIC_COOKIE_LEN;
00631
00632 write_iceauth (addfp, &(*_authDataEntries)[i]);
00633 write_iceauth (addfp, &(*_authDataEntries)[i+1]);
00634
00635 IceSetPaAuthData (2, &(*_authDataEntries)[i]);
00636
00637 IceSetHostBasedAuthProc (_listenObjs[i/2], HostBasedAuthProc);
00638 }
00639
00640 fclose (addfp);
00641
00642 umask (original_umask);
00643
00644 command = DCOPClient::iceauthPath();
00645
00646 if (command.isEmpty())
00647 {
00648 fprintf( stderr, "[dcopserver] 'iceauth' not found in path, aborting." );
00649 exit(1);
00650 }
00651
00652 command += " source ";
00653 command += addAuthFile;
00654 system (command);
00655
00656 unlink(addAuthFile);
00657
00658 return (1);
00659
00660 bad:
00661
00662 if (addfp)
00663 fclose (addfp);
00664
00665 if (addAuthFile) {
00666 unlink(addAuthFile);
00667 free(addAuthFile);
00668 }
00669
00670 umask (original_umask);
00671
00672 return (0);
00673 }
00674
00675
00676
00677
00678 void
00679 FreeAuthenticationData(int count, IceAuthDataEntry *_authDataEntries)
00680 {
00681
00682 int i;
00683
00684 for (i = 0; i < count * 2; i++) {
00685 free (_authDataEntries[i].network_id);
00686 free (_authDataEntries[i].auth_data);
00687 }
00688
00689 free(_authDataEntries);
00690 free(addAuthFile);
00691 }
00692
00693 void DCOPWatchProc ( IceConn iceConn, IcePointer client_data, Bool opening, IcePointer* watch_data)
00694 {
00695 DCOPServer* ds = static_cast<DCOPServer*>(client_data);
00696
00697 if (opening) {
00698 *watch_data = static_cast<IcePointer>(ds->watchConnection( iceConn ));
00699 }
00700 else {
00701 ds->removeConnection( static_cast<void*>(*watch_data) );
00702 }
00703 }
00704
00705 void DCOPProcessMessage( IceConn iceConn, IcePointer ,
00706 int opcode, unsigned long length, Bool swap)
00707 {
00708 the_server->processMessage( iceConn, opcode, length, swap );
00709 }
00710
00711 void DCOPServer::processMessage( IceConn iceConn, int opcode,
00712 unsigned long length, Bool )
00713 {
00714 DCOPConnection* conn = clients.find( iceConn );
00715 if ( !conn ) {
00716 tqWarning("[dcopserver] DCOPServer::processMessage message from unknown connection. [opcode = %d]", opcode);
00717 return;
00718 }
00719 switch( opcode ) {
00720 case DCOPSend:
00721 case DCOPReplyDelayed:
00722 {
00723 DCOPMsg *pMsg = 0;
00724 IceReadMessageHeader(iceConn, sizeof(DCOPMsg), DCOPMsg, pMsg);
00725 CARD32 key = pMsg->key;
00726 TQByteArray ba( length );
00727 IceReadData(iceConn, length, ba.data() );
00728 TQDataStream ds( ba, IO_ReadOnly );
00729 TQCString fromApp = readQCString(ds);
00730 TQCString toApp = readQCString(ds);
00731
00732 DCOPConnection* target = findApp( toApp );
00733 int datalen = ba.size();
00734 if ( opcode == DCOPReplyDelayed ) {
00735 if ( !target )
00736 tqWarning("[dcopserver] DCOPServer::DCOPReplyDelayed for unknown connection.");
00737 else if ( !conn )
00738 tqWarning("[dcopserver] DCOPServer::DCOPReplyDelayed from unknown connection.");
00739 else if (!conn->waitingForDelayedReply.removeRef( target->iceConn ))
00740 tqWarning("[dcopserver] DCOPServer::DCOPReplyDelayed from/to does not match. (#2)");
00741 else if (!target->waitingOnReply.removeRef(iceConn))
00742 tqWarning("[dcopserver] DCOPServer::DCOPReplyDelayed for client who wasn't waiting on one!");
00743 }
00744 if ( target ) {
00745 #ifdef DCOP_DEBUG
00746 if (opcode == DCOPSend)
00747 {
00748 TQCString obj = readQCString(ds);
00749 TQCString fun = readQCString(ds);
00750 tqWarning("[dcopserver] Sending %d bytes from %s to %s. DCOPSend %s", length, fromApp.data(), toApp.data(), fun.data());
00751 }
00752 #endif
00753 IceGetHeader( target->iceConn, majorOpcode, opcode,
00754 sizeof(DCOPMsg), DCOPMsg, pMsg );
00755 pMsg->key = key;
00756 pMsg->length += datalen;
00757 _DCOPIceSendBegin( target->iceConn );
00758 DCOPIceSendData(target->iceConn, ba);
00759 _DCOPIceSendEnd();
00760 } else if ( toApp == "DCOPServer" ) {
00761 TQCString obj = readQCString(ds);
00762 TQCString fun = readQCString(ds);
00763 TQByteArray data = readQByteArray(ds);
00764
00765 TQCString replyType;
00766 TQByteArray replyData;
00767 if ( !receive( toApp, obj, fun, data, replyType, replyData, iceConn ) ) {
00768 tqWarning("[dcopserver] %s failure: object '%s' has no function '%s'", toApp.data(), obj.data(), fun.data() );
00769 }
00770 } else if ( toApp[toApp.length()-1] == '*') {
00771 #ifdef DCOP_DEBUG
00772 if (opcode == DCOPSend)
00773 {
00774 TQCString obj = readQCString(ds);
00775 TQCString fun = readQCString(ds);
00776 tqWarning("[dcopserver] Sending %d bytes from %s to %s. DCOPSend %s", length, fromApp.data(), toApp.data(), fun.data());
00777 }
00778 #endif
00779
00780 TQAsciiDictIterator<DCOPConnection> aIt(appIds);
00781 int l = toApp.length()-1;
00782 for ( ; aIt.current(); ++aIt) {
00783 DCOPConnection *client = aIt.current();
00784 if (!l || (strncmp(client->appId.data(), toApp.data(), l) == 0))
00785 {
00786 IceGetHeader(client->iceConn, majorOpcode, DCOPSend,
00787 sizeof(DCOPMsg), DCOPMsg, pMsg);
00788 pMsg->key = key;
00789 pMsg->length += datalen;
00790 _DCOPIceSendBegin( client->iceConn );
00791 DCOPIceSendData(client->iceConn, ba);
00792 _DCOPIceSendEnd();
00793 }
00794 }
00795 }
00796 }
00797 break;
00798 case DCOPCall:
00799 case DCOPFind:
00800 {
00801 DCOPMsg *pMsg = 0;
00802 IceReadMessageHeader(iceConn, sizeof(DCOPMsg), DCOPMsg, pMsg);
00803 CARD32 key = pMsg->key;
00804 TQByteArray ba( length );
00805 IceReadData(iceConn, length, ba.data() );
00806 TQDataStream ds( ba, IO_ReadOnly );
00807 TQCString fromApp = readQCString(ds);
00808 TQCString toApp = readQCString(ds);
00809 DCOPConnection* target = findApp( toApp );
00810 int datalen = ba.size();
00811
00812 if ( target ) {
00813 #ifdef DCOP_DEBUG
00814 if (opcode == DCOPCall)
00815 {
00816 TQCString obj = readQCString(ds);
00817 TQCString fun = readQCString(ds);
00818 tqWarning("[dcopserver] Sending %d bytes from %s to %s. DCOPCall %s", length, fromApp.data(), toApp.data(), fun.data());
00819 }
00820 #endif
00821 target->waitingForReply.append( iceConn );
00822 conn->waitingOnReply.append( target->iceConn);
00823
00824 IceGetHeader( target->iceConn, majorOpcode, opcode,
00825 sizeof(DCOPMsg), DCOPMsg, pMsg );
00826 pMsg->key = key;
00827 pMsg->length += datalen;
00828 _DCOPIceSendBegin( target->iceConn );
00829 DCOPIceSendData(target->iceConn, ba);
00830 _DCOPIceSendEnd();
00831 } else {
00832 TQCString replyType;
00833 TQByteArray replyData;
00834 bool b = false;
00835
00836 if ( (opcode == DCOPCall) && (toApp == "DCOPServer") ) {
00837 TQCString obj = readQCString(ds);
00838 TQCString fun = readQCString(ds);
00839 TQByteArray data = readQByteArray(ds);
00840 b = receive( toApp, obj, fun, data, replyType, replyData, iceConn );
00841 if ( !b )
00842 tqWarning("[dcopserver] %s failure: object '%s' has no function '%s'", toApp.data(), obj.data(), fun.data() );
00843 }
00844
00845 if (b) {
00846 TQByteArray reply;
00847 TQDataStream replyStream( reply, IO_WriteOnly );
00848 replyStream << toApp << fromApp << replyType << replyData.size();
00849 int replylen = reply.size() + replyData.size();
00850 IceGetHeader( iceConn, majorOpcode, DCOPReply,
00851 sizeof(DCOPMsg), DCOPMsg, pMsg );
00852 if ( key != 0 )
00853 pMsg->key = key;
00854 else
00855 pMsg->key = serverKey++;
00856 pMsg->length += replylen;
00857 _DCOPIceSendBegin( iceConn );
00858 DCOPIceSendData( iceConn, reply);
00859 DCOPIceSendData( iceConn, replyData);
00860 _DCOPIceSendEnd();
00861 } else {
00862 TQByteArray reply;
00863 TQDataStream replyStream( reply, IO_WriteOnly );
00864 replyStream << toApp << fromApp;
00865 IceGetHeader( iceConn, majorOpcode, DCOPReplyFailed,
00866 sizeof(DCOPMsg), DCOPMsg, pMsg );
00867 if ( key != 0 )
00868 pMsg->key = key;
00869 else
00870 pMsg->key = serverKey++;
00871 pMsg->length += reply.size();
00872 _DCOPIceSendBegin( iceConn );
00873 DCOPIceSendData( iceConn, reply );
00874 _DCOPIceSendEnd();
00875 }
00876 }
00877 }
00878 break;
00879 case DCOPReply:
00880 case DCOPReplyFailed:
00881 case DCOPReplyWait:
00882 {
00883 DCOPMsg *pMsg = 0;
00884 IceReadMessageHeader(iceConn, sizeof(DCOPMsg), DCOPMsg, pMsg);
00885 CARD32 key = pMsg->key;
00886 TQByteArray ba( length );
00887 IceReadData(iceConn, length, ba.data() );
00888 TQDataStream ds( ba, IO_ReadOnly );
00889 TQCString fromApp = readQCString(ds);
00890 TQCString toApp = readQCString(ds);
00891
00892 DCOPConnection* connreply = findApp( toApp );
00893 int datalen = ba.size();
00894
00895 if ( !connreply )
00896 tqWarning("[dcopserver] DCOPServer::DCOPReply for unknown connection.");
00897 else {
00898 conn->waitingForReply.removeRef( connreply->iceConn );
00899 if ( opcode == DCOPReplyWait )
00900 {
00901 conn->waitingForDelayedReply.append( connreply->iceConn );
00902 }
00903 else
00904 {
00905 if (!connreply->waitingOnReply.removeRef(iceConn))
00906 tqWarning("[dcopserver] DCOPReply from %s to %s who wasn't waiting on one!",
00907 fromApp.data(), toApp.data());
00908 }
00909 IceGetHeader( connreply->iceConn, majorOpcode, opcode,
00910 sizeof(DCOPMsg), DCOPMsg, pMsg );
00911 pMsg->key = key;
00912 pMsg->length += datalen;
00913 _DCOPIceSendBegin( connreply->iceConn );
00914 DCOPIceSendData(connreply->iceConn, ba);
00915 _DCOPIceSendEnd();
00916 }
00917 }
00918 break;
00919 default:
00920 tqWarning("[dcopserver] DCOPServer::processMessage unknown message");
00921 }
00922 }
00923
00924 static const IcePaVersionRec DCOPServerVersions[] = {
00925 { DCOPVersionMajor, DCOPVersionMinor, DCOPProcessMessage }
00926 };
00927
00928 static const IcePoVersionRec DUMMYVersions[] = {
00929 { DCOPVersionMajor, DCOPVersionMinor, 0 }
00930 };
00931
00932 static Status DCOPServerProtocolSetupProc ( IceConn ,
00933 int majorVersion, int minorVersion,
00934 char* vendor, char* release,
00935 IcePointer *clientDataRet,
00936 char ** )
00937 {
00938
00939
00940
00941
00942 if (vendor)
00943 free (vendor);
00944 if (release)
00945 free (release);
00946
00947 *clientDataRet = 0;
00948
00949 return (majorVersion == DCOPVersionMajor && minorVersion == DCOPVersionMinor);
00950 }
00951
00952 #ifndef Q_OS_WIN
00953 static int pipeOfDeath[2];
00954
00955 static void sighandler(int sig)
00956 {
00957 if (sig == SIGHUP) {
00958 signal(SIGHUP, sighandler);
00959 return;
00960 }
00961
00962 write(pipeOfDeath[1], "x", 1);
00963 }
00964 #endif
00965
00966 extern "C"
00967 {
00968 extern int _kde_IceLastMajorOpcode;
00969 }
00970
00971 DCOPServer::DCOPServer(bool _suicide)
00972 : TQObject(0,0), currentClientNumber(0), appIds(263), clients(263)
00973 {
00974 serverKey = 42;
00975
00976 suicide = _suicide;
00977 shutdown = false;
00978
00979 dcopSignals = new DCOPSignals;
00980
00981 if (_kde_IceLastMajorOpcode < 1 )
00982 IceRegisterForProtocolSetup(const_cast<char *>("DUMMY"),
00983 const_cast<char *>("DUMMY"),
00984 const_cast<char *>("DUMMY"),
00985 1, const_cast<IcePoVersionRec *>(DUMMYVersions),
00986 DCOPAuthCount, const_cast<char **>(DCOPAuthNames),
00987 DCOPClientAuthProcs, 0);
00988 if (_kde_IceLastMajorOpcode < 1 )
00989 tqWarning("[dcopserver] DCOPServer Error: incorrect major opcode!");
00990
00991 the_server = this;
00992 if (( majorOpcode = IceRegisterForProtocolReply (const_cast<char *>("DCOP"),
00993 const_cast<char *>(DCOPVendorString),
00994 const_cast<char *>(DCOPReleaseString),
00995 1, const_cast<IcePaVersionRec *>(DCOPServerVersions),
00996 1, const_cast<char **>(DCOPAuthNames),
00997 DCOPServerAuthProcs,
00998 HostBasedAuthProc,
00999 DCOPServerProtocolSetupProc,
01000 NULL,
01001
01002
01003
01004 NULL
01005 )) < 0)
01006 {
01007 tqWarning("[dcopserver] Could not register DCOP protocol with ICE");
01008 }
01009
01010 char errormsg[256];
01011 int orig_umask = umask(077);
01012 if (!IceListenForConnections (&numTransports, &listenObjs,
01013 256, errormsg))
01014 {
01015 fprintf (stderr, "[dcopserver] %s", errormsg);
01016 exit (1);
01017 } else {
01018 (void) umask(orig_umask);
01019
01020 TQCString fName = DCOPClient::dcopServerFile();
01021 FILE *f;
01022 if(!(f = ::fopen(fName.data(), "w+"))) {
01023 fprintf (stderr, "[dcopserver] Can not create file %s: %s",
01024 fName.data(), ::strerror(errno));
01025 exit(1);
01026 }
01027 char *idlist = IceComposeNetworkIdList(numTransports, listenObjs);
01028 if (idlist != 0) {
01029 fprintf(f, "%s", idlist);
01030 free(idlist);
01031 }
01032 fprintf(f, "\n%i\n", getpid());
01033 fclose(f);
01034 #ifndef Q_OS_WIN32
01035 if (TQCString(getenv("DCOPAUTHORITY")).isEmpty())
01036 {
01037
01038 TQCString compatName = DCOPClient::dcopServerFileOld();
01039 ::symlink(fName,compatName);
01040 }
01041 #endif // Q_OS_WIN32
01042 }
01043
01044 #if 0
01045 if (!SetAuthentication_local(numTransports, listenObjs))
01046 tqFatal("DCOPSERVER: authentication setup failed.");
01047 #endif
01048 if (!SetAuthentication(numTransports, listenObjs, &authDataEntries))
01049 tqFatal("DCOPSERVER: authentication setup failed.");
01050
01051 IceAddConnectionWatch (DCOPWatchProc, static_cast<IcePointer>(this));
01052 _IceWriteHandler = DCOPIceWriteChar;
01053
01054 listener.setAutoDelete( true );
01055 DCOPListener* con;
01056 for ( int i = 0; i < numTransports; i++) {
01057 con = new DCOPListener( listenObjs[i] );
01058 listener.append( con );
01059 connect( con, TQT_SIGNAL( activated(int) ), this, TQT_SLOT( newClient(int) ) );
01060 }
01061 char c = 0;
01062 write(ready[1], &c, 1);
01063 close(ready[1]);
01064
01065 m_timer = new TQTimer(this);
01066 connect( m_timer, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotTerminate()) );
01067 m_deadConnectionTimer = new TQTimer(this);
01068 connect( m_deadConnectionTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotCleanDeadConnections()) );
01069
01070 #ifdef Q_OS_WIN
01071 char szEventName[256];
01072 sprintf(szEventName,"dcopserver%i",GetCurrentProcessId());
01073 m_evTerminate = CreateEventA(NULL,TRUE,FALSE,(LPCSTR)szEventName);
01074 ResetEvent(m_evTerminate);
01075 m_hTerminateThread = CreateThread(NULL,0,TerminatorThread,this,0,&m_dwTerminateThreadId);
01076 if(m_hTerminateThread)
01077 CloseHandle(m_hTerminateThread);
01078 #endif
01079
01080 #ifdef DCOP_LOG
01081 char hostname_buffer[256];
01082 memset( hostname_buffer, 0, sizeof( hostname_buffer ) );
01083 if ( gethostname( hostname_buffer, 255 ) < 0 )
01084 hostname_buffer[0] = '\0';
01085 m_logger = new TQFile( TQString( "%1/.dcop-%2.log" ).arg( TQDir::homeDirPath() ).arg( hostname_buffer ) );
01086 if ( m_logger->open( IO_WriteOnly ) ) {
01087 m_stream = new TQTextStream( m_logger );
01088 }
01089 #endif
01090 }
01091
01092 DCOPServer::~DCOPServer()
01093 {
01094 system(findDcopserverShutdown()+" --nokill");
01095 IceFreeListenObjs(numTransports, listenObjs);
01096 FreeAuthenticationData(numTransports, authDataEntries);
01097 delete dcopSignals;
01098 #ifdef DCOP_LOG
01099 delete m_stream;
01100 m_logger->close();
01101 delete m_logger;
01102 #endif
01103 #ifdef Q_OS_WIN
01104 SetEvent(m_evTerminate);
01105 CloseHandle(m_evTerminate);
01106 #endif
01107 }
01108
01109 DCOPConnection* DCOPServer::findApp( const TQCString& appId )
01110 {
01111 if ( appId.isNull() )
01112 return 0;
01113 DCOPConnection* conn = appIds.find( appId );
01114 return conn;
01115 }
01116
01120 void DCOPServer::slotCleanDeadConnections()
01121 {
01122 tqWarning("[dcopserver] DCOP Cleaning up dead connections.");
01123 while(!deadConnections.isEmpty())
01124 {
01125 IceConn iceConn = deadConnections.take(0);
01126 IceSetShutdownNegotiation (iceConn, False);
01127 (void) IceCloseConnection( iceConn );
01128 }
01129 }
01130
01134 void DCOPServer::ioError( IceConn iceConn )
01135 {
01136 deadConnections.removeRef(iceConn);
01137 deadConnections.prepend(iceConn);
01138 m_deadConnectionTimer->start(0, true);
01139 }
01140
01141
01142 void DCOPServer::processData( int )
01143 {
01144 IceConn iceConn = static_cast<const DCOPConnection*>(sender())->iceConn;
01145 IceProcessMessagesStatus status = IceProcessMessages( iceConn, 0, 0 );
01146 if ( status == IceProcessMessagesIOError ) {
01147 deadConnections.removeRef(iceConn);
01148 if (deadConnections.isEmpty())
01149 m_deadConnectionTimer->stop();
01150 IceSetShutdownNegotiation (iceConn, False);
01151 (void) IceCloseConnection( iceConn );
01152 }
01153 }
01154
01155 void DCOPServer::newClient( int )
01156 {
01157 IceAcceptStatus status;
01158 IceConn iceConn = IceAcceptConnection( static_cast<const DCOPListener*>(sender())->listenObj, &status);
01159 if (!iceConn) {
01160 if (status == IceAcceptBadMalloc)
01161 tqWarning("[dcopserver] Failed to alloc connection object!");
01162 else
01163 tqWarning("[dcopserver] Failed to accept ICE connection!");
01164 return;
01165 }
01166
01167 IceSetShutdownNegotiation( iceConn, False );
01168
01169 IceConnectStatus cstatus;
01170 while ((cstatus = IceConnectionStatus (iceConn))==IceConnectPending) {
01171 (void) IceProcessMessages( iceConn, 0, 0 );
01172 }
01173
01174 if (cstatus != IceConnectAccepted) {
01175 if (cstatus == IceConnectIOError)
01176 tqWarning ("[dcopserver] IO error opening ICE Connection!");
01177 else
01178 tqWarning ("[dcopserver] ICE Connection rejected!");
01179 deadConnections.removeRef(iceConn);
01180 (void) IceCloseConnection (iceConn);
01181 }
01182 }
01183
01184 void* DCOPServer::watchConnection( IceConn iceConn )
01185 {
01186 DCOPConnection* con = new DCOPConnection( iceConn );
01187 connect( con, TQT_SIGNAL( activated(int) ), this, TQT_SLOT( processData(int) ) );
01188
01189 clients.insert(iceConn, con );
01190 fd_clients.insert( IceConnectionNumber(iceConn), con);
01191
01192 return static_cast<void*>(con);
01193 }
01194
01195 void DCOPServer::removeConnection( void* data )
01196 {
01197 DCOPConnection* conn = static_cast<DCOPConnection*>(data);
01198
01199 dcopSignals->removeConnections(conn);
01200
01201 clients.remove(conn->iceConn );
01202 fd_clients.remove( IceConnectionNumber(conn->iceConn) );
01203
01204
01205 while (!conn->waitingForReply.isEmpty()) {
01206 IceConn iceConn = conn->waitingForReply.take(0);
01207 if (iceConn) {
01208 DCOPConnection* target = clients.find( iceConn );
01209 tqWarning("[dcopserver] DCOP aborting call from '%s' to '%s'", target ? target->appId.data() : "<unknown>" , conn->appId.data() );
01210 TQByteArray reply;
01211 DCOPMsg *pMsg;
01212 IceGetHeader( iceConn, majorOpcode, DCOPReplyFailed,
01213 sizeof(DCOPMsg), DCOPMsg, pMsg );
01214 pMsg->key = 1;
01215 pMsg->length += reply.size();
01216 _DCOPIceSendBegin( iceConn );
01217 DCOPIceSendData(iceConn, reply);
01218 _DCOPIceSendEnd();
01219 if (!target)
01220 tqWarning("[dcopserver] Unknown target in waitingForReply");
01221 else if (!target->waitingOnReply.removeRef(conn->iceConn))
01222 tqWarning("[dcopserver] Client in waitingForReply wasn't waiting on reply");
01223 }
01224 }
01225
01226
01227 while (!conn->waitingForDelayedReply.isEmpty()) {
01228 IceConn iceConn = conn->waitingForDelayedReply.take(0);
01229 if (iceConn) {
01230 DCOPConnection* target = clients.find( iceConn );
01231 tqWarning("[dcopserver] DCOP aborting (delayed) call from '%s' to '%s'", target ? target->appId.data() : "<unknown>", conn->appId.data() );
01232 TQByteArray reply;
01233 DCOPMsg *pMsg;
01234 IceGetHeader( iceConn, majorOpcode, DCOPReplyFailed,
01235 sizeof(DCOPMsg), DCOPMsg, pMsg );
01236 pMsg->key = 1;
01237 pMsg->length += reply.size();
01238 _DCOPIceSendBegin( iceConn );
01239 DCOPIceSendData( iceConn, reply );
01240 _DCOPIceSendEnd();
01241 if (!target)
01242 tqWarning("[dcopserver] Unknown target in waitingForDelayedReply");
01243 else if (!target->waitingOnReply.removeRef(conn->iceConn))
01244 tqWarning("[dcopserver] Client in waitingForDelayedReply wasn't waiting on reply");
01245 }
01246 }
01247 while (!conn->waitingOnReply.isEmpty())
01248 {
01249 IceConn iceConn = conn->waitingOnReply.take(0);
01250 if (iceConn) {
01251 DCOPConnection* target = clients.find( iceConn );
01252 if (!target)
01253 {
01254 tqWarning("[dcopserver] Still waiting for answer from non-existing client.");
01255 continue;
01256 }
01257 tqWarning("[dcopserver] DCOP aborting while waiting for answer from '%s'", target->appId.data());
01258 if (!target->waitingForReply.removeRef(conn->iceConn) &&
01259 !target->waitingForDelayedReply.removeRef(conn->iceConn))
01260 tqWarning("[dcopserver] Called client has forgotten about caller");
01261 }
01262 }
01263
01264 if ( !conn->appId.isNull() ) {
01265 #ifndef NDEBUG
01266 tqDebug("DCOP: unregister '%s'", conn->appId.data() );
01267 #endif
01268 if ( !conn->daemon )
01269 {
01270 currentClientNumber--;
01271 }
01272
01273 appIds.remove( conn->appId );
01274
01275 broadcastApplicationRegistration( conn, "applicationRemoved(TQCString)", conn->appId );
01276 }
01277
01278 delete conn;
01279
01280 if ( suicide && (currentClientNumber == 0) )
01281 {
01282 m_timer->start( 10000 );
01283 }
01284 if ( shutdown && appIds.isEmpty())
01285 {
01286 m_timer->start( 10 );
01287 }
01288 }
01289
01290 void DCOPServer::slotTerminate()
01291 {
01292 #ifndef NDEBUG
01293 fprintf( stderr, "[dcopserver] slotTerminate() -> sending terminateTDE signal." );
01294 #endif
01295 TQByteArray data;
01296 dcopSignals->emitSignal(0L , "terminateTDE()", data, false);
01297 disconnect( m_timer, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotTerminate()) );
01298 connect( m_timer, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotSuicide()) );
01299 system(findDcopserverShutdown()+" --nokill");
01300 }
01301
01302 void DCOPServer::slotSuicide()
01303 {
01304 #ifndef NDEBUG
01305 fprintf( stderr, "[dcopserver] slotSuicide() -> exit." );
01306 #endif
01307 exit(0);
01308 }
01309
01310 void DCOPServer::slotShutdown()
01311 {
01312 #ifndef NDEBUG
01313 fprintf( stderr, "[dcopserver] slotShutdown() -> waiting for clients to disconnect." );
01314 #endif
01315 char c;
01316 #ifndef Q_OS_WIN
01317 read(pipeOfDeath[0], &c, 1);
01318 #endif
01319 if (!shutdown)
01320 {
01321 shutdown = true;
01322 TQByteArray data;
01323 dcopSignals->emitSignal(0L , "terminateTDE()", data, false);
01324 m_timer->start( 10000 );
01325 disconnect( m_timer, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotTerminate()) );
01326 connect( m_timer, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotExit()) );
01327 if (appIds.isEmpty())
01328 slotExit();
01329 }
01330 }
01331
01332 void DCOPServer::slotExit()
01333 {
01334 #ifndef NDEBUG
01335 fprintf( stderr, "[dcopserver] slotExit() -> exit." );
01336 #endif
01337 #ifdef Q_OS_WIN
01338 SetEvent(m_evTerminate);
01339 if(m_dwTerminateThreadId != GetCurrentThreadId())
01340 WaitForSingleObject(m_hTerminateThread,INFINITE);
01341 CloseHandle(m_hTerminateThread);
01342 #endif
01343 exit(0);
01344 }
01345
01346 bool DCOPServer::receive(const TQCString &, const TQCString &obj,
01347 const TQCString &fun, const TQByteArray& data,
01348 TQCString& replyType, TQByteArray &replyData,
01349 IceConn iceConn)
01350 {
01351 #ifdef DCOP_LOG
01352 (*m_stream) << "Received a message: obj =\""
01353 << obj << "\", fun =\""
01354 << fun << "\", replyType =\""
01355 << replyType << "\", data.size() =\""
01356 << data.size() << "\", replyData.size() ="
01357 << replyData.size() << "";
01358 m_logger->flush();
01359 #endif
01360
01361 if ( obj == "emit")
01362 {
01363 DCOPConnection* conn = clients.find( iceConn );
01364 if (conn) {
01365
01366 dcopSignals->emitSignal(conn, fun, data, false);
01367 }
01368 replyType = "void";
01369 return true;
01370 }
01371 if ( fun == "setDaemonMode(bool)" ) {
01372 TQDataStream args( data, IO_ReadOnly );
01373 if ( !args.atEnd() ) {
01374 TQ_INT8 iDaemon;
01375 bool daemon;
01376 args >> iDaemon;
01377
01378 daemon = static_cast<bool>( iDaemon );
01379
01380 DCOPConnection* conn = clients.find( iceConn );
01381 if ( conn && !conn->appId.isNull() ) {
01382 if ( daemon ) {
01383 if ( !conn->daemon )
01384 {
01385 conn->daemon = true;
01386
01387 #ifndef NDEBUG
01388 tqDebug( "DCOP: new daemon %s", conn->appId.data() );
01389 #endif
01390
01391 currentClientNumber--;
01392
01393
01394
01395
01396 }
01397 } else
01398 {
01399 if ( conn->daemon ) {
01400 conn->daemon = false;
01401
01402 currentClientNumber++;
01403
01404 m_timer->stop();
01405 }
01406 }
01407 }
01408
01409 replyType = "void";
01410 return true;
01411 }
01412 }
01413 if ( fun == "registerAs(TQCString)" ) {
01414 TQDataStream args( data, IO_ReadOnly );
01415 if (!args.atEnd()) {
01416 TQCString app2 = readQCString(args);
01417 TQDataStream reply( replyData, IO_WriteOnly );
01418 DCOPConnection* conn = clients.find( iceConn );
01419 if ( conn && !app2.isEmpty() ) {
01420 if ( !conn->appId.isNull() &&
01421 appIds.find( conn->appId ) == conn ) {
01422 appIds.remove( conn->appId );
01423
01424 }
01425
01426 TQCString oldAppId;
01427 if ( conn->appId.isNull() )
01428 {
01429 currentClientNumber++;
01430 m_timer->stop();
01431 #ifndef NDEBUG
01432 tqDebug("DCOP: register '%s' -> number of clients is now %d", app2.data(), currentClientNumber );
01433 #endif
01434 }
01435 #ifndef NDEBUG
01436 else
01437 {
01438 oldAppId = conn->appId;
01439 tqDebug("DCOP: '%s' now known as '%s'", conn->appId.data(), app2.data() );
01440 }
01441 #endif
01442
01443 conn->appId = app2;
01444 if ( appIds.find( app2 ) != 0 ) {
01445
01446 int n = 1;
01447 TQCString tmp;
01448 do {
01449 n++;
01450 tmp.setNum( n );
01451 tmp.prepend("-");
01452 tmp.prepend( app2 );
01453 } while ( appIds.find( tmp ) != 0 );
01454 conn->appId = tmp;
01455 }
01456 appIds.insert( conn->appId, conn );
01457
01458 int c = conn->appId.find( '-' );
01459 if ( c > 0 )
01460 conn->plainAppId = conn->appId.left( c );
01461 else
01462 conn->plainAppId = conn->appId;
01463
01464 if( !oldAppId.isEmpty())
01465 broadcastApplicationRegistration( conn,
01466 "applicationRemoved(TQCString)", oldAppId );
01467 broadcastApplicationRegistration( conn, "applicationRegistered(TQCString)", conn->appId );
01468 }
01469 replyType = "TQCString";
01470 reply << conn->appId;
01471 return true;
01472 }
01473 }
01474 else if ( fun == "registeredApplications()" ) {
01475 TQDataStream reply( replyData, IO_WriteOnly );
01476 QCStringList applications;
01477 TQAsciiDictIterator<DCOPConnection> it( appIds );
01478 while ( it.current() ) {
01479 applications << it.currentKey();
01480 ++it;
01481 }
01482 replyType = "QCStringList";
01483 reply << applications;
01484 return true;
01485 } else if ( fun == "isApplicationRegistered(TQCString)" ) {
01486 TQDataStream args( data, IO_ReadOnly );
01487 if (!args.atEnd()) {
01488 TQCString s = readQCString(args);
01489 TQDataStream reply( replyData, IO_WriteOnly );
01490 int b = ( findApp( s ) != 0 );
01491 replyType = "bool";
01492 reply << b;
01493 return true;
01494 }
01495 } else if ( fun == "setNotifications(bool)" ) {
01496 TQDataStream args( data, IO_ReadOnly );
01497 if (!args.atEnd()) {
01498 TQ_INT8 notifyActive;
01499 args >> notifyActive;
01500 DCOPConnection* conn = clients.find( iceConn );
01501 if ( conn ) {
01502 if ( notifyActive )
01503 conn->notifyRegister++;
01504 else if ( conn->notifyRegister > 0 )
01505 conn->notifyRegister--;
01506 }
01507 replyType = "void";
01508 return true;
01509 }
01510 } else if ( fun == "connectSignal(TQCString,TQCString,TQCString,TQCString,TQCString,bool)") {
01511 DCOPConnection* conn = clients.find( iceConn );
01512 if (!conn) return false;
01513 TQDataStream args(data, IO_ReadOnly );
01514 if (args.atEnd()) return false;
01515 TQCString sender = readQCString(args);
01516 TQCString senderObj = readQCString(args);
01517 TQCString signal = readQCString(args);
01518 TQCString receiverObj = readQCString(args);
01519 TQCString slot = readQCString(args);
01520 TQ_INT8 Volatile;
01521 args >> Volatile;
01522 #ifdef DCOP_DEBUG
01523 tqDebug("DCOPServer: connectSignal(sender = %s senderObj = %s signal = %s recvObj = %s slot = %s)", sender.data(), senderObj.data(), signal.data(), receiverObj.data(), slot.data());
01524 #endif
01525 bool b = dcopSignals->connectSignal(sender, senderObj, signal, conn, receiverObj, slot, (Volatile != 0));
01526 replyType = "bool";
01527 TQDataStream reply( replyData, IO_WriteOnly );
01528 reply << (TQ_INT8) (b?1:0);
01529 return true;
01530 } else if ( fun == "disconnectSignal(TQCString,TQCString,TQCString,TQCString,TQCString)") {
01531 DCOPConnection* conn = clients.find( iceConn );
01532 if (!conn) return false;
01533 TQDataStream args(data, IO_ReadOnly );
01534 if (args.atEnd()) return false;
01535 TQCString sender = readQCString(args);
01536 TQCString senderObj = readQCString(args);
01537 TQCString signal = readQCString(args);
01538 TQCString receiverObj = readQCString(args);
01539 TQCString slot = readQCString(args);
01540 #ifdef DCOP_DEBUG
01541 tqDebug("DCOPServer: disconnectSignal(sender = %s senderObj = %s signal = %s recvObj = %s slot = %s)", sender.data(), senderObj.data(), signal.data(), receiverObj.data(), slot.data());
01542 #endif
01543 bool b = dcopSignals->disconnectSignal(sender, senderObj, signal, conn, receiverObj, slot);
01544 replyType = "bool";
01545 TQDataStream reply( replyData, IO_WriteOnly );
01546 reply << (TQ_INT8) (b?1:0);
01547 return true;
01548 }
01549
01550 return false;
01551 }
01552
01553 void DCOPServer::broadcastApplicationRegistration( DCOPConnection* conn, const TQCString type,
01554 const TQCString& appId )
01555 {
01556 TQByteArray data;
01557 TQDataStream datas( data, IO_WriteOnly );
01558 datas << appId;
01559 TQPtrDictIterator<DCOPConnection> it( clients );
01560 TQByteArray ba;
01561 TQDataStream ds( ba, IO_WriteOnly );
01562 ds <<TQCString("DCOPServer") << TQCString("") << TQCString("")
01563 << type << data;
01564 int datalen = ba.size();
01565 DCOPMsg *pMsg = 0;
01566 while ( it.current() ) {
01567 DCOPConnection* c = it.current();
01568 ++it;
01569 if ( c->notifyRegister && (c != conn) ) {
01570 IceGetHeader( c->iceConn, majorOpcode, DCOPSend,
01571 sizeof(DCOPMsg), DCOPMsg, pMsg );
01572 pMsg->key = 1;
01573 pMsg->length += datalen;
01574 _DCOPIceSendBegin(c->iceConn);
01575 DCOPIceSendData( c->iceConn, ba );
01576 _DCOPIceSendEnd();
01577 }
01578 }
01579 }
01580
01581 void
01582 DCOPServer::sendMessage(DCOPConnection *conn, const TQCString &sApp,
01583 const TQCString &rApp, const TQCString &rObj,
01584 const TQCString &rFun, const TQByteArray &data)
01585 {
01586 TQByteArray ba;
01587 TQDataStream ds( ba, IO_WriteOnly );
01588 ds << sApp << rApp << rObj << rFun << data;
01589 int datalen = ba.size();
01590 DCOPMsg *pMsg = 0;
01591
01592 IceGetHeader( conn->iceConn, majorOpcode, DCOPSend,
01593 sizeof(DCOPMsg), DCOPMsg, pMsg );
01594 pMsg->length += datalen;
01595 pMsg->key = 1;
01596
01597 #ifdef DCOP_LOG
01598 (*m_stream) << "Sending a message: sApp =\""
01599 << sApp << "\", rApp =\""
01600 << rApp << "\", rObj =\""
01601 << rObj << "\", rFun =\""
01602 << rFun << "\", datalen ="
01603 << datalen << "\n";
01604 m_logger->flush();
01605 #endif
01606
01607 _DCOPIceSendBegin( conn->iceConn );
01608 DCOPIceSendData(conn->iceConn, ba);
01609 _DCOPIceSendEnd();
01610 }
01611
01612 void IoErrorHandler ( IceConn iceConn)
01613 {
01614 the_server->ioError( iceConn );
01615 }
01616
01617 static bool isRunning(const TQCString &fName, bool printNetworkId = false)
01618 {
01619 if (::access(fName.data(), R_OK) == 0) {
01620 TQFile f(fName);
01621 f.open(IO_ReadOnly);
01622 int size = TQMIN( (qint64)1024, f.size() );
01623 TQCString contents( size+1 );
01624 bool ok = f.readBlock( contents.data(), size ) == size;
01625 contents[size] = '\0';
01626 int pos = contents.find('\n');
01627 ok = ok && ( pos != -1 );
01628 pid_t pid = ok ? contents.mid(pos+1).toUInt(&ok) : 0;
01629 f.close();
01630 if (ok && pid && (kill(pid, SIGHUP) == 0)) {
01631 if (printNetworkId)
01632 tqWarning("[dcopserver] %s", contents.left(pos).data());
01633 else
01634 tqWarning( "---------------------------------\n"
01635 "[dcopserver] It looks like dcopserver is already running. If you are sure\n"
01636 "that it is not already running, remove %s\n"
01637 "and start dcopserver again.\n"
01638 "---------------------------------",
01639 fName.data() );
01640
01641
01642 return true;
01643 } else {
01644
01645
01646 unlink(fName.data());
01647 }
01648 } else if (errno != ENOENT) {
01649
01650 unlink(fName.data());
01651 }
01652 return false;
01653 }
01654
01655 const char* const ABOUT =
01656 "Usage: dcopserver [--nofork] [--nosid] [--help]\n"
01657 " dcopserver --serverid\n"
01658 "\n"
01659 "DCOP is TDE's Desktop Communications Protocol. It is a lightweight IPC/RPC\n"
01660 "mechanism built on top of the X Consortium's Inter Client Exchange protocol.\n"
01661 "It enables desktop applications to communicate reliably with low overhead.\n"
01662 "\n"
01663 "Copyright (C) 1999-2001, The KDE Developers <http://www.kde.org>\n"
01664 ;
01665
01666 extern "C" DCOP_EXPORT int kdemain( int argc, char* argv[] )
01667 {
01668 bool serverid = false;
01669 bool nofork = false;
01670 bool nosid = false;
01671 bool suicide = false;
01672 for(int i = 1; i < argc; i++) {
01673 if (strcmp(argv[i], "--nofork") == 0)
01674 nofork = true;
01675 else if (strcmp(argv[i], "--nosid") == 0)
01676 nosid = true;
01677 else if (strcmp(argv[i], "--nolocal") == 0)
01678 ;
01679 else if (strcmp(argv[i], "--suicide") == 0)
01680 suicide = true;
01681 else if (strcmp(argv[i], "--serverid") == 0)
01682 serverid = true;
01683 else {
01684 fprintf(stdout, "%s", ABOUT );
01685 return 0;
01686 }
01687 }
01688
01689 if (serverid)
01690 {
01691 if (isRunning(DCOPClient::dcopServerFile(), true))
01692 return 0;
01693 return 1;
01694 }
01695
01696
01697 if (isRunning(DCOPClient::dcopServerFile()))
01698 return 0;
01699 #ifndef Q_OS_WIN32
01700 if (TQCString(getenv("DCOPAUTHORITY")).isEmpty() &&
01701 isRunning(DCOPClient::dcopServerFileOld()))
01702 {
01703
01704 TQCString oldFile = DCOPClient::dcopServerFileOld();
01705 TQCString newFile = DCOPClient::dcopServerFile();
01706 symlink(oldFile.data(), newFile.data());
01707 return 0;
01708 }
01709
01710 struct rlimit limits;
01711
01712 int retcode = getrlimit(RLIMIT_NOFILE, &limits);
01713 if (!retcode) {
01714 if (limits.rlim_max > 512 && limits.rlim_cur < 512)
01715 {
01716 int cur_limit = limits.rlim_cur;
01717 limits.rlim_cur = 512;
01718 retcode = setrlimit(RLIMIT_NOFILE, &limits);
01719
01720 if (retcode != 0)
01721 {
01722 tqWarning("[dcopserver] Could not raise limit on number of open files.");
01723 tqWarning("[dcopserver] Current limit = %d", cur_limit);
01724 }
01725 }
01726 }
01727 #endif
01728 pipe(ready);
01729
01730 #ifndef Q_OS_WIN32
01731 if (!nofork) {
01732 pid_t pid = fork();
01733 if (pid > 0) {
01734 char c = 1;
01735 close(ready[1]);
01736 read(ready[0], &c, 1);
01737 close(ready[0]);
01738
01739 if (c == 0)
01740 {
01741
01742 DCOPClient client;
01743 if (client.attach())
01744 return 0;
01745 }
01746 tqWarning("[dcopserver] DCOPServer self-test failed.");
01747 system(findDcopserverShutdown()+" --kill");
01748 return 1;
01749 }
01750 close(ready[0]);
01751
01752 if (!nosid)
01753 setsid();
01754
01755 if (fork() > 0)
01756 return 0;
01757 }
01758
01759 pipe(pipeOfDeath);
01760
01761 signal(SIGHUP, sighandler);
01762 signal(SIGTERM, sighandler);
01763 signal(SIGPIPE, SIG_IGN);
01764 #else
01765 {
01766 char c = 1;
01767 close(ready[1]);
01768 read(ready[0], &c, 1);
01769 close(ready[0]);
01770 }
01771 #endif
01772 putenv(strdup("SESSION_MANAGER="));
01773
01774 TQApplication a( argc, argv, false );
01775
01776 IceSetIOErrorHandler (IoErrorHandler );
01777 DCOPServer *server = new DCOPServer(suicide);
01778
01779 #ifdef Q_OS_WIN
01780 SetConsoleCtrlHandler(DCOPServer::dcopServerConsoleProc,TRUE);
01781 #else
01782 TQSocketNotifier DEATH(pipeOfDeath[0], TQSocketNotifier::Read, 0, 0);
01783 server->connect(&DEATH, TQT_SIGNAL(activated(int)), TQT_SLOT(slotShutdown()));
01784 #endif
01785
01786 int ret = a.exec();
01787 delete server;
01788 return ret;
01789 }
01790
01791 #ifdef Q_OS_WIN
01792 #include "dcopserver_win.cpp"
01793 #endif
01794
01795 #include "dcopserver.moc"