qftrans/csendthread.cpp
2009-04-20 13:29:36 +02:00

218 lines
6.7 KiB
C++

/***************************************************************************
* Copyright (C) 2008 by Oliver Groß *
* z.o.gross@gmx.de *
* *
* This program 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 2 of the License, or *
* (at your option) any later version. *
* *
* 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. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "csenderthread.h"
#include <QTcpSocket>
#include <QByteArray>
#include <QDataStream>
#include <QFile>
namespace qftrans {
CSenderThread::CSenderThread(QTcpSocket * socket, QObject * parent) : QThread(parent), m_Socket(socket), m_IdCounter(0) {
}
CSenderThread::~CSenderThread() {
}
void CSenderThread::addUpload(TransferData * upload) {
if (!m_DataDict.contains(upload)) {
qDebug() << "adding upload";
m_DataDict.insert(upload, m_IdCounter);
m_IdCounter++;
}
}
void CSenderThread::removeUpload(TransferData * transfer) {
transfer->status = TS_CLOSING;
if (m_Socket->bytesToWrite() == 0) {
qDebug() << "executing upload";
writeData();
}
}
void CSenderThread::startUpload(TransferData * upload) {
if (m_DataDict.contains(upload) && upload->status == TS_WAITING) {
qDebug() << "scheduling upload for announce";
upload->status = TS_ANNOUNCING;
if (m_Socket->bytesToWrite() == 0) {
qDebug() << "executing upload";
writeData();
}
}
}
void CSenderThread::startUploadData(quint32 id) {
TransferData * transfer = m_DataDict.key(id);
if (transfer) {
qDebug() << "scheduling upload for transfer";
transfer->status = TS_TRANSFERING;
if (m_Socket->bytesToWrite() == 0) {
qDebug() << "executing upload";
writeData();
}
}
}
void CSenderThread::sendAcknowledge(quint32 id) {
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_4_0);
TransferHeader header;
// header.descriptor = DESCRIPTOR_STRING;
header.type = HT_ACK;
header.id = id;
header.length = 0;
out.writeRawData((const char *)(&header), sizeof(TransferHeader));
qDebug() << "sending HT_ACK" << id;
m_Socket->write(block);
}
void CSendThread::writeData() {
if (m_DataDict.isEmpty())
exit();
QByteArray block;
QDataStream out(&block, QIODevice::ReadWrite);
out.setVersion(QDataStream::Qt_4_0);
QTransferDataList transfers = m_DataDict.keys();
QTransferDataList::iterator i;
for (i = transfers.begin(); i != transfers.end(); ++i) {
block.clear();
TransferHeader header;
// header.descriptor = DESCRIPTOR_STRING;
switch ((*i)->status) {
case TS_ANNOUNCING: {
qDebug() << "announcing" << m_DataDict[*i];
if ((*i)->transfered)
(*i)->transfered = 0;
// ID header with no data
header.type = HT_ID;
header.id = m_DataDict[*i];
header.length = 0;
out.writeRawData((const char *)(&header), sizeof(TransferHeader));
//size header with size
header.type = HT_SIZE;
header.length = sizeof(qint64);
out.writeRawData((const char *)(&header), sizeof(TransferHeader));
qDebug() << "sending size" << (*i)->size;
out << (*i)->size;
//name header with file name
qint64 oldPosition = block.size();
//fake write filename
out << (*i)->fileName;
out.device()->seek(oldPosition);
header.type = HT_NAME;
header.length = quint32(block.size() - oldPosition);
// qDebug() << "pos" << out.device()->pos() << block.size();
out.writeRawData((const char *)(&header), sizeof(TransferHeader));
// qDebug() << "pos post header" << out.device()->pos() << block.size();
// qint64 oldPosition = block.size() - sizeof(quint32);
qDebug() << "sending filename" << (*i)->fileName;
out << (*i)->fileName;
// qDebug() << "pos post filename" << out.device()->pos() << block.size();
// out.device()->seek(oldPosition);
// qDebug() << "pos post seek" << out.device()->pos();
/* qDebug() << "filename data length" << header.length;
out << header.length;
out.device()->seek(oldPosition);
out >> header.length;
qDebug() << "written length" << header.length;
out.device()->seek(block.size());
qDebug() << "pos post length correct" << out.device()->pos() << block.size();*/
(*i)->status = TS_WAITING;
}
break;
case TS_TRANSFERING: {
// qDebug() << "transfering" << m_DataDict[*i];
header.type = HT_DATA;
header.id = m_DataDict[*i];
if ((*i)->transfered + DATA_BLOCK_SIZE < (*i)->size)
header.length = DATA_BLOCK_SIZE;
else
header.length = (*i)->size - (*i)->transfered;
out.writeRawData((const char *)(&header), sizeof(TransferHeader));
char * buffer = new char[header.length];
QFile file((*i)->fileDir + (*i)->fileName);
file.open(QIODevice::ReadOnly);
QDataStream in(&file);
in.readRawData(buffer, header.length);
out.writeRawData((const char *)(buffer), header.length);
(*i)->transfered += header.length;
delete[] buffer;
if ((*i)->transfered >= (*i)->size)
(*i)->status = TS_CLOSING;
emit uploadUpdated(*i);
}
break;
case TS_CLOSING:
header.type = HT_CLOSE;
header.id = m_DataDict[*i];
header.length = 0;
out.writeRawData((const char *)(&header), sizeof(TransferHeader));
(*i)->status = TS_FINISHED;
m_DataDict.remove(*i);
break;
default:
break;
}
if (!block.isEmpty())
m_Socket->write(block);
}
}
void CSendThread::run() {
qDebug() << "start sender thread";
connect(m_Socket, SIGNAL(bytesWritten(qint64)), this, SLOT(writeData()));
exec();
disconnect(m_Socket, SIGNAL(bytesWritten(qint64)), this, SLOT(writeData()));
}
}