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