dcop Library API Documentation

dcopserver.cpp

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