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 00922 dcopSignals = new DCOPSignals; 00923 00924 extern int _kde_IceLastMajorOpcode; // from libICE 00925 if (_kde_IceLastMajorOpcode < 1 ) 00926 IceRegisterForProtocolSetup(const_cast<char *>("DUMMY"), 00927 const_cast<char *>("DUMMY"), 00928 const_cast<char *>("DUMMY"), 00929 1, const_cast<IcePoVersionRec *>(DUMMYVersions), 00930 DCOPAuthCount, const_cast<char **>(DCOPAuthNames), 00931 DCOPClientAuthProcs, 0); 00932 if (_kde_IceLastMajorOpcode < 1 ) 00933 qWarning("DCOPServer Error: incorrect major opcode!"); 00934 00935 the_server = this; 00936 if (( majorOpcode = IceRegisterForProtocolReply (const_cast<char *>("DCOP"), 00937 const_cast<char *>(DCOPVendorString), 00938 const_cast<char *>(DCOPReleaseString), 00939 1, const_cast<IcePaVersionRec *>(DCOPServerVersions), 00940 1, const_cast<char **>(DCOPAuthNames), 00941 DCOPServerAuthProcs, 00942 HostBasedAuthProc, 00943 DCOPServerProtocolSetupProc, 00944 NULL, /* IceProtocolActivateProc - we don't care about 00945 when the Protocol Reply is sent, because the 00946 session manager can not immediately send a 00947 message - it must wait for RegisterClient. */ 00948 NULL /* IceIOErrorProc */ 00949 )) < 0) 00950 { 00951 qWarning("Could not register DCOP protocol with ICE"); 00952 } 00953 00954 char errormsg[256]; 00955 int orig_umask = umask(0); /*old libICE's don't reset the umask() they set */ 00956 if (!IceListenForConnections (&numTransports, &listenObjs, 00957 256, errormsg)) 00958 { 00959 fprintf (stderr, "%s\n", errormsg); 00960 exit (1); 00961 } else { 00962 (void) umask(orig_umask); 00963 // publish available transports. 00964 QCString fName = DCOPClient::dcopServerFile(); 00965 FILE *f; 00966 if(!(f = ::fopen(fName.data(), "w+"))) { 00967 fprintf (stderr, "Can not create file %s: %s\n", 00968 fName.data(), ::strerror(errno)); 00969 exit(1); 00970 } 00971 char *idlist = IceComposeNetworkIdList(numTransports, listenObjs); 00972 if (idlist != 0) { 00973 fprintf(f, "%s", idlist); 00974 free(idlist); 00975 } 00976 fprintf(f, "\n%i\n", getpid()); 00977 fclose(f); 00978 if (QCString(getenv("DCOPAUTHORITY")).isEmpty()) 00979 { 00980 // Create a link named like the old-style (KDE 2.x) naming 00981 QCString compatName = DCOPClient::dcopServerFileOld(); 00982 ::symlink(fName,compatName); 00983 } 00984 } 00985 00986 #if 0 00987 if (!SetAuthentication_local(numTransports, listenObjs)) 00988 qFatal("DCOPSERVER: authentication setup failed."); 00989 #endif 00990 if (!SetAuthentication(numTransports, listenObjs, &authDataEntries)) 00991 qFatal("DCOPSERVER: authentication setup failed."); 00992 00993 IceAddConnectionWatch (DCOPWatchProc, static_cast<IcePointer>(this)); 00994 _IceWriteHandler = DCOPIceWriteChar; 00995 00996 listener.setAutoDelete( true ); 00997 DCOPListener* con; 00998 for ( int i = 0; i < numTransports; i++) { 00999 con = new DCOPListener( listenObjs[i] ); 01000 listener.append( con ); 01001 connect( con, SIGNAL( activated(int) ), this, SLOT( newClient(int) ) ); 01002 } 01003 char c = 0; 01004 write(ready[1], &c, 1); // dcopserver is started 01005 close(ready[1]); 01006 01007 m_timer = new QTimer(this); 01008 connect( m_timer, SIGNAL(timeout()), this, SLOT(slotTerminate()) ); 01009 m_deadConnectionTimer = new QTimer(this); 01010 connect( m_deadConnectionTimer, SIGNAL(timeout()), this, SLOT(slotCleanDeadConnections()) ); 01011 01012 #ifdef DCOP_LOG 01013 char hostname_buffer[256]; 01014 memset( hostname_buffer, 0, sizeof( hostname_buffer ) ); 01015 if ( gethostname( hostname_buffer, 255 ) < 0 ) 01016 hostname_buffer[0] = '\0'; 01017 m_logger = new QFile( QString( "%1/.dcop-%2.log" ).arg( QDir::homeDirPath() ).arg( hostname_buffer ) ); 01018 if ( m_logger->open( IO_WriteOnly ) ) { 01019 m_stream = new QTextStream( m_logger ); 01020 } 01021 #endif 01022 } 01023 01024 DCOPServer::~DCOPServer() 01025 { 01026 system(findDcopserverShutdown()+" --nokill"); 01027 IceFreeListenObjs(numTransports, listenObjs); 01028 FreeAuthenticationData(numTransports, authDataEntries); 01029 delete dcopSignals; 01030 #ifdef DCOP_LOG 01031 delete m_stream; 01032 m_logger->close(); 01033 delete m_logger; 01034 #endif 01035 } 01036 01037 01038 DCOPConnection* DCOPServer::findApp( const QCString& appId ) 01039 { 01040 if ( appId.isNull() ) 01041 return 0; 01042 DCOPConnection* conn = appIds.find( appId ); 01043 return conn; 01044 } 01045 01049 void DCOPServer::slotCleanDeadConnections() 01050 { 01051 qWarning("DCOP Cleaning up dead connections."); 01052 while(!deadConnections.isEmpty()) 01053 { 01054 IceConn iceConn = deadConnections.take(0); 01055 IceSetShutdownNegotiation (iceConn, False); 01056 (void) IceCloseConnection( iceConn ); 01057 } 01058 } 01059 01063 void DCOPServer::ioError( IceConn iceConn ) 01064 { 01065 deadConnections.removeRef(iceConn); 01066 deadConnections.prepend(iceConn); 01067 m_deadConnectionTimer->start(0, true); 01068 } 01069 01070 01071 void DCOPServer::processData( int /*socket*/ ) 01072 { 01073 IceConn iceConn = static_cast<const DCOPConnection*>(sender())->iceConn; 01074 IceProcessMessagesStatus status = IceProcessMessages( iceConn, 0, 0 ); 01075 if ( status == IceProcessMessagesIOError ) { 01076 deadConnections.removeRef(iceConn); 01077 if (deadConnections.isEmpty()) 01078 m_deadConnectionTimer->stop(); 01079 IceSetShutdownNegotiation (iceConn, False); 01080 (void) IceCloseConnection( iceConn ); 01081 } 01082 } 01083 01084 void DCOPServer::newClient( int /*socket*/ ) 01085 { 01086 IceAcceptStatus status; 01087 IceConn iceConn = IceAcceptConnection( static_cast<const DCOPListener*>(sender())->listenObj, &status); 01088 if (!iceConn) { 01089 if (status == IceAcceptBadMalloc) 01090 qWarning("Failed to alloc connection object!\n"); 01091 else // IceAcceptFailure 01092 qWarning("Failed to accept ICE connection!\n"); 01093 return; 01094 } 01095 01096 IceSetShutdownNegotiation( iceConn, False ); 01097 01098 IceConnectStatus cstatus; 01099 while ((cstatus = IceConnectionStatus (iceConn))==IceConnectPending) { 01100 (void) IceProcessMessages( iceConn, 0, 0 ); 01101 } 01102 01103 if (cstatus != IceConnectAccepted) { 01104 if (cstatus == IceConnectIOError) 01105 qWarning ("IO error opening ICE Connection!\n"); 01106 else 01107 qWarning ("ICE Connection rejected!\n"); 01108 deadConnections.removeRef(iceConn); 01109 (void) IceCloseConnection (iceConn); 01110 } 01111 } 01112 01113 void* DCOPServer::watchConnection( IceConn iceConn ) 01114 { 01115 DCOPConnection* con = new DCOPConnection( iceConn ); 01116 connect( con, SIGNAL( activated(int) ), this, SLOT( processData(int) ) ); 01117 01118 clients.insert(iceConn, con ); 01119 fd_clients.insert( IceConnectionNumber(iceConn), con); 01120 01121 return static_cast<void*>(con); 01122 } 01123 01124 void DCOPServer::removeConnection( void* data ) 01125 { 01126 DCOPConnection* conn = static_cast<DCOPConnection*>(data); 01127 01128 dcopSignals->removeConnections(conn); 01129 01130 clients.remove(conn->iceConn ); 01131 fd_clients.remove( IceConnectionNumber(conn->iceConn) ); 01132 01133 // Send DCOPReplyFailed to all in conn->waitingForReply 01134 while (!conn->waitingForReply.isEmpty()) { 01135 IceConn iceConn = conn->waitingForReply.take(0); 01136 if (iceConn) { 01137 DCOPConnection* target = clients.find( iceConn ); 01138 qWarning("DCOP aborting call from '%s' to '%s'", target ? target->appId.data() : "<unknown>" , conn->appId.data() ); 01139 QByteArray reply; 01140 DCOPMsg *pMsg; 01141 IceGetHeader( iceConn, majorOpcode, DCOPReplyFailed, 01142 sizeof(DCOPMsg), DCOPMsg, pMsg ); 01143 pMsg->key = 1; 01144 pMsg->length += reply.size(); 01145 _DCOPIceSendBegin( iceConn ); 01146 DCOPIceSendData(iceConn, reply); 01147 _DCOPIceSendEnd(); 01148 if (!target) 01149 qWarning("DCOP Error: unknown target in waitingForReply"); 01150 else if (!target->waitingOnReply.removeRef(conn->iceConn)) 01151 qWarning("DCOP Error: client in waitingForReply wasn't waiting on reply"); 01152 } 01153 } 01154 01155 // Send DCOPReplyFailed to all in conn->waitingForDelayedReply 01156 while (!conn->waitingForDelayedReply.isEmpty()) { 01157 IceConn iceConn = conn->waitingForDelayedReply.take(0); 01158 if (iceConn) { 01159 DCOPConnection* target = clients.find( iceConn ); 01160 qWarning("DCOP aborting (delayed) call from '%s' to '%s'", target ? target->appId.data() : "<unknown>", conn->appId.data() ); 01161 QByteArray reply; 01162 DCOPMsg *pMsg; 01163 IceGetHeader( iceConn, majorOpcode, DCOPReplyFailed, 01164 sizeof(DCOPMsg), DCOPMsg, pMsg ); 01165 pMsg->key = 1; 01166 pMsg->length += reply.size(); 01167 _DCOPIceSendBegin( iceConn ); 01168 DCOPIceSendData( iceConn, reply ); 01169 _DCOPIceSendEnd(); 01170 if (!target) 01171 qWarning("DCOP Error: unknown target in waitingForDelayedReply"); 01172 else if (!target->waitingOnReply.removeRef(conn->iceConn)) 01173 qWarning("DCOP Error: client in waitingForDelayedReply wasn't waiting on reply"); 01174 } 01175 } 01176 while (!conn->waitingOnReply.isEmpty()) 01177 { 01178 IceConn iceConn = conn->waitingOnReply.take(0); 01179 if (iceConn) { 01180 DCOPConnection* target = clients.find( iceConn ); 01181 if (!target) 01182 { 01183 qWarning("DCOP Error: still waiting for answer from non-existing client."); 01184 continue; 01185 } 01186 qWarning("DCOP aborting while waiting for answer from '%s'", target->appId.data()); 01187 if (!target->waitingForReply.removeRef(conn->iceConn) && 01188 !target->waitingForDelayedReply.removeRef(conn->iceConn)) 01189 qWarning("DCOP Error: called client has forgotten about caller"); 01190 } 01191 } 01192 01193 if ( !conn->appId.isNull() ) { 01194 #ifndef NDEBUG 01195 qDebug("DCOP: unregister '%s'", conn->appId.data() ); 01196 #endif 01197 if ( !conn->daemon ) 01198 { 01199 currentClientNumber--; 01200 } 01201 01202 appIds.remove( conn->appId ); 01203 01204 broadcastApplicationRegistration( conn, "applicationRemoved(QCString)", conn->appId ); 01205 } 01206 01207 delete conn; 01208 01209 if ( suicide && (currentClientNumber == 0) ) 01210 { 01211 m_timer->start( 10000 ); // if within 10 seconds nothing happens, we'll terminate 01212 } 01213 } 01214 01215 void DCOPServer::slotTerminate() 01216 { 01217 #ifndef NDEBUG 01218 fprintf( stderr, "DCOPServer : slotTerminate() -> sending terminateKDE signal.\n" ); 01219 #endif 01220 QByteArray data; 01221 dcopSignals->emitSignal(0L /* dcopserver */, "terminateKDE()", data, false); 01222 disconnect( m_timer, SIGNAL(timeout()), this, SLOT(slotTerminate()) ); 01223 connect( m_timer, SIGNAL(timeout()), this, SLOT(slotSuicide()) ); 01224 system(findDcopserverShutdown()+" --nokill"); 01225 } 01226 01227 void DCOPServer::slotSuicide() 01228 { 01229 #ifndef NDEBUG 01230 fprintf( stderr, "DCOPServer : slotSuicide() -> exit.\n" ); 01231 #endif 01232 exit(0); 01233 } 01234 01235 bool DCOPServer::receive(const QCString &/*app*/, const QCString &obj, 01236 const QCString &fun, const QByteArray& data, 01237 QCString& replyType, QByteArray &replyData, 01238 IceConn iceConn) 01239 { 01240 #ifdef DCOP_LOG 01241 (*m_stream) << "Received a message: obj =\"" 01242 << obj << "\", fun =\"" 01243 << fun << "\", replyType =\"" 01244 << replyType << "\", data.size() =\"" 01245 << data.size() << "\", replyData.size() =" 01246 << replyData.size() << "\n"; 01247 m_logger->flush(); 01248 #endif 01249 01250 if ( obj == "emit") 01251 { 01252 DCOPConnection* conn = clients.find( iceConn ); 01253 if (conn) { 01254 //qDebug("DCOPServer: %s emits %s", conn->appId.data(), fun.data()); 01255 dcopSignals->emitSignal(conn, fun, data, false); 01256 } 01257 replyType = "void"; 01258 return true; 01259 } 01260 if ( fun == "setDaemonMode(bool)" ) { 01261 QDataStream args( data, IO_ReadOnly ); 01262 if ( !args.atEnd() ) { 01263 Q_INT8 iDaemon; 01264 bool daemon; 01265 args >> iDaemon; 01266 01267 daemon = static_cast<bool>( iDaemon ); 01268 01269 DCOPConnection* conn = clients.find( iceConn ); 01270 if ( conn && !conn->appId.isNull() ) { 01271 if ( daemon ) { 01272 if ( !conn->daemon ) 01273 { 01274 conn->daemon = true; 01275 01276 #ifndef NDEBUG 01277 qDebug( "DCOP: new daemon %s", conn->appId.data() ); 01278 #endif 01279 01280 currentClientNumber--; 01281 01282 // David says it's safer not to do this :-) 01283 // if ( currentClientNumber == 0 ) 01284 // m_timer->start( 10000 ); 01285 } 01286 } else 01287 { 01288 if ( conn->daemon ) { 01289 conn->daemon = false; 01290 01291 currentClientNumber++; 01292 01293 m_timer->stop(); 01294 } 01295 } 01296 } 01297 01298 replyType = "void"; 01299 return true; 01300 } 01301 } 01302 if ( fun == "registerAs(QCString)" ) { 01303 QDataStream args( data, IO_ReadOnly ); 01304 if (!args.atEnd()) { 01305 QCString app2 = readQCString(args); 01306 QDataStream reply( replyData, IO_WriteOnly ); 01307 DCOPConnection* conn = clients.find( iceConn ); 01308 if ( conn && !app2.isEmpty() ) { 01309 if ( !conn->appId.isNull() && 01310 appIds.find( conn->appId ) == conn ) { 01311 appIds.remove( conn->appId ); 01312 01313 } 01314 01315 QCString oldAppId; 01316 if ( conn->appId.isNull() ) 01317 { 01318 currentClientNumber++; 01319 m_timer->stop(); // abort termination if we were planning one 01320 #ifndef NDEBUG 01321 qDebug("DCOP: register '%s' -> number of clients is now %d", app2.data(), currentClientNumber ); 01322 #endif 01323 } 01324 #ifndef NDEBUG 01325 else 01326 { 01327 oldAppId = conn->appId; 01328 qDebug("DCOP: '%s' now known as '%s'", conn->appId.data(), app2.data() ); 01329 } 01330 #endif 01331 01332 conn->appId = app2; 01333 if ( appIds.find( app2 ) != 0 ) { 01334 // we already have this application, unify 01335 int n = 1; 01336 QCString tmp; 01337 do { 01338 n++; 01339 tmp.setNum( n ); 01340 tmp.prepend("-"); 01341 tmp.prepend( app2 ); 01342 } while ( appIds.find( tmp ) != 0 ); 01343 conn->appId = tmp; 01344 } 01345 appIds.insert( conn->appId, conn ); 01346 01347 int c = conn->appId.find( '-' ); 01348 if ( c > 0 ) 01349 conn->plainAppId = conn->appId.left( c ); 01350 else 01351 conn->plainAppId = conn->appId; 01352 01353 if( !oldAppId.isEmpty()) 01354 broadcastApplicationRegistration( conn, 01355 "applicationRemoved(QCString)", oldAppId ); 01356 broadcastApplicationRegistration( conn, "applicationRegistered(QCString)", conn->appId ); 01357 } 01358 replyType = "QCString"; 01359 reply << conn->appId; 01360 return true; 01361 } 01362 } 01363 else if ( fun == "registeredApplications()" ) { 01364 QDataStream reply( replyData, IO_WriteOnly ); 01365 QCStringList applications; 01366 QAsciiDictIterator<DCOPConnection> it( appIds ); 01367 while ( it.current() ) { 01368 applications << it.currentKey(); 01369 ++it; 01370 } 01371 replyType = "QCStringList"; 01372 reply << applications; 01373 return true; 01374 } else if ( fun == "isApplicationRegistered(QCString)" ) { 01375 QDataStream args( data, IO_ReadOnly ); 01376 if (!args.atEnd()) { 01377 QCString s = readQCString(args); 01378 QDataStream reply( replyData, IO_WriteOnly ); 01379 int b = ( findApp( s ) != 0 ); 01380 replyType = "bool"; 01381 reply << b; 01382 return true; 01383 } 01384 } else if ( fun == "setNotifications(bool)" ) { 01385 QDataStream args( data, IO_ReadOnly ); 01386 if (!args.atEnd()) { 01387 Q_INT8 notifyActive; 01388 args >> notifyActive; 01389 DCOPConnection* conn = clients.find( iceConn ); 01390 if ( conn ) { 01391 if ( notifyActive ) 01392 conn->notifyRegister++; 01393 else if ( conn->notifyRegister > 0 ) 01394 conn->notifyRegister--; 01395 } 01396 replyType = "void"; 01397 return true; 01398 } 01399 } else if ( fun == "connectSignal(QCString,QCString,QCString,QCString,QCString,bool)") { 01400 DCOPConnection* conn = clients.find( iceConn ); 01401 if (!conn) return false; 01402 QDataStream args(data, IO_ReadOnly ); 01403 if (args.atEnd()) return false; 01404 QCString sender = readQCString(args); 01405 QCString senderObj = readQCString(args); 01406 QCString signal = readQCString(args); 01407 QCString receiverObj = readQCString(args); 01408 QCString slot = readQCString(args); 01409 Q_INT8 Volatile; 01410 args >> Volatile; 01411 //qDebug("DCOPServer: connectSignal(sender = %s senderObj = %s signal = %s recvObj = %s slot = %s)", sender.data(), senderObj.data(), signal.data(), receiverObj.data(), slot.data()); 01412 bool b = dcopSignals->connectSignal(sender, senderObj, signal, conn, receiverObj, slot, (Volatile != 0)); 01413 replyType = "bool"; 01414 QDataStream reply( replyData, IO_WriteOnly ); 01415 reply << (Q_INT8) (b?1:0); 01416 return true; 01417 } else if ( fun == "disconnectSignal(QCString,QCString,QCString,QCString,QCString)") { 01418 DCOPConnection* conn = clients.find( iceConn ); 01419 if (!conn) return false; 01420 QDataStream args(data, IO_ReadOnly ); 01421 if (args.atEnd()) return false; 01422 QCString sender = readQCString(args); 01423 QCString senderObj = readQCString(args); 01424 QCString signal = readQCString(args); 01425 QCString receiverObj = readQCString(args); 01426 QCString slot = readQCString(args); 01427 //qDebug("DCOPServer: disconnectSignal(sender = %s senderObj = %s signal = %s recvObj = %s slot = %s)", sender.data(), senderObj.data(), signal.data(), receiverObj.data(), slot.data()); 01428 bool b = dcopSignals->disconnectSignal(sender, senderObj, signal, conn, receiverObj, slot); 01429 replyType = "bool"; 01430 QDataStream reply( replyData, IO_WriteOnly ); 01431 reply << (Q_INT8) (b?1:0); 01432 return true; 01433 } 01434 01435 return false; 01436 } 01437 01438 void DCOPServer::broadcastApplicationRegistration( DCOPConnection* conn, const QCString type, 01439 const QString& /*appId*/ ) 01440 { 01441 QByteArray data; 01442 QDataStream datas( data, IO_WriteOnly ); 01443 datas << conn->appId; 01444 QPtrDictIterator<DCOPConnection> it( clients ); 01445 QByteArray ba; 01446 QDataStream ds( ba, IO_WriteOnly ); 01447 ds <<QCString("DCOPServer") << QCString("") << QCString("") 01448 << type << data; 01449 int datalen = ba.size(); 01450 DCOPMsg *pMsg = 0; 01451 while ( it.current() ) { 01452 DCOPConnection* c = it.current(); 01453 ++it; 01454 if ( c->notifyRegister && (c != conn) ) { 01455 IceGetHeader( c->iceConn, majorOpcode, DCOPSend, 01456 sizeof(DCOPMsg), DCOPMsg, pMsg ); 01457 pMsg->key = 1; 01458 pMsg->length += datalen; 01459 _DCOPIceSendBegin(c->iceConn); 01460 DCOPIceSendData( c->iceConn, ba ); 01461 _DCOPIceSendEnd(); 01462 } 01463 } 01464 } 01465 01466 void 01467 DCOPServer::sendMessage(DCOPConnection *conn, const QCString &sApp, 01468 const QCString &rApp, const QCString &rObj, 01469 const QCString &rFun, const QByteArray &data) 01470 { 01471 QByteArray ba; 01472 QDataStream ds( ba, IO_WriteOnly ); 01473 ds << sApp << rApp << rObj << rFun << data; 01474 int datalen = ba.size(); 01475 DCOPMsg *pMsg = 0; 01476 01477 IceGetHeader( conn->iceConn, majorOpcode, DCOPSend, 01478 sizeof(DCOPMsg), DCOPMsg, pMsg ); 01479 pMsg->length += datalen; 01480 pMsg->key = 1; // important! 01481 01482 #ifdef DCOP_LOG 01483 (*m_stream) << "Sending a message: sApp =\"" 01484 << sApp << "\", rApp =\"" 01485 << rApp << "\", rObj =\"" 01486 << rObj << "\", rFun =\"" 01487 << rFun << "\", datalen =" 01488 << datalen << "\n"; 01489 m_logger->flush(); 01490 #endif 01491 01492 _DCOPIceSendBegin( conn->iceConn ); 01493 DCOPIceSendData(conn->iceConn, ba); 01494 _DCOPIceSendEnd(); 01495 } 01496 01497 void IoErrorHandler ( IceConn iceConn) 01498 { 01499 the_server->ioError( iceConn ); 01500 } 01501 01502 static bool isRunning(const QCString &fName, bool printNetworkId = false) 01503 { 01504 if (::access(fName.data(), R_OK) == 0) { 01505 QFile f(fName); 01506 f.open(IO_ReadOnly); 01507 int size = QMIN( 1024, f.size() ); // protection against a huge file 01508 QCString contents( size+1 ); 01509 bool ok = f.readBlock( contents.data(), size ) == size; 01510 contents[size] = '\0'; 01511 int pos = contents.find('\n'); 01512 ok = ok && ( pos != -1 ); 01513 pid_t pid = ok ? contents.mid(pos+1).toUInt(&ok) : 0; 01514 f.close(); 01515 if (ok && pid && (kill(pid, SIGHUP) == 0)) { 01516 if (printNetworkId) 01517 qWarning("%s", contents.left(pos).data()); 01518 else 01519 qWarning( "---------------------------------\n" 01520 "It looks like dcopserver is already running. If you are sure\n" 01521 "that it is not already running, remove %s\n" 01522 "and start dcopserver again.\n" 01523 "---------------------------------\n", 01524 fName.data() ); 01525 01526 // lock file present, die silently. 01527 return true; 01528 } else { 01529 // either we couldn't read the PID or kill returned an error. 01530 // remove lockfile and continue 01531 unlink(fName.data()); 01532 } 01533 } else if (errno != ENOENT) { 01534 // remove lockfile and continue 01535 unlink(fName.data()); 01536 } 01537 return false; 01538 } 01539 01540 const char* const ABOUT = 01541 "Usage: dcopserver [--nofork] [--nosid] [--help]\n" 01542 " dcopserver --serverid\n" 01543 "\n" 01544 "DCOP is KDE's Desktop Communications Protocol. It is a lightweight IPC/RPC\n" 01545 "mechanism built on top of the X Consortium's Inter Client Exchange protocol.\n" 01546 "It enables desktop applications to communicate reliably with low overhead.\n" 01547 "\n" 01548 "Copyright (C) 1999-2001, The KDE Developers <http://www.kde.org>\n" 01549 ; 01550 01551 extern "C" int kdemain( int argc, char* argv[] ) 01552 { 01553 bool serverid = false; 01554 bool nofork = false; 01555 bool nosid = false; 01556 bool suicide = false; 01557 for(int i = 1; i < argc; i++) { 01558 if (strcmp(argv[i], "--nofork") == 0) 01559 nofork = true; 01560 else if (strcmp(argv[i], "--nosid") == 0) 01561 nosid = true; 01562 else if (strcmp(argv[i], "--nolocal") == 0) 01563 ; // Ignore 01564 else if (strcmp(argv[i], "--suicide") == 0) 01565 suicide = true; 01566 else if (strcmp(argv[i], "--serverid") == 0) 01567 serverid = true; 01568 else { 01569 fprintf(stdout, ABOUT ); 01570 return 0; 01571 } 01572 } 01573 01574 if (serverid) 01575 { 01576 if (isRunning(DCOPClient::dcopServerFile(), true)) 01577 return 0; 01578 return 1; 01579 } 01580 01581 // check if we are already running 01582 if (isRunning(DCOPClient::dcopServerFile())) 01583 return 0; 01584 if (QCString(getenv("DCOPAUTHORITY")).isEmpty() && 01585 isRunning(DCOPClient::dcopServerFileOld())) 01586 { 01587 // Make symlink for compatibility 01588 QCString oldFile = DCOPClient::dcopServerFileOld(); 01589 QCString newFile = DCOPClient::dcopServerFile(); 01590 symlink(oldFile.data(), newFile.data()); 01591 return 0; 01592 } 01593 01594 struct rlimit limits; 01595 01596 int retcode = getrlimit(RLIMIT_NOFILE, &limits); 01597 if (!retcode) { 01598 if (limits.rlim_max > 512 && limits.rlim_cur < 512) 01599 { 01600 int cur_limit = limits.rlim_cur; 01601 limits.rlim_cur = 512; 01602 retcode = setrlimit(RLIMIT_NOFILE, &limits); 01603 01604 if (retcode != 0) 01605 { 01606 qWarning("dcopserver: Could not raise limit on number of open files."); 01607 qWarning("dcopserver: Current limit = %d", cur_limit); 01608 } 01609 } 01610 } 01611 01612 pipe(ready); 01613 01614 if (!nofork) { 01615 pid_t pid = fork(); 01616 if (pid > 0) { 01617 char c = 1; 01618 close(ready[1]); 01619 read(ready[0], &c, 1); // Wait till dcopserver is started 01620 close(ready[0]); 01621 // I am the parent 01622 if (c == 0) 01623 { 01624 // Test whether we are functional. 01625 DCOPClient client; 01626 if (client.attach()) 01627 return 0; 01628 } 01629 qWarning("DCOPServer self-test failed."); 01630 system(findDcopserverShutdown()+" --kill"); 01631 return 1; 01632 } 01633 close(ready[0]); 01634 01635 if (!nosid) 01636 setsid(); 01637 01638 if (fork() > 0) 01639 return 0; // get rid of controlling terminal 01640 } 01641 01642 pipe(pipeOfDeath); 01643 01644 signal(SIGHUP, sighandler); 01645 signal(SIGTERM, sighandler); 01646 signal(SIGPIPE, SIG_IGN); 01647 01648 putenv(strdup("SESSION_MANAGER=")); 01649 01650 QApplication a( argc, argv, false ); 01651 01652 QSocketNotifier DEATH(pipeOfDeath[0], QSocketNotifier::Read, 0, 0); 01653 a.connect(&DEATH, SIGNAL(activated(int)), SLOT(quit())); 01654 01655 IceSetIOErrorHandler (IoErrorHandler ); 01656 DCOPServer *server = new DCOPServer(suicide); // this sets the_server 01657 01658 int ret = a.exec(); 01659 delete server; 01660 return ret; 01661 } 01662 01663 #include "dcopserver.moc"
KDE Logo
This file is part of the documentation for dcop Library Version 3.3.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Sep 29 09:42:57 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003