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