A Few Bug Fixes

- fixed a bug that prevented the creator of a channel from being
  added to it's member list as the owner.

- fixed a bug that caused the host to open all sub-channels in
  read only mode.

- fixed a bug that caused mod processes to not get called to
  shutdown when the session is closed.

- removed the internal module idle timer, this removed an
  un-needed redundancy. with that, the idle timeout for mod
  processes are now 5 secs while the timeout for cmd processes
  remain at 2 mins.
This commit is contained in:
Maurice ONeal 2020-04-01 11:34:13 -04:00
parent 577784ad6f
commit 629029ebce
12 changed files with 107 additions and 70 deletions

View File

@ -375,7 +375,20 @@ void Session::openSubChannel(const QByteArray &data)
{
if (addBlockToBlockset(data.data(), openSubChs, MAX_OPEN_SUB_CHANNELS, BLKSIZE_SUB_CHANNEL))
{
auto chId = rd64BitFromBlock(data.data());
auto sub = rd8BitFromBlock(data.data() + 8);
auto level = channelAccessLevel(rdFromBlock(userId, BLKSIZE_USER_ID), chOwnerOverride, chId);
if (!rdOnlyFlagExists(chId, sub, level))
{
addBlockToBlockset(data.data(), openWritableSubChs, MAX_OPEN_SUB_CHANNELS, BLKSIZE_SUB_CHANNEL);
}
containsActiveCh(openSubChs, activeUpdate);
rd8BitFromBlock(activeUpdate);
if (rd8BitFromBlock(activeUpdate))
{
castPeerStat(QByteArray(openSubChs, MAX_OPEN_SUB_CHANNELS * BLKSIZE_SUB_CHANNEL), false);
}
}
}

View File

