• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • dcop
 

dcop

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

dcop

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

dcop

Skip menu "dcop"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for dcop by doxygen 1.7.6.1
This website is maintained by Timothy Pearson.