📄 largedatagram.cpp
字号:
/*************************************************************************** * Copyright (C) 2007 by Anistratov Oleg * * ower@users.sourceforge.net * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License version 2 * * as published by the Free Software Foundation; * * * * This program 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. * * * ***************************************************************************/#include "largedatagram.h"#include "globals.h"#include <assert.h>#include <QHostAddress>#include "chatcore.h"#include "userinfo.h"LargeDatagram::LargeDatagram(quint64 IP, quint32 ID, QObject* parent) : QObject(parent), m_remain (101), m_isFile (false), m_fileInited (false), m_inited (false), m_srcIP (IP), m_datagramID (ID), m_lastFragmentNum (0), m_fragments (NULL), m_data (NULL), m_requestInterval (1000), m_selfDestroyInterval(60 * 1000){ qDebug("[LargeDatagram::LargeDatagram]: ID = %lu", (unsigned long)ID); m_requestTimer = new QTimer(this); m_selfDestroyTimer = new QTimer(this); connect(m_requestTimer , SIGNAL(timeout()), this, SLOT(slot_fragmentsRequest ())); connect(m_selfDestroyTimer, SIGNAL(timeout()), this, SLOT(slot_selfDestroy ()));}//\*****************************************************************************LargeDatagram::~LargeDatagram(){ qDebug("[~LargeDatagram]: ID = %lu", (unsigned long)m_datagramID); free(m_fragments); free(m_data);}//\*****************************************************************************void LargeDatagram::initDatagram(const char* dtgrm, quint32 dtgrm_len){ quint8 cnl; // comp_name_len quint8 unl; // user_name_len if(m_inited || dtgrm_len < AbstractChatCore::protocolLen()) return; m_programVersion = ChatCore::programVersion (dtgrm); m_protocolVersion = ChatCore::protocolVersion(dtgrm); m_destIP = ChatCore::destIp (dtgrm); m_packetType = ChatCore::packetType (dtgrm); m_fragmentSize = ChatCore::fragmentSize (dtgrm); m_firstFragmentTime = ChatCore::time (dtgrm); m_channelType = ChatCore::channelType (dtgrm); cnl = ChatCore::compNameLen (dtgrm); unl = ChatCore::userNameLen (dtgrm); if(dtgrm_len < quint32(AbstractChatCore::protocolLen() + unl + cnl + AbstractChatCore::optionsLen(dtgrm))) return; m_totalFragments = ChatCore::messageLen (dtgrm); m_totalSize = ChatCore::parametrsLen(dtgrm); m_senderCompName = ChatCore::compName (dtgrm, dtgrm_len); m_senderName = ChatCore::userName (dtgrm, dtgrm_len); // не m_totalFragments-1, потому что 0-й фрагмент является инициализирующим m_lastFragmentNum = m_totalFragments; // вычисляем есть ли остаток if(m_totalSize < m_fragmentSize * m_totalFragments) m_lastFragmentSize = m_totalSize - (m_fragmentSize * (m_totalFragments - 1)); else m_lastFragmentSize = m_fragmentSize; m_currentSize = 0; m_fragmentsRemain = m_totalFragments; m_fragments = (char*)calloc(m_totalFragments, 1); assert(NULL != m_fragments); //****************** if(AbstractChatCore::packetType(dtgrm) == AbstractChatCore::FILE) { QByteArray ba; quint16 size; if(dtgrm_len >= quint32(AbstractChatCore::protocolLen() + unl + cnl + 2 + AbstractChatCore::optionsLen(dtgrm))) { size = str2US(dtgrm + AbstractChatCore::protocolLen() + unl + cnl + AbstractChatCore::optionsLen(dtgrm)); if(dtgrm_len >= quint32(AbstractChatCore::protocolLen() + unl + cnl + 2 + size + AbstractChatCore::optionsLen(dtgrm))) { m_filename = QString().fromUtf8(dtgrm + AbstractChatCore::protocolLen() + unl + cnl + 2, size + AbstractChatCore::optionsLen(dtgrm)); // FIXME kraine koryavo qDebug("[LargeDatagram::initDatagram]: filename = %s", m_filename.toLocal8Bit().data()); } m_isFile = true; } else { m_selfDestroyTimer->setInterval(m_selfDestroyInterval); m_selfDestroyTimer->start(); return; } } //****************** else { m_data = (char*)calloc(m_totalSize, 1); assert(NULL != m_data); } m_inited = true; if((!m_isFile || m_fileInited) && m_requestTimer && m_selfDestroyTimer) { m_requestTimer->setInterval(m_requestInterval); m_requestTimer->start(); m_selfDestroyTimer->setInterval(m_selfDestroyInterval); m_selfDestroyTimer->start(); } else if(!m_requestTimer || !m_selfDestroyTimer) { Globals::addError("Timer(s) is(are) NULL!"); qWarning("[LargeDatagram[%d]::initDatagram]: Timer(s) is(are) NULL! req_timer = %p, destr_timer = %p\n ", m_datagramID, m_requestTimer, m_selfDestroyTimer); }}//\*****************************************************************************void LargeDatagram::addFragment(const char* dtgrm, quint32 dtgrm_len){// qDebug("[LargeDatagram[%d]::addFragment]:", m_datagramID); // TODO proveryat' sootvetstvie dtgrm_len neobhodimomu razmeru if(!m_inited || !m_fragmentsRemain || dtgrm_len < AbstractChatCore::protocolLen()) return; quint32 num = ChatCore::packetNum (dtgrm); quint8 cnl = ChatCore::compNameLen(dtgrm); quint8 unl = ChatCore::userNameLen(dtgrm); if((dtgrm_len < quint32(AbstractChatCore::protocolLen() + unl + cnl + AbstractChatCore::optionsLen(dtgrm))) || m_fragments[num - 1] || (ChatCore::packetType(dtgrm) == AbstractChatCore::FILE)) return; // если фрагмент последний - его размер может быть меньше чем у остальных.. выясним это: int fragment_size = (num != m_totalFragments) ? m_fragmentSize : m_lastFragmentSize; if(dtgrm_len < quint32(AbstractChatCore::protocolLen() + unl + cnl + fragment_size + AbstractChatCore::optionsLen(dtgrm))) return; memcpy((m_data + (num - 1) * m_fragmentSize), dtgrm + AbstractChatCore::protocolLen() + cnl + unl + AbstractChatCore::optionsLen(dtgrm), fragment_size); m_fragmentsRemain--; m_currentSize += fragment_size; m_fragments[num - 1] = 1; if(!m_fragmentsRemain) { m_finalFragmentTime = time(NULL); m_requestTimer->stop(); m_selfDestroyTimer->stop(); delete m_selfDestroyTimer; delete m_requestTimer; m_selfDestroyTimer = NULL; m_requestTimer = NULL; return; } else if(num == m_lastFragmentNum) { qDebug("[LargeDatagram[%d]::addFragment]: fragmentsRemain = %d", m_datagramID, m_fragmentsRemain); qDebug("[LargeDatagram[%d]::addFragment]: lastFragmentNum = %d", m_datagramID, m_lastFragmentNum); for(int i = m_lastFragmentNum; i >= 0; i--) if(!m_fragments[i]) { m_lastFragmentNum = i; break; } qDebug("[LargeDatagram[%d]::addFragment]: newLastFragmentNum = %d", m_datagramID, m_lastFragmentNum); emit wantFragments(m_fragments, m_totalFragments, m_datagramID, m_srcIP); } if(m_requestTimer) m_requestTimer->start(m_requestInterval); if(m_selfDestroyTimer) m_selfDestroyTimer->start(m_selfDestroyInterval);}//\*****************************************************************************void LargeDatagram::addFileFragment(const char* dtgrm, quint32 dtgrm_len){ if(!m_inited || !m_fragmentsRemain || dtgrm_len < AbstractChatCore::protocolLen() || (m_isFile && !m_fileInited)) return; quint32 num = ChatCore::packetNum (dtgrm); quint8 cnl = ChatCore::compNameLen(dtgrm); quint8 unl = ChatCore::userNameLen(dtgrm); if(dtgrm_len < quint32(AbstractChatCore::protocolLen() + unl + cnl + AbstractChatCore::optionsLen(dtgrm))) return; if(m_fragments[num - 1]) return; // если фрагмент последний - его размер может быть меньше чем у остальных.. выясним это: int fragment_size = (num != m_totalFragments) ? m_fragmentSize : m_lastFragmentSize; if(dtgrm_len < quint32(AbstractChatCore::protocolLen() + unl + cnl + fragment_size + AbstractChatCore::optionsLen(dtgrm))) return; m_file.seek(m_fragmentSize * (num - 1)); m_file.write(dtgrm + AbstractChatCore::protocolLen() + cnl + unl + AbstractChatCore::optionsLen(dtgrm), fragment_size); m_fragmentsRemain--; m_currentSize += fragment_size; m_fragments[num - 1] = 1; if(!m_fragmentsRemain) { m_finalFragmentTime = time(NULL); printf("[LargeDatagram[%d]::addFileFragment]: 0%% left\n", m_datagramID); emit percentsRemain(0, m_datagramID, m_srcIP); m_file.close(); m_requestTimer->stop(); m_selfDestroyTimer->stop(); delete m_selfDestroyTimer; delete m_requestTimer; m_selfDestroyTimer = NULL; m_requestTimer = NULL; emit completed(this); return; } else if(num == m_lastFragmentNum) { qDebug("[LargeDatagram[%d]::addFileFragment]: fragmentsRemain = %d", m_datagramID, m_fragmentsRemain); qDebug("[LargeDatagram[%d]::addFileFragment]: lastFragmentNum = %d", m_datagramID, m_lastFragmentNum); for(int i = m_lastFragmentNum; i >= 0; i--) if(!m_fragments[i]) { m_lastFragmentNum = i; break; } qDebug("[LargeDatagram[%d]::addFileFragment]: newLastFragmentNum = %d", m_datagramID, m_lastFragmentNum); emit wantFragments(m_fragments, m_totalFragments, m_datagramID, m_srcIP); } quint8 remain = (quint8)((double)m_fragmentsRemain / ((double)m_totalFragments / (double)100)); if(remain < m_remain) { m_remain = remain; printf("[LargeDatagram[%d]::addFileFragment]: %d%% left\n", m_datagramID, remain); emit percentsRemain(remain, m_datagramID, m_srcIP); } if(m_requestTimer) m_requestTimer->start(m_requestInterval); if(m_selfDestroyTimer) m_selfDestroyTimer->start(m_selfDestroyInterval);}//\*****************************************************************************bool LargeDatagram::fillHeader(QC_DatagramHeader* Hdr){ qDebug("[LargeDatagram(%lu, %lu)::fillHeader], m_inited = %d", (unsigned long)m_srcIP, (unsigned long)m_datagramID, m_inited); int shift; shift = /*m_protocolVersion >= 4 ? 0 :*/ 8; if(m_inited == false || m_programVersion < 5 || (m_protocolVersion != AbstractChatCore::protocolVersion())) return 0; Hdr->programVersion = m_programVersion; Hdr->protocolVersion = m_protocolVersion; Hdr->dest_ip = m_destIP; Hdr->src_ip = m_srcIP; Hdr->type = m_packetType; Hdr->tm = m_firstFragmentTime; Hdr->receive_tm = m_finalFragmentTime; Hdr->name = m_senderName; Hdr->comp_name = m_senderCompName; Hdr->chnnl_id = m_channelType; Hdr->msg_len = str2UL(m_data ); Hdr->parametrs_len = str2UL(m_data + 4); printf("protver = %d\n", m_protocolVersion);// if(m_protocolVersion >= 4)// {// Hdr->msg_len = AbstractChatCore::messageLen(m_data);// Hdr->parametrs_len = AbstractChatCore::parametrsLen(m_data);// } if(m_totalSize < shift + Hdr->msg_len + Hdr->parametrs_len) { qWarning("[LargeDatagram::fillHeader]: [error] wrong length of fragmented packet (total size smaller than expected[%jd < %lu]) [3]\n Exiting from fillHeader\n", m_totalSize, shift + Hdr->msg_len + Hdr->parametrs_len );// qWarning("[LargeDatagram::fillHeader]: %d + %d\n", Hdr->msg_len, Hdr->parametrs_len); return 0; } Hdr->msg = QString().fromUtf8( QByteArray(m_data + shift, Hdr->msg_len), Hdr->msg_len ); Hdr->parametrs = QByteArray(m_data + shift + Hdr->msg_len, Hdr->parametrs_len); Hdr->color = ChatCore::getColorParametr(&Hdr->parametrs); // getting versionName QByteArray ba = ChatCore::getParametr("Version", Hdr->parametrs); if(!ba.isEmpty()) Hdr->versionName = QString().fromUtf8(ba); else if(Hdr->programVersion <= Globals::VersionID) Hdr->versionName = QString(Globals::VersionsTable[Hdr->programVersion - 1]); else Hdr->versionName = QString("New Version[id = %1]").arg(Hdr->programVersion); // getting status Hdr->status = Globals::FREE; ba = ChatCore::getParametr("Status", Hdr->parametrs); if(!ba.isEmpty()) Hdr->status = ba[0]; clear(); emit completed(this); return 1;}//\*****************************************************************************void LargeDatagram::clear(){ if(m_inited) { free(m_data); free(m_fragments); m_data = NULL; m_fragments = NULL; } m_inited = false;}//\*****************************************************************************void LargeDatagram::slot_fragmentsRequest(){ qDebug("[LargeDatagram[%d]::slot_fragmentsRequest]", m_datagramID); if(m_inited && m_fragmentsRemain) emit wantFragments(m_fragments, m_totalFragments, m_datagramID, m_srcIP);}//\*****************************************************************************void LargeDatagram::slot_selfDestroy(){ qDebug("[LargeDatagram[%d]::selfDestroy]", m_datagramID); delete m_requestTimer; delete m_selfDestroyTimer; clear(); m_inited = false; emit wantDie(this);}//\*****************************************************************************void LargeDatagram::allocateSpace(){ if(!m_fileInited) return; m_file.open(QIODevice::WriteOnly); m_file.resize(m_totalSize); m_file.seek(0);}//\*****************************************************************************void LargeDatagram::slot_initFile(const QString & filename){ m_file.setFileName(filename); m_fileInited = true; allocateSpace(); m_requestTimer->setInterval(m_requestInterval); m_requestTimer->start(); emit readyReceive(m_datagramID, m_srcIP);}//\*****************************************************************************
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -