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