@ -19,16 +19,12 @@
IPCWorker::IPCWorker(const QString &pipe, QObject *parent) : QObject(parent)
{
pipeName = pipe;
idleTimer = new IdleTimer(this);
ipcSocket = new QLocalSocket(this);
flags = 0;
connect(ipcSocket, &QLocalSocket::readyRead, this, &IPCWorker::rdFromIPC);
connect(ipcSocket, &QLocalSocket::disconnected, this, &IPCWorker::ipcClosed);
connect(ipcSocket, &QLocalSocket::connected, this, &IPCWorker::ipcOpened);
connect(idleTimer, &IdleTimer::timeout, this, &IPCWorker::termProc);
idleTimer->attach(ipcSocket, 60000); //1min idle timeout
}
void IPCWorker::rdFromIPC()
@ -46,7 +42,7 @@ void IPCWorker::rdFromIPC()
}
else if (ipcSocket->bytesAvailable() >= (FRAME_HEADER_SIZE - 4))
{
QByteArray header = ipcSocket->read(FRAME_HEADER_SIZE - 4);
auto header = ipcSocket->read(FRAME_HEADER_SIZE - 4);
ipcTypeId = static_cast<quint8>(header[0]);
ipcDataSize = static_cast<quint32>(rdInt(header.mid(1, 3)));

View File

@ -29,7 +29,6 @@ private slots:
private:
IdleTimer *idleTimer;
QLocalSocket *ipcSocket;
quint32 flags;
quint8 ipcTypeId;

View File

@ -232,8 +232,6 @@ void ModProcess::newIPCLink()
connect(ipcSocket, &QLocalSocket::readyRead, this, &ModProcess::rdFromIPC);
connect(ipcSocket, &QLocalSocket::disconnected, this, &ModProcess::ipcDisconnected);
idleTimer->attach(ipcSocket, 120000); //2min idle timeout
onReady();
}
}
@ -270,6 +268,9 @@ void ModProcess::setSessionParams(QHash<quint16, QString> *uniqueNames,
void ModProcess::onFailToStart()
{
emit dataToClient(toCmdId32(ASYNC_SYS_MSG, 0), toTEXT("\nerr: A module failed to start so some commands may not have loaded. detailed error information was logged for admin review.\n"), ERR);
emit modProcFinished();
deleteLater();
}
void ModProcess::err(QProcess::ProcessError error)
@ -278,8 +279,6 @@ void ModProcess::err(QProcess::ProcessError error)
{
qDebug() << "err: Module process: " << program() << " failed to start. reason: " << errorString();
emit finished(1, QProcess::CrashExit);
onFailToStart();
}
}
@ -356,8 +355,11 @@ void ModProcess::cleanupPipe()
void ModProcess::onReady()
{
QStringList hostVer = QCoreApplication::applicationVersion().split('.');
QByteArray verFrame;
idleTimer->attach(ipcSocket, 5000); // 5sec idle timeout
auto hostVer = QCoreApplication::applicationVersion().split('.');
QByteArray verFrame;
verFrame.append(wrInt(hostVer[0].toULongLong(), 16));
verFrame.append(wrInt(hostVer[1].toULongLong(), 16));
@ -371,6 +373,8 @@ void ModProcess::onFinished(int exitCode, QProcess::ExitStatus exitStatus)
Q_UNUSED(exitCode)
Q_UNUSED(exitStatus)
emit modProcFinished();
cleanupPipe();
deleteLater();
}
@ -423,17 +427,25 @@ void CmdProcess::killCmd32(quint32 id32)
void CmdProcess::onReady()
{
emit cmdProcReady(cmdId, this);
idleTimer->attach(ipcSocket, 120000); // 2min idle timeout
emit cmdProcReady(cmdId);
}
void CmdProcess::onFailToStart()
{
emit dataToClient(cmdId, toTEXT("err: The command failed to start. error details were logged for admin review.\n"), ERR);
emit dataToClient(cmdId, wrInt(FAILED_TO_START, 16), IDLE);
emit cmdProcFinished(cmdId);
deleteLater();
}
void CmdProcess::onFinished(int exitCode, QProcess::ExitStatus exitStatus)
{
Q_UNUSED(exitCode)
Q_UNUSED(exitStatus)
if (!cmdIdle)
{
emit dataToClient(cmdId, toTEXT("err: The command has stopped unexpectedly or it has failed to send an IDLE frame before exiting.\n"), ERR);
@ -442,7 +454,8 @@ void CmdProcess::onFinished(int exitCode, QProcess::ExitStatus exitStatus)
emit cmdProcFinished(cmdId);
ModProcess::onFinished(exitCode, exitStatus);
cleanupPipe();
deleteLater();
}
void CmdProcess::rdFromStdErr()

View File

@ -31,7 +31,6 @@ private:
QHash<quint16, QString> *cmdRealNames;
QHash<quint16, QString> *cmdAppById;
QList<quint16> *cmdIds;
IdleTimer *idleTimer;
quint16 genCmdId();
QString makeCmdUnique(const QString &name);
@ -47,6 +46,7 @@ protected:
quint32 ipcDataSize;
quint32 hostRank;
quint32 flags;
IdleTimer *idleTimer;
QLocalServer *ipcServ;
QLocalSocket *ipcSocket;
@ -92,6 +92,7 @@ public slots:
signals:
void modProcFinished();
void cmdUnloaded(quint16 cmdId);
void dataToClient(quint32 cmdId, const QByteArray &data, quint8 typeId);
};
@ -140,7 +141,7 @@ public:
signals:
void cmdProcFinished(quint32 id);
void cmdProcReady(quint32 id, CmdProcess *obj);
void cmdProcReady(quint32 id);
void pubIPC(quint16 cmdId, const QByteArray &data);
void privIPC(quint16 cmdId, const QByteArray &data);
void pubIPCWithFeedBack(quint16 cmdId, const QByteArray &data);

View File

