/* # Copyright (c) 2009 - OpenSLX Project, Computer Center University of Freiburg # # This program is free software distributed under the GPL version 2. # See http://openslx.org/COPYING # # If you have any feedback please consult http://openslx.org/feedback and # send your suggestions, praise, or complaints to feedback@openslx.org # # General information about OpenSLX can be found at http://openslx.org/ # ----------------------------------------------------------------------------- # src/net/mcast/McastReceiver.h # - implement the receiver-side multicast file transfer protocol -- implementation # ----------------------------------------------------------------------------- */ #include #include #include #include // OpenPGM #defines bool. This is bad in C++. #undef bool #include "McastConstants.h" #include "McastReceiver.h" McastReceiver::McastReceiver(QIODevice* iodev, McastConfiguration* config, QObject* parent) : QObject(parent), _config(config ? new McastConfiguration(*config) : 0), _socket(0), _curoffs(0), _closed(false), _hash(QCryptographicHash::Md5), _iodev(iodev) { _config->setParent(this); } McastReceiver::~McastReceiver() { if (_config) delete _config; } void McastReceiver::config(McastConfiguration const* config) { if (_config) delete _config; _config = new McastConfiguration(*config, this); } bool McastReceiver::start() { McastConfiguration *config = _config; if (!config) config = new McastConfiguration(); if (_socket) { delete _socket; } _socket = new McastPGMSocket(this); connect(_socket, SIGNAL(receivedPacket(QByteArray)), SLOT(receivedPacket(QByteArray))); connect(_socket, SIGNAL(connectionReset()), SLOT(connectionReset())); // connect(_socket, SIGNAL(connectionFinished()), this, SLOT(connectionFinished())); if (_socket->open(_config, McastPGMSocket::PSOCK_READ)) { return true; } else { disconnect(_socket, SIGNAL(receivedPacket(QByteArray)), this, SLOT(receivedPacket(QByteArray))); disconnect(_socket, SIGNAL(connectionReset()), this, SLOT(connectionReset())); return false; } } void McastReceiver::abort() { if (_socket) { delete _socket; _socket = 0; } if (_iodev) { _iodev->close(); } } void McastReceiver::receivedPacket(QByteArray const& bytes) { if(_closed) return; quint16 checksum_should = qChecksum(bytes.constData(), bytes.size() - 2); QDataStream strm(bytes); strm.setByteOrder(QDataStream::BigEndian); // read the packet quint64 magic; quint64 offset; quint16 checksum; strm >> magic; if(magic != MCASTFT_MAGIC) { qCritical() << "Received packet whose magic number does not match. Ignoring."; return; } strm >> offset; qDebug() << " Received packet for offset" << offset; if (offset == UINT64_C(0xffffffffffffffff)) { // this is the end of the data stream. QByteArray md5; strm >> md5; quint16 fchecksum; strm >> fchecksum; // compare the hash value if ((fchecksum != checksum_should) || (md5 != _hash.result())) { _close(RES_MD5_MISMATCH); } else { _close(RES_OK); } return; } else if (offset != _curoffs) { qCritical() << "Packet loss or double delivery. PGM should have prevented this. Bailing out."; _close(RES_OFFSET_MISMATCH); return; } QByteArray contents; strm >> contents; _curoffs += contents.size(); strm >> checksum; if(checksum != checksum_should) { qCritical() << "Checksum does not match. Bailing out."; _close(RES_CHECKSUM_MISMATCH); return; } _hash.addData(contents); _iodev->write(contents); emit progress(_curoffs); } void McastReceiver::connectionReset() { _close(RES_CONNECTION_RESET); } void McastReceiver::_close(Result result) { _iodev->close(); _socket->finish(); _closed = true; emit finished(result); }