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     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"
KDE Logo
This file is part of the documentation for dcop Library Version 3.4.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Thu Sep 15 10:18:27 2005 by doxygen 1.4.4 written by Dimitri van Heesch, © 1997-2003