Add logout timer to remote server and client

master
Timothy Pearson 12 years ago
parent b140795f1f
commit 9178fa8161

@ -29,12 +29,17 @@ using namespace std;
#include "views/instrumentview.h" #include "views/instrumentview.h"
#include "dialogs/selectserverdlg.h" #include "dialogs/selectserverdlg.h"
#define STATUSBAR_TIMEOUT_ID 5
RemoteMDI::RemoteMDI() RemoteMDI::RemoteMDI()
: KMdiMainFrm(0, "RemoteMDI", KMdi::ChildframeMode), m_children(0), m_rsvSvrSocket(NULL), connToServerConnecting(false), connToServerState(-1), connToServerTimeoutTimer(NULL) : KMdiMainFrm(0, "RemoteMDI", KMdi::ChildframeMode), m_children(0), m_rsvSvrSocket(NULL), connToServerConnecting(false), connToServerState(-1), connToServerTimeoutTimer(NULL)
{ {
setXMLFile("remotelabui.rc"); setXMLFile("remotelabui.rc");
setIcon(SmallIcon("remote_laboratory_client")); setIcon(SmallIcon("remote_laboratory_client"));
masterPollTimer = new TQTimer();
connect(masterPollTimer, SIGNAL(timeout()), this, SLOT(masterPoll()));
// Create some actions // Create some actions
KStdAction::close(this, SLOT(closeCurrent()), actionCollection()); KStdAction::close(this, SLOT(closeCurrent()), actionCollection());
KStdAction::quit(this, SLOT(close()), actionCollection()); KStdAction::quit(this, SLOT(close()), actionCollection());
@ -67,6 +72,10 @@ RemoteMDI::RemoteMDI()
// Create the status bar // Create the status bar
updateStatusBarMainMessage(i18n("No active instruments")); updateStatusBarMainMessage(i18n("No active instruments"));
KStatusBar* sb = statusBar();
if (sb) {
sb->insertItem(i18n("Unknown Time Remaining"), STATUSBAR_TIMEOUT_ID, 0, true);
}
processActions(); processActions();
@ -77,6 +86,11 @@ RemoteMDI::RemoteMDI()
RemoteMDI::~RemoteMDI() RemoteMDI::~RemoteMDI()
{ {
if (masterPollTimer) {
masterPollTimer->stop();
delete masterPollTimer;
}
while (m_pCurrentWindow) { while (m_pCurrentWindow) {
closeCurrent(); closeCurrent();
} }
@ -255,6 +269,7 @@ void RemoteMDI::finishConnectingToServer() {
} }
connToServerState = 3; connToServerState = 3;
connToServerConnecting = false; connToServerConnecting = false;
masterPollTimer->start(0, TRUE);
processLockouts(); processLockouts();
break; break;
} }
@ -263,6 +278,67 @@ void RemoteMDI::finishConnectingToServer() {
} }
} }
void RemoteMDI::masterPoll() {
// Query current termination timestamp
if (m_rsvSvrSocket) {
if (m_rsvSvrSocket->state() == TQSocket::Connected) {
TQDataStream ds(m_rsvSvrSocket);
ds.setPrintableData(true);
TQ_ULLONG terminationStamp;
long long currentStamp;
ds << TQString("TSTP");
m_rsvSvrSocket->writeEndOfFrame();
while (!m_rsvSvrSocket->canReadFrame()) {
tqApp->processEvents();
if (!m_rsvSvrSocket) {
masterPollTimer->start(1000, TRUE);
return;
}
}
ds >> terminationStamp;
m_rsvSvrSocket->clearFrameTail();
currentStamp = TQDateTime::currentDateTime().toTime_t();
KStatusBar* sb = statusBar();
if (sb) {
if (terminationStamp == 0) {
sb->changeItem(i18n("Unlimited Time Remaining"), STATUSBAR_TIMEOUT_ID);
}
else {
long long difference = terminationStamp - currentStamp;
int seconds = 0;
int minutes = 0;
int hours = 0;
int days = 0;
if (difference >= 0) {
days = (difference / 86400);
difference = difference - (days * 86400);
hours = (difference / 3600);
difference = difference - (hours * 3600);
minutes = (difference / 60);
difference = difference - (minutes * 60);
seconds = difference;
}
TQString differenceString;
if (days > 0) {
differenceString.append(i18n("%1 day(s), ").arg(days));
}
if ((days > 0) || (hours > 0)) {
differenceString.append(i18n("%1 hours(s), ").arg(hours));
}
if ((days > 0) || (hours > 0) || (minutes > 0)) {
differenceString.append(i18n("%1 minutes(s), ").arg(minutes));
}
differenceString.append(i18n("%1 seconds(s)").arg(seconds));
sb->changeItem(i18n("%1 Remaining").arg(differenceString), STATUSBAR_TIMEOUT_ID);
}
}
}
}
masterPollTimer->start(1000, TRUE);
}
void RemoteMDI::connectToServer() { void RemoteMDI::connectToServer() {
if (m_rsvSvrSocket) { if (m_rsvSvrSocket) {
if (m_rsvSvrSocket->state() != TQSocket::Idle) { if (m_rsvSvrSocket->state() != TQSocket::Idle) {
@ -394,6 +470,13 @@ void RemoteMDI::processLockouts() {
for (TQPtrList<KAction>::Iterator it(m_instrumentActionList.begin()); it != m_instrumentActionList.end(); ++it) { for (TQPtrList<KAction>::Iterator it(m_instrumentActionList.begin()); it != m_instrumentActionList.end(); ++it) {
(*it)->setEnabled(connected); (*it)->setEnabled(connected);
} }
if (!connected) {
KStatusBar* sb = statusBar();
if (sb) {
sb->changeItem(i18n("Unknown Time Remaining"), STATUSBAR_TIMEOUT_ID);
}
}
} }
void RemoteMDI::configToolbars() { void RemoteMDI::configToolbars() {

@ -69,6 +69,7 @@ class RemoteMDI : public KMdiMainFrm
void processLockouts(); void processLockouts();
void processActions(); void processActions();
void startModule(); void startModule();
void masterPoll();
protected: protected:
virtual bool queryClose(); virtual bool queryClose();
@ -86,6 +87,7 @@ class RemoteMDI : public KMdiMainFrm
bool connToServerConnecting; bool connToServerConnecting;
int connToServerState; int connToServerState;
TQTimer *connToServerTimeoutTimer; TQTimer *connToServerTimeoutTimer;
TQTimer *masterPollTimer;
KAction *connect_action; KAction *connect_action;
KAction *disconnect_action; KAction *disconnect_action;

@ -61,6 +61,10 @@ If BIND was previously commanded on this connection, the server must respond wit
Example: SERV EOF Example: SERV EOF
libremotelab_fpgaviewer EOF libremotelab_fpgaviewer EOF
TSTP:
Returns a long long value containing the termination timestamp, if set
If an administrator has enabled automatic termination of the client's session, a UNIX timestamp with the exact termination time must be returned. If automatic termination has not been enabled, the server must return zero.
QUIT: QUIT:
Gracefully terminates the connection. Gracefully terminates the connection.
The server should return the case-sensitive text "OK" and must immediately close all active connections for the current user. The server should return the case-sensitive text "OK" and must immediately close all active connections for the current user.

@ -181,6 +181,8 @@ void SysCtlSocket::commandLoop() {
ds >> subCommand; ds >> subCommand;
if (subCommand == "TERMINALS") { if (subCommand == "TERMINALS") {
clearFrameTail(); clearFrameTail();
ds << TQString("OK");
writeEndOfFrame();
TQSqlCursor databaseActivityCursor("sessions", TRUE, m_terminals_database); TQSqlCursor databaseActivityCursor("sessions", TRUE, m_terminals_database);
databaseActivityCursor.select(); databaseActivityCursor.select();
while (databaseActivityCursor.next()) { while (databaseActivityCursor.next()) {
@ -205,6 +207,8 @@ void SysCtlSocket::commandLoop() {
} }
else if (subCommand == "WORKSPACES") { else if (subCommand == "WORKSPACES") {
clearFrameTail(); clearFrameTail();
ds << TQString("OK");
writeEndOfFrame();
TQSqlCursor databaseActivityCursor("activity", TRUE, m_workspaces_database); TQSqlCursor databaseActivityCursor("activity", TRUE, m_workspaces_database);
databaseActivityCursor.select(); databaseActivityCursor.select();
while (databaseActivityCursor.next()) { while (databaseActivityCursor.next()) {
@ -224,6 +228,8 @@ void SysCtlSocket::commandLoop() {
} }
else { else {
clearFrameTail(); clearFrameTail();
ds << TQString("ERRINVCMD");
writeEndOfFrame();
} }
} }
else if (command == "SESSION") { else if (command == "SESSION") {
@ -235,22 +241,69 @@ void SysCtlSocket::commandLoop() {
TQ_UINT32 delay; TQ_UINT32 delay;
ds >> delay; ds >> delay;
clearFrameTail(); clearFrameTail();
// FIXME // FIXME UNIMPLEMENTED
ds << TQString("ERRINVCMD");
writeEndOfFrame();
} }
else if (subCommand == "CANCEL_LOGOFF_TERMINAL") { else if (subCommand == "CANCEL_LOGOFF_TERMINAL") {
clearFrameTail(); clearFrameTail();
// FIXME // FIXME UNIMPLEMENTED
ds << TQString("ERRINVCMD");
writeEndOfFrame();
} }
else if (subCommand == "KILL_TERMINAL") { else if (subCommand == "KILL_TERMINAL") {
clearFrameTail(); clearFrameTail();
// FIXME TQSqlCursor databaseActivityCursor("sessions", TRUE, m_terminals_database);
databaseActivityCursor.select(TQString("pk=%1").arg(sessionID));
if (databaseActivityCursor.next()) {
// Gather server information
TQString server_name = databaseActivityCursor.value("servername").toString();
int server_pid = databaseActivityCursor.value("server_pid").toInt();
// Kill server process
TQString command = TQString("ssh root@%1 'kill -9 %2'").arg(server_name).arg(server_pid);
if (system(command.ascii()) == 0) {
// Remove database entry
databaseActivityCursor.select(TQString("pk=%1").arg(sessionID));
if (databaseActivityCursor.next()) {
databaseActivityCursor.primeDelete();
databaseActivityCursor.del(true);
}
ds << TQString("OK");
}
else {
ds << TQString("ERRFAILED");
}
writeEndOfFrame();
}
else {
ds << TQString("ERRINVCMD");
}
writeEndOfFrame();
} }
else if (subCommand == "KILL_WORKSPACE") { else if (subCommand == "KILL_WORKSPACE") {
clearFrameTail(); clearFrameTail();
// FIXME TQSqlCursor databaseActivityCursor("activity", TRUE, m_workspaces_database);
databaseActivityCursor.select(TQString("pk=%1").arg(sessionID));
if (databaseActivityCursor.next()) {
databaseActivityCursor.select(TQString("pk=%1").arg(sessionID));
if (databaseActivityCursor.next()) {
TQSqlRecord *buffer = databaseActivityCursor.primeUpdate();
buffer->setValue("terminate", true);
databaseActivityCursor.update();
}
ds << TQString("OK");
writeEndOfFrame();
}
else {
ds << TQString("ERRINVCMD");
}
writeEndOfFrame();
} }
else { else {
clearFrameTail(); clearFrameTail();
ds << TQString("ERRINVCMD");
writeEndOfFrame();
} }
} }
else { else {

@ -41,7 +41,7 @@ struct exit_exception {
instance of this class. instance of this class.
*/ */
AuthSocket::AuthSocket(int sock, int serverID, TQObject *parent, const char *name) : AuthSocket::AuthSocket(int sock, int serverID, TQObject *parent, const char *name) :
TDEKerberosServerSocket(parent, name), m_criticalSection(0), m_stationID(-1), m_bound(false), m_serverID(serverID), m_servActive(false), m_servState(0), m_servClientSocket(NULL), m_servClientTimeout(NULL), m_loopTimer(NULL), m_config(static_cast<AuthServer*>(parent)->m_config), m_database(NULL), m_databaseStationsCursor(NULL), TDEKerberosServerSocket(parent, name), m_criticalSection(0), m_stationID(-1), m_bound(false), m_serviceID(0), m_serverID(serverID), m_terminationStamp(0), m_servActive(false), m_servState(0), m_servClientSocket(NULL), m_servClientTimeout(NULL), m_loopTimer(NULL), m_pollTimer(NULL), m_config(static_cast<AuthServer*>(parent)->m_config), m_database(NULL), m_databaseStationsCursor(NULL),
m_databaseServicesCursor(NULL), m_databaseServiceTypesCursor(NULL), m_databasePermissionsCursor(NULL), m_databaseActivityCursor(NULL) m_databaseServicesCursor(NULL), m_databaseServiceTypesCursor(NULL), m_databasePermissionsCursor(NULL), m_databaseActivityCursor(NULL)
{ {
@ -59,6 +59,10 @@ AuthSocket::AuthSocket(int sock, int serverID, TQObject *parent, const char *nam
if (connectToDatabase() != 0) { if (connectToDatabase() != 0) {
exit(1); exit(1);
} }
m_pollTimer = new TQTimer();
connect(m_pollTimer, SIGNAL(timeout()), this, SLOT(pollFlags()));
m_pollTimer->start(0, TRUE);
} }
AuthSocket::~AuthSocket() { AuthSocket::~AuthSocket() {
@ -67,6 +71,11 @@ AuthSocket::~AuthSocket() {
delete m_kerberosInitTimer; delete m_kerberosInitTimer;
m_kerberosInitTimer = NULL; m_kerberosInitTimer = NULL;
} }
if (m_pollTimer) {
m_pollTimer->stop();
delete m_pollTimer;
m_pollTimer = NULL;
}
if (m_loopTimer) { if (m_loopTimer) {
m_loopTimer->stop(); m_loopTimer->stop();
delete m_loopTimer; delete m_loopTimer;
@ -102,13 +111,11 @@ void AuthSocket::close() {
void AuthSocket::connectionClosedHandler() { void AuthSocket::connectionClosedHandler() {
printf("[DEBUG] Connection from %s closed\n\r", m_remoteHost.ascii()); printf("[DEBUG] Connection from %s closed\n\r", m_remoteHost.ascii());
if (m_bound) { // Update database
// Update database m_databaseActivityCursor->select(TQString("station='%1' AND username='%2' AND realmname='%3' AND serviceid=%4").arg(m_stationID).arg(m_authenticatedUserName).arg(m_authenticatedRealmName).arg(m_serviceID));
m_databaseActivityCursor->select(TQString("station='%1' AND username='%2' AND realmname='%3'").arg(m_stationID).arg(m_authenticatedUserName).arg(m_authenticatedRealmName)); if (m_databaseActivityCursor->next()) {
if (m_databaseActivityCursor->next()) { m_databaseActivityCursor->primeDelete();
m_databaseActivityCursor->primeDelete(); m_databaseActivityCursor->del(true);
m_databaseActivityCursor->del(true);
}
} }
if (m_criticalSection > 0) { if (m_criticalSection > 0) {
@ -321,6 +328,24 @@ int AuthSocket::servLoop() {
} }
} }
void AuthSocket::pollFlags() {
if ((m_bound) || (m_servActive)) {
long long timestamp = TQDateTime::currentDateTime().toTime_t();
m_databaseActivityCursor->select(TQString("station='%1' AND username='%2' AND realmname='%3' AND serviceid=%4").arg(m_stationID).arg(m_authenticatedUserName).arg(m_authenticatedRealmName).arg(m_serviceID));
if (m_databaseActivityCursor->next()) {
m_terminationStamp = m_databaseActivityCursor->value("terminate").toLongLong();
if (m_terminationStamp > 0) {
if (m_terminationStamp <= timestamp) {
printf("[DEBUG] Got termination request from database (%lld <= %lld)\n\r", m_terminationStamp, timestamp); fflush(stdout);
close();
}
}
}
}
m_pollTimer->start(1000, TRUE);
}
void AuthSocket::commandLoop() { void AuthSocket::commandLoop() {
bool transferred_data; bool transferred_data;
@ -447,6 +472,8 @@ void AuthSocket::commandLoop() {
buffer->setValue("realmname", m_authenticatedRealmName); buffer->setValue("realmname", m_authenticatedRealmName);
buffer->setValue("logontime", TQDateTime::currentDateTime().toTime_t()); buffer->setValue("logontime", TQDateTime::currentDateTime().toTime_t());
buffer->setValue("serverid", m_serverID); buffer->setValue("serverid", m_serverID);
buffer->setValue("serviceid", 0);
buffer->setValue("terminate", 0);
m_databaseActivityCursor->insert(); m_databaseActivityCursor->insert();
ds << TQString("OK"); ds << TQString("OK");
@ -465,7 +492,7 @@ void AuthSocket::commandLoop() {
clearFrameTail(); clearFrameTail();
printf("[DEBUG] SERV command parameter was %s from user %s@%s\n\r", libname.ascii(), m_authenticatedUserName.ascii(), m_authenticatedRealmName.ascii()); fflush(stdout); printf("[DEBUG] SERV command parameter was %s from user %s@%s\n\r", libname.ascii(), m_authenticatedUserName.ascii(), m_authenticatedRealmName.ascii()); fflush(stdout);
m_databaseActivityCursor->select(TQString("username='%1' AND realmname='%2'").arg(m_authenticatedUserName).arg(m_authenticatedRealmName)); m_databaseActivityCursor->select(TQString("username='%1' AND realmname='%2' AND serviceid=0").arg(m_authenticatedUserName).arg(m_authenticatedRealmName));
if (m_databaseActivityCursor->next()) { if (m_databaseActivityCursor->next()) {
m_stationID = m_databaseActivityCursor->value("station").toInt(); m_stationID = m_databaseActivityCursor->value("station").toInt();
} }
@ -497,6 +524,18 @@ void AuthSocket::commandLoop() {
m_srvServiceHostName = m_databaseServicesCursor->value("hostname").toString(); m_srvServiceHostName = m_databaseServicesCursor->value("hostname").toString();
m_srvServicePort = m_databaseServicesCursor->value("port").toInt(); m_srvServicePort = m_databaseServicesCursor->value("port").toInt();
// Update database
m_serviceID = sid;
TQSqlRecord *buffer = m_databaseActivityCursor->primeInsert();
buffer->setValue("station", m_stationID);
buffer->setValue("username", m_authenticatedUserName);
buffer->setValue("realmname", m_authenticatedRealmName);
buffer->setValue("logontime", TQDateTime::currentDateTime().toTime_t());
buffer->setValue("serverid", m_serverID);
buffer->setValue("serviceid", m_serviceID);
buffer->setValue("terminate", 0);
m_databaseActivityCursor->insert();
if (!m_servClientSocket) m_servClientSocket = new TDEKerberosClientSocket; if (!m_servClientSocket) m_servClientSocket = new TDEKerberosClientSocket;
m_servClientSocket->setServiceName("remotefpga"); m_servClientSocket->setServiceName("remotefpga");
@ -514,6 +553,10 @@ void AuthSocket::commandLoop() {
} }
} }
} }
else if (command == "TSTP") {
ds << m_terminationStamp;
writeEndOfFrame();
}
else { else {
ds << TQString("ERRINVCMD"); ds << TQString("ERRINVCMD");
writeEndOfFrame(); writeEndOfFrame();
@ -589,9 +632,9 @@ AuthServer::AuthServer(TQObject* parent) :
// Delete existing activity entries for this server ID // Delete existing activity entries for this server ID
TQSqlCursor databaseActivityCursor("activity", TRUE, m_database); TQSqlCursor databaseActivityCursor("activity", TRUE, m_database);
databaseActivityCursor.select(TQString("serverid='%1'").arg(m_serverID)); databaseActivityCursor.select(TQString("serverid='%1'").arg(m_serverID));
if (databaseActivityCursor.next()) { while (databaseActivityCursor.next()) {
databaseActivityCursor.primeDelete(); databaseActivityCursor.primeDelete();
databaseActivityCursor.del(true); databaseActivityCursor.del(false);
} }
if ( !ok() ) { if ( !ok() ) {

@ -60,6 +60,7 @@ class AuthSocket : public TDEKerberosServerSocket
void connectionClosedHandler(); void connectionClosedHandler();
void commandLoop(); void commandLoop();
int servLoop(); int servLoop();
void pollFlags();
private: private:
int line; int line;
@ -67,7 +68,9 @@ class AuthSocket : public TDEKerberosServerSocket
TQString m_remoteHost; TQString m_remoteHost;
int m_stationID; int m_stationID;
bool m_bound; bool m_bound;
int m_serviceID;
int m_serverID; int m_serverID;
TQ_ULLONG m_terminationStamp;
bool m_servActive; bool m_servActive;
int m_servState; int m_servState;
@ -78,6 +81,7 @@ class AuthSocket : public TDEKerberosServerSocket
TQTimer* m_kerberosInitTimer; TQTimer* m_kerberosInitTimer;
TQTimer* m_loopTimer; TQTimer* m_loopTimer;
TQTimer* m_pollTimer;
TQByteArray m_loopBuffer; TQByteArray m_loopBuffer;
KSimpleConfig* m_config; KSimpleConfig* m_config;

Loading…
Cancel
Save