dcop Library API Documentation

dcopserver.cpp

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