#include "mem_share.h" // This file is part of MRCI. // MRCI is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // MRCI is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with MRCI under the LICENSE.md file. If not, see // . QString createHostSharedMem(QSharedMemory *mem) { auto len = 0; QString ret; len += BLKSIZE_HOST_LOAD; // hostLoad mem->setKey(HOST_NON_NATIVE_KEY); if (mem->create(len)) { ret = mem->nativeKey(); } else if (mem->attach()) { ret = mem->nativeKey(); } return ret; } int posOfLikeBlock(const QByteArray &block, const char *blocks, quint32 numOfBlocks, quint32 bytesPerBlock) { auto ret = -1; auto cmpLen = static_cast(block.size()); if (cmpLen > bytesPerBlock) { cmpLen = bytesPerBlock; } for (uint i = 0; i < numOfBlocks; i += bytesPerBlock) { if (memcmp(block.data(), blocks + i, cmpLen) == 0) { ret = static_cast(i); break; } } return ret; } int posOfBlock(const char *block, const char *blocks, quint32 numOfBlocks, quint32 bytesPerBlock) { int ret = -1; for (uint i = 0; i < numOfBlocks; i += bytesPerBlock) { if (memcmp(block, blocks + i, bytesPerBlock) == 0) { ret = static_cast(i); break; } } return ret; } int countNonEmptyBlocks(const char *blocks, quint32 numOfBlocks, quint32 bytesPerBlock) { int ret = 0; char *blank = new char[bytesPerBlock]; memset(blank, 0, bytesPerBlock); for (uint i = 0; i < numOfBlocks; i += bytesPerBlock) { if (memcmp(blank, blocks + i, bytesPerBlock) != 0) { ret++; } } delete[] blank; return ret; } int posOfEmptyBlock(const char *blocks, quint32 numOfBlocks, quint32 bytesPerBlock) { char *blank = new char[bytesPerBlock]; memset(blank, 0, bytesPerBlock); int ret = posOfBlock(blank, blocks, numOfBlocks, bytesPerBlock); delete[] blank; return ret; } bool addBlockToBlockset(const char *block, char *blocks, quint32 numOfBlocks, quint32 bytesPerBlock) { auto ret = false; if (posOfBlock(block, blocks, numOfBlocks, bytesPerBlock) == -1) { int pos = posOfEmptyBlock(blocks, numOfBlocks, bytesPerBlock); if (pos != -1) { memcpy(blocks + pos, block, bytesPerBlock); ret = true; } } return ret; } bool addStringToBlockset(const QString &str, char *blocks, quint32 numOfBlocks, quint32 bytesPerBlock) { char *block = new char[bytesPerBlock]; wrStringToBlock(str, block, bytesPerBlock); bool ret = addBlockToBlockset(block, blocks, numOfBlocks, bytesPerBlock); delete[] block; return ret; } bool rmBlockFromBlockset(const char *block, char *blocks, quint32 numOfBlocks, quint32 bytesPerBlock) { bool ret = false; int pos = posOfBlock(block, blocks, numOfBlocks, bytesPerBlock); if (pos != -1) { memset(blocks + pos, 0, bytesPerBlock); ret = true; } return ret; } bool rmLikeBlkFromBlkset(const QByteArray &block, char *blocks, quint32 numOfBlocks, quint32 bytesPerBlock) { bool ret = false; int pos = posOfLikeBlock(block, blocks, numOfBlocks, bytesPerBlock); if (pos != -1) { memset(blocks + pos, 0, bytesPerBlock); ret = true; } return ret; } bool isEmptyBlock(const char *block, quint32 blockSize) { char *blank = new char[blockSize]; memset(blank, 0, blockSize); return memcmp(block, blank, blockSize) == 0; } void wrStringToBlock(const QString &str, char *block, quint32 blockSize) { auto strBytes = str.toUtf8(); auto strByteSize = static_cast(strBytes.size()); if (strByteSize > blockSize) { strByteSize = blockSize; } else if (strByteSize != blockSize) { memset(block, 0, blockSize); } memcpy(block, strBytes.data(), strByteSize); } void wr8BitToBlock(quint8 num, char *block) { memcpy(block, &num, 1); } void wr16BitToBlock(quint16 num, char *block) { memcpy(block, &num, 2); } void wr32BitToBlock(quint32 num, char *block) { memcpy(block, &num, 4); } void wr64BitToBlock(quint64 num, char *block) { memcpy(block, &num, 8); } void wrToBlock(const QByteArray &data, char *block, quint32 blockSize) { quint32 actualSize = static_cast(data.size()); if (actualSize > blockSize) { actualSize = blockSize; } else if (actualSize != blockSize) { memset(block, 0, blockSize); } memcpy(block, data.data(), actualSize); } QByteArray wrInt(quint64 num, int numOfBits) { QByteArray ret(numOfBits / 8, static_cast(0)); num = qToLittleEndian(num); memcpy(ret.data(), &num, static_cast(ret.size())); return ret; } QByteArray wrInt(qint64 num, int numOfBits) { return wrInt(static_cast(num), numOfBits); } QByteArray wrInt(int num, int numOfBits) { return wrInt(static_cast(num), numOfBits); } QByteArray wrInt(uint num, int numOfBits) { return wrInt(static_cast(num), numOfBits); } quint8 rd8BitFromBlock(const char *block) { return static_cast(block[0]); } quint16 rd16BitFromBlock(const char *block) { quint16 ret; memcpy(&ret, block, 2); return ret; } quint32 rd32BitFromBlock(const char *block) { quint32 ret; memcpy(&ret, block, 4); return ret; } quint64 rd64BitFromBlock(const char *block) { quint64 ret; memcpy(&ret, block, 8); return ret; } QString rdStringFromBlock(const char *block, quint32 blockSize) { quint32 len = 0; for (quint32 i = 0; i < blockSize; i++) { if (block[i] == 0) { break; } else { len++; } } return QString(QByteArray(block, len)); } QByteArray rdFromBlock(const char *block, quint32 blockSize) { if (blockSize == 0) { return QByteArray(); } else { return QByteArray::fromRawData(block, static_cast(blockSize)); } } quint64 rdInt(const QByteArray &bytes) { quint64 ret = 0; memcpy(&ret, bytes.data(), static_cast(bytes.size())); return qFromLittleEndian(ret); } MemShare::MemShare(QObject *parent) : QObject(parent) { sharedMem = new QSharedMemory(this); hostSharedMem = new QSharedMemory(this); } bool MemShare::createSharedMem(const QByteArray &sesId, const QString &hostKey) { auto len = 0; auto ret = false; sharedMem->setKey(sesId.toHex()); hostSharedMem->setNativeKey(hostKey); len += BLKSIZE_SESSION_ID; // sessionId len += BLKSIZE_USER_ID; // userId len += BLKSIZE_CLIENT_IP; // clientIp len += BLKSIZE_APP_NAME; // appName len += BLKSIZE_USER_NAME; // userName len += BLKSIZE_DISP_NAME; // displayName len += BLKSIZE_HOST_RANK; // hostRank len += BLKSIZE_ACT_UPDATE; // activeUpdate len += BLKSIZE_CH_OVERRIDE; // chOwnerOverride len += (BLKSIZE_CHANNEL_ID * MAX_CHANNELS_PER_USER); // chList len += (BLKSIZE_SUB_CHANNEL * MAX_OPEN_SUB_CHANNELS); // openSubChs len += (BLKSIZE_SUB_CHANNEL * MAX_OPEN_SUB_CHANNELS); // openWritableSubChs len += (BLKSIZE_SESSION_ID * MAX_P2P_LINKS); // p2pPending len += (BLKSIZE_SESSION_ID * MAX_P2P_LINKS); // p2pAccepted if (!sharedMem->create(len)) { qDebug() << "err: Failed to create a shared memory master block. reason: " + sharedMem->errorString(); } else if (!hostSharedMem->attach()) { qDebug() << "err: Failed to attach to the host shared memory master block. reason: " + hostSharedMem->errorString(); } else { memset(sharedMem->data(), 0, static_cast(len)); memcpy(sharedMem->data(), sesId.data(), BLKSIZE_SESSION_ID); ret = true; } return ret; } bool MemShare::attachSharedMem(const QString &sKey, const QString &hKey) { bool ret = false; sharedMem->setNativeKey(sKey); hostSharedMem->setNativeKey(hKey); if (!sharedMem->attach()) { qDebug() << "err: Failed to attach to the session shared memory master block. reason: " + sharedMem->errorString(); } else if (!hostSharedMem->attach()) { qDebug() << "err: Failed to attach to the host shared memory master block. reason: " + hostSharedMem->errorString(); } else { ret = true; } return ret; } void MemShare::setupDataBlocks() { if (sharedMem->isAttached() && hostSharedMem->isAttached()) { char *sesMasterBlock = static_cast(sharedMem->data()); char *hosMasterBlock = static_cast(hostSharedMem->data()); int sesOffs = 0; int hosOffs = 0; sessionId = sesMasterBlock + sesOffs; sesOffs += BLKSIZE_SESSION_ID; userId = sesMasterBlock + sesOffs; sesOffs += BLKSIZE_USER_ID; clientIp = sesMasterBlock + sesOffs; sesOffs += BLKSIZE_CLIENT_IP; appName = sesMasterBlock + sesOffs; sesOffs += BLKSIZE_APP_NAME; userName = sesMasterBlock + sesOffs; sesOffs += BLKSIZE_USER_NAME; displayName = sesMasterBlock + sesOffs; sesOffs += BLKSIZE_DISP_NAME; hostRank = sesMasterBlock + sesOffs; sesOffs += BLKSIZE_HOST_RANK; activeUpdate = sesMasterBlock + sesOffs; sesOffs += BLKSIZE_ACT_UPDATE; chOwnerOverride = sesMasterBlock + sesOffs; sesOffs += BLKSIZE_CH_OVERRIDE; chList = sesMasterBlock + sesOffs; sesOffs += (BLKSIZE_CHANNEL_ID * MAX_CHANNELS_PER_USER); openSubChs = sesMasterBlock + sesOffs; sesOffs += (BLKSIZE_SUB_CHANNEL * MAX_OPEN_SUB_CHANNELS); openWritableSubChs = sesMasterBlock + sesOffs; sesOffs += (BLKSIZE_SUB_CHANNEL * MAX_OPEN_SUB_CHANNELS); p2pPending = sesMasterBlock + sesOffs; sesOffs += (BLKSIZE_SESSION_ID * MAX_P2P_LINKS); p2pAccepted = sesMasterBlock + sesOffs; sesOffs += (BLKSIZE_SESSION_ID * MAX_P2P_LINKS); hostLoad = hosMasterBlock + hosOffs; hosOffs += BLKSIZE_HOST_LOAD; sesMemKey = sharedMem->nativeKey(); hostMemKey = hostSharedMem->nativeKey(); } } QByteArray MemShare::createPeerInfoFrame() { auto sesId = rdFromBlock(sessionId, BLKSIZE_SESSION_ID); auto usrId = rdFromBlock(userId, BLKSIZE_USER_ID); auto uName = rdFromBlock(userName, BLKSIZE_USER_NAME); auto aName = rdFromBlock(appName, BLKSIZE_APP_NAME); auto dName = rdFromBlock(displayName, BLKSIZE_DISP_NAME); return sesId + usrId + uName + aName + dName; }