Logo Search packages:      
Sourcecode: qchat version File versions  Download package

largedatagramout.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 "largedatagramout.h"
#include "globals.h"

#include <QThread>

#include "chatcore.h"

LargeDatagramOut::LargeDatagramOut(QObject *parent)
 : QObject(parent),
  m_confirmed          (false),
  m_inited             (false),
  m_header             (NULL),
  m_data               (NULL),
  m_fragments          (NULL),
  m_selfDestroyInterval(10 * 1000)
{
  m_selfDestroyTimer = new QTimer(this);

  connect(m_selfDestroyTimer, SIGNAL(timeout()), this, SLOT(selfDestroy()));
}
//\*****************************************************************************
LargeDatagramOut::~LargeDatagramOut()
{
  qDebug("[~LargeDatagramOut]: ID = %lu", (unsigned long)m_id);
  free(m_header);
  free(m_data);
  free(m_fragments);
}
//\*****************************************************************************
void LargeDatagramOut::init(char* header, quint16 header_size,
                            char* data  , quint32 data_size  , const QHostAddress & addr, quint32 ID)
{
  m_id              = ID;
  m_destAddr        = addr;
  m_header          = header;
  m_data            = data  ;
  m_headerSize      = header_size;
  m_dataSize        = data_size;
  m_sizePerFragment = (MAX_PACKET_LEN - m_headerSize);
  m_rest            = m_dataSize % m_sizePerFragment;
  m_totalFragments  = m_dataSize / m_sizePerFragment + m_rest;
  m_fragmentsRemain = m_totalFragments;
  m_fragments       = (char*)calloc(m_totalFragments + 1, 1);// + 1, t.k. nado otoslat' esche i initsializir. paket!
  m_inited          = true;
  m_confirmed       = true;
}
//\*****************************************************************************
void LargeDatagramOut::init(char*   header, quint16 header_size,
                            const QString & filename, const QHostAddress & addr, quint32 ID)
{
  m_id         = ID;
  m_destAddr   = addr;
  m_header     = header;
  m_data       = NULL;
  m_headerSize = header_size;
  m_dataSize   = 0;
  m_filename   = filename;

  m_file.setFileName(filename);

  if(!m_file.open(QIODevice::ReadOnly))
  {
    qWarning("[LargeDatagramOut::init]: Failed. couldn't open file %s for reading!\n", m_filename.toLocal8Bit().data());
    emit wantDie(this);
    emit sendingCancelled(ID);
    return;
  }

  if(m_file.handle() < 0)
  {
    qWarning("[LargeDatagramOut::init]: m_file.handle() < 0\n");
//     emit wantDie(this);
//     return;
  }

  m_fileSize        = m_file.size();
  m_sizePerFragment = (MAX_PACKET_LEN - m_headerSize);
  m_rest            = m_fileSize % m_sizePerFragment;
  m_totalFragments  = m_fileSize / m_sizePerFragment + m_rest;
  m_fragmentsRemain = m_totalFragments;
  m_fragments       = (char*)calloc(m_totalFragments + 1, 1);// + 1, t.k. nado otoslat' esche i initsializir. paket!
  m_inited          = true;
}
//\*****************************************************************************
void LargeDatagramOut::prepareInitHeader()
{
  if(!m_inited)
    return;

  catUS2str(m_header + 39, m_id             ); //PacketID
  catUS2str(m_header + 41, m_sizePerFragment);
  catUL2str(m_header + 43, 0              ); //PacketNUM
  catUL2str(m_header + 61, (quint32)(m_totalFragments)); // +61 MsgLen        / TotalFragments / DataLen

  // FIXME !!!file size may be greater then quint32!!!
  if(!m_filename.isEmpty())
    catUL2str(m_header + 65, (quint32)m_fileSize);
  else
    catUL2str(m_header + 65, (quint32)m_dataSize); // +65 ParametersLen / TotalSize      / == 0
}
//\*****************************************************************************
void LargeDatagramOut::sendNextFragment(QUdpSocket* socket, quint16 port, char* buf)
{
  quint32 num;
  quint32 i;
  quint32 size;

  if(!m_fragmentsRemain)
  {
    if(m_selfDestroyTimer && (m_selfDestroyTimer->timerId() < 0))
    {
      m_selfDestroyTimer->setSingleShot(true);
      m_selfDestroyTimer->start(m_selfDestroyInterval);
    }
    return;
  }

  // TODO optimizirovat'
  for(i = 0; i <= m_totalFragments; i++)
    if(m_fragments[i] == 0)
      break;

  num = i;

  if(num != 0 && !m_confirmed)
    return;

  if(num > m_totalFragments)// znachit net neotoslannyh fragmentov. i soobschenii o peresylke ne prihodilo
    return;

  size = writeFragment(buf, num);

  if(socket->writeDatagram(buf, size, m_destAddr, port) < 0)
    qWarning("\n[LargeDatagramOut::sendNextFragment]: datagram send error !\n");
  else
  {
    m_fragments[num] = 1;
    if(num)
      m_fragmentsRemain--;

    // esli vse otoslali - zhdem nekotoroe vremya zaprosov pereslat' zanovo fragmenty,
    // i esli zaprosa ne prihodit unichtozhaemsya
    if(!m_fragmentsRemain)
    {
      m_selfDestroyTimer->setSingleShot(true);
      m_selfDestroyTimer->start(m_selfDestroyInterval);
    }
  }


}
//\*****************************************************************************
quint32 LargeDatagramOut::writeFragment(char* buf, quint32 num)
{
  if(!m_inited || !buf || num > m_totalFragments)
    return 0;

  if(num == m_totalFragments && m_rest)
  {
    catUL2str(m_header + 65 , 0                     ); // +65 ParametersLen / TotalSize      / == 0
    catUL2str(m_header + 43 , num                   ); //PacketNUM
    catUL2str(m_header + 61 , m_sizePerFragment     ); // +61 MsgLen        / TotalFragments / DataLen
    memcpy  (buf           , m_header, m_headerSize);

    if(!m_filename.isEmpty())
    {
      m_file.seek((num - 1) * m_sizePerFragment);
      m_file.read(buf + m_headerSize, m_fileSize % m_sizePerFragment);

      return m_headerSize + (m_fileSize % m_sizePerFragment);
    }

    memcpy(buf + m_headerSize, m_data + (m_sizePerFragment * (num - 1)), m_dataSize % m_sizePerFragment);

    return m_headerSize + (m_dataSize % m_sizePerFragment);
  }

  if(!num)
  {
    prepareInitHeader();
    memcpy(buf, m_header, m_headerSize);

    if(!m_filename.isEmpty())
    {
      QByteArray ba = m_filename.right(m_filename.size() - 1 - m_filename.lastIndexOf("/")).toUtf8();
      catUS2str(buf + m_headerSize    , ba.size());
      memcpy  (buf + m_headerSize + 2, ba.data(), ba.size());

      return m_headerSize + 2 + ba.size();
    }

    return m_headerSize;
  }

  catUL2str(m_header + 65 , 0                     ); // +65 ParametersLen / TotalSize      / == 0
  catUL2str(m_header + 43 , num                   ); //PacketNUM
  catUL2str(m_header + 61 , m_sizePerFragment     ); // +61 MsgLen        / TotalFragments / DataLen
  memcpy  (buf           , m_header, m_headerSize);

  if(!m_filename.isEmpty())
  {
    m_file.seek((num - 1) * m_sizePerFragment);
    m_file.read(buf + m_headerSize, m_sizePerFragment);

    return m_headerSize + m_sizePerFragment;
  }

  memcpy(buf + m_headerSize, m_data + (m_sizePerFragment * (num - 1)), m_sizePerFragment);

  return m_headerSize + m_sizePerFragment;
}
//\*****************************************************************************
void LargeDatagramOut::selfDestroy()
{
  qDebug("[LargeDatagramOut[%d]::selfDestroy]", m_id);
  emit wantDie(this);
}
//\*****************************************************************************
void LargeDatagramOut::slot_confirmed(unsigned short ID)
{
  if(m_id == ID)
    m_confirmed = true;
}
//\*****************************************************************************
void LargeDatagramOut::fragmentsRequest(const char* dtgrm, quint16 len)
{
//   qDebug("[LargeDatagramOut::fragmentsRequest]");
  quint32     i;
  quint32     shift = 69 + dtgrm[59] + dtgrm[60] + str2UL(dtgrm + 61);
  quint32     pars_len = str2UL(dtgrm + 65);

  if(len - shift < pars_len)
    return;

  QByteArray  pars(dtgrm + shift, pars_len);
  QByteArray  buf;
  quint16     frags_len;
  const char* frags;

  if(!m_inited)
    return;

  buf       = ChatCore::getParametr("FragmentsLen", pars);
  frags_len = str2US(buf.data());

  qDebug("[LargeDatagramOut::fragmentsRequest]: fragments_len = %d", frags_len);

  buf       = ChatCore::getParametr("FragmentsRequest", pars);
  frags     = buf.constData();

  qDebug("[LargeDatagramOut::fragmentsRequest]: fragmentsRemain before = %d", m_fragmentsRemain);

  for(i = 0; i < frags_len && i < m_totalFragments; i++)
    if(!frags[i])
    {
      m_fragmentsRemain += m_fragments[i + 1];
      m_fragments[i + 1] = 0;
    }

  qDebug("[LargeDatagramOut::fragmentsRequest]: fragmentsRemain after  = %d", m_fragmentsRemain);

  if(m_fragmentsRemain)
    m_selfDestroyTimer->stop();
}
//\*****************************************************************************

Generated by  Doxygen 1.6.0   Back to index