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