From 65ea633f475c7ab2b524dc1ffb369f6607df3e6b Mon Sep 17 00:00:00 2001 From: Timothy Pearson Date: Thu, 28 Jun 2012 18:28:19 -0500 Subject: [PATCH] Convert servers to cooperative multitasking --- clients/tde/src/app/remotemdi.cpp | 11 +- clients/tde/src/app/views/instrumentview.cpp | 28 +- clients/tde/src/app/views/instrumentview.h | 5 +- clients/tde/src/part/fpgaview/part.cpp | 119 ++--- lib/libtdekrb/src/tdekrbclientsocket.cpp | 64 ++- lib/libtdekrb/src/tdekrbclientsocket.h | 5 +- lib/libtdekrb/src/tdekrbserversocket.cpp | 60 ++- lib/libtdekrb/src/tdekrbserversocket.h | 5 +- servers/auth_server_lin/src/auth_conn.cpp | 468 +++++++++++-------- servers/auth_server_lin/src/auth_conn.h | 9 + servers/fpga_server_lin/src/fpga_conn.cpp | 19 +- servers/fpga_server_lin/src/fpga_conn.h | 1 + 12 files changed, 497 insertions(+), 297 deletions(-) diff --git a/clients/tde/src/app/remotemdi.cpp b/clients/tde/src/app/remotemdi.cpp index 11ab75e..3ecf181 100644 --- a/clients/tde/src/app/remotemdi.cpp +++ b/clients/tde/src/app/remotemdi.cpp @@ -343,7 +343,12 @@ void RemoteMDI::childWindowCloseRequest(KMdiChildView *pWnd) { // Give the child a chance to finish what it was doing and exit cleanly (i.e. without crashing!) iview->closeConnections(); iview->hide(); - KMdiMainFrm::childWindowCloseRequest(pWnd); + + // RAJA FIXME + // Executing KMdiMainFrm::childWindowCloseRequest(pWnd) here will probably cause a crash + // We need to call this AFTER control has been returned to the main event loop at least once + // This is related to my lack of proper returning to the event loop, which MUST BE FIXED +// KMdiMainFrm::childWindowCloseRequest(pWnd); // RAJA UNCOMMENT ME } } @@ -363,11 +368,11 @@ void RemoteMDI::closeSpecifiedWindow(KMdiChildView *window) { if (window) { // Notify the status bar of the removal of the window statusBar()->message(i18n("%1 removed").arg(window->tabCaption())); - + // We could also call removeWindowFromMdi, but it doesn't delete the // pointer. This way, we're sure that the view will get deleted. closeWindow(window); - + // Synchronize combo box if (m_pCurrentWindow) { currentChanged(m_pCurrentWindow); diff --git a/clients/tde/src/app/views/instrumentview.cpp b/clients/tde/src/app/views/instrumentview.cpp index 68b469a..ca3c853 100644 --- a/clients/tde/src/app/views/instrumentview.cpp +++ b/clients/tde/src/app/views/instrumentview.cpp @@ -15,6 +15,7 @@ InstrumentView::InstrumentView(const TQString &library, TQWidget *parentWidget, : KMdiChildView(parentWidget, name, f) , m_libraryName(library) , m_instrumentPart( 0 ) + , m_canary( NULL ) { init(); } @@ -23,12 +24,15 @@ InstrumentView::InstrumentView(const TQString &library, const TQString &caption, : KMdiChildView(caption, parentWidget, name, f) , m_libraryName(library) , m_instrumentPart( 0 ) + , m_canary( NULL ) { init(); } InstrumentView::~InstrumentView() { - // + if (m_canary) { + *m_canary = true; + } } void InstrumentView::init() { @@ -44,10 +48,13 @@ void InstrumentView::init() { } bool InstrumentView::queryExit() { - if( !m_instrumentPart ) //apparently std::exit() still calls this function, and abort() causes a crash.. + if (!m_instrumentPart) { // apparently std::exit() still calls this function, and abort() causes a crash.. return true; + } +printf("[RAJA DEBUG 700.0] In InstrumentView::queryExit\n\r"); fflush(stdout); m_instrumentPart->closeURL(); +printf("[RAJA DEBUG 700.1] In InstrumentView::queryExit\n\r"); fflush(stdout); return true; } @@ -57,11 +64,24 @@ void InstrumentView::closeConnections() { } void InstrumentView::connectServer(TQString server) { + if (!m_canary) { + m_canary = new bool; + *m_canary = false; + } + bool* canary = m_canary; + if (m_instrumentPart) { - if (m_instrumentPart->openURL(KURL(server))) { - close(); + if (m_instrumentPart->openURL(KURL(server))) { // This can call processEvents, therefore this object may not exist when it returns! + if (*canary == true) { + delete canary; + return; + } + TQTimer::singleShot(0, this, SLOT(close())); } } + + delete m_canary; + m_canary = NULL; } /********************************************** diff --git a/clients/tde/src/app/views/instrumentview.h b/clients/tde/src/app/views/instrumentview.h index c9df8d2..64d4d5d 100644 --- a/clients/tde/src/app/views/instrumentview.h +++ b/clients/tde/src/app/views/instrumentview.h @@ -26,14 +26,15 @@ class InstrumentView : public KMdiChildView void closeConnections(); protected: - virtual void saveProperties( KConfig * ); - virtual void readProperties( KConfig * ); + virtual void saveProperties(KConfig *); + virtual void readProperties(KConfig *); virtual bool queryExit(); private: void init(); TQString m_libraryName; RemoteLab::InstrumentPart *m_instrumentPart; + bool* m_canary; }; } // namespace RemoteLab diff --git a/clients/tde/src/part/fpgaview/part.cpp b/clients/tde/src/part/fpgaview/part.cpp index 4eae27d..52a1d92 100644 --- a/clients/tde/src/part/fpgaview/part.cpp +++ b/clients/tde/src/part/fpgaview/part.cpp @@ -46,12 +46,6 @@ #include "floatspinbox.h" #include "layout.h" -/* exception handling */ -struct exit_exception { - int c; - exit_exception(int c):c(c) { } -}; - namespace RemoteLab { typedef KParts::GenericFactory Factory; @@ -82,7 +76,7 @@ FPGAViewPart::FPGAViewPart(TQWidget *parentWidget, const char *widgetName, TQObj FPGAViewPart::~FPGAViewPart() { if (m_connectionMutex->locked()) { - throw exit_exception(-1); + printf("[WARNING] Exiting when data transfer still in progress!\n\r"); fflush(stdout); } if (m_socket) { @@ -95,11 +89,14 @@ FPGAViewPart::~FPGAViewPart() { } void FPGAViewPart::processLockouts() { - if ((m_socket) && (m_socket->state() == TQSocket::Connected)) { - widget()->setEnabled(true); - } - else { - widget()->setEnabled(false); + TQWidget* mainWidget = widget(); + if (mainWidget) { + if ((m_socket) && (m_socket->state() == TQSocket::Connected)) { + mainWidget->setEnabled(true); + } + else { + mainWidget->setEnabled(false); + } } } @@ -114,22 +111,27 @@ void FPGAViewPart::postInit() { bool FPGAViewPart::openURL(const KURL &url) { int ret; ret = connectToServer(url.url()); + // RAJA FIXME + // Need canary? processLockouts(); return (ret != 0); } bool FPGAViewPart::closeURL() { - if (m_connectionMutex->locked()) { - throw exit_exception(-1); - } - +printf("[RAJA DEBUG 710.0] In FPGAViewPart::closeURL\n\r"); fflush(stdout); +printf("[RAJA DEBUG 710.1] In FPGAViewPart::closeURL\n\r"); fflush(stdout); if (m_socket) { m_socket->clearPendingData(); +printf("[RAJA DEBUG 710.2] In FPGAViewPart::closeURL\n\r"); fflush(stdout); m_socket->close(); - delete m_socket; +printf("[RAJA DEBUG 710.3] In FPGAViewPart::closeURL\n\r"); fflush(stdout); + m_socket->deleteLater(); +printf("[RAJA DEBUG 710.4] In FPGAViewPart::closeURL\n\r"); fflush(stdout); m_socket = NULL; +printf("[RAJA DEBUG 710.5] In FPGAViewPart::closeURL\n\r"); fflush(stdout); } +printf("[RAJA DEBUG 710.6] In FPGAViewPart::closeURL\n\r"); fflush(stdout); processLockouts(); m_url = KURL(); @@ -138,6 +140,11 @@ bool FPGAViewPart::closeURL() { } int FPGAViewPart::connectToServer(TQString server) { +printf("[RAJA DEBUG 200.0] In FPGAViewPart::connectToServer\n\r"); fflush(stdout); + if (m_socket) { +printf("[RAJA DEBUG 200.1] In FPGAViewPart::connectToServer TRIED TO CONNECT TWICE!!!\n\r"); fflush(stdout); + return -1; + } if (!m_socket) { m_socket = new TDEKerberosClientSocket(this); } @@ -146,63 +153,61 @@ int FPGAViewPart::connectToServer(TQString server) { m_socket->connectToHost(server, 4004); while ((m_socket->state() != TQSocket::Connected) && (m_socket->state() != TQSocket::Idle)) { tqApp->eventLoop()->processEvents(TQEventLoop::AllEvents); + if (!m_socket) return -1; // Any entry into the event loop could end up deleting the socket object depending on user interaction } if (m_socket->state() != TQSocket::Connected) { return -1; } if (m_socket->setUsingKerberos(true) != 0) { + if (!m_socket) return -1; // Any entry into the event loop could end up deleting the socket object depending on user interaction m_socket->close(); KMessageBox::error(0, i18n("Unable to establish Kerberos protocol with remote server

Please verify that you currently hold a valid Kerberos ticket"), i18n("Connection Failed")); return -1; } connect(m_socket, SIGNAL(connectionClosed()), this, SLOT(connectionClosed())); - try { - m_connectionMutex->lock(); - TQString response; - TQDataStream ds(m_socket); - // Read magic number and proto version from server - TQ_UINT32 magicnum; - TQ_UINT32 protover; - ds >> magicnum; - ds >> protover; - printf("[DEBUG] Got magic number %d and protocol version %d\n\r", magicnum, protover); fflush(stdout); - // Request connection to backend server - ds << TQString("SERV"); - ds << TQString(CLIENT_LIBRARY); - ds >> response; -printf("[RAJA DEBUG 400.0] Got '%s' from the server\n\r", response.ascii()); fflush(stdout); - if (response == "OK") { - m_connectionMutex->unlock(); - return 0; - } - else if (response == "ERRNOCONN") { - KMessageBox::error(0, i18n("Unable to establish connection with backend server

Please verify that you are currently connected to a workspace"), i18n("Connection Failed")); - m_connectionMutex->unlock(); - return -1; - } - else if (response == "ERRNOTAVL") { - KMessageBox::error(0, i18n("The backend server is not available at this time

Please try a different workspace, or try again later"), i18n("Connection Failed")); - m_connectionMutex->unlock(); - return -1; - } - else if (response == "ERRNOSERV") { - KMessageBox::error(0, i18n("The active laboratory workspace does not support the requested service"), i18n("Service Unavailable")); - m_connectionMutex->unlock(); - return -1; - } - else { - KMessageBox::error(0, i18n("Unable to establish connection with remote server"), i18n("Connection Failed")); - m_connectionMutex->unlock(); - return -1; - } + // Kerberos connection established! + m_connectionMutex->lock(); + TQString response; + TQDataStream ds(m_socket); + // Read magic number and proto version from server + TQ_UINT32 magicnum; + TQ_UINT32 protover; + ds >> magicnum; + ds >> protover; + printf("[DEBUG] Got magic number %d and protocol version %d\n\r", magicnum, protover); fflush(stdout); + // Request connection to backend server + ds << TQString("SERV"); + ds << TQString(CLIENT_LIBRARY); + ds >> response; +printf("[RAJA DEBUG 400.0] Got '%s' from the server\n\r", response.ascii()); fflush(stdout); + if (response == "OK") { m_connectionMutex->unlock(); return 0; } - catch (exit_exception& e) { + else if (response == "ERRNOCONN") { + KMessageBox::error(0, i18n("Unable to establish connection with backend server

Please verify that you are currently connected to a workspace"), i18n("Connection Failed")); + m_connectionMutex->unlock(); + return -1; + } + else if (response == "ERRNOTAVL") { + KMessageBox::error(0, i18n("The backend server is not available at this time

Please try a different workspace, or try again later"), i18n("Connection Failed")); m_connectionMutex->unlock(); return -1; } + else if (response == "ERRNOSERV") { + KMessageBox::error(0, i18n("The active laboratory workspace does not support the requested service"), i18n("Service Unavailable")); + m_connectionMutex->unlock(); + return -1; + } + else { + KMessageBox::error(0, i18n("Unable to establish connection with remote server"), i18n("Connection Failed")); + m_connectionMutex->unlock(); + return -1; + } + + m_connectionMutex->unlock(); + return 0; } void FPGAViewPart::updateDisplay() { diff --git a/lib/libtdekrb/src/tdekrbclientsocket.cpp b/lib/libtdekrb/src/tdekrbclientsocket.cpp index 9ea30fa..2736f5a 100644 --- a/lib/libtdekrb/src/tdekrbclientsocket.cpp +++ b/lib/libtdekrb/src/tdekrbclientsocket.cpp @@ -32,6 +32,20 @@ #define NET_SEC_BUF_SIZE (2048) +// When control comes back from processEvents() my object may be completely gone! This attempts to mitigate the risk +#define SAFELY_PROCESS_EVENTS if (!m_canary) { \ + m_canary = new bool; \ + *m_canary = false; \ + } \ + bool* canary = m_canary; \ + tqApp->processEvents(); \ + if (*canary == true) { \ + delete canary; \ + return -1; \ + } \ + delete m_canary; \ + m_canary = NULL; + /* exception handling */ struct exit_exception { int c; @@ -79,7 +93,7 @@ static int logSASLMessages(void *context __attribute__((unused)), int priority, return SASL_OK; } -TDEKerberosClientSocket::TDEKerberosClientSocket(TQObject *parent, const char *name) : TQSocket(parent, name), m_kerberosRequested(false), m_criticalSection(0), m_bufferLength(0), m_negotiatedMaxBufferSize(NET_SEC_BUF_SIZE) { +TDEKerberosClientSocket::TDEKerberosClientSocket(TQObject *parent, const char *name) : TQSocket(parent, name), m_kerberosRequested(false), m_criticalSection(0), m_bufferLength(0), m_canary(NULL), m_negotiatedMaxBufferSize(NET_SEC_BUF_SIZE) { saslData = new SASLDataPrivate; saslData->m_krbConnection = NULL; m_buffer = new TQBuffer(); @@ -87,6 +101,9 @@ TDEKerberosClientSocket::TDEKerberosClientSocket(TQObject *parent, const char *n } TDEKerberosClientSocket::~TDEKerberosClientSocket() { + if (m_canary) { + *m_canary = true; + } m_buffer->close(); delete m_buffer; delete saslData; @@ -102,9 +119,6 @@ bool TDEKerberosClientSocket::open(int mode) { void TDEKerberosClientSocket::close() { TQSocket::close(); - if (m_criticalSection > 0) { - throw exit_exception(-1); - } } void TDEKerberosClientSocket::flush() { @@ -221,6 +235,10 @@ TQ_LONG TDEKerberosClientSocket::readBlock(char *data, TQ_ULONG maxlen) { int wrlen; char* buf = (char*)malloc(m_negotiatedMaxBufferSize); reclen = receiveEncryptedData(buf, m_negotiatedMaxBufferSize); + if (reclen < 0) { + free(buf); + return -1; + } if (reclen > 0) { m_buffer->at(m_bufferLength); wrlen = m_buffer->writeBlock(buf, reclen); @@ -278,6 +296,10 @@ TQ_LONG TDEKerberosClientSocket::readLine(char *data, TQ_ULONG maxlen) { int wrlen; char* buf = (char*)malloc(m_negotiatedMaxBufferSize); reclen = receiveEncryptedData(buf, m_negotiatedMaxBufferSize); + if (reclen < 0) { + free(buf); + return -1; + } if (reclen > 0) { m_buffer->at(m_bufferLength); wrlen = m_buffer->writeBlock(buf, reclen); @@ -325,6 +347,10 @@ TQString TDEKerberosClientSocket::readLine() { maxlen = m_negotiatedMaxBufferSize; char* buf = (char*)malloc(m_negotiatedMaxBufferSize); reclen = receiveEncryptedData(buf, m_negotiatedMaxBufferSize); + if (reclen < 0) { + free(buf); + return TQString::null; + } if (reclen > 0) { m_buffer->at(m_bufferLength); wrlen = m_buffer->writeBlock(buf, reclen); @@ -410,17 +436,25 @@ void TDEKerberosClientSocket::sendSASLDataToNetwork(const char *buffer, unsigned free(buf); } -int TDEKerberosClientSocket::getSASLDataFromNetwork(char *buf, int trunclen) { +int TDEKerberosClientSocket::getSASLDataFromNetwork(char *buf, int trunclen, bool shouldblock) { m_criticalSection++; try { unsigned int len; int result; - + TQByteArray ba(2048); - + + if (!shouldblock) { + if ((!TQSocket::canReadLine()) || (state() != TQSocket::Connected)) { + return 0; + } + } + len = 0; while (1) { - tqApp->processEvents(); + if (shouldblock) { + SAFELY_PROCESS_EVENTS + } if (state() != TQSocket::Connected) { m_criticalSection--; return -1; @@ -435,7 +469,13 @@ int TDEKerberosClientSocket::getSASLDataFromNetwork(char *buf, int trunclen) { } } else { - usleep(1000); + if (shouldblock) { + + usleep(1000); + } + else { + break; + } } if (len >= (ba.size()-1)) { ba.resize(ba.size()+2048); @@ -486,21 +526,21 @@ int TDEKerberosClientSocket::transmitEncryptedData(int fd, const char* readbuf, data_remaining = data_remaining - data_to_write_len; remnant_position = remnant_position + data_to_write_len; if (data_remaining > 0) { - tqApp->processEvents(); + SAFELY_PROCESS_EVENTS } } return 0; } -int TDEKerberosClientSocket::receiveEncryptedData(char *buf, unsigned int trunclen) { +int TDEKerberosClientSocket::receiveEncryptedData(char *buf, unsigned int trunclen, bool shouldblock) { unsigned int recv_len; const char *recv_data; int result; int len; char *encbuf = (char*)malloc(m_negotiatedMaxBufferSize); - len = getSASLDataFromNetwork(encbuf, m_negotiatedMaxBufferSize); + len = getSASLDataFromNetwork(encbuf, m_negotiatedMaxBufferSize, shouldblock); if (len < 0) { return -1; } diff --git a/lib/libtdekrb/src/tdekrbclientsocket.h b/lib/libtdekrb/src/tdekrbclientsocket.h index fde4eee..ddba47a 100644 --- a/lib/libtdekrb/src/tdekrbclientsocket.h +++ b/lib/libtdekrb/src/tdekrbclientsocket.h @@ -58,9 +58,9 @@ class TDEKerberosClientSocket : public TQSocket int initializeKerberosInterface(); void freeKerberosConnection(); void sendSASLDataToNetwork(const char *buffer, unsigned length, int netfd); - int getSASLDataFromNetwork(char *buf, int trunclen); + int getSASLDataFromNetwork(char *buf, int trunclen, bool shouldblock=true); int transmitEncryptedData(int fd, const char* readbuf, int cc); - int receiveEncryptedData(char *buf, unsigned int trunclen); + int receiveEncryptedData(char *buf, unsigned int trunclen, bool shouldblock=true); private: bool m_kerberosRequested; @@ -69,6 +69,7 @@ class TDEKerberosClientSocket : public TQSocket int m_criticalSection; TQBuffer* m_buffer; long m_bufferLength; + bool* m_canary; private: SASLDataPrivate *saslData; diff --git a/lib/libtdekrb/src/tdekrbserversocket.cpp b/lib/libtdekrb/src/tdekrbserversocket.cpp index 89cb05d..e1e2c02 100644 --- a/lib/libtdekrb/src/tdekrbserversocket.cpp +++ b/lib/libtdekrb/src/tdekrbserversocket.cpp @@ -32,6 +32,20 @@ #define NET_SEC_BUF_SIZE (2048) +// When control comes back from processEvents() my object may be completely gone! This attempts to mitigate the risk +#define SAFELY_PROCESS_EVENTS if (!m_canary) { \ + m_canary = new bool; \ + *m_canary = false; \ + } \ + bool* canary = m_canary; \ + tqApp->processEvents(); \ + if (*canary == true) { \ + delete canary; \ + return -1; \ + } \ + delete m_canary; \ + m_canary = NULL; + /* exception handling */ struct exit_exception { int c; @@ -79,7 +93,7 @@ static int logSASLMessages(void *context __attribute__((unused)), int priority, return SASL_OK; } -TDEKerberosServerSocket::TDEKerberosServerSocket(TQObject *parent, const char *name) : TQSocket(parent, name), m_kerberosRequested(false), m_criticalSection(0), m_bufferLength(0), m_negotiatedMaxBufferSize(NET_SEC_BUF_SIZE) { +TDEKerberosServerSocket::TDEKerberosServerSocket(TQObject *parent, const char *name) : TQSocket(parent, name), m_kerberosRequested(false), m_criticalSection(0), m_bufferLength(0), m_canary(NULL), m_negotiatedMaxBufferSize(NET_SEC_BUF_SIZE) { saslData = new SASLDataPrivate; saslData->m_krbConnection = NULL; m_buffer = new TQBuffer(); @@ -87,6 +101,9 @@ TDEKerberosServerSocket::TDEKerberosServerSocket(TQObject *parent, const char *n } TDEKerberosServerSocket::~TDEKerberosServerSocket() { + if (m_canary) { + *m_canary = true; + } m_buffer->close(); delete m_buffer; delete saslData; @@ -102,9 +119,6 @@ bool TDEKerberosServerSocket::open(int mode) { void TDEKerberosServerSocket::close() { TQSocket::close(); - if (m_criticalSection > 0) { - throw exit_exception(-1); - } } void TDEKerberosServerSocket::flush() { @@ -221,6 +235,10 @@ TQ_LONG TDEKerberosServerSocket::readBlock(char *data, TQ_ULONG maxlen) { int wrlen; char* buf = (char*)malloc(m_negotiatedMaxBufferSize); reclen = receiveEncryptedData(buf, m_negotiatedMaxBufferSize); + if (reclen < 0) { + free(buf); + return -1; + } if (reclen > 0) { m_buffer->at(m_bufferLength); wrlen = m_buffer->writeBlock(buf, reclen); @@ -278,6 +296,10 @@ TQ_LONG TDEKerberosServerSocket::readLine(char *data, TQ_ULONG maxlen) { int wrlen; char* buf = (char*)malloc(m_negotiatedMaxBufferSize); reclen = receiveEncryptedData(buf, m_negotiatedMaxBufferSize); + if (reclen < 0) { + free(buf); + return -1; + } if (reclen > 0) { m_buffer->at(m_bufferLength); wrlen = m_buffer->writeBlock(buf, reclen); @@ -325,6 +347,10 @@ TQString TDEKerberosServerSocket::readLine() { maxlen = m_negotiatedMaxBufferSize; char* buf = (char*)malloc(m_negotiatedMaxBufferSize); reclen = receiveEncryptedData(buf, m_negotiatedMaxBufferSize); + if (reclen < 0) { + free(buf); + return TQString::null; + } if (reclen > 0) { m_buffer->at(m_bufferLength); wrlen = m_buffer->writeBlock(buf, reclen); @@ -410,7 +436,7 @@ void TDEKerberosServerSocket::sendSASLDataToNetwork(const char *buffer, unsigned free(buf); } -int TDEKerberosServerSocket::getSASLDataFromNetwork(char *buf, int trunclen) { +int TDEKerberosServerSocket::getSASLDataFromNetwork(char *buf, int trunclen, bool shouldblock) { m_criticalSection++; try { unsigned int len; @@ -418,9 +444,17 @@ int TDEKerberosServerSocket::getSASLDataFromNetwork(char *buf, int trunclen) { TQByteArray ba(2048); + if (!shouldblock) { + if ((!TQSocket::canReadLine()) || (state() != TQSocket::Connected)) { + return 0; + } + } + len = 0; while (1) { - tqApp->processEvents(); + if (shouldblock) { + SAFELY_PROCESS_EVENTS + } if (state() != TQSocket::Connected) { m_criticalSection--; return -1; @@ -435,7 +469,13 @@ int TDEKerberosServerSocket::getSASLDataFromNetwork(char *buf, int trunclen) { } } else { - usleep(1000); + if (shouldblock) { + + usleep(1000); + } + else { + break; + } } if (len >= (ba.size()-1)) { ba.resize(ba.size()+2048); @@ -486,21 +526,21 @@ int TDEKerberosServerSocket::transmitEncryptedData(int fd, const char* readbuf, data_remaining = data_remaining - data_to_write_len; remnant_position = remnant_position + data_to_write_len; if (data_remaining > 0) { - tqApp->processEvents(); + SAFELY_PROCESS_EVENTS } } return 0; } -int TDEKerberosServerSocket::receiveEncryptedData(char *buf, unsigned int trunclen) { +int TDEKerberosServerSocket::receiveEncryptedData(char *buf, unsigned int trunclen, bool shouldblock) { unsigned int recv_len; const char *recv_data; int result; int len; char *encbuf = (char*)malloc(m_negotiatedMaxBufferSize); - len = getSASLDataFromNetwork(encbuf, m_negotiatedMaxBufferSize); + len = getSASLDataFromNetwork(encbuf, m_negotiatedMaxBufferSize, shouldblock); if (len < 0) { return -1; } diff --git a/lib/libtdekrb/src/tdekrbserversocket.h b/lib/libtdekrb/src/tdekrbserversocket.h index 0d71faf..80c84fd 100644 --- a/lib/libtdekrb/src/tdekrbserversocket.h +++ b/lib/libtdekrb/src/tdekrbserversocket.h @@ -58,9 +58,9 @@ class TDEKerberosServerSocket : public TQSocket int initializeKerberosInterface(); void freeKerberosConnection(); void sendSASLDataToNetwork(const char *buffer, unsigned length, int netfd); - int getSASLDataFromNetwork(char *buf, int trunclen); + int getSASLDataFromNetwork(char *buf, int trunclen, bool shouldblock=true); int transmitEncryptedData(int fd, const char* readbuf, int cc); - int receiveEncryptedData(char *buf, unsigned int trunclen); + int receiveEncryptedData(char *buf, unsigned int trunclen, bool shouldblock=true); protected: TQString m_authenticatedUserName; @@ -73,6 +73,7 @@ class TDEKerberosServerSocket : public TQSocket int m_criticalSection; TQBuffer* m_buffer; long m_bufferLength; + bool* m_canary; private: SASLDataPrivate *saslData; diff --git a/servers/auth_server_lin/src/auth_conn.cpp b/servers/auth_server_lin/src/auth_conn.cpp index 28c8427..451b8d9 100644 --- a/servers/auth_server_lin/src/auth_conn.cpp +++ b/servers/auth_server_lin/src/auth_conn.cpp @@ -29,10 +29,6 @@ #include "auth_conn.h" #define ABORT_SOCKET(s) s->close(); \ - tqApp->processEvents(); \ - while (s->state() == TQSocket::Closing) { \ - tqApp->processEvents(); \ - } \ s->disconnect(); \ delete s; \ s = NULL; @@ -49,7 +45,7 @@ struct exit_exception { instance of this class. */ AuthSocket::AuthSocket(int sock, TQObject *parent, const char *name) : - TDEKerberosServerSocket(parent, name), m_criticalSection(0), m_stationID(-1), m_bound(false), m_config(static_cast(parent)->m_config), m_database(NULL), m_databaseStationsCursor(NULL), + TDEKerberosServerSocket(parent, name), m_criticalSection(0), m_stationID(-1), m_bound(false), m_servActive(false), m_servState(0), m_servClientSocket(NULL), m_servClientTimeout(NULL), m_config(static_cast(parent)->m_config), m_database(NULL), m_databaseStationsCursor(NULL), m_databaseServicesCursor(NULL), m_databaseServiceTypesCursor(NULL), m_databasePermissionsCursor(NULL), m_databaseActivityCursor(NULL) { @@ -80,6 +76,9 @@ AuthSocket::~AuthSocket() { if (m_databaseActivityCursor) { delete m_databaseActivityCursor; } + if (m_servClientSocket) { + delete m_servClientSocket; + } } void AuthSocket::close() { @@ -122,235 +121,312 @@ int AuthSocket::initiateKerberosHandshake() { } } -int AuthSocket::enterCommandLoop() { - m_criticalSection++; - try { +void AuthSocket::servLoop() { + if (m_servActive) { TQString command; TQDataStream ds(this); + + switch (m_servState) { + case 0: + if (!m_servClientTimeout) { + m_servClientTimeout = new TQTimer(); + m_servClientTimeout->start(5000, TRUE); + } + if ((m_servClientSocket->state() == TQSocket::Connecting) || (m_servClientSocket->state() == TQSocket::HostLookup)) { + if (!m_servClientTimeout->isActive()) { + m_servClientSocket->close(); + ds << TQString("ERRNOTAVL"); + 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; + m_servClientTimeout = NULL; + } + } + else { + if (m_servClientTimeout) { + m_servClientTimeout->stop(); + delete m_servClientTimeout; + m_servClientTimeout = NULL; + } + m_servState = 1; + } + break; + case 1: + if (m_servClientSocket->state() == TQSocket::Connected) { + if (m_servClientSocket->setUsingKerberos(true) != 0) { + m_servClientSocket->close(); + ds << TQString("ERRNOTAVL"); + 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; + m_servClientTimeout = NULL; + } + m_servState = 2; + } + else { + m_servClientSocket->close(); + ds << TQString("ERRNOTAVL"); + 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; + m_servClientTimeout = NULL; + } + break; + case 2: + if (!m_servClientTimeout) { + m_servClientTimeout = new TQTimer(); + m_servClientTimeout->start(5000, TRUE); + } + if (m_servClientSocket->state() == TQSocket::Connected) { + if (m_servClientSocket->canReadLine()) { + TQDataStream clientDS(m_servClientSocket); + TQString server_reply; - while (state() == TQSocket::Connected) { - ds >> command; - 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") { - // Send list of available servers... - m_slist.clear(); - - // Get all stations from the database - m_databaseStationsCursor->select(); - while (m_databaseStationsCursor->next()) { - bool authorized = false; - bool in_use = false; - - m_databasePermissionsCursor->select(TQString("station=%1").arg(m_databaseStationsCursor->value("pk").toInt())); - while (m_databasePermissionsCursor->next()) { - if (m_databasePermissionsCursor->value("username").toString() == m_authenticatedUserName) { - authorized = true; - } + clientDS >> server_reply; + if (server_reply == "OK") { + ds << TQString("OK"); + m_servState = 3; } - m_databaseActivityCursor->select(TQString("station=%1").arg(m_databaseStationsCursor->value("pk").toInt())); - while (m_databaseActivityCursor->next()) { - if (m_databaseActivityCursor->value("username").toString() != "") { - in_use = true; - } + else { + m_servClientSocket->close(); + ds << TQString("ERRNOTAVL"); + 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; + m_servClientTimeout = NULL; } - - if ((authorized) && (!in_use)) { - StationType st; - st.id = m_databaseStationsCursor->value("pk").toInt(); - st.name = m_databaseStationsCursor->value("name").toString(); - st.description = m_databaseStationsCursor->value("description").toString(); - m_databaseServicesCursor->select(TQString("station=%1").arg(m_databaseStationsCursor->value("pk").toInt())); - while (m_databaseServicesCursor->next()) { - m_databaseServiceTypesCursor->select(TQString("serviceid=%1").arg(m_databaseServicesCursor->value("servicetype").toInt())); - ServiceType svt; - if (m_databaseServiceTypesCursor->next()) { - svt.name = m_databaseServiceTypesCursor->value("name").toString(); - svt.description = m_databaseServiceTypesCursor->value("description").toString(); - svt.clientLibrary = m_databaseServiceTypesCursor->value("client_library").toString(); - svt.version = m_databaseServiceTypesCursor->value("version").toInt(); + } + else { + if (!m_servClientTimeout->isActive()) { + // Timeout! + m_servClientSocket->close(); + ds << TQString("ERRNOTAVL"); + 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; + m_servClientTimeout = NULL; + } + } + } + else { + m_servClientSocket->close(); + ds << TQString("ERRNOTAVL"); + 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; + m_servClientTimeout = NULL; + } + break; + case 3: + if (m_servClientSocket->state() == TQSocket::Connected) { + TQByteArray ba(8192); + TQ_ULONG reclen; + + if (canReadLine()) { + reclen = readBlock(ba.data(), 8192); + m_servClientSocket->writeBlock(ba.data(), reclen); + } + if (m_servClientSocket->canReadLine()) { + reclen = m_servClientSocket->readBlock(ba.data(), 8192); + writeBlock(ba.data(), reclen); + } + } + else { + m_servClientSocket->close(); + ds << TQString("ERRNOTAVL"); + 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; + } + break; + } + } +} + +void AuthSocket::commandLoop() { + if (m_servActive) { + servLoop(); + TQTimer::singleShot(0, this, SLOT(commandLoop())); + return; + } + + m_criticalSection++; + try { + if (state() == TQSocket::Connected) { + if (canReadLine()) { + TQString command; + TQDataStream ds(this); + + ds >> command; + 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") { + // Send list of available servers... + m_slist.clear(); + + // Get all stations from the database + m_databaseStationsCursor->select(); + while (m_databaseStationsCursor->next()) { + bool authorized = false; + bool in_use = false; + + m_databasePermissionsCursor->select(TQString("station=%1").arg(m_databaseStationsCursor->value("pk").toInt())); + while (m_databasePermissionsCursor->next()) { + if (m_databasePermissionsCursor->value("username").toString() == m_authenticatedUserName) { + authorized = true; } - if (svt.name == "") { - svt.name = i18n(""); + } + m_databaseActivityCursor->select(TQString("station=%1").arg(m_databaseStationsCursor->value("pk").toInt())); + while (m_databaseActivityCursor->next()) { + if (m_databaseActivityCursor->value("username").toString() != "") { + in_use = true; } - if (svt.description == "") { - svt.description = i18n(""); + } + + if ((authorized) && (!in_use)) { + StationType st; + st.id = m_databaseStationsCursor->value("pk").toInt(); + st.name = m_databaseStationsCursor->value("name").toString(); + st.description = m_databaseStationsCursor->value("description").toString(); + m_databaseServicesCursor->select(TQString("station=%1").arg(m_databaseStationsCursor->value("pk").toInt())); + while (m_databaseServicesCursor->next()) { + m_databaseServiceTypesCursor->select(TQString("serviceid=%1").arg(m_databaseServicesCursor->value("servicetype").toInt())); + ServiceType svt; + if (m_databaseServiceTypesCursor->next()) { + svt.name = m_databaseServiceTypesCursor->value("name").toString(); + svt.description = m_databaseServiceTypesCursor->value("description").toString(); + svt.clientLibrary = m_databaseServiceTypesCursor->value("client_library").toString(); + svt.version = m_databaseServiceTypesCursor->value("version").toInt(); + } + if (svt.name == "") { + svt.name = i18n(""); + } + if (svt.description == "") { + svt.description = i18n(""); + } + st.services.append(svt); } - st.services.append(svt); + + m_slist.append(st); } - - m_slist.append(st); } + + ds << m_slist; } + else if (command == "BIND") { + // Get desired Station Type from client + StationType st; + ds >> st; + + // Attempt to bind to station matching desired Service Type list... + m_stationID = -1; - ds << m_slist; - } - else if (command == "BIND") { - // Get desired Station Type from client - StationType st; - ds >> st; - - // Attempt to bind to station matching desired Service Type list... - m_stationID = -1; - - // Ensure that this user is not already connected - int activeID = -1; - m_databaseActivityCursor->select(TQString("username='%1' AND realmname='%2'").arg(m_authenticatedUserName).arg(m_authenticatedRealmName)); - if (m_databaseActivityCursor->next()) { - activeID = m_databaseActivityCursor->value("station").toInt(); - } - if (activeID < 0) { - for (StationList::Iterator it(m_slist.begin()); it != m_slist.end(); ++it) { - if ((*it).services == st.services) { - m_stationID = (*it).id; - break; - } + // Ensure that this user is not already connected + int activeID = -1; + m_databaseActivityCursor->select(TQString("username='%1' AND realmname='%2'").arg(m_authenticatedUserName).arg(m_authenticatedRealmName)); + if (m_databaseActivityCursor->next()) { + activeID = m_databaseActivityCursor->value("station").toInt(); } + if (activeID < 0) { + for (StationList::Iterator it(m_slist.begin()); it != m_slist.end(); ++it) { + if ((*it).services == st.services) { + m_stationID = (*it).id; + break; + } + } + + if (m_stationID < 0) { + ds << TQString("ERRUNAVAL"); + } + else { + m_bound = true; - if (m_stationID < 0) { - ds << TQString("ERRUNAVAL"); + // Update database + 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()); + m_databaseActivityCursor->insert(); + + ds << TQString("OK"); + } } else { - m_bound = true; - - // Update database - 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()); - m_databaseActivityCursor->insert(); - - ds << TQString("OK"); + ds << TQString("ERRPREVCN"); } } - else { - ds << TQString("ERRPREVCN"); - } - } - else if (command == "SERV") { - // Get client library name from the client - TQString libname; - ds >> libname; - - m_databaseActivityCursor->select(TQString("username='%1' AND realmname='%2'").arg(m_authenticatedUserName).arg(m_authenticatedRealmName)); - if (m_databaseActivityCursor->next()) { - m_stationID = m_databaseActivityCursor->value("station").toInt(); - } - - if (m_bound == true) { - ds << TQString("ERRINVCMD"); - } - else { - if (m_stationID < 0) { - ds << TQString("ERRNOCONN"); + else if (command == "SERV") { + // Get client library name from the client + TQString libname; + ds >> libname; + + m_databaseActivityCursor->select(TQString("username='%1' AND realmname='%2'").arg(m_authenticatedUserName).arg(m_authenticatedRealmName)); + if (m_databaseActivityCursor->next()) { + m_stationID = m_databaseActivityCursor->value("station").toInt(); + } + + if (m_bound == true) { + ds << TQString("ERRINVCMD"); } else { - // Find the service ID for the specified client library name - TQ_INT32 sid = -1; - m_databaseServiceTypesCursor->select(TQString("client_library='%1'").arg(libname)); - if (m_databaseServiceTypesCursor->next()) { - sid = m_databaseServiceTypesCursor->value("serviceid").toInt(); - } - if (sid < 0) { - ds << TQString("ERRNOSERV"); + if (m_stationID < 0) { + ds << TQString("ERRNOCONN"); } else { - // Attempt to connect to the backend server - m_databaseServicesCursor->select(TQString("pk=%1 AND station=%2").arg(sid).arg(m_stationID)); - if (m_databaseServicesCursor->next()) { - TQString serviceHostName = m_databaseServicesCursor->value("hostname").toString(); - int servicePort = m_databaseServicesCursor->value("port").toInt(); - - TDEKerberosClientSocket clientSocket; - clientSocket.setServiceName("remotefpga"); - - clientSocket.setServerFQDN(serviceHostName); - clientSocket.connectToHost(serviceHostName, servicePort); - - TQTimer connectionTimeout; - connectionTimeout.start(5000, TRUE); - while ((clientSocket.state() == TQSocket::Connecting) || (clientSocket.state() == TQSocket::HostLookup)) { - tqApp->processEvents(); - if (!connectionTimeout.isActive()) { - break; - } - } - connectionTimeout.stop(); - if (clientSocket.state() == TQSocket::Connected) { - if (clientSocket.setUsingKerberos(true) != 0) { - clientSocket.close(); - ds << TQString("ERRNOTAVL"); - printf("[DEBUG] Connection failed to %s:%d for user %s@%s due to Kerberos failure\n\r", serviceHostName.ascii(), servicePort, m_authenticatedUserName.ascii(), m_authenticatedRealmName.ascii()); fflush(stdout); - } - else { - TQDataStream clientDS(&clientSocket); - TQString server_reply; - connectionTimeout.start(5000, TRUE); - while ((!clientSocket.canReadLine()) && (clientSocket.state() == TQSocket::Connected)) { - tqApp->processEvents(); - if (!connectionTimeout.isActive()) { - break; - } - } - connectionTimeout.stop(); - if ((clientSocket.canReadLine()) && (clientSocket.state() == TQSocket::Connected)) { - clientDS >> server_reply; - } - if (server_reply == "OK") { - ds << TQString("OK"); - TQByteArray ba(8192); - TQ_ULONG reclen; - while ((state() == TQSocket::Connected) && (clientSocket.state() == TQSocket::Connected)) { - // RAJA FIXME - if (canReadLine()) { - reclen = readBlock(ba.data(), 8192); - clientSocket.writeBlock(ba.data(), reclen); - } - if (clientSocket.canReadLine()) { - reclen = clientSocket.readBlock(ba.data(), 8192); - writeBlock(ba.data(), reclen); - } - tqApp->processEvents(); - } - clientSocket.close(); - } - else { - clientSocket.close(); - ds << TQString("ERRNOTAVL"); - printf("[DEBUG] Connection failed to %s:%d for user %s@%s due to remote server returning %s\n\r", serviceHostName.ascii(), servicePort, m_authenticatedUserName.ascii(), m_authenticatedRealmName.ascii(), server_reply.ascii()); fflush(stdout); - } - } + // Find the service ID for the specified client library name + TQ_INT32 sid = -1; + m_databaseServiceTypesCursor->select(TQString("client_library='%1'").arg(libname)); + if (m_databaseServiceTypesCursor->next()) { + sid = m_databaseServiceTypesCursor->value("serviceid").toInt(); + } + if (sid < 0) { + ds << TQString("ERRNOSERV"); + } + else { + // Attempt to connect to the backend server + m_databaseServicesCursor->select(TQString("pk=%1 AND station=%2").arg(sid).arg(m_stationID)); + if (m_databaseServicesCursor->next()) { + m_srvServiceHostName = m_databaseServicesCursor->value("hostname").toString(); + m_srvServicePort = m_databaseServicesCursor->value("port").toInt(); + + if (!m_servClientSocket) m_servClientSocket = new TDEKerberosClientSocket; + m_servClientSocket->setServiceName("remotefpga"); + + m_servClientSocket->setServerFQDN(m_srvServiceHostName); + m_servClientSocket->connectToHost(m_srvServiceHostName, m_srvServicePort); + + m_servState = 0; + m_servActive = true; } else { - clientSocket.close(); - ds << TQString("ERRNOTAVL"); - printf("[DEBUG] Connection failed to %s:%d for user %s@%s\n\r", serviceHostName.ascii(), servicePort, m_authenticatedUserName.ascii(), m_authenticatedRealmName.ascii()); fflush(stdout); + ds << TQString("ERRNOSERV"); } } - else { - ds << TQString("ERRNOSERV"); - } } } } - } - else { - ds << TQString("ERRINVCMD"); + else { + ds << TQString("ERRINVCMD"); + } } } - tqApp->processEvents(); - } - m_criticalSection--; - return 0; + m_criticalSection--; + TQTimer::singleShot(0, this, SLOT(commandLoop())); + return; + } } catch (...) { m_criticalSection--; - return -1; + return; } } +int AuthSocket::enterCommandLoop() { + TQTimer::singleShot(0, this, SLOT(commandLoop())); + return 0; +} + int AuthSocket::connectToDatabase() { if (m_database) { return -2; diff --git a/servers/auth_server_lin/src/auth_conn.h b/servers/auth_server_lin/src/auth_conn.h index 55bb5de..f1b3295 100644 --- a/servers/auth_server_lin/src/auth_conn.h +++ b/servers/auth_server_lin/src/auth_conn.h @@ -57,6 +57,8 @@ class AuthSocket : public TDEKerberosServerSocket private slots: int connectToDatabase(); void connectionClosedHandler(); + void commandLoop(); + void servLoop(); private: int line; @@ -65,6 +67,13 @@ class AuthSocket : public TDEKerberosServerSocket int m_stationID; bool m_bound; + bool m_servActive; + int m_servState; + TDEKerberosClientSocket* m_servClientSocket; + TQTimer* m_servClientTimeout; + TQString m_srvServiceHostName; + int m_srvServicePort; + KSimpleConfig* m_config; TQSqlDatabase* m_database; TQSqlCursor* m_databaseStationsCursor; diff --git a/servers/fpga_server_lin/src/fpga_conn.cpp b/servers/fpga_server_lin/src/fpga_conn.cpp index ddd430a..4c6f65e 100644 --- a/servers/fpga_server_lin/src/fpga_conn.cpp +++ b/servers/fpga_server_lin/src/fpga_conn.cpp @@ -41,10 +41,6 @@ #include "fpga_conn.h" #define ABORT_SOCKET(s) s->close(); \ - tqApp->processEvents(); \ - while (s->state() == TQSocket::Closing) { \ - tqApp->processEvents(); \ - } \ s->disconnect(); \ delete s; \ s = NULL; @@ -153,13 +149,13 @@ int FPGASocket::setupSerial() { return 0; } -int FPGASocket::enterCommandLoop() { +void FPGASocket::commandLoop() { int cc; char buffer[10000]; m_criticalSection++; try { - while (state() == TQSocket::Connected) { + if (state() == TQSocket::Connected) { cc = read(m_fd_tty, buffer, 10000); if (cc > 0) { writeBlock(buffer, cc); @@ -175,16 +171,21 @@ int FPGASocket::enterCommandLoop() { } } } - m_criticalSection--; - return 0; + TQTimer::singleShot(0, this, SLOT(commandLoop())); + return; } catch (...) { m_criticalSection--; - return -1; + return; } } +int FPGASocket::enterCommandLoop() { + TQTimer::singleShot(0, this, SLOT(commandLoop())); + return 0; +} + /* The FPGAServer class handles new connections to the server. For every client that connects, it creates a new FPGASocket -- that instance is now diff --git a/servers/fpga_server_lin/src/fpga_conn.h b/servers/fpga_server_lin/src/fpga_conn.h index be11de7..8c99794 100644 --- a/servers/fpga_server_lin/src/fpga_conn.h +++ b/servers/fpga_server_lin/src/fpga_conn.h @@ -54,6 +54,7 @@ class FPGASocket : public TDEKerberosServerSocket private slots: void connectionClosedHandler(); int setupSerial(); + void commandLoop(); private: int line;