dcop Library API Documentation

dcopserver.cpp

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