Add preliminary database connections to admin server

master
Timothy Pearson 12 years ago
parent 5e3618366d
commit b140795f1f

File diff suppressed because it is too large Load Diff

@ -56,12 +56,7 @@ struct exit_exception {
};
enum connectionStates {
StateIdle = 0,
StateGetFileSize = 1,
StateGetFileContents = 2,
StateStartProgramming = 3,
StateCheckProgrammingStatus = 4,
StateProgammingFinished = 5
StateIdle = 0
};
/*
@ -70,8 +65,7 @@ enum connectionStates {
instance of this class.
*/
SysCtlSocket::SysCtlSocket(int sock, TQObject *parent, const char *name) :
TDEKerberosServerSocket(parent, name), m_criticalSection(0), m_loopTimer(NULL), m_config(static_cast<SysCtlServer*>(parent)->m_config), m_commandLoopState(StateIdle),
m_progpipe(NULL), m_progpipefd(-1), m_progErrorFlag(false), m_progDoneFlag(false)
TDEKerberosServerSocket(parent, name), m_criticalSection(0), m_loopTimer(NULL), m_config(static_cast<SysCtlServer*>(parent)->m_config), m_terminals_database(NULL), m_workspaces_database(NULL), m_commandLoopState(StateIdle)
{
// Initialize timers
@ -85,6 +79,10 @@ SysCtlSocket::SysCtlSocket(int sock, TQObject *parent, const char *name) :
connect(this, SIGNAL(connectionClosed()), SLOT(connectionClosedHandler()));
connect(this, SIGNAL(connectionClosed()), parent, SLOT(remoteConnectionClosed()));
setSocket(sock);
if (connectToDatabase() != 0) {
exit(1);
}
}
SysCtlSocket::~SysCtlSocket() {
@ -168,7 +166,7 @@ void SysCtlSocket::commandLoop() {
try {
transferred_data = false;
if (state() == TQSocket::Connected) {
if ((m_commandLoopState == StateIdle) || (m_commandLoopState == StateStartProgramming) || (m_commandLoopState == StateCheckProgrammingStatus) || (m_commandLoopState == StateProgammingFinished)) {
if (m_commandLoopState == StateIdle) {
// Certain commands can come in at any time during some operations
if (canReadLine()) {
processPendingData();
@ -178,146 +176,89 @@ void SysCtlSocket::commandLoop() {
ds.setPrintableData(true);
TQString command;
ds >> command;
clearFrameTail();
if (command == "STATUS") {
if (m_logMessages != "") {
ds << TQString("LOGMESSAGES");
writeEndOfFrame();
ds << m_logMessages;
writeEndOfFrame();
m_logMessages = "";
}
else if (m_progErrorFlag) {
ds << TQString("ERROR");
m_progErrorFlag = false;
writeEndOfFrame();
}
else if (m_progDoneFlag) {
ds << TQString("DONE");
ds << m_progRetCode;
m_progDoneFlag = false;
writeEndOfFrame();
}
else if (m_commandLoopState == StateIdle) {
ds << TQString("IDLE");
if (command == "USERS") {
TQString subCommand;
ds >> subCommand;
if (subCommand == "TERMINALS") {
clearFrameTail();
TQSqlCursor databaseActivityCursor("sessions", TRUE, m_terminals_database);
databaseActivityCursor.select();
while (databaseActivityCursor.next()) {
TQ_UINT32 protocolVersion = 1;
TQDateTime loginStamp;
TQDateTime activityStamp;
loginStamp.setTime_t(databaseActivityCursor.value("stamp_start").toInt());
activityStamp.setTime_t(databaseActivityCursor.value("stamp_statechange").toInt());
ds << protocolVersion;
ds << databaseActivityCursor.value("pk").toInt();
ds << databaseActivityCursor.value("username").toString();
ds << databaseActivityCursor.value("servername").toString();
ds << databaseActivityCursor.value("server_pid").toInt();
ds << databaseActivityCursor.value("wm_pid").toInt();
ds << databaseActivityCursor.value("state").toInt();
ds << databaseActivityCursor.value("display").toInt();
ds << loginStamp;
ds << activityStamp;
}
writeEndOfFrame();
}
else if ((m_commandLoopState == StateStartProgramming) || (m_commandLoopState == StateCheckProgrammingStatus) || (m_commandLoopState == StateProgammingFinished)) {
ds << TQString("PROGRAMMING");
else if (subCommand == "WORKSPACES") {
clearFrameTail();
TQSqlCursor databaseActivityCursor("activity", TRUE, m_workspaces_database);
databaseActivityCursor.select();
while (databaseActivityCursor.next()) {
TQ_UINT32 protocolVersion = 1;
TQDateTime loginStamp;
loginStamp.setTime_t(databaseActivityCursor.value("logontime").toInt());
ds << protocolVersion;
ds << databaseActivityCursor.value("pk").toInt();
ds << databaseActivityCursor.value("station").toInt();
ds << databaseActivityCursor.value("username").toString();
ds << databaseActivityCursor.value("realmname").toString();
ds << databaseActivityCursor.value("serverid").toInt();
ds << loginStamp;
}
writeEndOfFrame();
}
else {
ds << TQString("UNKNOWN");
writeEndOfFrame();
clearFrameTail();
}
}
else if (m_commandLoopState == StateIdle) {
if (command == "FILE") {
m_commandLoopState = StateGetFileSize;
else if (command == "SESSION") {
TQString subCommand;
TQString sessionID;
ds >> subCommand;
ds >> sessionID;
if (subCommand == "LOGOFF_TERMINAL") {
TQ_UINT32 delay;
ds >> delay;
clearFrameTail();
// FIXME
}
else if (subCommand == "CANCEL_LOGOFF_TERMINAL") {
clearFrameTail();
// FIXME
}
else if (command == "PROGRAM") {
m_commandLoopState = StateStartProgramming;
else if (subCommand == "KILL_TERMINAL") {
clearFrameTail();
// FIXME
}
else if (subCommand == "KILL_WORKSPACE") {
clearFrameTail();
// FIXME
}
else {
printf("[WARNING] Received unknown command '%s'\n\r", command.ascii());
clearFrameTail();
}
}
transferred_data = true;
}
}
if (m_commandLoopState == StateGetFileSize) {
if (canReadLine()) {
processPendingData();
}
if (canReadFrame()) {
TQDataStream ds(this);
ds.setPrintableData(true);
ds >> m_programmingFileSize;
clearFrameTail();
m_servClientTimeout->start(NETWORK_COMM_TIMEOUT_MS, TRUE);
m_commandLoopState = StateGetFileContents;
}
}
else if (m_commandLoopState == StateGetFileContents) {
if (canReadLine()) {
m_servClientTimeout->start(NETWORK_COMM_TIMEOUT_MS, TRUE);
processPendingData();
}
if (bytesAvailable() >= m_programmingFileSize) {
TQByteArray fileContents(m_programmingFileSize);
readBlock(fileContents.data(), fileContents.size());
m_programmingFileName = TQString("/tmp/%1#%2.dat").arg(m_remoteHost).arg(port());
TQFile outputFile(m_programmingFileName);
if (outputFile.open(IO_ReadWrite)) {
outputFile.writeBlock(fileContents);
outputFile.flush();
outputFile.close();
else {
clearFrameTail();
}
transferred_data = true;
m_commandLoopState = StateIdle;
}
else {
if (!m_servClientTimeout->isActive()) {
m_progErrorFlag = true;
transferred_data = true;
m_commandLoopState = StateIdle;
}
}
}
else if (m_commandLoopState == StateStartProgramming) {
// Start programming!
// Open programming process
m_config->setGroup("Programming");
TQString programmingScript = m_config->readEntry("script");
programmingScript.replace("%f", m_programmingFileName);
if (!programmingScript.contains("2>&1")) {
programmingScript.append(" 2>&1");
}
if ((m_progpipe = popen(programmingScript.ascii(), "r")) == NULL) {
m_logMessages.append(TQString("The system was unable to execute '%1'\nPlease contact your system administrator with this information").arg(programmingScript));
m_progErrorFlag = true;
transferred_data = true;
m_commandLoopState = StateIdle;
}
else {
m_progpipefd = fileno(m_progpipe);
fcntl(m_progpipefd, F_SETFL, O_NONBLOCK);
}
m_commandLoopState = StateCheckProgrammingStatus;
}
else if (m_commandLoopState == StateCheckProgrammingStatus) {
// Check programming status
TQCString buf;
buf.resize(8192);
ssize_t r = read(m_progpipefd, buf.data(), buf.size());
if ((r == -1) && (errno == EAGAIN)) {
// No data available yet
}
else if (r > 0) {
// Data was received
buf.data()[r] = 0;
m_logMessages.append(buf);
}
else {
// Process terminated
m_commandLoopState = StateProgammingFinished;
}
}
else if (m_commandLoopState == StateProgammingFinished) {
// Programming process terminated; get exit code and clean up
if (m_progpipe) {
m_progRetCode = pclose(m_progpipe);
}
else {
m_progRetCode = -1;
}
m_progpipe = NULL;
m_progpipefd = -1;
m_progDoneFlag = true;
m_commandLoopState = StateIdle;
}
}
m_criticalSection--;
if (transferred_data) {
@ -344,13 +285,32 @@ int SysCtlSocket::enterCommandLoop() {
return 0;
}
int SysCtlSocket::connectToDatabase() {
if ((m_terminals_database) && (m_workspaces_database)) {
return -2;
}
m_terminals_database = TQSqlDatabase::database("terminals");
m_workspaces_database = TQSqlDatabase::database("workspaces");
if ((!m_terminals_database) || (!m_workspaces_database)) {
printf("[ERROR] Databases were not constructed by the application\n\r"); fflush(stdout);
return -1;
}
return 0;
}
/*
The SysCtlServer class handles new connections to the server. For every
client that connects, it creates a new SysCtlSocket -- that instance is now
responsible for the communication with that client.
*/
SysCtlServer::SysCtlServer(TQObject* parent, int port, KSimpleConfig* config) :
TQServerSocket( port, 1, parent ), m_config(config), m_numberOfConnections(0) {
TQServerSocket( port, 1, parent ), m_config(config), m_numberOfConnections(0), m_terminals_database(NULL), m_workspaces_database(NULL), m_sqlPingTimer(NULL) {
if (connectToDatabase() != 0) {
exit(1);
}
if ( !ok() ) {
printf("[ERROR] Failed to bind to port %d\n\r", port);
@ -361,7 +321,68 @@ SysCtlServer::SysCtlServer(TQObject* parent, int port, KSimpleConfig* config) :
}
SysCtlServer::~SysCtlServer() {
//
if (m_sqlPingTimer) {
m_sqlPingTimer->stop();
delete m_sqlPingTimer;
m_sqlPingTimer = NULL;
}
if (m_terminals_database) {
TQSqlDatabase::removeDatabase(m_terminals_database);
m_terminals_database = NULL;
}
if (m_workspaces_database) {
TQSqlDatabase::removeDatabase(m_workspaces_database);
m_workspaces_database = NULL;
}
}
int SysCtlServer::connectToDatabase() {
m_config->setGroup("Terminals Database");
m_terminals_database = TQSqlDatabase::addDatabase(m_config->readEntry("driver"), "terminals");
m_terminals_database->setDatabaseName(m_config->readEntry("database"));
m_terminals_database->setUserName(m_config->readEntry("username"));
m_terminals_database->setPassword(m_config->readEntry("password"));
m_terminals_database->setHostName(m_config->readEntry("server"));
if(!m_terminals_database->open()) {
printf("[ERROR] Failed to connect to control database on server '%s' [%s]\n\r", m_terminals_database->hostName().ascii(), m_terminals_database->lastError().text().ascii()); fflush(stdout);
TQSqlDatabase::removeDatabase(m_terminals_database);
m_terminals_database = NULL;
return -1;
}
m_config->setGroup("Workspaces Database");
m_workspaces_database = TQSqlDatabase::addDatabase(m_config->readEntry("driver"), "workspaces");
m_workspaces_database->setDatabaseName(m_config->readEntry("database"));
m_workspaces_database->setUserName(m_config->readEntry("username"));
m_workspaces_database->setPassword(m_config->readEntry("password"));
m_workspaces_database->setHostName(m_config->readEntry("server"));
if(!m_workspaces_database->open()) {
printf("[ERROR] Failed to connect to control database on server '%s' [%s]\n\r", m_workspaces_database->hostName().ascii(), m_workspaces_database->lastError().text().ascii()); fflush(stdout);
TQSqlDatabase::removeDatabase(m_workspaces_database);
m_workspaces_database = NULL;
return -1;
}
// FIXME
// We currently have no way to handle something as simple as the database server going offline!
// Start database ping process
m_sqlPingTimer = new TQTimer();
connect(m_sqlPingTimer, SIGNAL(timeout()), this, SLOT(pingSQLServer()));
m_sqlPingTimer->start(60*1000);
return 0;
}
void SysCtlServer::pingSQLServer() {
TQSqlQuery terminals_query(TQString::null, m_terminals_database);
terminals_query.exec("SELECT * FROM sessions");
TQSqlQuery workspaces_query(TQString::null, m_workspaces_database);
workspaces_query.exec("SELECT * FROM activity");
}
void SysCtlServer::newConnection(int socket) {

@ -28,6 +28,8 @@
#include <tqlabel.h>
#include <tqpushbutton.h>
#include <tqtextstream.h>
#include <tqsqldatabase.h>
#include <tqsqlcursor.h>
#include <ksimpleconfig.h>
@ -55,6 +57,7 @@ class SysCtlSocket : public TDEKerberosServerSocket
void finishKerberosHandshake();
void connectionClosedHandler();
void commandLoop();
int connectToDatabase();
private:
int line;
@ -66,18 +69,10 @@ class SysCtlSocket : public TDEKerberosServerSocket
TQTimer* m_servClientTimeout;
KSimpleConfig* m_config;
TQSqlDatabase* m_terminals_database;
TQSqlDatabase* m_workspaces_database;
int m_commandLoopState;
TQ_ULONG m_programmingFileSize;
TQString m_programmingFileName;
FILE *m_progpipe;
int m_progpipefd;
bool m_progErrorFlag;
bool m_progDoneFlag;
TQ_INT32 m_progRetCode;
TQString m_logMessages;
friend class SysCtlServer;
};
@ -93,6 +88,8 @@ class SysCtlServer : public TQServerSocket
private slots:
void remoteConnectionClosed();
int connectToDatabase();
void pingSQLServer();
signals:
void newConnect(SysCtlSocket*);
@ -100,6 +97,9 @@ class SysCtlServer : public TQServerSocket
private:
KSimpleConfig* m_config;
int m_numberOfConnections;
TQSqlDatabase* m_terminals_database;
TQSqlDatabase* m_workspaces_database;
TQTimer* m_sqlPingTimer;
friend class SysCtlSocket;

Loading…
Cancel
Save