diff --git a/src/async_funcs.cpp b/src/async_funcs.cpp index 22a38cb..3582f57 100644 --- a/src/async_funcs.cpp +++ b/src/async_funcs.cpp @@ -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); + } } } diff --git a/src/cmd_object.cpp b/src/cmd_object.cpp index 7e92894..9b2e42a 100644 --- a/src/cmd_object.cpp +++ b/src/cmd_object.cpp @@ -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(header[0]); ipcDataSize = static_cast(rdInt(header.mid(1, 3))); diff --git a/src/cmd_object.h b/src/cmd_object.h index ca1ce6c..fd6fbc3 100644 --- a/src/cmd_object.h +++ b/src/cmd_object.h @@ -29,7 +29,6 @@ private slots: private: - IdleTimer *idleTimer; QLocalSocket *ipcSocket; quint32 flags; quint8 ipcTypeId; diff --git a/src/cmd_proc.cpp b/src/cmd_proc.cpp index 58c256f..0fcd5db 100644 --- a/src/cmd_proc.cpp +++ b/src/cmd_proc.cpp @@ -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 *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() diff --git a/src/cmd_proc.h b/src/cmd_proc.h index 6ef17f3..c74bc7b 100644 --- a/src/cmd_proc.h +++ b/src/cmd_proc.h @@ -31,7 +31,6 @@ private: QHash *cmdRealNames; QHash *cmdAppById; QList *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); diff --git a/src/commands/cast.cpp b/src/commands/cast.cpp index 2db5883..df04d4e 100644 --- a/src/commands/cast.cpp +++ b/src/commands/cast.cpp @@ -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(subId.toInt()), level.toInt())) + else if (rdOnlyFlagExists(chId, static_cast(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(subId.toInt()), level.toInt())) + else if (!rdOnlyFlagExists(chId, static_cast(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 { diff --git a/src/commands/channels.cpp b/src/commands/channels.cpp index 2385fd9..9b2d85f 100644 --- a/src/commands/channels.cpp +++ b/src/commands/channels.cpp @@ -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); diff --git a/src/common.cpp b/src/common.cpp index 807758b..938c995 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -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(); diff --git a/src/common.h b/src/common.h index 98877d7..0c83250 100644 --- a/src/common.h +++ b/src/common.h @@ -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); diff --git a/src/db.h b/src/db.h index a7ea9af..ebcf166 100644 --- a/src/db.h +++ b/src/db.h @@ -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 diff --git a/src/session.cpp b/src/session.cpp index 3787117..967130c 100644 --- a/src/session.cpp +++ b/src/session.cpp @@ -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); } } diff --git a/src/session.h b/src/session.h index 58c1018..3106ee1 100644 --- a/src/session.h +++ b/src/session.h @@ -39,6 +39,7 @@ private: QHash cmdRealNames; QHash cmdAppById; QList 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);