@ -185,34 +185,34 @@ void LsOpenChannels::procIn(const QByteArray &binIn, quint8 dType)
{
QStringList columnData;
db.setType(Query::INNER_JOIN_PULL, TABLE_SUB_CHANNELS);
db.addTableColumn(TABLE_SUB_CHANNELS, COLUMN_SUB_CH_NAME);
db.addTableColumn(TABLE_CHANNELS, COLUMN_CHANNEL_NAME);
db.addJoinCondition(COLUMN_CHANNEL_ID, TABLE_CHANNELS);
db.setType(Query::PULL, TABLE_CHANNELS);
db.addColumn(COLUMN_CHANNEL_NAME);
db.addCondition(COLUMN_CHANNEL_ID, chId);
db.exec();
columnData.append(db.getData(COLUMN_CHANNEL_NAME).toString());
db.setType(Query::PULL, TABLE_SUB_CHANNELS);
db.addColumn(COLUMN_SUB_CH_NAME);
db.addCondition(COLUMN_SUB_CH_ID, subId);
db.exec();
auto chName = db.getData(COLUMN_CHANNEL_NAME).toString();
auto subName = db.getData(COLUMN_SUB_CH_NAME).toString();
columnData.append(db.getData(COLUMN_SUB_CH_NAME).toString());
columnData.append(QString::number(chId));
columnData.append(QString::number(subId));
QString rdOnly;
if (posOfBlock(openSubChs + i, openWritableSubChs, MAX_OPEN_SUB_CHANNELS, BLKSIZE_SUB_CHANNEL) != -1)
{
// the sub-channel id being present in openWritableSubChs mean it is writable and
// therefore is NOT read only.
if (posOfBlock(openSubChs + i, openWritableSubChs, MAX_OPEN_SUB_CHANNELS, BLKSIZE_SUB_CHANNEL) == -1)
{
rdOnly = "1";
columnData.append("0");
}
else
{
rdOnly = "0";
columnData.append("1");
}
columnData.append(chName);
columnData.append(subName);
columnData.append(QString::number(chId));
columnData.append(QString::number(subId));
columnData.append(rdOnly);
for (int k = 0; k < justLens.size(); ++k)
{
if (justLens[k] < columnData[k].size()) justLens[k] = columnData[k].size();
@ -300,9 +300,9 @@ void AddRDOnlyFlag::procIn(const QByteArray &binIn, quint8 dType)
{
errTxt("err: Access denied.\n");
}
else if (rdOnlyFlagExists(chName, static_cast<quint8>(subId.toInt()), level.toInt()))
else if (rdOnlyFlagExists(chId, static_cast<quint8>(subId.toInt()), level.toUInt()))
{
errTxt("err: A read only flag for sub_id: " + QString::number(subId.toInt()) + " level: " + QString::number(level.toInt()) + " already exists.\n");
errTxt("err: A read only flag for sub_id: " + QString::number(subId.toInt()) + " level: " + QString::number(level.toUInt()) + " already exists.\n");
}
else
{
@ -368,9 +368,9 @@ void RemoveRDOnlyFlag::procIn(const QByteArray &binIn, quint8 dType)
{
errTxt("err: Access denied.\n");
}
else if (!rdOnlyFlagExists(chName, static_cast<quint8>(subId.toInt()), level.toInt()))
else if (!rdOnlyFlagExists(chId, static_cast<quint8>(subId.toUInt()), level.toUInt()))
{
errTxt("err: A read only flag for sub_id: " + QString::number(subId.toInt()) + " level: " + QString::number(level.toInt()) + " does not exists.\n");
errTxt("err: A read only flag for sub_id: " + QString::number(subId.toUInt()) + " level: " + QString::number(level.toUInt()) + " does not exists.\n");
}
else
{

View File

@ -275,8 +275,6 @@ void CreateChannel::procIn(const QByteArray &binIn, uchar dType)
auto args = parseArgs(binIn, 2);
auto chName = getParam("-ch_name", args);
quint64 chId;
retCode = INVALID_PARAMS;
if (chName.isEmpty())
@ -287,7 +285,7 @@ void CreateChannel::procIn(const QByteArray &binIn, uchar dType)
{
errTxt("err: Invalid channel name. it must be between 4-32 chars long and contain no spaces.\n");
}
else if (channelExists(chName, &chId))
else if (channelExists(chName))
{
errTxt("err: Channel name '" + chName + "' already exists.\n");
}
@ -301,6 +299,12 @@ void CreateChannel::procIn(const QByteArray &binIn, uchar dType)
db.addColumn(COLUMN_CHANNEL_NAME, chName);
db.exec();
db.setType(Query::PULL, TABLE_CHANNELS);
db.addColumn(COLUMN_CHANNEL_ID);
db.addCondition(COLUMN_CHANNEL_NAME, chName);
db.exec();
auto chId = db.getData(COLUMN_CHANNEL_ID).toUInt();
auto uId = rdFromBlock(userId, BLKSIZE_USER_ID);
auto uName = rdStringFromBlock(userName, BLKSIZE_USER_NAME);
auto dName = rdStringFromBlock(displayName, BLKSIZE_DISP_NAME);

View File

@ -421,14 +421,14 @@ bool modExists(const QString &modPath)
return db.rows();
}
bool rdOnlyFlagExists(const QString &chName, uchar subId, int level)
bool rdOnlyFlagExists(quint64 chId, quint8 subId, quint32 level)
{
Query db;
db.setType(Query::PULL, TABLE_RDONLY_CAST);
db.addColumn(COLUMN_ACCESS_LEVEL);
db.addCondition(COLUMN_SUB_CH_ID, subId);
db.addCondition(COLUMN_CHANNEL_NAME, chName);
db.addCondition(COLUMN_CHANNEL_ID, chId);
db.addCondition(COLUMN_ACCESS_LEVEL, level);
db.exec();

View File

@ -260,7 +260,7 @@ bool inviteExists(const QByteArray &uId, quint64 chId);
bool channelExists(const QString &chName, quint64 *chId = nullptr);
bool channelSubExists(quint64 chId, const QString &sub, quint8 *subId = nullptr);
bool recoverPWExists(const QByteArray &uId);
bool rdOnlyFlagExists(const QString &chName, uchar subId, int level);
bool rdOnlyFlagExists(quint64 chId, quint8 subId, quint32 level);
bool isBool(const QString &str);
bool isInt(const QString &str);
bool isLocked(const QByteArray &uId);

View File

@ -37,7 +37,7 @@
#include "shell.h"
#define APP_NAME "MRCI"
#define APP_VER "3.0.0.0"
#define APP_VER "3.1.0.0"
#define APP_TARGET "mrci"
#ifdef Q_OS_WIN

View File

@ -35,6 +35,7 @@ Session::Session(const QString &hostKey, QSslSocket *tcp, QObject *parent) : Mem
tcpPayloadSize = 0;
tcpFrameType = 0;
flags = 0;
activeMods = 0;
}
void Session::init()
@ -135,10 +136,18 @@ void Session::cmdProcFinished(quint32 cmdId)
}
}
void Session::cmdProcStarted(quint32 cmdId, CmdProcess *obj)
void Session::modProcFinished()
{
cmdProcesses.insert(cmdId, obj);
activeMods--;
if (flags & END_SESSION_EMPTY_PROC)
{
endSession();
}
}
void Session::cmdProcStarted(quint32 cmdId)
{
if (frameQueue.contains(cmdId))
{
for (auto&& frame : frameQueue[cmdId])
@ -152,8 +161,6 @@ void Session::cmdProcStarted(quint32 cmdId, CmdProcess *obj)
void Session::endSession()
{
emit killMods();
logout("", false);
if (flags & ACTIVE_PAYLOAD)
@ -162,7 +169,7 @@ void Session::endSession()
}
else
{
if (cmdProcesses.isEmpty())
if (cmdProcesses.isEmpty() && (activeMods == 0))
{
addIpAction("Session Ended");
cleanupDbConnection();
@ -173,21 +180,17 @@ void Session::endSession()
{
flags |= END_SESSION_EMPTY_PROC;
for (auto id : cmdProcesses.keys())
{
emit killCmd32(id);
}
emit killMods();
}
}
}
void Session::startCmdProc(quint32 cmdId)
{
quint16 cmdId16 = toCmdId16(cmdId);
QString modApp = cmdAppById[cmdId16];
QString pipe = rdFromBlock(sessionId, BLKSIZE_USER_ID).toHex() + "-cmd-" + QString::number(cmdId);
auto *proc = new CmdProcess(cmdId, cmdRealNames[cmdId16], modApp, sesMemKey, hostMemKey, pipe, this);
auto cmdId16 = toCmdId16(cmdId);
auto modApp = cmdAppById[cmdId16];
auto pipe = rdFromBlock(sessionId, BLKSIZE_USER_ID).toHex() + "-cmd-" + QString::number(cmdId);
auto *proc = new CmdProcess(cmdId, cmdRealNames[cmdId16], modApp, sesMemKey, hostMemKey, pipe, this);
proc->setWorkingDirectory(currentDir);
proc->setSessionParams(sharedMem, sessionId, openWritableSubChs, &hookCmdId32);
@ -202,15 +205,17 @@ void Session::startCmdProc(quint32 cmdId)
connect(this, &Session::killCmd16, proc, &CmdProcess::killCmd16);
connect(this, &Session::killCmd32, proc, &CmdProcess::killCmd32);
connect(this, &Session::killMods, proc, &CmdProcess::killProc);
cmdProcesses.insert(cmdId, proc);
proc->startCmdProc();
}
ModProcess *Session::initModProc(const QString &modApp)
{
QString pipe = rdFromBlock(sessionId, BLKSIZE_USER_ID).toHex() + "-mod-" + genSerialNumber();
quint32 rnk = rd32BitFromBlock(hostRank);
auto pipe = rdFromBlock(sessionId, BLKSIZE_USER_ID).toHex() + "-mod-" + genSerialNumber();
auto rnk = rd32BitFromBlock(hostRank);
auto *proc = new ModProcess(modApp, sesMemKey, hostMemKey, pipe, this);
proc->setWorkingDirectory(currentDir);
@ -218,9 +223,12 @@ ModProcess *Session::initModProc(const QString &modApp)
connect(proc, &ModProcess::dataToClient, this, &Session::dataToClient);
connect(proc, &ModProcess::cmdUnloaded, this, &Session::killCmd16);
connect(proc, &ModProcess::modProcFinished, this, &Session::modProcFinished);
connect(this, &Session::killMods, proc, &ModProcess::killProc);
activeMods++;
return proc;
}
@ -255,7 +263,7 @@ void Session::loadCmds()
void Session::dataToCmd(quint32 cmdId, const QByteArray &data, quint8 typeId)
{
quint16 cmdId16 = toCmdId16(cmdId);
auto cmdId16 = toCmdId16(cmdId);
if (cmdIds.contains(cmdId16))
{
@ -521,15 +529,16 @@ void Session::sendLocalInfo()
dataToClient(ASYNC_SYS_MSG, frame, MY_INFO);
}
void Session::castPeerStat(const QByteArray &oldSubIds, bool isDisconnecting)
void Session::castPeerStat(const QByteArray &targets, bool isDisconnecting)
{
if (rd8BitFromBlock(activeUpdate))
{
// format: [54bytes(chIds)][1byte(typeId)][rest-of-bytes(PEER_STAT)]
QByteArray typeId = wrInt(PEER_STAT, 8);
QByteArray sesId = rdFromBlock(sessionId, BLKSIZE_SESSION_ID);
QByteArray openSubs = rdFromBlock(openSubChs, MAX_OPEN_SUB_CHANNELS * BLKSIZE_SUB_CHANNEL);
auto typeId = wrInt(PEER_STAT, 8);
auto sesId = rdFromBlock(sessionId, BLKSIZE_SESSION_ID);
auto openSubs = rdFromBlock(openSubChs, MAX_OPEN_SUB_CHANNELS * BLKSIZE_SUB_CHANNEL);
QByteArray dc;
if (isDisconnecting)
@ -541,7 +550,7 @@ void Session::castPeerStat(const QByteArray &oldSubIds, bool isDisconnecting)
dc = QByteArray(1, 0x00);
}
emit asyncToPeers(ASYNC_LIMITED_CAST, oldSubIds + typeId + sesId + openSubs + dc);
emit asyncToPeers(ASYNC_LIMITED_CAST, targets + typeId + sesId + openSubs + dc);
}
}

View File

@ -39,6 +39,7 @@ private:
QHash<quint16, QString> cmdRealNames;
QHash<quint16, QString> cmdAppById;
QList<quint16> cmdIds;
quint32 activeMods;
quint32 flags;
quint32 hookCmdId32;
quint32 tcpPayloadSize;
@ -55,7 +56,7 @@ private:
void startCmdProc(quint32 cmdId);
void startModProc(const QString &modApp);
void addIpAction(const QString &action);
void castPeerStat(const QByteArray &oldSubIds, bool isDisconnecting);
void castPeerStat(const QByteArray &targets, bool isDisconnecting);
ModProcess *initModProc(const QString &modApp);
QByteArray genSessionId();
@ -90,8 +91,9 @@ private slots:
void dataFromClient();
void payloadDeleted();
void modProcFinished();
void cmdProcFinished(quint32 cmdId);
void cmdProcStarted(quint32 cmdId, CmdProcess *obj);
void cmdProcStarted(quint32 cmdId);
void asyncToClient(quint16 cmdId, const QByteArray &data, quint8 typeId);
void dataToClient(quint32 cmdId, const QByteArray &data, quint8 typeId);
void dataToCmd(quint32 cmdId, const QByteArray &data, quint8 typeId);