dcopserver.cpp Source File (dcop Library)

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

# dcopserver.cpp

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

This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 12:42:41 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001