/* * NetworkMessage.cpp * * Created on: 18.01.2013 * Author: sr */ #include #include #include "networkmessage.h" #define HEADER_LEN 8 #define MAX_MSG_LEN 60000 #define BYTE_SWAP4(x) \ ((((x) & 0xFF000000u) >> 24) | \ (((x) & 0x00FF0000u) >> 8) | \ (((x) & 0x0000FF00u) << 8) | \ (((x) & 0x000000FFu) << 24)) #define BYTE_SWAP2(x) \ ((((x) & 0xFF00u) >> 8) | \ (((x) & 0x00FFu) << 8)) static quint16 _htons(const quint16 x) { if (QSysInfo::ByteOrder == QSysInfo::BigEndian) return x; return (quint16)BYTE_SWAP2(x); } static quint32 _htonl(const quint32 x) { if (QSysInfo::ByteOrder == QSysInfo::BigEndian) return x; return (quint32)BYTE_SWAP4(x); } static quint16 _ntohs(const char *in) { return quint16(quint8(in[0]) << 8 | quint8(in[1])); } static quint32 _ntohl(const char *in) { return quint32(quint8(in[0])) << 24 | quint32(quint8(in[1])) << 16 | quint32(quint8(in[2])) << 8 | quint32(quint8(in[3])); } /* // ####################################################### \\ ° . ° \\ ####################################################### // \___/ */ NetworkMessage::NetworkMessage() : _buffer(nullptr), _bufferSize(0), _bufferPos(0), _lastBufferSize(0), _mode(0) { // } NetworkMessage::~NetworkMessage() { if (_buffer) delete[] _buffer; } inline void NetworkMessage::allocBuffer() { if (_lastBufferSize < _bufferSize || _buffer == nullptr) { if (_buffer) delete[] _buffer; _lastBufferSize = _bufferSize; _buffer = new char[_lastBufferSize]; } } int NetworkMessage::readMessage(QAbstractSocket* socket) { // Check/Set the _mode variable, so read and write calls are not mixed if (_mode != 1) { if (_mode != 0) { qDebug("NetworkMessage::readMessage(TCP) called when class was in mode %d!", _mode); return NM_READ_FAILED; } _mode = 1; } // buffer size == 0 means the header hasn't been received yet. do so and set things up if (_bufferSize == 0) { if (socket->bytesAvailable() < HEADER_LEN) return NM_READ_INCOMPLETE; char header[HEADER_LEN]; if (socket->read(header, HEADER_LEN) != HEADER_LEN) { qDebug("FIXME: Socket said 8 bytes available, but could not read 8..."); return NM_READ_FAILED; } if (!this->parseHeader(header)) return NM_READ_FAILED; //qDebug() << "Expecting message of " << _bufferSize << " bytes"; allocBuffer(); } if (_bufferSize > _bufferPos) { while (_bufferSize > _bufferPos && socket->bytesAvailable() > 0) { const qint64 ret = socket->read(_buffer + _bufferPos, _bufferSize - _bufferPos); //qDebug() << "Read " << ret << " bytes"; if (ret < 0 || ret > (_bufferSize - _bufferPos)) { qDebug("Socket read failed (TCP), return code %d", (int)ret); return NM_READ_FAILED; } _bufferPos += (quint32)ret; //qDebug() << "Buffer has now " << _bufferPos << " of " << _bufferSize << " bytes"; } if (_bufferSize == _bufferPos) { if (!this->parseMessage(_buffer)) return NM_READ_FAILED; } } return NM_READ_OK; } int NetworkMessage::readMessage(char* data, quint32 len) { // Check/Set the _mode variable, so read and write calls are not mixed if (_mode != 1) { if (_mode != 0) { qDebug("NetworkMessage::readMessage(UDP) called when class was in mode %d!", _mode); return NM_READ_FAILED; } _mode = 1; } if (len < HEADER_LEN) { qDebug("UDP message shorter than 8 bytes. ignored."); return NM_READ_FAILED; } if (!this->parseHeader(data)) return NM_READ_FAILED; if (len != _bufferSize + HEADER_LEN) { qDebug("UDP packet has wrong size. Is %d, expected %d", (int)_bufferSize, len - HEADER_LEN); return NM_READ_FAILED; } return this->parseMessage(data + HEADER_LEN) ? NM_READ_OK : NM_READ_FAILED; } bool NetworkMessage::parseHeader(char *header) { if (header[0] != 'P' || header[1] != 'V' || header[2] != 'S' || header[3] != '2') { qDebug("Protocol magic wrong."); return false; } _bufferPos = 0; _bufferSize = _ntohl(header + 4); if (_bufferSize > MAX_MSG_LEN) { qDebug("Disconnecting Client: MAX_MSG_LEN exceeded."); return false; } if (_bufferSize < 4) { // TODO: magic number. msg needs to be at least 4 bytes for 1 key/value pair of length 0 each. qDebug("A Client sent an empty message."); return false; } return true; } bool NetworkMessage::parseMessage(char *buffer) { char *ptr = buffer; while (_bufferSize - (ptr - buffer) >= 4) { const quint16 keyLen = _ntohs(ptr); ptr += 2; const quint16 valLen = _ntohs(ptr); ptr += 2; if (_bufferSize - (ptr - buffer) < keyLen + valLen) { qDebug() << "Warning: Error parsing message. key(" << keyLen << ")+value(" << valLen << ") length > total remaining bytes (" << (_bufferSize - (ptr - buffer)) << ")"; return false; } _fields.insert(QByteArray(ptr, keyLen), QByteArray(ptr + keyLen, valLen)); //qDebug() << "Got " << QString::fromUtf8(ptr, keyLen) << " -> " << QString::fromUtf8(ptr + keyLen, valLen); ptr += keyLen + valLen; } _mode = 3; return true; } bool NetworkMessage::writeMessage(QAbstractSocket * const socket) { if (_mode != 2) { if (_mode == 1) { qDebug("NetworkMessage::writeMessage called when class was in mode %d!", _mode); return false; } _mode = 1; _bufferPos = 0; } // key/value pairs have not been serialized yet... if (_bufferSize == 0) { this->serializeMessage(); } const qint64 ret = socket->write(_buffer + _bufferPos, _bufferSize - _bufferPos); if (ret == 0) return true; if (ret < 0 || ret > (_bufferSize - _bufferPos)) return false; _bufferPos += (quint32)ret; if (_bufferPos == _bufferSize) { _bufferPos = 0; _mode = 4; } return true; } bool NetworkMessage::writeMessage(QUdpSocket* socket, const QHostAddress& address, quint16 port) { if (_mode != 4) { if (_mode == 1) { qDebug("NetworkMessage::writeMessage called when class was in mode %d!", _mode); return false; } _mode = 4; _bufferPos = 0; } // key/value pairs have not been serialized yet... if (_bufferSize == 0) { this->serializeMessage(); } const qint64 ret = socket->writeDatagram(_buffer, _bufferSize, address, port); if (ret != _bufferSize) return false; if (ret < 0) return false; _bufferPos = 0; return true; } void NetworkMessage::serializeMessage() { QByteArray buf; //qDebug() << "Default size: " << buf.capacity(); buf.reserve(_lastBufferSize > 0 ? int(_lastBufferSize) : 200); for (QHash::const_iterator it = _fields.begin(); it != _fields.end(); ++it) { const QByteArray &ba = it.key(); const QByteArray &val = it.value(); quint16 keyLen = _htons((quint16)ba.size()); quint16 valLen = _htons((quint16)val.size()); //qDebug() << "Adding to msg(" << ba.size() << "/" << val.size() << "): " << ba << " -> " << val; buf.append((char*)&keyLen, 2); buf.append((char*)&valLen, 2); buf.append(ba); buf.append(val); } _bufferSize = quint32(buf.length() + HEADER_LEN); allocBuffer(); memcpy(_buffer + HEADER_LEN, buf.data(), size_t(buf.size())); _buffer[0] = 'P'; _buffer[1] = 'V'; _buffer[2] = 'S'; _buffer[3] = '2'; const quint32 flipped = _htonl(_bufferSize - HEADER_LEN); memcpy(_buffer + 4, &flipped, 4); } void NetworkMessage::buildErrorMessage(const QString& error) { this->reset(); this->setField(_ID, _ERROR); this->setField(_ERROR, error); }