• 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 #include <tqfile.h>
00051 #include <tqtextstream.h>
00052 #include <tqdatastream.h>
00053 #include <tqptrstack.h>
00054 #include <tqtimer.h>
00055 
00056 #include "dcopserver.h"
00057 
00058 #include <dcopsignals.h>
00059 #include <dcopclient.h>
00060 #include <dcopglobal.h>
00061 #include "dcop-path.h"
00062 
00063 #ifdef DCOP_LOG
00064 #undef Unsorted
00065 #include <tqdir.h>
00066 #include <string.h>
00067 #endif
00068 
00069 // #define DCOP_DEBUG
00070 
00071 DCOPServer* the_server;
00072 
00073 template class TQDict<DCOPConnection>;
00074 template class TQPtrDict<DCOPConnection>;
00075 template class TQPtrList<DCOPListener>;
00076 
00077 #define _DCOPIceSendBegin(x)    \
00078    int fd = IceConnectionNumber( x );       \
00079    long fd_fl = fcntl(fd, F_GETFL, 0);      \
00080    fcntl(fd, F_SETFL, fd_fl | O_NDELAY);
00081 #define _DCOPIceSendEnd()   \
00082    fcntl(fd, F_SETFL, fd_fl);
00083 
00084 static TQCString findDcopserverShutdown()
00085 {
00086 #ifdef Q_OS_WIN32
00087     char szPath[512];
00088     char *pszFilePart;
00089     int ret;
00090     ret = SearchPathA(NULL,"dcopserver_shutdown","exe",sizeof(szPath)/sizeof(szPath[0]),szPath,&pszFilePart);
00091     if(ret != 0)
00092         return TQCString(szPath);
00093 #else
00094    TQCString path = getenv("PATH");
00095    char *dir = strtok(path.data(), ":");
00096    while (dir)
00097    {
00098       TQCString file = dir;
00099       file += "/dcopserver_shutdown";
00100       if (access(file.data(), X_OK) == 0)
00101          return file;
00102       dir = strtok(NULL, ":");
00103    }
00104    TQCString file = DCOP_PATH;
00105    file += "/dcopserver_shutdown";
00106    if (access(file.data(), X_OK) == 0)
00107       return file;
00108 #endif
00109    return TQCString("dcopserver_shutdown");
00110 }
00111 
00112 static Bool HostBasedAuthProc ( char* /*hostname*/)
00113 {
00114     return false; // no host based authentication
00115 }
00116 
00117 extern "C" {
00118 extern IceWriteHandler _kde_IceWriteHandler;
00119 extern IceIOErrorHandler _kde_IceIOErrorHandler;
00120 void DCOPIceWriteChar(register IceConn iceConn, unsigned long nbytes, char *ptr);
00121 }
00122 
00123 static TQCString readQCString(TQDataStream &ds)
00124 {
00125    TQCString result;
00126    TQ_UINT32 len;
00127    ds >> len;
00128    TQIODevice *device = ds.device();
00129    int bytesLeft = device->size()-device->at();
00130    if ((bytesLeft < 0 ) || (len > (uint) bytesLeft))
00131    {
00132       tqWarning("[dcopserver] Corrupt data!");
00133       printf("[dcopserver] bytesLeft: %d, len: %d", bytesLeft, len);
00134       return result;
00135    }
00136    result.TQByteArray::resize( (uint)len );
00137    if (len > 0)
00138       ds.readRawBytes( result.data(), (uint)len);
00139    return result;
00140 }
00141 
00142 static TQByteArray readQByteArray(TQDataStream &ds)
00143 {
00144    TQByteArray result;
00145    TQ_UINT32 len;
00146    ds >> len;
00147    TQIODevice *device = ds.device();
00148    int bytesLeft = device->size()-device->at();
00149    if ((bytesLeft < 0 ) || (len > (uint) bytesLeft))
00150    {
00151       tqWarning("[dcopserver] Corrupt data!");
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 tqWarning("[dcopserver] DCOPIceWriteChar() Writing %d bytes [%s]", nbytes, conn ? conn->appId.data() : "<unknown>");
00244 #endif
00245 
00246     if (conn)
00247     {
00248        if (conn->outputBlocked)
00249        {
00250           TQByteArray _data(nbytes);
00251           memcpy(_data.data(), ptr, nbytes);
00252 #ifdef DCOP_DEBUG
00253 tqWarning("[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         TQByteArray _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 TQByteArray &_data)
00272 {
00273     DCOPConnection* conn = the_server->findConn( iceConn );
00274 #ifdef DCOP_DEBUG
00275 tqWarning("[dcopserver] DCOPIceWrite() Writing %d bytes [%s]", _data.size(), conn ? conn->appId.data() : "<unknown>");
00276 #endif
00277     if (conn)
00278     {
00279        if (conn->outputBlocked)
00280        {
00281 #ifdef DCOP_DEBUG
00282 tqWarning("[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(), const_cast<TQByteArray&>(_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 TQByteArray &_data, int start)
00299 {
00300 #ifdef DCOP_DEBUG
00301 tqWarning("[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 TQSocketNotifier(socket(), Write);
00309       connect(outputBufferNotifier, TQT_SIGNAL(activated(int)),
00310               the_server, TQT_SLOT(slotOutputReady(int)));
00311    }
00312    outputBufferNotifier->setEnabled(true);
00313    return;
00314 }
00315 
00316 void DCOPServer::slotOutputReady(int socket)
00317 {
00318 #ifdef DCOP_DEBUG
00319 tqWarning("[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    TQByteArray 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 tqWarning("[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 tqWarning("[dcopserver] slotOutputRead() all data transmitted.");
00373 #endif
00374          outputBlocked = false;
00375          outputBufferNotifier->setEnabled(false);
00376       }
00377 #ifdef DCOP_DEBUG
00378 else
00379 {
00380 tqWarning("[dcopserver] slotOutputRead() more data to send.");
00381 }
00382 #endif
00383    }
00384 }
00385 
00386 static void DCOPIceSendData(register IceConn _iceConn,
00387                             const TQByteArray &_data)
00388 {
00389    if (_iceConn->outbufptr > _iceConn->outbuf)
00390    {
00391 #ifdef DCOP_DEBUG
00392 tqWarning("[dcopserver] Flushing data, fd = %d", IceConnectionNumber(_iceConn));
00393 #endif
00394       IceFlush( _iceConn );
00395    }
00396    DCOPIceWrite(_iceConn, _data);
00397 }
00398 
00399 class DCOPListener : public TQSocketNotifier
00400 {
00401 public:
00402     DCOPListener( IceListenObj obj )
00403     : TQSocketNotifier( IceGetListenConnectionNumber( obj ),
00404                TQSocketNotifier::Read, 0, 0)
00405 {
00406     listenObj = obj;
00407 }
00408 
00409     IceListenObj listenObj;
00410 };
00411 
00412 DCOPConnection::DCOPConnection( IceConn conn )
00413     : TQSocketNotifier( IceConnectionNumber( conn ),
00414                TQSocketNotifier::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     TQCString 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." );
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     tqWarning("[dcopserver] 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         TQByteArray ba( length );
00726         IceReadData(iceConn, length, ba.data() );
00727         TQDataStream ds( ba, IO_ReadOnly );
00728         TQCString fromApp = readQCString(ds);
00729             TQCString toApp = readQCString(ds);
00730 
00731         DCOPConnection* target = findApp( toApp );
00732         int datalen = ba.size();
00733         if ( opcode == DCOPReplyDelayed ) {
00734         if ( !target )
00735             tqWarning("[dcopserver] DCOPServer::DCOPReplyDelayed for unknown connection.");
00736         else if ( !conn )
00737             tqWarning("[dcopserver] DCOPServer::DCOPReplyDelayed from unknown connection.");
00738         else if (!conn->waitingForDelayedReply.removeRef( target->iceConn ))
00739             tqWarning("[dcopserver] DCOPServer::DCOPReplyDelayed from/to does not match. (#2)");
00740                 else if (!target->waitingOnReply.removeRef(iceConn))
00741                        tqWarning("[dcopserver] DCOPServer::DCOPReplyDelayed for client who wasn't waiting on one!");
00742         }
00743         if ( target ) {
00744 #ifdef DCOP_DEBUG
00745 if (opcode == DCOPSend)
00746 {
00747    TQCString obj = readQCString(ds);
00748    TQCString fun = readQCString(ds);
00749    tqWarning("[dcopserver] 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         TQCString obj = readQCString(ds);
00761         TQCString fun = readQCString(ds);
00762         TQByteArray data = readQByteArray(ds);
00763 
00764         TQCString replyType;
00765         TQByteArray replyData;
00766         if ( !receive( toApp, obj, fun, data, replyType, replyData, iceConn ) ) {
00767             tqWarning("[dcopserver] %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    TQCString obj = readQCString(ds);
00774    TQCString fun = readQCString(ds);
00775    tqWarning("[dcopserver] Sending %d bytes from %s to %s. DCOPSend %s", length, fromApp.data(), toApp.data(), fun.data());
00776 }
00777 #endif
00778         // handle a multicast.
00779         TQAsciiDictIterator<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         TQByteArray ba( length );
00804         IceReadData(iceConn, length, ba.data() );
00805         TQDataStream ds( ba, IO_ReadOnly );
00806         TQCString fromApp = readQCString(ds);
00807         TQCString 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    TQCString obj = readQCString(ds);
00816    TQCString fun = readQCString(ds);
00817    tqWarning("[dcopserver] 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         TQCString replyType;
00832         TQByteArray replyData;
00833         bool b = false;
00834         // DCOPServer itself does not do DCOPFind.
00835         if ( (opcode == DCOPCall) && (toApp == "DCOPServer") ) {
00836             TQCString obj = readQCString(ds);
00837             TQCString fun = readQCString(ds);
00838             TQByteArray data = readQByteArray(ds);
00839             b = receive( toApp, obj, fun, data, replyType, replyData, iceConn );
00840             if ( !b )
00841             tqWarning("[dcopserver] %s failure: object '%s' has no function '%s'", toApp.data(), obj.data(), fun.data() );
00842         }
00843 
00844         if (b) {
00845             TQByteArray reply;
00846             TQDataStream 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             TQByteArray reply;
00862             TQDataStream 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         TQByteArray ba( length );
00886         IceReadData(iceConn, length, ba.data() );
00887         TQDataStream ds( ba, IO_ReadOnly );
00888             TQCString fromApp = readQCString(ds);
00889             TQCString toApp = readQCString(ds);
00890 
00891         DCOPConnection* connreply = findApp( toApp );
00892         int datalen = ba.size();
00893 
00894         if ( !connreply )
00895         tqWarning("[dcopserver] 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                        tqWarning("[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     tqWarning("[dcopserver] 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     : TQObject(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     tqWarning("[dcopserver] 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         tqWarning("[dcopserver] 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, "[dcopserver] %s", errormsg);
01015         exit (1);
01016     } else {
01017         (void) umask(orig_umask);
01018         // publish available transports.
01019         TQCString fName = DCOPClient::dcopServerFile();
01020         FILE *f;
01021         if(!(f = ::fopen(fName.data(), "w+"))) {
01022             fprintf (stderr, "[dcopserver] Can not create file %s: %s",
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 (TQCString(getenv("DCOPAUTHORITY")).isEmpty())
01035         {
01036                 // Create a link named like the old-style (KDE 2.x) naming
01037                 TQCString 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         tqFatal("DCOPSERVER: authentication setup failed.");
01046 #endif
01047     if (!SetAuthentication(numTransports, listenObjs, &authDataEntries))
01048         tqFatal("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, TQT_SIGNAL( activated(int) ), this, TQT_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 TQTimer(this);
01065     connect( m_timer, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotTerminate()) );
01066     m_deadConnectionTimer = new TQTimer(this);
01067     connect( m_deadConnectionTimer, TQT_SIGNAL(timeout()), this, TQT_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 TQFile( TQString( "%1/.dcop-%2.log" ).arg( TQDir::homeDirPath() ).arg( hostname_buffer ) );
01085     if ( m_logger->open( IO_WriteOnly ) ) {
01086         m_stream = new TQTextStream( 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 TQCString& 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 tqWarning("[dcopserver] 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      tqWarning("[dcopserver] Failed to alloc connection object!");
01161       else // IceAcceptFailure
01162          tqWarning("[dcopserver] Failed to accept ICE connection!");
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         tqWarning ("[dcopserver] IO error opening ICE Connection!");
01176     else
01177         tqWarning ("[dcopserver] ICE Connection rejected!");
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, TQT_SIGNAL( activated(int) ), this, TQT_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         tqWarning("[dcopserver] DCOP aborting call from '%s' to '%s'", target ? target->appId.data() : "<unknown>" , conn->appId.data() );
01209         TQByteArray 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                tqWarning("[dcopserver] Unknown target in waitingForReply");
01220             else if (!target->waitingOnReply.removeRef(conn->iceConn))
01221                tqWarning("[dcopserver] 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         tqWarning("[dcopserver] DCOP aborting (delayed) call from '%s' to '%s'", target ? target->appId.data() : "<unknown>", conn->appId.data() );
01231         TQByteArray 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                tqWarning("[dcopserver] Unknown target in waitingForDelayedReply");
01242             else if (!target->waitingOnReply.removeRef(conn->iceConn))
01243                tqWarning("[dcopserver] 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                tqWarning("[dcopserver] Still waiting for answer from non-existing client.");
01254                continue;
01255            }
01256            tqWarning("[dcopserver] 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               tqWarning("[dcopserver] Called client has forgotten about caller");
01260         }
01261     }
01262 
01263     if ( !conn->appId.isNull() ) {
01264 #ifndef NDEBUG
01265     tqDebug("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(TQCString)", 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 terminateTDE signal." );
01293 #endif
01294     TQByteArray data;
01295     dcopSignals->emitSignal(0L /* dcopserver */, "terminateTDE()", data, false);
01296     disconnect( m_timer, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotTerminate()) );
01297     connect( m_timer, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotSuicide()) );
01298     system(findDcopserverShutdown()+" --nokill");
01299 }
01300 
01301 void DCOPServer::slotSuicide()
01302 {
01303 #ifndef NDEBUG
01304     fprintf( stderr, "[dcopserver] slotSuicide() -> exit." );
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." );
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        TQByteArray data;
01322        dcopSignals->emitSignal(0L /* dcopserver */, "terminateTDE()", data, false);
01323        m_timer->start( 10000 ); // if within 10 seconds nothing happens, we'll terminate
01324        disconnect( m_timer, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotTerminate()) );
01325        connect( m_timer, TQT_SIGNAL(timeout()), this, TQT_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." );
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 TQCString &/*app*/, const TQCString &obj,
01346              const TQCString &fun, const TQByteArray& data,
01347              TQCString& replyType, TQByteArray &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() << "";
01357     m_logger->flush();
01358 #endif
01359 
01360     if ( obj == "emit")
01361     {
01362         DCOPConnection* conn = clients.find( iceConn );
01363         if (conn) {
01364         //tqDebug("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         TQDataStream args( data, IO_ReadOnly );
01372         if ( !args.atEnd() ) {
01373             TQ_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                         tqDebug( "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(TQCString)" ) {
01413     TQDataStream args( data, IO_ReadOnly );
01414     if (!args.atEnd()) {
01415         TQCString app2 = readQCString(args);
01416         TQDataStream 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                 TQCString oldAppId;
01426         if ( conn->appId.isNull() )
01427                 {
01428                     currentClientNumber++;
01429                     m_timer->stop(); // abort termination if we were planning one
01430 #ifndef NDEBUG
01431                     tqDebug("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             tqDebug("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             TQCString 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(TQCString)", oldAppId );
01466                 broadcastApplicationRegistration( conn, "applicationRegistered(TQCString)", conn->appId );
01467         }
01468         replyType = "TQCString";
01469         reply << conn->appId;
01470         return true;
01471     }
01472     }
01473     else if ( fun == "registeredApplications()" ) {
01474     TQDataStream reply( replyData, IO_WriteOnly );
01475     QCStringList applications;
01476     TQAsciiDictIterator<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(TQCString)" ) {
01485     TQDataStream args( data, IO_ReadOnly );
01486     if (!args.atEnd()) {
01487         TQCString s = readQCString(args);
01488         TQDataStream 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     TQDataStream args( data, IO_ReadOnly );
01496     if (!args.atEnd()) {
01497         TQ_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(TQCString,TQCString,TQCString,TQCString,TQCString,bool)") {
01510         DCOPConnection* conn = clients.find( iceConn );
01511         if (!conn) return false;
01512         TQDataStream args(data, IO_ReadOnly );
01513         if (args.atEnd()) return false;
01514         TQCString sender = readQCString(args);
01515         TQCString senderObj = readQCString(args);
01516         TQCString signal = readQCString(args);
01517         TQCString receiverObj = readQCString(args);
01518         TQCString slot = readQCString(args);
01519         TQ_INT8 Volatile;
01520         args >> Volatile;
01521 #ifdef DCOP_DEBUG
01522         tqDebug("DCOPServer: connectSignal(sender = %s senderObj = %s signal = %s recvObj = %s slot = %s)", sender.data(), senderObj.data(), signal.data(), receiverObj.data(), slot.data());
01523 #endif
01524         bool b = dcopSignals->connectSignal(sender, senderObj, signal, conn, receiverObj, slot, (Volatile != 0));
01525         replyType = "bool";
01526         TQDataStream reply( replyData, IO_WriteOnly );
01527         reply << (TQ_INT8) (b?1:0);
01528         return true;
01529     } else if ( fun == "disconnectSignal(TQCString,TQCString,TQCString,TQCString,TQCString)") {
01530         DCOPConnection* conn = clients.find( iceConn );
01531         if (!conn) return false;
01532         TQDataStream args(data, IO_ReadOnly );
01533         if (args.atEnd()) return false;
01534         TQCString sender = readQCString(args);
01535         TQCString senderObj = readQCString(args);
01536         TQCString signal = readQCString(args);
01537         TQCString receiverObj = readQCString(args);
01538         TQCString slot = readQCString(args);
01539 #ifdef DCOP_DEBUG
01540         tqDebug("DCOPServer: disconnectSignal(sender = %s senderObj = %s signal = %s recvObj = %s slot = %s)", sender.data(), senderObj.data(), signal.data(), receiverObj.data(), slot.data());
01541 #endif
01542         bool b = dcopSignals->disconnectSignal(sender, senderObj, signal, conn, receiverObj, slot);
01543         replyType = "bool";
01544         TQDataStream reply( replyData, IO_WriteOnly );
01545         reply << (TQ_INT8) (b?1:0);
01546         return true;
01547     }
01548 
01549     return false;
01550 }
01551 
01552 void DCOPServer::broadcastApplicationRegistration( DCOPConnection* conn, const TQCString type,
01553     const TQCString& appId )
01554 {
01555     TQByteArray data;
01556     TQDataStream datas( data, IO_WriteOnly );
01557     datas << appId;
01558     TQPtrDictIterator<DCOPConnection> it( clients );
01559     TQByteArray ba;
01560     TQDataStream ds( ba, IO_WriteOnly );
01561     ds <<TQCString("DCOPServer") <<  TQCString("") << TQCString("")
01562        << type << data;
01563     int datalen = ba.size();
01564     DCOPMsg *pMsg = 0;
01565     while ( it.current() ) {
01566         DCOPConnection* c = it.current();
01567         ++it;
01568         if ( c->notifyRegister && (c != conn) ) {
01569             IceGetHeader( c->iceConn, majorOpcode, DCOPSend,
01570                           sizeof(DCOPMsg), DCOPMsg, pMsg );
01571             pMsg->key = 1;
01572         pMsg->length += datalen;
01573             _DCOPIceSendBegin(c->iceConn);
01574         DCOPIceSendData( c->iceConn, ba );
01575             _DCOPIceSendEnd();
01576         }
01577     }
01578 }
01579 
01580 void
01581 DCOPServer::sendMessage(DCOPConnection *conn, const TQCString &sApp,
01582                         const TQCString &rApp, const TQCString &rObj,
01583                         const TQCString &rFun,  const TQByteArray &data)
01584 {
01585    TQByteArray ba;
01586    TQDataStream ds( ba, IO_WriteOnly );
01587    ds << sApp << rApp << rObj << rFun << data;
01588    int datalen = ba.size();
01589    DCOPMsg *pMsg = 0;
01590 
01591    IceGetHeader( conn->iceConn, majorOpcode, DCOPSend,
01592                  sizeof(DCOPMsg), DCOPMsg, pMsg );
01593    pMsg->length += datalen;
01594    pMsg->key = 1; // important!
01595 
01596 #ifdef DCOP_LOG
01597    (*m_stream) << "Sending a message: sApp =\""
01598                << sApp << "\", rApp =\""
01599                << rApp << "\", rObj =\""
01600                << rObj << "\", rFun =\""
01601                << rFun << "\", datalen ="
01602                << datalen << "\n";
01603    m_logger->flush();
01604 #endif
01605 
01606    _DCOPIceSendBegin( conn->iceConn );
01607    DCOPIceSendData(conn->iceConn, ba);
01608    _DCOPIceSendEnd();
01609 }
01610 
01611 void IoErrorHandler ( IceConn iceConn)
01612 {
01613     the_server->ioError( iceConn );
01614 }
01615 
01616 static bool isRunning(const TQCString &fName, bool printNetworkId = false)
01617 {
01618     if (::access(fName.data(), R_OK) == 0) {
01619     TQFile f(fName);
01620     f.open(IO_ReadOnly);
01621     int size = TQMIN( (qint64)1024, f.size() ); // protection against a huge file
01622     TQCString contents( size+1 );
01623     bool ok = f.readBlock( contents.data(), size ) == size;
01624     contents[size] = '\0';
01625     int pos = contents.find('\n');
01626     ok = ok && ( pos != -1 );
01627     pid_t pid = ok ? contents.mid(pos+1).toUInt(&ok) : 0;
01628     f.close();
01629     if (ok && pid && (kill(pid, SIGHUP) == 0)) {
01630         if (printNetworkId)
01631             tqWarning("[dcopserver] %s", contents.left(pos).data());
01632         else
01633         tqWarning( "---------------------------------\n"
01634               "[dcopserver] It looks like dcopserver is already running. If you are sure\n"
01635               "that it is not already running, remove %s\n"
01636               "and start dcopserver again.\n"
01637               "---------------------------------",
01638               fName.data() );
01639 
01640         // lock file present, die silently.
01641         return true;
01642     } else {
01643         // either we couldn't read the PID or kill returned an error.
01644         // remove lockfile and continue
01645         unlink(fName.data());
01646     }
01647     } else if (errno != ENOENT) {
01648         // remove lockfile and continue
01649         unlink(fName.data());
01650     }
01651     return false;
01652 }
01653 
01654 const char* const ABOUT =
01655 "Usage: dcopserver [--nofork] [--nosid] [--help]\n"
01656 "       dcopserver --serverid\n"
01657 "\n"
01658 "DCOP is TDE's Desktop Communications Protocol. It is a lightweight IPC/RPC\n"
01659 "mechanism built on top of the X Consortium's Inter Client Exchange protocol.\n"
01660 "It enables desktop applications to communicate reliably with low overhead.\n"
01661 "\n"
01662 "Copyright (C) 1999-2001, The KDE Developers <http://www.kde.org>\n"
01663 ;
01664 
01665 extern "C" DCOP_EXPORT int kdemain( int argc, char* argv[] )
01666 {
01667     bool serverid = false;
01668     bool nofork = false;
01669     bool nosid = false;
01670     bool suicide = false;
01671     for(int i = 1; i < argc; i++) {
01672     if (strcmp(argv[i], "--nofork") == 0)
01673         nofork = true;
01674     else if (strcmp(argv[i], "--nosid") == 0)
01675         nosid = true;
01676     else if (strcmp(argv[i], "--nolocal") == 0)
01677         ; // Ignore
01678     else if (strcmp(argv[i], "--suicide") == 0)
01679         suicide = true;
01680     else if (strcmp(argv[i], "--serverid") == 0)
01681         serverid = true;
01682     else {
01683         fprintf(stdout, "%s", ABOUT );
01684         return 0;
01685     }
01686     }
01687 
01688     if (serverid)
01689     {
01690        if (isRunning(DCOPClient::dcopServerFile(), true))
01691           return 0;
01692        return 1;
01693     }
01694 
01695     // check if we are already running
01696     if (isRunning(DCOPClient::dcopServerFile()))
01697        return 0;
01698 #ifndef Q_OS_WIN32
01699     if (TQCString(getenv("DCOPAUTHORITY")).isEmpty() &&
01700         isRunning(DCOPClient::dcopServerFileOld()))
01701     {
01702        // Make symlink for compatibility
01703        TQCString oldFile = DCOPClient::dcopServerFileOld();
01704        TQCString newFile = DCOPClient::dcopServerFile();
01705        symlink(oldFile.data(), newFile.data());
01706        return 0;
01707     }
01708 
01709     struct rlimit limits;
01710 
01711     int retcode = getrlimit(RLIMIT_NOFILE, &limits);
01712     if (!retcode) {
01713        if (limits.rlim_max > 512 && limits.rlim_cur < 512)
01714        {
01715           int cur_limit = limits.rlim_cur;
01716           limits.rlim_cur = 512;
01717           retcode = setrlimit(RLIMIT_NOFILE, &limits);
01718 
01719           if (retcode != 0)
01720           {
01721              tqWarning("[dcopserver] Could not raise limit on number of open files.");
01722              tqWarning("[dcopserver] Current limit = %d", cur_limit);
01723           }
01724        }
01725     }
01726 #endif
01727     pipe(ready);
01728 
01729 #ifndef Q_OS_WIN32
01730     if (!nofork) {
01731         pid_t pid = fork();
01732     if (pid > 0) {
01733         char c = 1;
01734         close(ready[1]);
01735         read(ready[0], &c, 1); // Wait till dcopserver is started
01736         close(ready[0]);
01737         // I am the parent
01738         if (c == 0)
01739             {
01740                // Test whether we are functional.
01741                DCOPClient client;
01742                if (client.attach())
01743                   return 0;
01744             }
01745             tqWarning("[dcopserver] DCOPServer self-test failed.");
01746             system(findDcopserverShutdown()+" --kill");
01747             return 1;
01748     }
01749     close(ready[0]);
01750 
01751     if (!nosid)
01752         setsid();
01753 
01754     if (fork() > 0)
01755         return 0; // get rid of controlling terminal
01756     }
01757 
01758     pipe(pipeOfDeath);
01759 
01760     signal(SIGHUP, sighandler);
01761     signal(SIGTERM, sighandler);
01762     signal(SIGPIPE, SIG_IGN);
01763 #else
01764     {
01765         char c = 1;
01766         close(ready[1]);
01767         read(ready[0], &c, 1); // Wait till dcopserver is started
01768         close(ready[0]);
01769     }
01770 #endif
01771     putenv(strdup("SESSION_MANAGER="));
01772 
01773     TQApplication a( argc, argv, false );
01774 
01775     IceSetIOErrorHandler (IoErrorHandler );
01776     DCOPServer *server = new DCOPServer(suicide); // this sets the_server
01777 
01778 #ifdef Q_OS_WIN
01779     SetConsoleCtrlHandler(DCOPServer::dcopServerConsoleProc,TRUE);
01780 #else
01781     TQSocketNotifier DEATH(pipeOfDeath[0], TQSocketNotifier::Read, 0, 0);
01782         server->connect(&DEATH, TQT_SIGNAL(activated(int)), TQT_SLOT(slotShutdown()));
01783 #endif
01784 
01785     int ret = a.exec();
01786     delete server;
01787     return ret;
01788 }
01789 
01790 #ifdef Q_OS_WIN
01791 #include "dcopserver_win.cpp"
01792 #endif
01793 
01794 #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.6.3
This website is maintained by Timothy Pearson.