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