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