• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

dcop

dcopserver.cpp

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

dcop

Skip menu "dcop"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal