dcop Library API Documentation

dcopserver.cpp

00001 /*****************************************************************
00002 
00003 #include "dcopserver.h"
00004 
00005 Copyright (c) 1999,2000 Preston Brown <pbrown@kde.org>
00006 Copyright (c) 1999,2000 Matthias Ettrich <ettrich@kde.org>
00007 Copyright (c) 1999,2001 Waldo Bastian <bastian@kde.org>
00008 
00009 Permission is hereby granted, free of charge, to any person obtaining a copy
00010 of this software and associated documentation files (the "Software"), to deal
00011 in the Software without restriction, including without limitation the rights
00012 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00013 copies of the Software, and to permit persons to whom the Software is
00014 furnished to do so, subject to the following conditions:
00015 
00016 The above copyright notice and this permission notice shall be included in
00017 all copies or substantial portions of the Software.
00018 
00019 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00020 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00021 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
00022 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
00023 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
00024 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00025 
00026 ******************************************************************/
00027 
00028 #include <config.h>
00029 
00030 #include <sys/types.h>
00031 #ifdef HAVE_SYS_STAT_H
00032 #include <sys/stat.h>
00033 #endif
00034 #ifdef HAVE_SYS_PARAM_H
00035 #include <sys/param.h>
00036 #endif
00037 #include <sys/resource.h>
00038                    
00039 #include <unistd.h>
00040 #include <stdlib.h>
00041 #include <signal.h>
00042 #include <unistd.h>
00043 #include <fcntl.h>
00044 #include <errno.h>
00045 #ifdef HAVE_LIMITS_H
00046 #include <limits.h>
00047 #endif
00048 
00049 #define QT_CLEAN_NAMESPACE 1
00050 #include <qfile.h>
00051 #include <qtextstream.h>
00052 #include <qdatastream.h>
00053 #include <qptrstack.h>
00054 #include <qtimer.h>
00055 
00056 #include <dcopserver.h>
00057 #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"
KDE Logo
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