26 #include "slavebase.h"
31 #ifdef HAVE_SYS_SELECT_H
32 #include <sys/select.h>
45 #include <dcopclient.h>
47 #include <tdeapplication.h>
50 #include <tdesu/client.h>
51 #include <tdelocale.h>
54 #include "kremoteencoding.h"
56 #include "tdeio/slavebase.h"
57 #include "tdeio/connection.h"
58 #include "tdeio/ioslave_defaults.h"
59 #include "tdeio/slaveinterface.h"
61 #include "uiserver_stub.h"
63 using namespace TDEIO;
65 template class TQPtrList<TQValueList<UDSAtom> >;
66 typedef TQValueList<TQCString> AuthKeysList;
67 typedef TQMap<TQString,TQCString> AuthKeysMap;
68 #define TDEIO_DATA TQByteArray data; TQDataStream stream( data, IO_WriteOnly ); stream
69 #define TDEIO_FILESIZE_T(x) (unsigned long)(x & 0xffffffff) << (unsigned long)(x >> 32)
73 class SlaveBaseConfig :
public TDEConfigBase
79 bool internalHasGroup(
const TQCString &)
const { tqWarning(
"hasGroup(const TQCString &)");
82 TQStringList groupList()
const {
return TQStringList(); }
84 TQMap<TQString,TQString> entryMap(
const TQString &group)
const
85 { Q_UNUSED(group);
return TQMap<TQString,TQString>(); }
87 void reparseConfiguration() { }
89 KEntryMap internalEntryMap(
const TQString &pGroup)
const { Q_UNUSED(pGroup);
return KEntryMap(); }
91 KEntryMap internalEntryMap()
const {
return KEntryMap(); }
93 void putData(
const KEntryKey &_key,
const KEntry&_data,
bool _checkGroup)
94 { Q_UNUSED(_key); Q_UNUSED(_data); Q_UNUSED(_checkGroup); }
96 KEntry lookupData(
const KEntryKey &_key)
const
99 TQString value = slave->metaData(_key.c_key);
101 entry.mValue = value.utf8();
109 class SlaveBasePrivate {
113 bool needSendCanResume:1;
117 SlaveBaseConfig *config;
120 struct timeval last_tv;
123 DCOPClient *dcopClient;
126 TQByteArray timeoutData;
132 long SlaveBase::s_seqNr;
134 static volatile bool slaveWriteError =
false;
136 static const char *s_protocol;
139 static void genericsig_handler(
int sigNumber)
141 signal(sigNumber,SIG_IGN);
149 signal(SIGALRM,SIG_DFL);
156 SlaveBase::SlaveBase(
const TQCString &protocol,
157 const TQCString &pool_socket,
158 const TQCString &app_socket )
159 : mProtocol(protocol), m_pConnection(0),
160 mPoolSocket( TQFile::decodeName(pool_socket)),
161 mAppSocket( TQFile::decodeName(app_socket))
163 s_protocol = protocol.data();
165 if (!getenv(
"TDE_DEBUG"))
167 TDECrash::setCrashHandler( sigsegv_handler );
168 signal(SIGILL,&sigsegv_handler);
169 signal(SIGTRAP,&sigsegv_handler);
170 signal(SIGABRT,&sigsegv_handler);
171 signal(SIGBUS,&sigsegv_handler);
172 signal(SIGALRM,&sigsegv_handler);
173 signal(SIGFPE,&sigsegv_handler);
175 signal(SIGPOLL, &sigsegv_handler);
178 signal(SIGSYS, &sigsegv_handler);
181 signal(SIGVTALRM, &sigsegv_handler);
184 signal(SIGXCPU, &sigsegv_handler);
187 signal(SIGXFSZ, &sigsegv_handler);
191 struct sigaction act;
192 act.sa_handler = sigpipe_handler;
193 sigemptyset( &act.sa_mask );
195 sigaction( SIGPIPE, &act, 0 );
197 signal(SIGINT,&genericsig_handler);
198 signal(SIGQUIT,&genericsig_handler);
199 signal(SIGTERM,&genericsig_handler);
205 listEntryCurrentSize = 100;
207 gettimeofday(&tp, 0);
208 listEntry_sec = tp.tv_sec;
209 listEntry_usec = tp.tv_usec;
210 mConnectedToApp =
true;
212 d =
new SlaveBasePrivate;
217 d->needSendCanResume =
false;
218 d->config =
new SlaveBaseConfig(
this);
221 d->last_tv.tv_sec = 0;
222 d->last_tv.tv_usec = 0;
225 d->sentListEntries=0;
227 connectSlave(mAppSocket);
233 SlaveBase::~SlaveBase()
244 if (!d->dcopClient->isAttached())
245 d->dcopClient->attach();
246 d->dcopClient->setDaemonMode(
true );
248 return d->dcopClient;
251 void SlaveBase::dispatchLoop()
253 #ifdef Q_OS_UNIX //TODO: WIN32
259 if (d->timeout && (d->timeout < time(0)))
261 TQByteArray
data = d->timeoutData;
263 d->timeoutData = TQByteArray();
268 assert(appconn->
inited());
269 int maxfd = appconn->
fd_from();
270 FD_SET(appconn->
fd_from(), &rfds);
273 FD_SET( d->dcopClient->socket(), &rfds );
274 if( d->dcopClient->socket() > maxfd )
275 maxfd = d->dcopClient->socket();
280 retval = select( maxfd + 1, &rfds, NULL, NULL, NULL);
285 tv.tv_sec = kMax(d->timeout-time(0),(time_t) 1);
287 retval = select( maxfd + 1, &rfds, NULL, NULL, &tv);
289 if ((retval>0) && FD_ISSET(appconn->
fd_from(), &rfds))
293 if ( appconn->
read(&cmd, data) != -1 )
300 if (mConnectedToApp && !mPoolSocket.isEmpty())
303 mConnectedToApp =
false;
313 if( retval > 0 && d->dcopClient && FD_ISSET( d->dcopClient->socket(), &rfds ))
315 d->dcopClient->processSocketData( d->dcopClient->socket());
317 if ((retval<0) && (errno != EINTR))
319 kdDebug(7019) <<
"dispatchLoop(): select returned " << retval <<
" "
320 << (errno==EBADF?
"EBADF":errno==EINTR?
"EINTR":errno==EINVAL?
"EINVAL":errno==ENOMEM?
"ENOMEM":
"unknown")
321 <<
" (" << errno <<
")" << endl;
327 kdDebug(7019)<<
" dispatchLoop() slave was killed, returning"<<endl;
332 #error The TDEIO slave system only works under UNIX
338 #ifdef Q_OS_UNIX //TODO: TDESocket not yet available on WIN32
339 appconn->
init(
new TDESocket(TQFile::encodeName(path).
data()));
342 kdDebug(7019) <<
"SlaveBase: failed to connect to " << path << endl;
346 setConnection(appconn);
350 void SlaveBase::disconnectSlave()
357 mOutgoingMetaData.replace(key, value);
362 if (mIncomingMetaData.contains(key))
363 return mIncomingMetaData[key];
364 if (d->configData.contains(key))
365 return d->configData[key];
366 return TQString::null;
371 if (mIncomingMetaData.contains(key))
373 if (d->configData.contains(key))
393 TDEIO_DATA << mOutgoingMetaData;
395 slaveWriteError =
false;
396 m_pConnection->
send( INF_META_DATA, data );
397 if (slaveWriteError) exit();
398 mOutgoingMetaData.clear();
403 if (d->remotefile != 0)
404 return d->remotefile;
411 if (!mOutgoingMetaData.isEmpty())
413 slaveWriteError =
false;
414 m_pConnection->
send( MSG_DATA, data );
415 if (slaveWriteError) exit();
424 if (d->needSendCanResume)
426 m_pConnection->
send( MSG_DATA_REQ );
431 mIncomingMetaData.clear();
432 mOutgoingMetaData.clear();
433 TDEIO_DATA << (TQ_INT32) _errid << _text;
435 m_pConnection->
send( MSG_ERROR, data );
437 listEntryCurrentSize = 100;
438 d->sentListEntries=0;
444 slaveWriteError =
false;
445 m_pConnection->
send( MSG_CONNECTED );
446 if (slaveWriteError) exit();
451 mIncomingMetaData.clear();
452 if (!mOutgoingMetaData.isEmpty())
454 m_pConnection->
send( MSG_FINISHED );
457 listEntryCurrentSize = 100;
458 d->sentListEntries=0;
464 m_pConnection->
send( MSG_NEED_SUBURL_DATA );
469 pid_t pid = getpid();
470 TQ_INT8 b = connected ? 1 : 0;
471 TDEIO_DATA << pid <<
mProtocol << host << b;
473 stream << d->onHoldUrl;
474 m_pConnection->
send( MSG_SLAVE_STATUS, data );
477 void SlaveBase::canResume()
479 m_pConnection->
send( MSG_CANRESUME );
484 TDEIO_DATA << TDEIO_FILESIZE_T(_bytes);
485 slaveWriteError =
false;
486 m_pConnection->
send( INF_TOTAL_SIZE, data );
487 if (slaveWriteError) exit();
491 gettimeofday(&tp, 0);
492 listEntry_sec = tp.tv_sec;
493 listEntry_usec = tp.tv_usec;
495 d->sentListEntries=0;
500 bool emitSignal=
false;
502 int gettimeofday_res=gettimeofday( &tv, 0L );
504 if( _bytes == d->totalSize )
506 else if ( gettimeofday_res == 0 ) {
507 time_t msecdiff = 2000;
508 if (d->last_tv.tv_sec) {
510 msecdiff = 1000 * ( tv.tv_sec - d->last_tv.tv_sec );
511 time_t usecdiff = tv.tv_usec - d->last_tv.tv_usec;
512 if ( usecdiff < 0 ) {
516 msecdiff += usecdiff / 1000;
518 emitSignal=msecdiff >= 100;
522 TDEIO_DATA << TDEIO_FILESIZE_T(_bytes);
523 slaveWriteError =
false;
524 m_pConnection->
send( INF_PROCESSED_SIZE, data );
525 if (slaveWriteError) exit();
526 if ( gettimeofday_res == 0 ) {
527 d->last_tv.tv_sec = tv.tv_sec;
528 d->last_tv.tv_usec = tv.tv_usec;
536 kdDebug(7019) <<
"SlaveBase::processedPercent: STUB" << endl;
542 TDEIO_DATA << (TQ_UINT32) _bytes_per_second;
543 slaveWriteError =
false;
544 m_pConnection->
send( INF_SPEED, data );
545 if (slaveWriteError) exit();
551 m_pConnection->
send( INF_REDIRECTION, data );
556 m_pConnection->
send( INF_ERROR_PAGE );
559 static bool isSubCommand(
int cmd)
561 return ( (cmd == CMD_REPARSECONFIGURATION) ||
562 (cmd == CMD_META_DATA) ||
563 (cmd == CMD_CONFIG) ||
564 (cmd == CMD_SUBURL) ||
565 (cmd == CMD_SLAVE_STATUS) ||
566 (cmd == CMD_SLAVE_CONNECT) ||
567 (cmd == CMD_SLAVE_HOLD) ||
568 (cmd == CMD_MULTI_GET));
578 if (!mOutgoingMetaData.isEmpty())
581 TDEIO_DATA << mOutgoingMetaData;
582 m_pConnection->
send( INF_META_DATA, data );
585 m_pConnection->
send( INF_MIME_TYPE, data );
589 if ( m_pConnection->
read( &cmd, data ) == -1 ) {
590 kdDebug(7019) <<
"SlaveBase: mimetype: read error" << endl;
594 if ( cmd == CMD_HOST)
596 if ( isSubCommand(cmd) )
598 dispatch( cmd, data );
604 while (cmd != CMD_NONE);
605 mOutgoingMetaData.clear();
608 void SlaveBase::exit()
617 m_pConnection->
send( INF_WARNING, data );
623 m_pConnection->
send( INF_INFOMESSAGE, data );
628 TDEIO_DATA << host << d->slaveid;
629 m_pConnection->
send( MSG_NET_REQUEST, data );
634 TQDataStream stream( data, IO_ReadOnly );
643 TDEIO_DATA << host << d->slaveid;
644 m_pConnection->
send( MSG_NET_DROP, data );
650 slaveWriteError =
false;
651 m_pConnection->
send( MSG_STAT_ENTRY, data );
652 if (slaveWriteError) exit();
657 static struct timeval tp;
658 static const int maximum_updatetime = 300;
659 static const int minimum_updatetime = 100;
662 pendingListEntries.append(entry);
664 if (pendingListEntries.count() > listEntryCurrentSize) {
665 gettimeofday(&tp, 0);
667 long diff = ((tp.tv_sec - listEntry_sec) * 1000000 +
668 tp.tv_usec - listEntry_usec) / 1000;
671 if (diff > maximum_updatetime) {
672 listEntryCurrentSize = listEntryCurrentSize * 3 / 4;
677 else if (((pendingListEntries.count()*maximum_updatetime)/diff) > (d->totalSize-d->sentListEntries))
678 listEntryCurrentSize=d->totalSize-d->sentListEntries+1;
681 else if (diff < minimum_updatetime)
682 listEntryCurrentSize = (pendingListEntries.count() * maximum_updatetime) / diff;
689 pendingListEntries.clear();
691 gettimeofday(&tp, 0);
692 listEntry_sec = tp.tv_sec;
693 listEntry_usec = tp.tv_usec;
699 TDEIO_DATA << (TQ_UINT32)list.count();
700 UDSEntryListConstIterator it = list.begin();
701 UDSEntryListConstIterator end = list.end();
702 for (; it != end; ++it)
704 slaveWriteError =
false;
705 m_pConnection->
send( MSG_LIST_ENTRIES, data);
706 if (slaveWriteError) exit();
707 d->sentListEntries+=(uint)list.count();
711 const TQCString& group,
714 TDEIO_DATA << key << group << keepPass;
715 m_pConnection->
send( MSG_AUTH_KEY, data );
720 TDEIO_DATA << key.utf8() ;
721 m_pConnection->
send( MSG_DEL_AUTH_KEY, data );
724 void SlaveBase::sigsegv_handler(
int sig)
730 signal(SIGALRM,SIG_DFL);
736 snprintf(buffer,
sizeof(buffer),
"tdeioslave: ####### CRASH ###### protocol = %s pid = %d signal = %d\n", s_protocol, getpid(), sig);
737 if (write(2, buffer, strlen(buffer)) >= 0) {
740 #else // SECURE_DEBUG
749 TQString backtrace = kdBacktrace();
750 if (write(2, backtrace.ascii(), backtrace.length()) < 0) {
754 #endif // SECURE_DEBUG
760 void SlaveBase::sigpipe_handler (
int)
766 slaveWriteError =
true;
818 bool local = remoteURL.isLocalFile();
829 TDEIO_DATA << islocal << retURL;
830 m_pConnection->
send( INF_LOCALURL, data );
833 bool SlaveBase::dispatch()
835 assert( m_pConnection );
839 if ( m_pConnection->
read( &cmd, data ) == -1 )
841 kdDebug(7019) <<
"SlaveBase::dispatch() has read error." << endl;
845 dispatch( cmd, data );
860 long windowId =
metaData(
"window-id").toLong();
861 long progressId =
metaData(
"progress-id").toLong();
862 unsigned long userTimestamp =
metaData(
"user-timestamp").toULong();
864 kdDebug(7019) <<
"SlaveBase::openPassDlg window-id=" << windowId <<
" progress-id=" << progressId << endl;
868 UIServer_stub uiserver(
"tdeio_uiserver",
"UIServer" );
870 uiserver.setJobVisible( progressId,
false );
872 TQDataStream stream(params, IO_WriteOnly);
874 if (
metaData(
"no-auth-prompt").lower() ==
"true")
875 stream << info << TQString(
"<NoAuthPrompt>") << windowId << s_seqNr << userTimestamp;
877 stream << info << errorMsg << windowId << s_seqNr << userTimestamp;
879 bool callOK = d->dcopClient->call(
"kded",
"kpasswdserver",
"queryAuthInfo(TDEIO::AuthInfo, TQString, long int, long int, unsigned long int)",
880 params, replyType, reply );
883 uiserver.setJobVisible( progressId,
true );
887 kdWarning(7019) <<
"Can't communicate with kded_kpasswdserver (openPassDlg)!" << endl;
891 if ( replyType ==
"TDEIO::AuthInfo" )
893 TQDataStream stream2( reply, IO_ReadOnly );
894 stream2 >> authResult >> s_seqNr;
898 kdError(7019) <<
"DCOP function queryAuthInfo(...) returns "
899 << replyType <<
", expected TDEIO::AuthInfo" << endl;
908 kdDebug(7019) <<
"SlaveBase::openPassDlg: username=" << info.
username << endl;
909 kdDebug(7019) <<
"SlaveBase::openPassDlg: password=[hidden]" << endl;
915 const TQString &buttonYes,
const TQString &buttonNo )
917 return messageBox( text, type, caption, buttonYes, buttonNo, TQString::null );
921 const TQString &buttonYes,
const TQString &buttonNo,
const TQString &dontAskAgainName )
923 kdDebug(7019) <<
"messageBox " << type <<
" " << text <<
" - " << caption << buttonYes << buttonNo << endl;
924 TDEIO_DATA << (TQ_INT32)type << text << caption << buttonYes << buttonNo << dontAskAgainName;
925 m_pConnection->
send( INF_MESSAGEBOX, data );
928 TQDataStream stream( data, IO_ReadOnly );
931 kdDebug(7019) <<
"got messagebox answer" << answer << endl;
939 kdDebug(7019) <<
"SlaveBase::canResume offset=" <<
TDEIO::number(offset) << endl;
940 d->needSendCanResume =
false;
941 TDEIO_DATA << TDEIO_FILESIZE_T(offset);
942 m_pConnection->
send( MSG_RESUME, data );
946 if (
waitForAnswer( CMD_RESUMEANSWER, CMD_NONE, data, &cmd ) != -1 )
948 kdDebug(7019) <<
"SlaveBase::canResume returning " << (cmd == CMD_RESUMEANSWER) << endl;
949 return cmd == CMD_RESUMEANSWER;
964 result = m_pConnection->
read( &cmd, data );
967 kdDebug(7019) <<
"SlaveBase::waitForAnswer has read error." << endl;
970 if ( cmd == expected1 || cmd == expected2 )
972 if ( pCmd ) *pCmd = cmd;
975 if ( isSubCommand(cmd) )
977 dispatch( cmd, data );
981 kdWarning() <<
"Got cmd " << cmd <<
" while waiting for an answer!" << endl;
997 d->timeout = time(0)+(time_t)timeout;
998 else if (timeout == 0)
1003 d->timeoutData =
data;
1006 void SlaveBase::dispatch(
int command,
const TQByteArray &data )
1008 TQDataStream stream( data, IO_ReadOnly );
1018 TQString host, user;
1019 stream >> host >> i >> user >> passwd;
1020 setHost( host, i, user, passwd );
1026 case CMD_DISCONNECT:
1029 case CMD_SLAVE_STATUS:
1032 case CMD_SLAVE_CONNECT:
1035 TQString app_socket;
1036 TQDataStream stream( data, IO_ReadOnly);
1037 stream >> app_socket;
1038 appconn->
send( MSG_SLAVE_ACK );
1040 mConnectedToApp =
true;
1043 case CMD_SLAVE_HOLD:
1046 TQDataStream stream( data, IO_ReadOnly);
1051 mConnectedToApp =
false;
1055 case CMD_REPARSECONFIGURATION:
1059 stream >> d->configData;
1060 #ifdef Q_OS_UNIX //TODO: not yet available on WIN32
1061 KSocks::setConfig(d->config);
1063 delete d->remotefile;
1074 TQ_INT8 iOverwrite, iResume;
1075 stream >> url >> iOverwrite >> iResume >> permissions;
1076 bool overwrite = ( iOverwrite != 0 );
1077 bool resume = ( iResume != 0 );
1082 d->needSendCanResume =
true ;
1084 put( url, permissions, overwrite, resume);
1106 stream >> url >> url2 >> iOverwrite;
1107 bool overwrite = (iOverwrite != 0);
1108 rename( url, url2, overwrite );
1114 stream >> target >> url >> iOverwrite;
1115 bool overwrite = (iOverwrite != 0);
1116 symlink( target, url, overwrite );
1123 stream >> url >> url2 >> permissions >> iOverwrite;
1124 bool overwrite = (iOverwrite != 0);
1125 copy( url, url2, permissions, overwrite );
1130 stream >> url >> isFile;
1131 del( url, isFile != 0);
1142 stream >> mIncomingMetaData;
1149 fprintf(stderr,
"Got unexpected CMD_NONE!\n");
1168 if( !url.isValid() )
1169 return TQString::null;
1172 TQString key = url.protocol();
1175 int port = url.port();
1190 int success = client.ping();
1193 success = client.startServer();
1196 kdDebug(7019) <<
"Cannot start a new deamon!!" << endl;
1199 kdDebug(7019) <<
"Sucessfully started new cache deamon!!" << endl;
1209 TQCString replyType;
1213 long windowId =
metaData(
"window-id").toLong();
1214 unsigned long userTimestamp =
metaData(
"user-timestamp").toULong();
1216 kdDebug(7019) <<
"SlaveBase::checkCachedAuthInfo window = " << windowId <<
" url = " << info.
url.url() << endl;
1220 TQDataStream stream(params, IO_WriteOnly);
1221 stream << info << windowId << userTimestamp;
1223 if ( !d->dcopClient->call(
"kded",
"kpasswdserver",
"checkAuthInfo(TDEIO::AuthInfo, long int, unsigned long int)",
1224 params, replyType, reply ) )
1226 kdWarning(7019) <<
"Can't communicate with kded_kpasswdserver (checkCachedAuthentication)!" << endl;
1230 if ( replyType ==
"TDEIO::AuthInfo" )
1232 TQDataStream stream2( reply, IO_ReadOnly );
1233 stream2 >> authResult;
1237 kdError(7019) <<
"DCOP function checkAuthInfo(...) returns "
1238 << replyType <<
", expected TDEIO::AuthInfo" << endl;
1253 long windowId =
metaData(
"window-id").toLong();
1257 TQDataStream stream(params, IO_WriteOnly);
1258 stream << info << windowId;
1260 d->dcopClient->send(
"kded",
"kpasswdserver",
"addAuthInfo(TDEIO::AuthInfo, long int)", params );
1268 TQString tmp =
metaData(
"ConnectTimeout");
1269 int result = tmp.toInt(&ok);
1272 return DEFAULT_CONNECT_TIMEOUT;
1278 TQString tmp =
metaData(
"ProxyConnectTimeout");
1279 int result = tmp.toInt(&ok);
1282 return DEFAULT_PROXY_CONNECT_TIMEOUT;
1289 TQString tmp =
metaData(
"ResponseTimeout");
1290 int result = tmp.toInt(&ok);
1293 return DEFAULT_RESPONSE_TIMEOUT;
1300 TQString tmp =
metaData(
"ReadTimeout");
1301 int result = tmp.toInt(&ok);
1304 return DEFAULT_READ_TIMEOUT;
1309 return d->wasKilled;
1317 void SlaveBase::virtual_hook(
int,
void* )