dcop Library: dcopserver.cpp Source File (dcop Library)

| # dcop Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Namespaces | Source Files

# 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     shutdown = false;
    00922
    00923     dcopSignals = new DCOPSignals;
    00924
    00925     extern int _kde_IceLastMajorOpcode; // from libICE
    00926     if (_kde_IceLastMajorOpcode < 1 )
    00927         IceRegisterForProtocolSetup(const_cast<char *>("DUMMY"),
    00928                     const_cast<char *>("DUMMY"),
    00929                     const_cast<char *>("DUMMY"),
    00930                     1, const_cast<IcePoVersionRec *>(DUMMYVersions),
    00931                     DCOPAuthCount, const_cast<char **>(DCOPAuthNames),
    00932                     DCOPClientAuthProcs, 0);
    00933     if (_kde_IceLastMajorOpcode < 1 )
    00934     qWarning("DCOPServer Error: incorrect major opcode!");
    00935
    00936     the_server = this;
    00937     if (( majorOpcode = IceRegisterForProtocolReply (const_cast<char *>("DCOP"),
    00938                              const_cast<char *>(DCOPVendorString),
    00939                              const_cast<char *>(DCOPReleaseString),
    00940                              1, const_cast<IcePaVersionRec *>(DCOPServerVersions),
    00941                              1, const_cast<char **>(DCOPAuthNames),
    00942                              DCOPServerAuthProcs,
    00943                              HostBasedAuthProc,
    00944                              DCOPServerProtocolSetupProc,
    00945                              NULL,  /* IceProtocolActivateProc - we don't care about
    00946                                    when the Protocol Reply is sent, because the
    00947                                    session manager can not immediately send a
    00948                                    message - it must wait for RegisterClient. */
    00949                              NULL   /* IceIOErrorProc */
    00950                              )) < 0)
    00951     {
    00952         qWarning("Could not register DCOP protocol with ICE");
    00953     }
    00954
    00955     char errormsg[256];
    00956     int orig_umask = umask(077); /*old libICE's don't reset the umask() they set */
    00957     if (!IceListenForConnections (&numTransports, &listenObjs,
    00958                   256, errormsg))
    00959     {
    00960         fprintf (stderr, "%s\n", errormsg);
    00961         exit (1);
    00962     } else {
    00963         (void) umask(orig_umask);
    00964         // publish available transports.
    00965         QCString fName = DCOPClient::dcopServerFile();
    00966         FILE *f;
    00967         if(!(f = ::fopen(fName.data(), "w+"))) {
    00968             fprintf (stderr, "Can not create file %s: %s\n",
    00969              fName.data(), ::strerror(errno));
    00970         exit(1);
    00971         }
    00972         char *idlist = IceComposeNetworkIdList(numTransports, listenObjs);
    00973         if (idlist != 0) {
    00974             fprintf(f, "%s", idlist);
    00975         free(idlist);
    00976         }
    00977         fprintf(f, "\n%i\n", getpid());
    00978         fclose(f);
    00979         if (QCString(getenv("DCOPAUTHORITY")).isEmpty())
    00980         {
    00981                 // Create a link named like the old-style (KDE 2.x) naming
    00982                 QCString compatName = DCOPClient::dcopServerFileOld();
    00983                 ::symlink(fName,compatName);
    00984             }
    00985     }
    00986
    00987 #if 0
    00988     if (!SetAuthentication_local(numTransports, listenObjs))
    00989         qFatal("DCOPSERVER: authentication setup failed.");
    00990 #endif
    00991     if (!SetAuthentication(numTransports, listenObjs, &authDataEntries))
    00992         qFatal("DCOPSERVER: authentication setup failed.");
    00993
    00994     IceAddConnectionWatch (DCOPWatchProc, static_cast<IcePointer>(this));
    00995     _IceWriteHandler = DCOPIceWriteChar;
    00996
    00997     listener.setAutoDelete( true );
    00998     DCOPListener* con;
    00999     for ( int i = 0; i < numTransports; i++) {
    01000     con = new DCOPListener( listenObjs[i] );
    01001     listener.append( con );
    01002     connect( con, SIGNAL( activated(int) ), this, SLOT( newClient(int) ) );
    01003     }
    01004     char c = 0;
    01005     write(ready[1], &c, 1); // dcopserver is started
    01006     close(ready[1]);
    01007
    01008     m_timer =  new QTimer(this);
    01009     connect( m_timer, SIGNAL(timeout()), this, SLOT(slotTerminate()) );
    01010     m_deadConnectionTimer = new QTimer(this);
    01011     connect( m_deadConnectionTimer, SIGNAL(timeout()), this, SLOT(slotCleanDeadConnections()) );
    01012
    01013 #ifdef DCOP_LOG
    01014     char hostname_buffer[256];
    01015     memset( hostname_buffer, 0, sizeof( hostname_buffer ) );
    01016     if ( gethostname( hostname_buffer, 255 ) < 0 )
    01017       hostname_buffer[0] = '\0';
    01018     m_logger = new QFile( QString( "%1/.dcop-%2.log" ).arg( QDir::homeDirPath() ).arg( hostname_buffer ) );
    01019     if ( m_logger->open( IO_WriteOnly ) ) {
    01020         m_stream = new QTextStream( m_logger );
    01021     }
    01022 #endif
    01023 }
    01024
    01025 DCOPServer::~DCOPServer()
    01026 {
    01027     system(findDcopserverShutdown()+" --nokill");
    01028     IceFreeListenObjs(numTransports, listenObjs);
    01029     FreeAuthenticationData(numTransports, authDataEntries);
    01030     delete dcopSignals;
    01031 #ifdef DCOP_LOG
    01032     delete m_stream;
    01033     m_logger->close();
    01034     delete m_logger;
    01035 #endif
    01036 }
    01037
    01038
    01039 DCOPConnection* DCOPServer::findApp( const QCString& appId )
    01040 {
    01041     if ( appId.isNull() )
    01042     return 0;
    01043     DCOPConnection* conn = appIds.find( appId );
    01044     return conn;
    01045 }
    01046
    01050 void DCOPServer::slotCleanDeadConnections()
    01051 {
    01052 qWarning("DCOP Cleaning up dead connections.");
    01053     while(!deadConnections.isEmpty())
    01054     {
    01055        IceConn iceConn = deadConnections.take(0);
    01056        IceSetShutdownNegotiation (iceConn, False);
    01057        (void) IceCloseConnection( iceConn );
    01058     }
    01059 }
    01060
    01064 void DCOPServer::ioError( IceConn iceConn  )
    01065 {
    01066     deadConnections.removeRef(iceConn);
    01067     deadConnections.prepend(iceConn);
    01068     m_deadConnectionTimer->start(0, true);
    01069 }
    01070
    01071
    01072 void DCOPServer::processData( int /*socket*/ )
    01073 {
    01074     IceConn iceConn = static_cast<const DCOPConnection*>(sender())->iceConn;
    01075     IceProcessMessagesStatus status = IceProcessMessages( iceConn, 0, 0 );
    01076     if ( status == IceProcessMessagesIOError ) {
    01077         deadConnections.removeRef(iceConn);
    01078         if (deadConnections.isEmpty())
    01079            m_deadConnectionTimer->stop();
    01080     IceSetShutdownNegotiation (iceConn, False);
    01081     (void) IceCloseConnection( iceConn );
    01082     }
    01083 }
    01084
    01085 void DCOPServer::newClient( int /*socket*/ )
    01086 {
    01087     IceAcceptStatus status;
    01088     IceConn iceConn = IceAcceptConnection( static_cast<const  DCOPListener*>(sender())->listenObj, &status);
    01089     if (!iceConn) {
    01090       if (status == IceAcceptBadMalloc)
    01091      qWarning("Failed to alloc connection object!\n");
    01092       else // IceAcceptFailure
    01093          qWarning("Failed to accept ICE connection!\n");
    01094       return;
    01095     }
    01096
    01097     IceSetShutdownNegotiation( iceConn, False );
    01098
    01099     IceConnectStatus cstatus;
    01100     while ((cstatus = IceConnectionStatus (iceConn))==IceConnectPending) {
    01101     (void) IceProcessMessages( iceConn, 0, 0 );
    01102     }
    01103
    01104     if (cstatus != IceConnectAccepted) {
    01105     if (cstatus == IceConnectIOError)
    01106         qWarning ("IO error opening ICE Connection!\n");
    01107     else
    01108         qWarning ("ICE Connection rejected!\n");
    01109         deadConnections.removeRef(iceConn);
    01110     (void) IceCloseConnection (iceConn);
    01111     }
    01112 }
    01113
    01114 void* DCOPServer::watchConnection( IceConn iceConn )
    01115 {
    01116     DCOPConnection* con = new DCOPConnection( iceConn );
    01117     connect( con, SIGNAL( activated(int) ), this, SLOT( processData(int) ) );
    01118
    01119     clients.insert(iceConn, con );
    01120     fd_clients.insert( IceConnectionNumber(iceConn), con);
    01121
    01122     return static_cast<void*>(con);
    01123 }
    01124
    01125 void DCOPServer::removeConnection( void* data )
    01126 {
    01127     DCOPConnection* conn = static_cast<DCOPConnection*>(data);
    01128
    01129     dcopSignals->removeConnections(conn);
    01130
    01131     clients.remove(conn->iceConn );
    01132     fd_clients.remove( IceConnectionNumber(conn->iceConn) );
    01133
    01134     // Send DCOPReplyFailed to all in conn->waitingForReply
    01135     while (!conn->waitingForReply.isEmpty()) {
    01136     IceConn iceConn = conn->waitingForReply.take(0);
    01137     if (iceConn) {
    01138         DCOPConnection* target = clients.find( iceConn );
    01139         qWarning("DCOP aborting call from '%s' to '%s'", target ? target->appId.data() : "<unknown>" , conn->appId.data() );
    01140         QByteArray reply;
    01141         DCOPMsg *pMsg;
    01142         IceGetHeader( iceConn, majorOpcode, DCOPReplyFailed,
    01143               sizeof(DCOPMsg), DCOPMsg, pMsg );
    01144         pMsg->key = 1;
    01145         pMsg->length += reply.size();
    01146             _DCOPIceSendBegin( iceConn );
    01147         DCOPIceSendData(iceConn, reply);
    01148             _DCOPIceSendEnd();
    01149             if (!target)
    01150                qWarning("DCOP Error: unknown target in waitingForReply");
    01151             else if (!target->waitingOnReply.removeRef(conn->iceConn))
    01152                qWarning("DCOP Error: client in waitingForReply wasn't waiting on reply");
    01153     }
    01154     }
    01155
    01156     // Send DCOPReplyFailed to all in conn->waitingForDelayedReply
    01157     while (!conn->waitingForDelayedReply.isEmpty()) {
    01158     IceConn iceConn = conn->waitingForDelayedReply.take(0);
    01159     if (iceConn) {
    01160         DCOPConnection* target = clients.find( iceConn );
    01161         qWarning("DCOP aborting (delayed) call from '%s' to '%s'", target ? target->appId.data() : "<unknown>", conn->appId.data() );
    01162         QByteArray reply;
    01163         DCOPMsg *pMsg;
    01164         IceGetHeader( iceConn, majorOpcode, DCOPReplyFailed,
    01165               sizeof(DCOPMsg), DCOPMsg, pMsg );
    01166         pMsg->key = 1;
    01167         pMsg->length += reply.size();
    01168             _DCOPIceSendBegin( iceConn );
    01169         DCOPIceSendData( iceConn, reply );
    01170             _DCOPIceSendEnd();
    01171             if (!target)
    01172                qWarning("DCOP Error: unknown target in waitingForDelayedReply");
    01173             else if (!target->waitingOnReply.removeRef(conn->iceConn))
    01174                qWarning("DCOP Error: client in waitingForDelayedReply wasn't waiting on reply");
    01175     }
    01176     }
    01177     while (!conn->waitingOnReply.isEmpty())
    01178     {
    01179     IceConn iceConn = conn->waitingOnReply.take(0);
    01180         if (iceConn) {
    01181            DCOPConnection* target = clients.find( iceConn );
    01182            if (!target)
    01183            {
    01184                qWarning("DCOP Error: still waiting for answer from non-existing client.");
    01185                continue;
    01186            }
    01187            qWarning("DCOP aborting while waiting for answer from '%s'", target->appId.data());
    01188            if (!target->waitingForReply.removeRef(conn->iceConn) &&
    01189                !target->waitingForDelayedReply.removeRef(conn->iceConn))
    01190               qWarning("DCOP Error: called client has forgotten about caller");
    01191         }
    01192     }
    01193
    01194     if ( !conn->appId.isNull() ) {
    01195 #ifndef NDEBUG
    01196     qDebug("DCOP: unregister '%s'", conn->appId.data() );
    01197 #endif
    01198         if ( !conn->daemon )
    01199         {
    01200             currentClientNumber--;
    01201         }
    01202
    01203     appIds.remove( conn->appId );
    01204
    01205         broadcastApplicationRegistration( conn, "applicationRemoved(QCString)", conn->appId );
    01206     }
    01207
    01208     delete conn;
    01209
    01210     if ( suicide && (currentClientNumber == 0) )
    01211     {
    01212         m_timer->start( 10000 ); // if within 10 seconds nothing happens, we'll terminate
    01213     }
    01214     if ( shutdown && appIds.isEmpty())
    01215     {
    01216         m_timer->start( 10 ); // Exit now
    01217     }
    01218 }
    01219
    01220 void DCOPServer::slotTerminate()
    01221 {
    01222 #ifndef NDEBUG
    01223     fprintf( stderr, "DCOPServer : slotTerminate() -> sending terminateKDE signal.\n" );
    01224 #endif
    01225     QByteArray data;
    01226     dcopSignals->emitSignal(0L /* dcopserver */, "terminateKDE()", data, false);
    01227     disconnect( m_timer, SIGNAL(timeout()), this, SLOT(slotTerminate()) );
    01228     connect( m_timer, SIGNAL(timeout()), this, SLOT(slotSuicide()) );
    01229     system(findDcopserverShutdown()+" --nokill");
    01230 }
    01231
    01232 void DCOPServer::slotSuicide()
    01233 {
    01234 #ifndef NDEBUG
    01235     fprintf( stderr, "DCOPServer : slotSuicide() -> exit.\n" );
    01236 #endif
    01237     exit(0);
    01238 }
    01239
    01240 void DCOPServer::slotShutdown()
    01241 {
    01242 #ifndef NDEBUG
    01243     fprintf( stderr, "DCOPServer : slotShutdown() -> waiting for clients to disconnect.\n" );
    01244 #endif
    01245     char c;
    01246     read(pipeOfDeath[0], &c, 1);
    01247     if (!shutdown)
    01248     {
    01249        shutdown = true;
    01250        m_timer->start( 10000 ); // if within 10 seconds nothing happens, we'll terminate
    01251        disconnect( m_timer, SIGNAL(timeout()), this, SLOT(slotTerminate()) );
    01252        connect( m_timer, SIGNAL(timeout()), this, SLOT(slotExit()) );
    01253        if (appIds.isEmpty())
    01254          slotExit(); // Exit now
    01255     }
    01256 }
    01257
    01258 void DCOPServer::slotExit()
    01259 {
    01260 #ifndef NDEBUG
    01261     fprintf( stderr, "DCOPServer : slotExit() -> exit.\n" );
    01262 #endif
    01263     exit(0);
    01264 }
    01265
    01266 bool DCOPServer::receive(const QCString &/*app*/, const QCString &obj,
    01267              const QCString &fun, const QByteArray& data,
    01268              QCString& replyType, QByteArray &replyData,
    01269              IceConn iceConn)
    01270 {
    01271 #ifdef DCOP_LOG
    01272     (*m_stream) << "Received a message: obj =\""
    01273                 << obj << "\", fun =\""
    01274                 << fun << "\", replyType =\""
    01275                 << replyType << "\", data.size() =\""
    01276                 << data.size() << "\", replyData.size() ="
    01277                 << replyData.size() << "\n";
    01278     m_logger->flush();
    01279 #endif
    01280
    01281     if ( obj == "emit")
    01282     {
    01283         DCOPConnection* conn = clients.find( iceConn );
    01284         if (conn) {
    01285         //qDebug("DCOPServer: %s emits %s", conn->appId.data(), fun.data());
    01286         dcopSignals->emitSignal(conn, fun, data, false);
    01287         }
    01288         replyType = "void";
    01289         return true;
    01290     }
    01291     if ( fun == "setDaemonMode(bool)" ) {
    01292         QDataStream args( data, IO_ReadOnly );
    01293         if ( !args.atEnd() ) {
    01294             Q_INT8 iDaemon;
    01295             bool daemon;
    01296             args >> iDaemon;
    01297
    01298             daemon = static_cast<bool>( iDaemon );
    01299
    01300         DCOPConnection* conn = clients.find( iceConn );
    01301             if ( conn && !conn->appId.isNull() ) {
    01302                 if ( daemon ) {
    01303                     if ( !conn->daemon )
    01304                     {
    01305                         conn->daemon = true;
    01306
    01307 #ifndef NDEBUG
    01308                         qDebug( "DCOP: new daemon %s", conn->appId.data() );
    01309 #endif
    01310
    01311                         currentClientNumber--;
    01312
    01313 // David says it's safer not to do this :-)
    01314 //                        if ( currentClientNumber == 0 )
    01315 //                            m_timer->start( 10000 );
    01316                     }
    01317                 } else
    01318                 {
    01319                     if ( conn->daemon ) {
    01320                         conn->daemon = false;
    01321
    01322                         currentClientNumber++;
    01323
    01324                         m_timer->stop();
    01325                     }
    01326                 }
    01327             }
    01328
    01329             replyType = "void";
    01330             return true;
    01331         }
    01332     }
    01333     if ( fun == "registerAs(QCString)" ) {
    01334     QDataStream args( data, IO_ReadOnly );
    01335     if (!args.atEnd()) {
    01336         QCString app2 = readQCString(args);
    01337         QDataStream reply( replyData, IO_WriteOnly );
    01338         DCOPConnection* conn = clients.find( iceConn );
    01339         if ( conn && !app2.isEmpty() ) {
    01340         if ( !conn->appId.isNull() &&
    01341              appIds.find( conn->appId ) == conn ) {
    01342             appIds.remove( conn->appId );
    01343
    01344         }
    01345
    01346                 QCString oldAppId;
    01347         if ( conn->appId.isNull() )
    01348                 {
    01349                     currentClientNumber++;
    01350                     m_timer->stop(); // abort termination if we were planning one
    01351 #ifndef NDEBUG
    01352                     qDebug("DCOP: register '%s' -> number of clients is now %d", app2.data(), currentClientNumber );
    01353 #endif
    01354                 }
    01355 #ifndef NDEBUG
    01356         else
    01357                 {
    01358                     oldAppId = conn->appId;
    01359             qDebug("DCOP:  '%s' now known as '%s'", conn->appId.data(), app2.data() );
    01360                 }
    01361 #endif
    01362
    01363         conn->appId = app2;
    01364         if ( appIds.find( app2 ) != 0 ) {
    01365             // we already have this application, unify
    01366             int n = 1;
    01367             QCString tmp;
    01368             do {
    01369             n++;
    01370             tmp.setNum( n );
    01371             tmp.prepend("-");
    01372             tmp.prepend( app2 );
    01373             } while ( appIds.find( tmp ) != 0 );
    01374             conn->appId = tmp;
    01375         }
    01376         appIds.insert( conn->appId, conn );
    01377
    01378         int c = conn->appId.find( '-' );
    01379         if ( c > 0 )
    01380             conn->plainAppId = conn->appId.left( c );
    01381         else
    01382             conn->plainAppId = conn->appId;
    01383
    01384                 if( !oldAppId.isEmpty())
    01385                     broadcastApplicationRegistration( conn,
    01386                         "applicationRemoved(QCString)", oldAppId );
    01387                 broadcastApplicationRegistration( conn, "applicationRegistered(QCString)", conn->appId );
    01388         }
    01389         replyType = "QCString";
    01390         reply << conn->appId;
    01391         return true;
    01392     }
    01393     }
    01394     else if ( fun == "registeredApplications()" ) {
    01395     QDataStream reply( replyData, IO_WriteOnly );
    01396     QCStringList applications;
    01397     QAsciiDictIterator<DCOPConnection> it( appIds );
    01398     while ( it.current() ) {
    01399         applications << it.currentKey();
    01400         ++it;
    01401     }
    01402     replyType = "QCStringList";
    01403     reply << applications;
    01404     return true;
    01405     } else if ( fun == "isApplicationRegistered(QCString)" ) {
    01406     QDataStream args( data, IO_ReadOnly );
    01407     if (!args.atEnd()) {
    01408         QCString s = readQCString(args);
    01409         QDataStream reply( replyData, IO_WriteOnly );
    01410         int b = ( findApp( s ) != 0 );
    01411         replyType = "bool";
    01412         reply << b;
    01413         return true;
    01414     }
    01415     } else if ( fun == "setNotifications(bool)" ) {
    01416     QDataStream args( data, IO_ReadOnly );
    01417     if (!args.atEnd()) {
    01418         Q_INT8 notifyActive;
    01419         args >> notifyActive;
    01420         DCOPConnection* conn = clients.find( iceConn );
    01421         if ( conn ) {
    01422         if ( notifyActive )
    01423             conn->notifyRegister++;
    01424         else if ( conn->notifyRegister > 0 )
    01425             conn->notifyRegister--;
    01426         }
    01427         replyType = "void";
    01428         return true;
    01429     }
    01430     } else if ( fun == "connectSignal(QCString,QCString,QCString,QCString,QCString,bool)") {
    01431         DCOPConnection* conn = clients.find( iceConn );
    01432         if (!conn) return false;
    01433         QDataStream args(data, IO_ReadOnly );
    01434         if (args.atEnd()) return false;
    01435         QCString sender = readQCString(args);
    01436         QCString senderObj = readQCString(args);
    01437         QCString signal = readQCString(args);
    01438         QCString receiverObj = readQCString(args);
    01439         QCString slot = readQCString(args);
    01440         Q_INT8 Volatile;
    01441         args >> Volatile;
    01442         //qDebug("DCOPServer: connectSignal(sender = %s senderObj = %s signal = %s recvObj = %s slot = %s)", sender.data(), senderObj.data(), signal.data(), receiverObj.data(), slot.data());
    01443         bool b = dcopSignals->connectSignal(sender, senderObj, signal, conn, receiverObj, slot, (Volatile != 0));
    01444         replyType = "bool";
    01445         QDataStream reply( replyData, IO_WriteOnly );
    01446         reply << (Q_INT8) (b?1:0);
    01447         return true;
    01448     } else if ( fun == "disconnectSignal(QCString,QCString,QCString,QCString,QCString)") {
    01449         DCOPConnection* conn = clients.find( iceConn );
    01450         if (!conn) return false;
    01451         QDataStream args(data, IO_ReadOnly );
    01452         if (args.atEnd()) return false;
    01453         QCString sender = readQCString(args);
    01454         QCString senderObj = readQCString(args);
    01455         QCString signal = readQCString(args);
    01456         QCString receiverObj = readQCString(args);
    01457         QCString slot = readQCString(args);
    01458         //qDebug("DCOPServer: disconnectSignal(sender = %s senderObj = %s signal = %s recvObj = %s slot = %s)", sender.data(), senderObj.data(), signal.data(), receiverObj.data(), slot.data());
    01459         bool b = dcopSignals->disconnectSignal(sender, senderObj, signal, conn, receiverObj, slot);
    01460         replyType = "bool";
    01461         QDataStream reply( replyData, IO_WriteOnly );
    01462         reply << (Q_INT8) (b?1:0);
    01463         return true;
    01464     }
    01465
    01466     return false;
    01467 }
    01468
    01469 void DCOPServer::broadcastApplicationRegistration( DCOPConnection* conn, const QCString type,
    01470     const QCString& appId )
    01471 {
    01472     QByteArray data;
    01473     QDataStream datas( data, IO_WriteOnly );
    01474     datas << appId;
    01475     QPtrDictIterator<DCOPConnection> it( clients );
    01476     QByteArray ba;
    01477     QDataStream ds( ba, IO_WriteOnly );
    01478     ds <<QCString("DCOPServer") <<  QCString("") << QCString("")
    01479        << type << data;
    01480     int datalen = ba.size();
    01481     DCOPMsg *pMsg = 0;
    01482     while ( it.current() ) {
    01483         DCOPConnection* c = it.current();
    01484         ++it;
    01485         if ( c->notifyRegister && (c != conn) ) {
    01486             IceGetHeader( c->iceConn, majorOpcode, DCOPSend,
    01487                           sizeof(DCOPMsg), DCOPMsg, pMsg );
    01488             pMsg->key = 1;
    01489         pMsg->length += datalen;
    01490             _DCOPIceSendBegin(c->iceConn);
    01491         DCOPIceSendData( c->iceConn, ba );
    01492             _DCOPIceSendEnd();
    01493         }
    01494     }
    01495 }
    01496
    01497 void
    01498 DCOPServer::sendMessage(DCOPConnection *conn, const QCString &sApp,
    01499                         const QCString &rApp, const QCString &rObj,
    01500                         const QCString &rFun,  const QByteArray &data)
    01501 {
    01502    QByteArray ba;
    01503    QDataStream ds( ba, IO_WriteOnly );
    01504    ds << sApp << rApp << rObj << rFun << data;
    01505    int datalen = ba.size();
    01506    DCOPMsg *pMsg = 0;
    01507
    01508    IceGetHeader( conn->iceConn, majorOpcode, DCOPSend,
    01509                  sizeof(DCOPMsg), DCOPMsg, pMsg );
    01510    pMsg->length += datalen;
    01511    pMsg->key = 1; // important!
    01512
    01513 #ifdef DCOP_LOG
    01514    (*m_stream) << "Sending a message: sApp =\""
    01515                << sApp << "\", rApp =\""
    01516                << rApp << "\", rObj =\""
    01517                << rObj << "\", rFun =\""
    01518                << rFun << "\", datalen ="
    01519                << datalen << "\n";
    01520    m_logger->flush();
    01521 #endif
    01522
    01523    _DCOPIceSendBegin( conn->iceConn );
    01524    DCOPIceSendData(conn->iceConn, ba);
    01525    _DCOPIceSendEnd();
    01526 }
    01527
    01528 void IoErrorHandler ( IceConn iceConn)
    01529 {
    01530     the_server->ioError( iceConn );
    01531 }
    01532
    01533 static bool isRunning(const QCString &fName, bool printNetworkId = false)
    01534 {
    01535     if (::access(fName.data(), R_OK) == 0) {
    01536     QFile f(fName);
    01537     f.open(IO_ReadOnly);
    01538     int size = QMIN( 1024, f.size() ); // protection against a huge file
    01539     QCString contents( size+1 );
    01540     bool ok = f.readBlock( contents.data(), size ) == size;
    01541     contents[size] = '\0';
    01542     int pos = contents.find('\n');
    01543     ok = ok && ( pos != -1 );
    01544     pid_t pid = ok ? contents.mid(pos+1).toUInt(&ok) : 0;
    01545     f.close();
    01546     if (ok && pid && (kill(pid, SIGHUP) == 0)) {
    01547         if (printNetworkId)
    01548             qWarning("%s", contents.left(pos).data());
    01549         else
    01550         qWarning( "---------------------------------\n"
    01551               "It looks like dcopserver is already running. If you are sure\n"
    01552               "that it is not already running, remove %s\n"
    01553               "and start dcopserver again.\n"
    01554               "---------------------------------\n",
    01555               fName.data() );
    01556
    01557         // lock file present, die silently.
    01558         return true;
    01559     } else {
    01560         // either we couldn't read the PID or kill returned an error.
    01561         // remove lockfile and continue
    01562         unlink(fName.data());
    01563     }
    01564     } else if (errno != ENOENT) {
    01565         // remove lockfile and continue
    01566         unlink(fName.data());
    01567     }
    01568     return false;
    01569 }
    01570
    01571 const char* const ABOUT =
    01572 "Usage: dcopserver [--nofork] [--nosid] [--help]\n"
    01573 "       dcopserver --serverid\n"
    01574 "\n"
    01575 "DCOP is KDE's Desktop Communications Protocol. It is a lightweight IPC/RPC\n"
    01576 "mechanism built on top of the X Consortium's Inter Client Exchange protocol.\n"
    01577 "It enables desktop applications to communicate reliably with low overhead.\n"
    01578 "\n"
    01579 "Copyright (C) 1999-2001, The KDE Developers <http://www.kde.org>\n"
    01580 ;
    01581
    01582 extern "C" DCOP_EXPORT int kdemain( int argc, char* argv[] )
    01583 {
    01584     bool serverid = false;
    01585     bool nofork = false;
    01586     bool nosid = false;
    01587     bool suicide = false;
    01588     for(int i = 1; i < argc; i++) {
    01589     if (strcmp(argv[i], "--nofork") == 0)
    01590         nofork = true;
    01591     else if (strcmp(argv[i], "--nosid") == 0)
    01592         nosid = true;
    01593     else if (strcmp(argv[i], "--nolocal") == 0)
    01594         ; // Ignore
    01595     else if (strcmp(argv[i], "--suicide") == 0)
    01596         suicide = true;
    01597     else if (strcmp(argv[i], "--serverid") == 0)
    01598         serverid = true;
    01599     else {
    01600         fprintf(stdout, ABOUT );
    01601         return 0;
    01602     }
    01603     }
    01604
    01605     if (serverid)
    01606     {
    01607        if (isRunning(DCOPClient::dcopServerFile(), true))
    01608           return 0;
    01609        return 1;
    01610     }
    01611
    01612     // check if we are already running
    01613     if (isRunning(DCOPClient::dcopServerFile()))
    01614        return 0;
    01615     if (QCString(getenv("DCOPAUTHORITY")).isEmpty() &&
    01616         isRunning(DCOPClient::dcopServerFileOld()))
    01617     {
    01618        // Make symlink for compatibility
    01619        QCString oldFile = DCOPClient::dcopServerFileOld();
    01620        QCString newFile = DCOPClient::dcopServerFile();
    01621        symlink(oldFile.data(), newFile.data());
    01622        return 0;
    01623     }
    01624
    01625     struct rlimit limits;
    01626
    01627     int retcode = getrlimit(RLIMIT_NOFILE, &limits);
    01628     if (!retcode) {
    01629        if (limits.rlim_max > 512 && limits.rlim_cur < 512)
    01630        {
    01631           int cur_limit = limits.rlim_cur;
    01632           limits.rlim_cur = 512;
    01633           retcode = setrlimit(RLIMIT_NOFILE, &limits);
    01634
    01635           if (retcode != 0)
    01636           {
    01637              qWarning("dcopserver: Could not raise limit on number of open files.");
    01638              qWarning("dcopserver: Current limit = %d", cur_limit);
    01639           }
    01640        }
    01641     }
    01642
    01643     pipe(ready);
    01644
    01645     if (!nofork) {
    01646         pid_t pid = fork();
    01647     if (pid > 0) {
    01648         char c = 1;
    01649         close(ready[1]);
    01650         read(ready[0], &c, 1); // Wait till dcopserver is started
    01651         close(ready[0]);
    01652         // I am the parent
    01653         if (c == 0)
    01654             {
    01655                // Test whether we are functional.
    01656                DCOPClient client;
    01657                if (client.attach())
    01658                   return 0;
    01659             }
    01660             qWarning("DCOPServer self-test failed.");
    01661             system(findDcopserverShutdown()+" --kill");
    01662             return 1;
    01663     }
    01664     close(ready[0]);
    01665
    01666     if (!nosid)
    01667         setsid();
    01668
    01669     if (fork() > 0)
    01670         return 0; // get rid of controlling terminal
    01671     }
    01672
    01673     pipe(pipeOfDeath);
    01674
    01675     signal(SIGHUP, sighandler);
    01676     signal(SIGTERM, sighandler);
    01677     signal(SIGPIPE, SIG_IGN);
    01678
    01679     putenv(strdup("SESSION_MANAGER="));
    01680
    01681     QApplication a( argc, argv, false );
    01682
    01683     IceSetIOErrorHandler (IoErrorHandler );
    01684     DCOPServer *server = new DCOPServer(suicide); // this sets the_server
    01685
    01686     QSocketNotifier DEATH(pipeOfDeath[0], QSocketNotifier::Read, 0, 0);
    01687     server->connect(&DEATH, SIGNAL(activated(int)), SLOT(slotShutdown()));
    01688
    01689     int ret = a.exec();
    01690     delete server;
    01691     return ret;
    01692 }
    01693
    01694 #include "dcopserver.moc"

This file is part of the documentation for dcop Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:16:55 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003