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