summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTimothy Pearson <kb9vqf@pearsoncomputing.net>2012-07-07 16:23:30 -0500
committerTimothy Pearson <kb9vqf@pearsoncomputing.net>2012-07-07 16:23:30 -0500
commitfc455268a511d91113f59c04b50fa08b7c37b554 (patch)
treed61462c8a4496fa788875918dc4113162382962b
parent1b8ef84fb9f47b82d0da6fa6e1b9fe439bc6b05c (diff)
downloadulab-fc455268a511d91113f59c04b50fa08b7c37b554.tar.gz
ulab-fc455268a511d91113f59c04b50fa08b7c37b554.zip
Convert to frame based protocol
Finish FPGA programming server/client
-rw-r--r--clients/tde/src/app/remotemdi.cpp28
-rw-r--r--clients/tde/src/part/fpgaprogram/part.cpp206
-rw-r--r--clients/tde/src/part/fpgaprogram/part.h3
-rw-r--r--clients/tde/src/part/fpgaview/part.cpp31
-rw-r--r--lib/libtdekrb/src/tdekrbclientsocket.cpp47
-rw-r--r--lib/libtdekrb/src/tdekrbclientsocket.h5
-rw-r--r--lib/libtdekrb/src/tdekrbserversocket.cpp49
-rw-r--r--lib/libtdekrb/src/tdekrbserversocket.h5
-rw-r--r--lib/libtqtrla/src/tqtrla.cpp6
-rw-r--r--lib/libtqtrla/src/tqtrla.h1
-rw-r--r--protocol.txt21
-rw-r--r--servers/auth_server_lin/src/auth_conn.cpp32
-rw-r--r--servers/fpga_programming_server_lin/src/fpga_conn.cpp136
-rw-r--r--servers/fpga_programming_server_lin/src/fpga_conn.h7
-rw-r--r--servers/fpga_server_lin/src/fpga_conn.cpp2
15 files changed, 461 insertions, 118 deletions
diff --git a/clients/tde/src/app/remotemdi.cpp b/clients/tde/src/app/remotemdi.cpp
index eec5144..0ae6680 100644
--- a/clients/tde/src/app/remotemdi.cpp
+++ b/clients/tde/src/app/remotemdi.cpp
@@ -215,6 +215,8 @@ void RemoteMDI::finishConnectingToServer() {
KMessageBox::error(this, i18n("<qt>Unable to establish Kerberos protocol with remote server<p>Please verify that you currently hold a valid Kerberos ticket</qt>"), i18n("Connection Failed"));
}
else {
+ connect(m_rsvSvrSocket, SIGNAL(readyRead()), m_rsvSvrSocket, SLOT(processPendingData()));
+ m_rsvSvrSocket->processPendingData();
connToServerState = 2;
}
}
@@ -223,10 +225,18 @@ void RemoteMDI::finishConnectingToServer() {
// Connection established!
// Read magic number and proto version from server
TQDataStream* ds = new TQDataStream(m_rsvSvrSocket);
+ ds->setPrintableData(true);
+ while (!m_rsvSvrSocket->canReadFrame()) {
+ tqApp->processEvents();
+ if (!m_rsvSvrSocket) {
+ return;
+ }
+ }
TQ_UINT32 magicnum;
TQ_UINT32 protover;
*ds >> magicnum;
*ds >> protover;
+ m_rsvSvrSocket->clearFrameTail();
printf("[DEBUG] Got magic number %d and protocol version %d\n\r", magicnum, protover); fflush(stdout);
delete ds;
if ((magicnum == MAGIC_NUMBER) && (protover == PROTOCOL_VERSION)) {
@@ -285,11 +295,20 @@ void RemoteMDI::promptForStationType() {
}
TQDataStream ds(m_rsvSvrSocket);
+ ds.setPrintableData(true);
// Request list of laboratory stations
StationList slist;
ds << TQString("LIST");
+ m_rsvSvrSocket->writeEndOfFrame();
+ while (!m_rsvSvrSocket->canReadFrame()) {
+ tqApp->processEvents();
+ if (!m_rsvSvrSocket) {
+ return;
+ }
+ }
ds >> slist;
+ m_rsvSvrSocket->clearFrameTail();
printf("[RAJA DEBUG 200.2] Got list of stations, count is %d\n\r", slist.count()); fflush(stdout);
@@ -298,8 +317,17 @@ void RemoteMDI::promptForStationType() {
if (ret == KDialog::Accepted) {
TQString result;
ds << TQString("BIND");
+ m_rsvSvrSocket->writeEndOfFrame();
ds << select.m_selectedStation;
+ m_rsvSvrSocket->writeEndOfFrame();
+ while (!m_rsvSvrSocket->canReadFrame()) {
+ tqApp->processEvents();
+ if (!m_rsvSvrSocket) {
+ return;
+ }
+ }
ds >> result;
+ m_rsvSvrSocket->clearFrameTail();
printf("[RAJA DEBUG 100.0] '%s'\n\r", result.ascii()); fflush(stdout);
if (result == "OK") {
// Success!
diff --git a/clients/tde/src/part/fpgaprogram/part.cpp b/clients/tde/src/part/fpgaprogram/part.cpp
index d1a19df..f70ab49 100644
--- a/clients/tde/src/part/fpgaprogram/part.cpp
+++ b/clients/tde/src/part/fpgaprogram/part.cpp
@@ -26,6 +26,7 @@
#include <kaboutdata.h> //::createAboutData()
#include <kaction.h>
#include <klocale.h>
+#include <ktextedit.h>
#include <kmessagebox.h> //::start()
#include <kparts/genericfactory.h>
#include <kstatusbar.h>
@@ -89,6 +90,7 @@ FPGAProgramPart::FPGAProgramPart(TQWidget *parentWidget, const char *widgetName,
m_base = new FPGAProgramBase(widget());
// Initialize widgets
+ m_base->programmingLogBox->setReadOnly(true);
connect(m_base->programRunButton, SIGNAL(clicked()), this, SLOT(programRunButtonClicked()));
connect(m_base->programmingInputFile, SIGNAL(textChanged(const TQString &)), this, SLOT(processLockouts()));
@@ -229,17 +231,21 @@ void FPGAProgramPart::finishConnectingToServer() {
// Connection established!
// Read magic number and proto version from server
m_socket->processPendingData();
- if (m_socket->bytesAvailable() > 0) {
+ if (m_socket->canReadFrame()) {
TQDataStream ds(m_socket);
+ ds.setPrintableData(true);
TQ_UINT32 magicnum;
TQ_UINT32 protover;
ds >> magicnum;
ds >> protover;
+ m_socket->clearFrameTail();
printf("[DEBUG] Got magic number %d and protocol version %d\n\r", magicnum, protover); fflush(stdout);
// Request connection to backend server
ds << TQString("SERV");
+ m_socket->writeEndOfFrame();
ds << TQString(CLIENT_LIBRARY);
+ m_socket->writeEndOfFrame();
connToServerState = 3;
}
break;
@@ -248,8 +254,10 @@ void FPGAProgramPart::finishConnectingToServer() {
m_socket->processPendingData();
if (m_socket->bytesAvailable() > 0) {
TQDataStream ds(m_socket);
+ ds.setPrintableData(true);
TQString response;
ds >> response;
+ m_socket->clearFrameTail();
if (response == "OK") {
connToServerState = 4;
connToServerConnecting = false;
@@ -312,9 +320,7 @@ void FPGAProgramPart::programRunButtonClicked() {
m_tickerState = 0; \
m_commHandlerState = 0; \
m_commHandlerMode = 0; \
- while (m_socket->bytesAvailable() > 0) { \
- m_socket->readBlock(data, 64); \
- } \
+ m_socket->clearIncomingData(); \
setStatusMessage(i18n("Server ping timeout. Please verify the status of your network connection.")); \
m_updateTimeoutTimer->start(NETWORK_COMM_TIMEOUT_MS, TRUE); \
m_connectionMutex->unlock(); \
@@ -323,8 +329,33 @@ void FPGAProgramPart::programRunButtonClicked() {
#define SET_WATCHDOG_TIMER if (!m_updateTimeoutTimer->isActive()) m_updateTimeoutTimer->start(NETWORK_COMM_TIMEOUT_MS, TRUE);
#define PAT_WATCHDOG_TIMER m_updateTimeoutTimer->stop(); m_updateTimeoutTimer->start(NETWORK_COMM_TIMEOUT_MS, TRUE);
+void FPGAProgramPart::setTickerMessage(TQString message) {
+ m_connectionActiveAndValid = true;
+ TQString tickerChar;
+ switch (m_tickerState) {
+ case 0:
+ tickerChar = "-";
+ break;
+ case 1:
+ tickerChar = "\\";
+ break;
+ case 2:
+ tickerChar = "|";
+ break;
+ case 3:
+ tickerChar = "/";
+ break;
+ }
+ setStatusMessage(message + TQString("... %1").arg(tickerChar));
+ m_tickerState++;
+ if (m_tickerState > 3) {
+ m_tickerState = 0;
+ }
+}
+
void FPGAProgramPart::mainEventLoop() {
TQDataStream ds(m_socket);
+ ds.setPrintableData(true);
if (!m_connectionMutex->tryLock()) {
TQTimer::singleShot(0, this, SLOT(mainEventLoop())); // Handle the concurrently received call immediately after current execution
@@ -332,59 +363,49 @@ void FPGAProgramPart::mainEventLoop() {
}
if (m_socket) {
- char data[64];
-
if (m_commHandlerMode == 0) {
// Normal operation
switch (m_commHandlerState) {
case 0:
// Get status of remote system
- // RAJA FIXME
-
+ // Clear buffers to synchronize frames in case of data corruption
+ m_socket->clearIncomingData();
ds << TQString("STATUS");
+ m_socket->writeEndOfFrame();
m_commHandlerState = 1;
break;
case 1:
// Get all data
- if (m_socket->bytesAvailable() > 0) {
+ if (m_socket->canReadFrame()) {
PAT_WATCHDOG_TIMER
- // RAJA FIXME
TQString status;
ds >> status;
-
-printf("[RAJA DEBUG 106.0] Status: '%s'\n\r", status.ascii()); fflush(stdout);
+ m_socket->clearFrameTail();
if (status == "") {
// Transfer probably failed
UPDATEDISPLAY_TIMEOUT
}
-
- m_connectionActiveAndValid = true;
- TQString tickerChar;
- switch (m_tickerState) {
- case 0:
- tickerChar = "-";
- break;
- case 1:
- tickerChar = "\\";
- break;
- case 2:
- tickerChar = "|";
- break;
- case 3:
- tickerChar = "/";
- break;
+ else if (status == "IDLE") {
+ // Do nothing
}
- setStatusMessage(i18n("Running") + TQString("... %1").arg(tickerChar));
- m_tickerState++;
- if (m_tickerState > 3) {
- m_tickerState = 0;
+ else if (status == "LOGMESSAGES") {
+ // Fire next event loop immediately
+ TQTimer::singleShot(0, this, SLOT(mainEventLoop()));
+ // Retrieve messages on next event loop
+ m_commHandlerState = 3;
+ m_commHandlerNextState = 2;
+ m_commHandlerNextMode = 0;
}
- m_pingDelayTimer->start(250, TRUE);
- m_commHandlerState = 2;
+ setTickerMessage(i18n("Connected"));
+
+ if (m_commHandlerState == 1) {
+ m_pingDelayTimer->start(250, TRUE);
+ m_commHandlerState = 2;
+ }
}
else {
if (!m_updateTimeoutTimer->isActive()) {
@@ -393,6 +414,7 @@ printf("[RAJA DEBUG 106.0] Status: '%s'\n\r", status.ascii()); fflush(stdout);
}
break;
case 2:
+ // Let the client and server rest for a bit to lower CPU/network overhead
if (!m_pingDelayTimer->isActive()) {
// Fire next event loop immediately
TQTimer::singleShot(0, this, SLOT(mainEventLoop()));
@@ -401,11 +423,37 @@ printf("[RAJA DEBUG 106.0] Status: '%s'\n\r", status.ascii()); fflush(stdout);
}
PAT_WATCHDOG_TIMER
break;
+ case 3:
+ // Get new log messages
+ if (m_socket->canReadFrame()) {
+ PAT_WATCHDOG_TIMER
+
+ TQString messages;
+ ds >> messages;
+ m_socket->clearFrameTail();
+
+ if (messages == "") {
+ // Transfer probably failed
+ UPDATEDISPLAY_TIMEOUT
+ }
+ else {
+ m_base->programmingLogBox->append(messages);
+
+ m_pingDelayTimer->start(250, TRUE);
+ m_commHandlerState = m_commHandlerNextState;
+ m_commHandlerMode = m_commHandlerNextMode;
+ }
+ }
+ else {
+ if (!m_updateTimeoutTimer->isActive()) {
+ UPDATEDISPLAY_TIMEOUT
+ }
+ }
+ break;
}
}
else if (m_commHandlerMode == 1) {
// Program mode!
- // RAJA FIXME
if (m_commHandlerState == 0) {
m_base->programmingStatusLabel->setText(i18n("Reading input file") + "...");
TQFile file(m_base->programmingInputFile->url());
@@ -413,15 +461,18 @@ printf("[RAJA DEBUG 106.0] Status: '%s'\n\r", status.ascii()); fflush(stdout);
m_programmingFileData = file.readAll();
file.close();
+ // Busy indicator
m_base->programmingProgressBar->setTotalSteps(0);
m_base->programmingProgressBar->setProgress(0);
// Transmit file to remote server
m_base->programmingStatusLabel->setText(i18n("Sending data to server") + "...");
ds << TQString("FILE");
+ m_socket->writeEndOfFrame();
m_programmingFileTotalSize = m_programmingFileData.size();
m_programmingFileTransferredBytes = 0;
ds << m_programmingFileTotalSize;
+ m_socket->writeEndOfFrame();
m_base->programmingProgressBar->setTotalSteps(m_programmingFileTotalSize);
m_commHandlerState = 1;
@@ -430,16 +481,17 @@ printf("[RAJA DEBUG 106.0] Status: '%s'\n\r", status.ascii()); fflush(stdout);
KMessageBox::error(0, i18n("<qt>Unable to open selected programming file</qt>"), i18n("Program Failed"));
m_commHandlerMode = 0;
m_commHandlerState = 0;
- m_base->programmingProgressBar->setTotalSteps(1);
- m_base->programmingProgressBar->setProgress(0);
+ m_base->programmingProgressBar->reset();
processLockouts();
}
+ PAT_WATCHDOG_TIMER
}
else if (m_commHandlerState == 1) {
TQ_ULONG bytesLeft = (m_programmingFileTotalSize-m_programmingFileTransferredBytes);
TQ_ULONG bytesToTransfer = bytesLeft;
- if (bytesToTransfer > 512) {
- bytesToTransfer = 512;
+ TQ_ULONG maxTransferChunk = maximumSocketDataChunkSize();
+ if (bytesToTransfer > maxTransferChunk) {
+ bytesToTransfer = maxTransferChunk;
}
m_programmingFileTransferredBytes = m_programmingFileTransferredBytes + m_socket->writeBlock(m_programmingFileData.data()+m_programmingFileTransferredBytes, bytesToTransfer);
m_base->programmingProgressBar->setProgress(m_programmingFileTransferredBytes);
@@ -447,86 +499,108 @@ printf("[RAJA DEBUG 106.0] Status: '%s'\n\r", status.ascii()); fflush(stdout);
// Initiate programming
m_base->programmingStatusLabel->setText(i18n("Programming device") + "...");
ds << TQString("PROGRAM");
+ m_socket->writeEndOfFrame();
// Request status
ds << TQString("STATUS");
+ m_socket->writeEndOfFrame();
+
+ // Busy indicator
+ m_base->programmingProgressBar->setTotalSteps(0);
+ m_base->programmingProgressBar->setProgress(0);
m_commHandlerState = 2;
}
else {
+ setTickerMessage(i18n("Transmitting data"));
// Fire next event loop immediately
TQTimer::singleShot(0, this, SLOT(mainEventLoop()));
}
+ PAT_WATCHDOG_TIMER
}
else if (m_commHandlerState == 2) {
// Get response
- if (m_socket->bytesAvailable() > 0) {
+ if (m_socket->canReadFrame()) {
PAT_WATCHDOG_TIMER
- // RAJA FIXME
TQString result;
ds >> result;
+ m_socket->clearFrameTail();
if (result == "PROGRAMMING") {
+ setTickerMessage(i18n("Programming device"));
// Request status
ds << TQString("STATUS");
+ m_socket->writeEndOfFrame();
+ }
+ else if (result == "LOGMESSAGES") {
+ // Fire next event loop immediately
+ TQTimer::singleShot(0, this, SLOT(mainEventLoop()));
+ // Retrieve messages on next event loop
+ m_commHandlerState = 3;
+ m_commHandlerMode = 0;
+ m_commHandlerNextState = 3;
+ m_commHandlerNextMode = 1;
}
else if (result == "DONE") {
- int retCode;
+ TQ_INT32 retCode;
TQString log;
ds >> retCode;
- ds >> log;
+ m_socket->clearFrameTail();
- // RAJA FIXME
- // Handle errors
- // This does not update the log as it should!
- if (retCode < 0) {
+ if (retCode != 0) {
// Error!
m_commHandlerMode = 0;
m_commHandlerState = 0;
TQTimer::singleShot(0, this, SLOT(mainEventLoop()));
- m_base->programmingProgressBar->setTotalSteps(1);
- m_base->programmingProgressBar->setProgress(0);
+ m_base->programmingProgressBar->reset();
KMessageBox::error(0, i18n("<qt>Programming process failure<p>Please see log for details</qt>"), i18n("Program Failed"));
processLockouts();
}
-
- // Done!
- m_commHandlerMode = 0;
- m_commHandlerState = 0;
- TQTimer::singleShot(0, this, SLOT(mainEventLoop()));
- m_base->programmingProgressBar->setTotalSteps(1);
- m_base->programmingProgressBar->setProgress(0);
- processLockouts();
- }
- else if (result == "") {
- // Transfer probably failed
- // Do nothing
+ else {
+ // Done!
+ m_commHandlerMode = 0;
+ m_commHandlerState = 0;
+ TQTimer::singleShot(0, this, SLOT(mainEventLoop()));
+ m_base->programmingProgressBar->reset();
+ processLockouts();
+ }
}
- else {
+ else if (result == "ERROR") {
// Error!
m_commHandlerMode = 0;
m_commHandlerState = 0;
TQTimer::singleShot(0, this, SLOT(mainEventLoop()));
- m_base->programmingProgressBar->setTotalSteps(1);
- m_base->programmingProgressBar->setProgress(0);
+ m_base->programmingProgressBar->reset();
KMessageBox::error(0, i18n("<qt>Unknown error</qt>"), i18n("Program Failed"));
processLockouts();
}
+ else {
+ // Unknown response
+ // Request status
+ ds << TQString("STATUS");
+ m_socket->writeEndOfFrame();
+ }
}
else {
if (!m_updateTimeoutTimer->isActive()) {
m_commHandlerMode = 0;
m_commHandlerState = 0;
TQTimer::singleShot(0, this, SLOT(mainEventLoop()));
- m_base->programmingProgressBar->setTotalSteps(1);
- m_base->programmingProgressBar->setProgress(0);
+ m_base->programmingProgressBar->reset();
processLockouts();
UPDATEDISPLAY_TIMEOUT
}
}
}
+ else if (m_commHandlerState == 3) {
+ // Request status
+ ds << TQString("STATUS");
+ m_socket->writeEndOfFrame();
+ m_commHandlerState = 2;
+ PAT_WATCHDOG_TIMER
+ }
}
SET_WATCHDOG_TIMER
diff --git a/clients/tde/src/part/fpgaprogram/part.h b/clients/tde/src/part/fpgaprogram/part.h
index 05f3431..db74e62 100644
--- a/clients/tde/src/part/fpgaprogram/part.h
+++ b/clients/tde/src/part/fpgaprogram/part.h
@@ -72,6 +72,7 @@ namespace RemoteLab
void connectionClosed();
void disconnectFromServer();
void finishConnectingToServer();
+ void setTickerMessage(TQString message);
void programRunButtonClicked();
@@ -89,6 +90,8 @@ namespace RemoteLab
int m_commHandlerState;
int m_commHandlerMode;
+ int m_commHandlerNextState;
+ int m_commHandlerNextMode;
bool m_connectionActiveAndValid;
unsigned char m_tickerState;
TQByteArray m_programmingFileData;
diff --git a/clients/tde/src/part/fpgaview/part.cpp b/clients/tde/src/part/fpgaview/part.cpp
index e4a56d4..7ac5dbf 100644
--- a/clients/tde/src/part/fpgaview/part.cpp
+++ b/clients/tde/src/part/fpgaview/part.cpp
@@ -1061,17 +1061,21 @@ void FPGAViewPart::finishConnectingToServer() {
// Connection established!
// Read magic number and proto version from server
m_socket->processPendingData();
- if (m_socket->bytesAvailable() > 0) {
+ if (m_socket->canReadFrame()) {
TQDataStream ds(m_socket);
+ ds.setPrintableData(true);
TQ_UINT32 magicnum;
TQ_UINT32 protover;
ds >> magicnum;
ds >> protover;
+ m_socket->clearFrameTail();
printf("[DEBUG] Got magic number %d and protocol version %d\n\r", magicnum, protover); fflush(stdout);
// Request connection to backend server
ds << TQString("SERV");
+ m_socket->writeEndOfFrame();
ds << TQString(CLIENT_LIBRARY);
+ m_socket->writeEndOfFrame();
connToServerState = 3;
}
break;
@@ -1080,8 +1084,10 @@ void FPGAViewPart::finishConnectingToServer() {
m_socket->processPendingData();
if (m_socket->bytesAvailable() > 0) {
TQDataStream ds(m_socket);
+ ds.setPrintableData(true);
TQString response;
ds >> response;
+ m_socket->clearFrameTail();
printf("[RAJA DEBUG 400.0] Got '%s' from the server\n\r", response.ascii()); fflush(stdout);
if (response == "OK") {
connToServerState = 4;
@@ -1332,7 +1338,7 @@ void FPGAViewPart::updateDisplay() {
KMessageBox::error(0, i18n("<qt>Unable to open selected batch output file</qt>"), i18n("Batch Failed"));
m_commHandlerMode = 0;
m_commHandlerState = 0;
- m_base->batchTestProgressBar->setProgress(0);
+ m_base->batchTestProgressBar->reset();
processLockouts();
}
}
@@ -1340,7 +1346,7 @@ void FPGAViewPart::updateDisplay() {
KMessageBox::error(0, i18n("<qt>Unable to open selected batch input file</qt>"), i18n("Batch Failed"));
m_commHandlerMode = 0;
m_commHandlerState = 0;
- m_base->batchTestProgressBar->setProgress(0);
+ m_base->batchTestProgressBar->reset();
processLockouts();
}
}
@@ -1353,7 +1359,7 @@ void FPGAViewPart::updateDisplay() {
m_batchOutputFile = NULL;
m_commHandlerMode = 0;
m_commHandlerState = 0;
- m_base->batchTestProgressBar->setProgress(0);
+ m_base->batchTestProgressBar->reset();
processLockouts();
}
else {
@@ -1403,7 +1409,7 @@ void FPGAViewPart::updateDisplay() {
m_batchOutputFile->close();
delete m_batchOutputFile;
m_batchOutputFile = NULL;
- m_base->batchTestProgressBar->setProgress(0);
+ m_base->batchTestProgressBar->reset();
m_commHandlerMode = 0;
m_commHandlerState = 0;
processLockouts();
@@ -1476,8 +1482,7 @@ void FPGAViewPart::updateDisplay() {
KMessageBox::error(0, i18n("<qt>Unable to open selected data output file</qt>"), i18n("Data Processing Failed"));
m_commHandlerMode = 0;
m_commHandlerState = 0;
- m_base->dataProcessingProgressBar->setTotalSteps(1);
- m_base->dataProcessingProgressBar->setProgress(0);
+ m_base->dataProcessingProgressBar->reset();
processLockouts();
}
}
@@ -1485,8 +1490,7 @@ void FPGAViewPart::updateDisplay() {
KMessageBox::error(0, i18n("<qt>Selected data input file exceeds the maximum allowed size of 16,384 bytes</qt>"), i18n("Data Processing Failed"));
m_commHandlerMode = 0;
m_commHandlerState = 0;
- m_base->dataProcessingProgressBar->setTotalSteps(1);
- m_base->dataProcessingProgressBar->setProgress(0);
+ m_base->dataProcessingProgressBar->reset();
processLockouts();
}
}
@@ -1494,8 +1498,7 @@ void FPGAViewPart::updateDisplay() {
KMessageBox::error(0, i18n("<qt>Unable to open selected data input file</qt>"), i18n("Data Processing Failed"));
m_commHandlerMode = 0;
m_commHandlerState = 0;
- m_base->dataProcessingProgressBar->setTotalSteps(1);
- m_base->dataProcessingProgressBar->setProgress(0);
+ m_base->dataProcessingProgressBar->reset();
processLockouts();
}
}
@@ -1546,8 +1549,7 @@ void FPGAViewPart::updateDisplay() {
m_dataOutputFile->close();
delete m_dataOutputFile;
m_dataOutputFile = NULL;
- m_base->dataProcessingProgressBar->setTotalSteps(1);
- m_base->dataProcessingProgressBar->setProgress(0);
+ m_base->dataProcessingProgressBar->reset();
m_commHandlerMode = 0;
m_commHandlerState = 0;
processLockouts();
@@ -1558,8 +1560,7 @@ void FPGAViewPart::updateDisplay() {
m_dataOutputFile->close();
delete m_dataOutputFile;
m_dataOutputFile = NULL;
- m_base->dataProcessingProgressBar->setTotalSteps(1);
- m_base->dataProcessingProgressBar->setProgress(0);
+ m_base->dataProcessingProgressBar->reset();
m_commHandlerMode = 0;
m_commHandlerState = 0;
processLockouts();
diff --git a/lib/libtdekrb/src/tdekrbclientsocket.cpp b/lib/libtdekrb/src/tdekrbclientsocket.cpp
index 02bee4d..9e9a27a 100644
--- a/lib/libtdekrb/src/tdekrbclientsocket.cpp
+++ b/lib/libtdekrb/src/tdekrbclientsocket.cpp
@@ -204,7 +204,7 @@ bool TDEKerberosClientSocket::atEnd() const {
bool ret;
if (kerberosStatus() == KerberosInUse) {
- ret = TQSocket::atEnd();
+ ret = ((m_bufferLength < 1) && TQSocket::atEnd());
}
else {
ret = TQSocket::atEnd();
@@ -710,6 +710,51 @@ bool TDEKerberosClientSocket::canReadData() {
return (TQSocket::canReadLine() || (m_bufferLength > 0));
}
+void TDEKerberosClientSocket::clearIncomingData() {
+ char data[64];
+ processPendingData();
+ while (canReadData()) {
+ readBlock(data, 64);
+ }
+}
+
+int TDEKerberosClientSocket::writeEndOfFrame() {
+ char data[1];
+ data[0] = 255;
+ return writeBlock(data, 1);
+}
+
+bool TDEKerberosClientSocket::canReadFrame() {
+ processPendingData();
+ if (m_buffer->buffer().contains(255) > 0) {
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+void TDEKerberosClientSocket::clearFrameTail() {
+ int i;
+ int eofLoc;
+ if (m_bufferLength > 0) {
+ eofLoc = m_buffer->buffer().find(255, 0) + 1;
+ if ((eofLoc > 0) && (eofLoc <= m_bufferLength)) {
+ // Remove the remaining frame bytes (including the End of Frame marker) from the buffer
+ m_bufferLength = m_bufferLength-eofLoc;
+ TQByteArray ba = m_buffer->buffer();
+ for (i=0; i<m_bufferLength;i++) {
+ ba[i] = ba[i+eofLoc];
+ }
+ if (m_bufferLength < 1) {
+ // Clear the buffer from memory
+ m_buffer->close();
+ m_buffer->open(IO_ReadWrite|IO_Truncate);
+ }
+ }
+ }
+}
+
void TDEKerberosClientSocket::setStatusMessage(TQString message) {
if (message != m_prevStatusMessage) {
emit(statusMessageUpdated(message));
diff --git a/lib/libtdekrb/src/tdekrbclientsocket.h b/lib/libtdekrb/src/tdekrbclientsocket.h
index 8fa2b25..a9034f0 100644
--- a/lib/libtdekrb/src/tdekrbclientsocket.h
+++ b/lib/libtdekrb/src/tdekrbclientsocket.h
@@ -71,6 +71,11 @@ class TDEKerberosClientSocket : public TQSocket
KerberosStatus kerberosStatus() const;
bool canReadData();
+ void clearIncomingData();
+
+ int writeEndOfFrame();
+ bool canReadFrame();
+ void clearFrameTail();
public slots:
int processPendingData();
diff --git a/lib/libtdekrb/src/tdekrbserversocket.cpp b/lib/libtdekrb/src/tdekrbserversocket.cpp
index 86c4212..f715af8 100644
--- a/lib/libtdekrb/src/tdekrbserversocket.cpp
+++ b/lib/libtdekrb/src/tdekrbserversocket.cpp
@@ -204,8 +204,8 @@ bool TDEKerberosServerSocket::at(TQIODevice::Offset off, int hidebasehack) {
bool TDEKerberosServerSocket::atEnd() const {
bool ret;
- if (m_kerberosRequested) {
- ret = TQSocket::atEnd();
+ if (kerberosStatus() == KerberosInUse) {
+ ret = ((m_bufferLength < 1) && TQSocket::atEnd());
}
else {
ret = TQSocket::atEnd();
@@ -719,6 +719,51 @@ bool TDEKerberosServerSocket::canReadData() {
return (TQSocket::canReadLine() || (m_bufferLength > 0));
}
+void TDEKerberosServerSocket::clearIncomingData() {
+ char data[64];
+ processPendingData();
+ while (canReadData()) {
+ readBlock(data, 64);
+ }
+}
+
+int TDEKerberosServerSocket::writeEndOfFrame() {
+ char data[1];
+ data[0] = 255;
+ return writeBlock(data, 1);
+}
+
+bool TDEKerberosServerSocket::canReadFrame() {
+ processPendingData();
+ if (m_buffer->buffer().contains(255) > 0) {
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+void TDEKerberosServerSocket::clearFrameTail() {
+ int i;
+ int eofLoc;
+ if (m_bufferLength > 0) {
+ eofLoc = m_buffer->buffer().find(255, 0) + 1;
+ if ((eofLoc > 0) && (eofLoc <= m_bufferLength)) {
+ // Remove the remaining frame bytes (including the End of Frame marker) from the buffer
+ m_bufferLength = m_bufferLength-eofLoc;
+ TQByteArray ba = m_buffer->buffer();
+ for (i=0; i<m_bufferLength;i++) {
+ ba[i] = ba[i+eofLoc];
+ }
+ if (m_bufferLength < 1) {
+ // Clear the buffer from memory
+ m_buffer->close();
+ m_buffer->open(IO_ReadWrite|IO_Truncate);
+ }
+ }
+ }
+}
+
void TDEKerberosServerSocket::setStatusMessage(TQString message) {
if (message != m_prevStatusMessage) {
emit(statusMessageUpdated(message));
diff --git a/lib/libtdekrb/src/tdekrbserversocket.h b/lib/libtdekrb/src/tdekrbserversocket.h
index 0394b49..1f4b4ff 100644
--- a/lib/libtdekrb/src/tdekrbserversocket.h
+++ b/lib/libtdekrb/src/tdekrbserversocket.h
@@ -71,6 +71,11 @@ class TDEKerberosServerSocket : public TQSocket
KerberosStatus kerberosStatus() const;
bool canReadData();
+ void clearIncomingData();
+
+ int writeEndOfFrame();
+ bool canReadFrame();
+ void clearFrameTail();
public slots:
int processPendingData();
diff --git a/lib/libtqtrla/src/tqtrla.cpp b/lib/libtqtrla/src/tqtrla.cpp
index d43c1f2..376a9d9 100644
--- a/lib/libtqtrla/src/tqtrla.cpp
+++ b/lib/libtqtrla/src/tqtrla.cpp
@@ -80,6 +80,12 @@ namespace KParts
emit(statusMessageSet(message));
}
+ TQ_ULONG RemoteInstrumentPart::maximumSocketDataChunkSize() {
+ // FIXME
+ // Dynamically set this!
+ return 512;
+ }
+
TQStringList RemoteInstrumentPart::textForServerError(TQString shortError) {
TQStringList ret;
diff --git a/lib/libtqtrla/src/tqtrla.h b/lib/libtqtrla/src/tqtrla.h
index 1f1ca22..c1c88e2 100644
--- a/lib/libtqtrla/src/tqtrla.h
+++ b/lib/libtqtrla/src/tqtrla.h
@@ -52,6 +52,7 @@ namespace KParts
protected:
TQStringList textForServerError(TQString shortError);
+ TQ_ULONG maximumSocketDataChunkSize();
protected slots:
void close();
diff --git a/protocol.txt b/protocol.txt
index 33df834..dda7c2d 100644
--- a/protocol.txt
+++ b/protocol.txt
@@ -9,10 +9,12 @@ The remote laboratory architecture is highly modularized, with the client contai
The client container itself must initiate the first connection and negotiate access to the requested type of laboratory resources, including prompting the user with a list of available resource types. Once the client container has established a connection, the client modules may connect to the master server and will receive stream access to the appropriate backend server daemon. If a client module attempts to connect to the master server when a container connection is not open, the server must reject the connection.
-Negotation and master control protocols must use TQDataStream to serialize and deserialize commands and responses, while client modules and their associated server daemons may choose to implement any binary or text-based communication protocol required for the specific application. The use of TQDataStream is strongly suggested where possible to maintain codebase consistency.
+Negotation and master control protocols must use a TQDataStream in printable (7-bit) mode to serialize and deserialize commands and responses, while client modules and their associated server daemons may choose to implement any binary or text-based communication protocol required for the specific application. The use of TQDataStream is strongly suggested where possible to maintain codebase consistency.
Due to the block encryption used by Kerberos, stream block delimeters are required at the transfer layer. The delimeter must be a single newline character, 0xD ('\n'), and will indicate the end of a block has been reached; therefore, the block is ready for decryption and processing. All block transfers must use Base64 encoding, and the encoded block text must not contain the newline character.
+Furthermore, to ensure robust command processing, the master server utilizes a frame-based protocol, with a single character of value 255 indicating the end of a frame. The value 255 is therefore reserved and must not appear in data transmitted to or from the master server, except when used to indicate the end of a frame. The three-character abbreviation EOF will be used to refer to this frame termination character within this document.
+
==================================================================================
Master Server
==================================================================================
@@ -22,6 +24,7 @@ The master server acts as a semi-transparent communications relay between the cl
On initial connection from the client container, the master server must negotiate a successful Kerberos connection. Once this connection is established, the server must transmit the following data types:
TQ_UINT32 [magic number]
TQ_UINT32 [protocol version]
+EOF
The client may terminate the connection at any time, or provide invalid data to the server. If the server loses connection sync with the client or receives invalid data from the client, it must gracefully terminate the connection without interruption to connections from other users. If the client container connection is terminated, all other service connections for that user must also be terminated.
@@ -33,7 +36,7 @@ QUIT
If an invalid command is specified, the server should respond with a string containing the case-sensitive text "ERRINVCMD".
-The expected actions and/or data transmission/reception on receipt of a valid command are detailed below.
+The expected actions and/or data transmission/reception on receipt of a valid command are detailed below. Each value returned by the server must be followed with an EOF character.
LIST:
Returns a list of available laboratory stations
@@ -42,26 +45,30 @@ The server should return a TQValueList<StationType>, where StationType consists
Descriptions should be constructed from station service type flags as known to the master server, and multiple stations with identical resources should be consolidated to one station type ID and description. Station type IDs do not need to be universally unique, but must not conflict with other station type IDs. Subsequent commands may alter the station type ID mappings.
+Example: LIST EOF
+
BIND <StationType 'Type ID'>:
Connects to a specified laboratory station
If a station with the specified Service ID list is available, the server must mark that station as in use by the authenticated user, must return the case-sensitive text "OK", and should block all commands other than QUIT. If a station with the specified Service ID list is not available, the server must respond with a string containing the case-sensitive text "ERRUNAVAL" and must re-enter command mode. If the specified user is already connected to a laboratory station, the server must return the case-sensitive text "ERRPREVCN", and should block all commands other than QUIT.
-Example: BIND
- StationType
+Example: BIND EOF
+ StationType EOF
SERV <TQString 'Client Library Name'>
Requests a connection to the specified backend server on the laboratory station
If BIND was previously commanded on this connection, the server must respond with a string containing the case-sensitive text "ERRINVCMD". If no station has been reserved for this user via a call to BIND on an active connection, the server must respond with a string containing the case-sensitive text "ERRNOCONN". If the backend server is not available, i.e. a connection attempt or attempts have failed to establish a connection, the server should respond with the string "ERRNOTAVL" and must close the client connection. If the backend service is not available in the active laboratory workspace, the server should respond with the string "ERRNOSERV" and must close the client connection. Otherwise, the server must return a string containing the case-sensitive text "OK" and then immediately enter binary pass-through mode between the backend server and the client.
-Example: SERV
- libremotelab_fpgaviewer
+Example: SERV EOF
+ libremotelab_fpgaviewer EOF
QUIT:
Gracefully terminates the connection.
The server should return the case-sensitive text "OK" and must immediately close all active connections for the current user.
+Example: QUIT EOF
+
==================================================================================
Backend Server
==================================================================================
-On initial connection from the client container, the master server must negotiate a successful Kerberos connection. Once this connection is established, the server must transmit a string containing the case-sensitive text "OK". The server has now fully established a secure bidirectional channel to the client and may proceeed to use the channel for any purpose. If the server wishes to reject the connection, for example due to a hardware failure, it must transmit a string containing the case-sensitive text "ERRNOTAVL", after which the server should close the client connection. \ No newline at end of file
+On initial connection from the client container, the master server must negotiate a successful Kerberos connection. Once this connection is established, the server must transmit a string containing the case-sensitive text "OK", followed by an EOF character. The server has now fully established a secure bidirectional channel to the client and may proceeed to use the channel for any purpose. If the server wishes to reject the connection, for example due to a hardware failure, it must transmit a string containing the case-sensitive text "ERRNOTAVL", followed by an EOF character, after which the server should close the client connection. \ No newline at end of file
diff --git a/servers/auth_server_lin/src/auth_conn.cpp b/servers/auth_server_lin/src/auth_conn.cpp
index 1356df4..cac5ba9 100644
--- a/servers/auth_server_lin/src/auth_conn.cpp
+++ b/servers/auth_server_lin/src/auth_conn.cpp
@@ -130,8 +130,10 @@ void AuthSocket::finishKerberosHandshake() {
TQ_UINT32 protover = PROTOCOL_VERSION;
TQDataStream ds(this);
+ ds.setPrintableData(true);
ds << magicnum;
ds << protover;
+ writeEndOfFrame();
enterCommandLoop();
return;
@@ -150,6 +152,7 @@ int AuthSocket::servLoop() {
if (m_servActive) {
TQString command;
TQDataStream ds(this);
+ ds.setPrintableData(true);
TDEKerberosClientSocket::KerberosStatus krbstat;
switch (m_servState) {
@@ -162,6 +165,7 @@ int AuthSocket::servLoop() {
if (!m_servClientTimeout->isActive()) {
m_servClientSocket->close();
ds << TQString("ERRNOTAVL");
+ writeEndOfFrame();
printf("[DEBUG] Connection failed to %s:%d for user %s@%s\n\r", m_srvServiceHostName.ascii(), m_srvServicePort, m_authenticatedUserName.ascii(), m_authenticatedRealmName.ascii()); fflush(stdout);
m_servActive = false;
delete m_servClientTimeout;
@@ -187,6 +191,7 @@ int AuthSocket::servLoop() {
else {
m_servClientSocket->close();
ds << TQString("ERRNOTAVL");
+ writeEndOfFrame();
printf("[DEBUG] Connection failed to %s:%d for user %s@%s\n\r", m_srvServiceHostName.ascii(), m_srvServicePort, m_authenticatedUserName.ascii(), m_authenticatedRealmName.ascii()); fflush(stdout);
m_servActive = false;
delete m_servClientTimeout;
@@ -205,6 +210,7 @@ int AuthSocket::servLoop() {
else {
m_servClientSocket->close();
ds << TQString("ERRNOTAVL");
+ writeEndOfFrame();
printf("[DEBUG] Connection failed to %s:%d for user %s@%s due to Kerberos failure\n\r", m_srvServiceHostName.ascii(), m_srvServicePort, m_authenticatedUserName.ascii(), m_authenticatedRealmName.ascii()); fflush(stdout);
m_servActive = false;
delete m_servClientTimeout;
@@ -218,19 +224,23 @@ int AuthSocket::servLoop() {
m_servClientTimeout->start(5000, TRUE);
}
if (m_servClientSocket->state() == TQSocket::Connected) {
- if (m_servClientSocket->canReadData()) {
+ if (m_servClientSocket->canReadFrame()) {
TQDataStream clientDS(m_servClientSocket);
+ clientDS.setPrintableData(true);
TQString server_reply;
clientDS >> server_reply;
+ m_servClientSocket->clearFrameTail();
if (server_reply == "OK") {
ds << TQString("OK");
+ writeEndOfFrame();
transferred_data = true;
m_servState = 4;
}
else {
m_servClientSocket->close();
ds << TQString("ERRNOTAVL");
+ writeEndOfFrame();
printf("[DEBUG] Connection failed to %s:%d for user %s@%s due to remote server returning %s\n\r", m_srvServiceHostName.ascii(), m_srvServicePort, m_authenticatedUserName.ascii(), m_authenticatedRealmName.ascii(), server_reply.ascii()); fflush(stdout);
m_servActive = false;
delete m_servClientTimeout;
@@ -243,6 +253,7 @@ int AuthSocket::servLoop() {
// Timeout!
m_servClientSocket->close();
ds << TQString("ERRNOTAVL");
+ writeEndOfFrame();
printf("[DEBUG] Connection failed to %s:%d for user %s@%s\n\r", m_srvServiceHostName.ascii(), m_srvServicePort, m_authenticatedUserName.ascii(), m_authenticatedRealmName.ascii()); fflush(stdout);
m_servActive = false;
delete m_servClientTimeout;
@@ -254,6 +265,7 @@ int AuthSocket::servLoop() {
else {
m_servClientSocket->close();
ds << TQString("ERRNOTAVL");
+ writeEndOfFrame();
printf("[DEBUG] Connection failed to %s:%d for user %s@%s\n\r", m_srvServiceHostName.ascii(), m_srvServicePort, m_authenticatedUserName.ascii(), m_authenticatedRealmName.ascii()); fflush(stdout);
m_servActive = false;
delete m_servClientTimeout;
@@ -279,6 +291,7 @@ int AuthSocket::servLoop() {
else {
m_servClientSocket->close();
ds << TQString("ERRNOTAVL");
+ writeEndOfFrame();
printf("[DEBUG] Connection terminated by remote host %s:%d for user %s@%s\n\r", m_srvServiceHostName.ascii(), m_srvServicePort, m_authenticatedUserName.ascii(), m_authenticatedRealmName.ascii()); fflush(stdout);
m_servActive = false;
close();
@@ -316,12 +329,14 @@ void AuthSocket::commandLoop() {
try {
transferred_data = false;
if (state() == TQSocket::Connected) {
- if (canReadData()) {
+ if (canReadFrame()) {
TQString command;
TQDataStream ds(this);
+ ds.setPrintableData(true);
transferred_data = true;
ds >> command;
+ clearFrameTail();
if (command != "") {
printf("[DEBUG] Got command %s from user %s@%s\n\r", command.ascii(), m_authenticatedUserName.ascii(), m_authenticatedRealmName.ascii()); fflush(stdout);
if (command == "LIST") {
@@ -378,13 +393,15 @@ void AuthSocket::commandLoop() {
m_slist.append(st);
}
}
-
+
ds << m_slist;
+ writeEndOfFrame();
}
else if (command == "BIND") {
// Get desired Station Type from client
StationType st;
ds >> st;
+ clearFrameTail();
// Attempt to bind to station matching desired Service Type list...
m_stationID = -1;
@@ -405,6 +422,7 @@ void AuthSocket::commandLoop() {
if (m_stationID < 0) {
ds << TQString("ERRUNAVAL");
+ writeEndOfFrame();
}
else {
m_bound = true;
@@ -418,16 +436,19 @@ void AuthSocket::commandLoop() {
m_databaseActivityCursor->insert();
ds << TQString("OK");
+ writeEndOfFrame();
}
}
else {
ds << TQString("ERRPREVCN");
+ writeEndOfFrame();
}
}
else if (command == "SERV") {
// Get client library name from the client
TQString libname;
ds >> libname;
+ clearFrameTail();
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));
@@ -437,10 +458,12 @@ void AuthSocket::commandLoop() {
if (m_bound == true) {
ds << TQString("ERRINVCMD");
+ writeEndOfFrame();
}
else {
if (m_stationID < 0) {
ds << TQString("ERRNOCONN");
+ writeEndOfFrame();
}
else {
// Find the service ID for the specified client library name
@@ -451,6 +474,7 @@ void AuthSocket::commandLoop() {
}
if (sid < 0) {
ds << TQString("ERRNOSERV");
+ writeEndOfFrame();
}
else {
// Attempt to connect to the backend server
@@ -470,6 +494,7 @@ void AuthSocket::commandLoop() {
}
else {
ds << TQString("ERRNOSERV");
+ writeEndOfFrame();
}
}
}
@@ -477,6 +502,7 @@ void AuthSocket::commandLoop() {
}
else {
ds << TQString("ERRINVCMD");
+ writeEndOfFrame();
}
}
}
diff --git a/servers/fpga_programming_server_lin/src/fpga_conn.cpp b/servers/fpga_programming_server_lin/src/fpga_conn.cpp
index 330e747..341d14a 100644
--- a/servers/fpga_programming_server_lin/src/fpga_conn.cpp
+++ b/servers/fpga_programming_server_lin/src/fpga_conn.cpp
@@ -25,6 +25,7 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h> /* read() */
+#include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
@@ -46,8 +47,7 @@
delete s; \
s = NULL;
-//#define NETWORK_COMM_TIMEOUT_MS 2000
-#define NETWORK_COMM_TIMEOUT_MS 4000
+#define NETWORK_COMM_TIMEOUT_MS 5000
/* exception handling */
struct exit_exception {
@@ -61,7 +61,9 @@ struct exit_exception {
instance of this class.
*/
FPGASocket::FPGASocket(int sock, TQObject *parent, const char *name) :
- TDEKerberosServerSocket(parent, name), m_criticalSection(0), m_loopTimer(NULL), m_config(static_cast<FPGAServer*>(parent)->m_config), m_commandLoopState(0) {
+ TDEKerberosServerSocket(parent, name), m_criticalSection(0), m_loopTimer(NULL), m_config(static_cast<FPGAServer*>(parent)->m_config), m_commandLoopState(0),
+ m_progpipe(NULL), m_progpipefd(-1), m_progErrorFlag(false), m_progDoneFlag(false)
+{
// Initialize timers
m_kerberosInitTimer = new TQTimer();
@@ -136,7 +138,9 @@ void FPGASocket::finishKerberosHandshake() {
setDataTimeout(NETWORK_COMM_TIMEOUT_MS);
TQDataStream ds(this);
+ ds.setPrintableData(true);
ds << TQString("OK");
+ writeEndOfFrame();
enterCommandLoop();
return;
@@ -155,54 +159,85 @@ void FPGASocket::commandLoop() {
try {
transferred_data = false;
if (state() == TQSocket::Connected) {
- if (m_commandLoopState == 0) {
-printf("[RAJA DEBUG 499.0] Waiting for command...\n\r"); fflush(stdout);
+ if ((m_commandLoopState == 0) || (m_commandLoopState == 3) || (m_commandLoopState == 4) || (m_commandLoopState == 5)) {
+ // Certain commands can come in at any time during some operations
if (canReadLine()) {
-printf("[RAJA DEBUG 499.1] Processing pending data (buffer: %d)...\n\r", bytesAvailable()); fflush(stdout);
processPendingData();
}
- if (bytesAvailable() > 0) {
+ if (canReadFrame()) {
TQDataStream ds(this);
+ ds.setPrintableData(true);
TQString command;
ds >> command;
- printf("[DEBUG] Received command '%s'\n\r", command.ascii());
+ clearFrameTail();
if (command == "STATUS") {
- ds << TQString("IDLE");
+ 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");
+ m_progDoneFlag = false;
+ writeEndOfFrame();
+ ds << m_progRetCode;
+ writeEndOfFrame();
+ }
+ else if (m_commandLoopState == 0) {
+ ds << TQString("IDLE");
+ writeEndOfFrame();
+ }
+ else if ((m_commandLoopState == 3) || (m_commandLoopState == 4) || (m_commandLoopState == 5)) {
+ ds << TQString("PROGRAMMING");
+ writeEndOfFrame();
+ }
+ else {
+ ds << TQString("UNKNOWN");
+ writeEndOfFrame();
+ }
}
- else if (command == "FILE") {
- m_commandLoopState = 1;
- }
- else {
- printf("[WARNING] Received unknown command '%s'\n\r", command.ascii());
+ else if (m_commandLoopState == 0) {
+ if (command == "FILE") {
+ m_commandLoopState = 1;
+ }
+ else if (command == "PROGRAM") {
+ m_commandLoopState = 3;
+ }
+ else {
+ printf("[WARNING] Received unknown command '%s'\n\r", command.ascii());
+ }
}
transferred_data = true;
}
}
- else if (m_commandLoopState == 1) {
+ if (m_commandLoopState == 1) {
if (canReadLine()) {
processPendingData();
}
-printf("[RAJA DEBUG 500.0] Waiting for file...\n\r"); fflush(stdout);
- if (bytesAvailable() > 0) {
-printf("[RAJA DEBUG 500.1] Waiting for file (buffer: %d)...\n\r", bytesAvailable()); fflush(stdout);
+ if (canReadFrame()) {
TQDataStream ds(this);
+ ds.setPrintableData(true);
ds >> m_programmingFileSize;
+ clearFrameTail();
m_servClientTimeout->start(NETWORK_COMM_TIMEOUT_MS, TRUE);
m_commandLoopState = 2;
}
}
else if (m_commandLoopState == 2) {
if (canReadLine()) {
-printf("[RAJA DEBUG 500.2] Processing pending data (buffer: %d)...\n\r", bytesAvailable()); fflush(stdout);
m_servClientTimeout->start(NETWORK_COMM_TIMEOUT_MS, TRUE);
processPendingData();
}
-printf("[RAJA DEBUG 500.3] Waiting for file contents (buffer: %d)...\n\r", bytesAvailable()); fflush(stdout);
if (bytesAvailable() >= m_programmingFileSize) {
TQByteArray fileContents(m_programmingFileSize);
readBlock(fileContents.data(), fileContents.size());
-printf("[RAJA DEBUG 500.4] Received file!\n\r"); fflush(stdout);
-printf("[RAJA DEBUG 500.5] fileContents size: %d\n\r", fileContents.size()); fflush(stdout);
m_programmingFileName = TQString("/tmp/%1#%2.dat").arg(m_remoteHost).arg(port());
TQFile outputFile(m_programmingFileName);
if (outputFile.open(IO_ReadWrite)) {
@@ -215,13 +250,66 @@ printf("[RAJA DEBUG 500.5] fileContents size: %d\n\r", fileContents.size()); ffl
}
else {
if (!m_servClientTimeout->isActive()) {
- TQDataStream ds(this);
- ds << TQString("ERROR");
+ m_progErrorFlag = true;
transferred_data = true;
m_commandLoopState = 0;
}
}
}
+ else if (m_commandLoopState == 3) {
+ // 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 = 0;
+ }
+ else {
+ m_progpipefd = fileno(m_progpipe);
+ fcntl(m_progpipefd, F_SETFL, O_NONBLOCK);
+ }
+ m_commandLoopState = 4;
+ }
+ else if (m_commandLoopState == 4) {
+ // 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 = 5;
+ }
+ }
+ else if (m_commandLoopState == 5) {
+ // 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 = 0;
+ }
}
m_criticalSection--;
if (transferred_data) {
diff --git a/servers/fpga_programming_server_lin/src/fpga_conn.h b/servers/fpga_programming_server_lin/src/fpga_conn.h
index ec2dd65..597b4cc 100644
--- a/servers/fpga_programming_server_lin/src/fpga_conn.h
+++ b/servers/fpga_programming_server_lin/src/fpga_conn.h
@@ -70,6 +70,13 @@ class FPGASocket : public TDEKerberosServerSocket
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 FPGAServer;
};
diff --git a/servers/fpga_server_lin/src/fpga_conn.cpp b/servers/fpga_server_lin/src/fpga_conn.cpp
index 1a4bbdb..fd1bdfa 100644
--- a/servers/fpga_server_lin/src/fpga_conn.cpp
+++ b/servers/fpga_server_lin/src/fpga_conn.cpp
@@ -129,7 +129,9 @@ void FPGASocket::finishKerberosHandshake() {
}
TQDataStream ds(this);
+ ds.setPrintableData(true);
ds << TQString("OK");
+ writeEndOfFrame();
enterCommandLoop();
return;