//// BasePacket.cpp// libraries/networking/src/udt//// Created by Stephen Birarda on 2015-07-23.// Copyright 2015 High Fidelity, Inc.// Copyright 2021 Vircadia contributors.//// Distributed under the Apache License, Version 2.0.// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html// #include "BasePacket.h" #include "../NetworkLogging.h" using namespace udt; const qint64 BasePacket::PACKET_WRITE_ERROR = -1; int BasePacket::localHeaderSize() { return 0;}int BasePacket::totalHeaderSize() { return 0;}int BasePacket::maxPayloadSize() { return MAX_PACKET_SIZE;} std::unique_ptr<BasePacket> BasePacket::create(qint64 size) { auto packet = std::unique_ptr<BasePacket>(new BasePacket(size)); packet->open(QIODevice::ReadWrite); return packet;} std::unique_ptr<BasePacket> BasePacket::fromReceivedPacket(std::unique_ptr<char[]> data, qint64 size, const SockAddr& senderSockAddr) { // Fail with invalid size Q_ASSERT(size >= 0); // allocate memory auto packet = std::unique_ptr<BasePacket>(new BasePacket(std::move(data), size, senderSockAddr)); packet->open(QIODevice::ReadOnly); return packet;} BasePacket::BasePacket(qint64 size) { auto maxPayload = BasePacket::maxPayloadSize(); if (size == -1) { // default size of -1, means biggest packet possible size = maxPayload; } // Sanity check Q_ASSERT(size >= 0 && size <= maxPayload); _packetSize = size; _packet.reset(new char[_packetSize]()); _payloadCapacity = _packetSize; _payloadSize = 0; _payloadStart = _packet.get();} BasePacket::BasePacket(std::unique_ptr<char[]> data, qint64 size, const SockAddr& senderSockAddr) : _packetSize(size), _packet(std::move(data)), _payloadStart(_packet.get()), _payloadCapacity(size), _payloadSize(size), _senderSockAddr(senderSockAddr){ } BasePacket& BasePacket::operator=(const BasePacket& other) { _packetSize = other._packetSize; _packet = std::unique_ptr<char[]>(new char[_packetSize]); memcpy(_packet.get(), other._packet.get(), _packetSize); _payloadStart = _packet.get() + (other._payloadStart - other._packet.get()); _payloadCapacity = other._payloadCapacity; _payloadSize = other._payloadSize; _senderSockAddr = other._senderSockAddr; if (other.isOpen() && !isOpen()) { open(other.openMode()); } seek(other.pos()); return *this;} BasePacket::BasePacket(BasePacket&& other) { *this = std::move(other);} BasePacket& BasePacket::operator=(BasePacket&& other) { _packetSize = other._packetSize; _packet = std::move(other._packet); _payloadStart = other._payloadStart; _payloadCapacity = other._payloadCapacity; _payloadSize = other._payloadSize; _senderSockAddr = std::move(other._senderSockAddr); if (other.isOpen() && !isOpen()) { open(other.openMode()); } seek(other.pos()); return *this;} void BasePacket::setPayloadSize(qint64 payloadSize) { if (isWritable()) { Q_ASSERT(payloadSize <= _payloadCapacity); _payloadSize = payloadSize; } else { qCDebug(networking) << "You can not call setPayloadSize for a non-writeable Packet."; Q_ASSERT(false); }} QByteArray BasePacket::read(qint64 maxSize) { qint64 sizeToRead = std::min(size() - pos(), maxSize); QByteArray data { getPayload() + pos(), (int) sizeToRead }; seek(pos() + sizeToRead); return data;} QByteArray BasePacket::readWithoutCopy(qint64 maxSize) { qint64 sizeToRead = std::min(size() - pos(), maxSize); QByteArray data { QByteArray::fromRawData(getPayload() + pos(), sizeToRead) }; seek(pos() + sizeToRead); return data;} qint64 BasePacket::writeString(const QString& string) { QByteArray data = string.toUtf8(); uint32_t length = data.length(); writePrimitive(length); write(data.constData(), data.length()); return length + sizeof(uint32_t);} QString BasePacket::readString() { uint32_t size; readPrimitive(&size); auto string = QString::fromUtf8(getPayload() + pos(), size); seek(pos() + size); return string;} bool BasePacket::reset() { if (isWritable()) { _payloadSize = 0; } return QIODevice::reset();} qint64 BasePacket::writeData(const char* data, qint64 maxSize) { Q_ASSERT_X(maxSize <= bytesAvailableForWrite(), "BasePacket::writeData", "not enough space for write"); // make sure we have the space required to write this block if (maxSize <= bytesAvailableForWrite()) { qint64 currentPos = pos(); // good to go - write the data memcpy(_payloadStart + currentPos, data, maxSize); // keep track of _payloadSize so we can just write the actual data when packet is about to be sent _payloadSize = std::max(currentPos + maxSize, _payloadSize); // return the number of bytes written return maxSize; } else { // not enough space left for this write - return an error return PACKET_WRITE_ERROR; }} qint64 BasePacket::readData(char* dest, qint64 maxSize) { // we're either reading what is left from the current position or what was asked to be read qint64 numBytesToRead = std::min(bytesLeftToRead(), maxSize); if (numBytesToRead > 0) { int currentPosition = pos(); // read out the data memcpy(dest, _payloadStart + currentPosition, numBytesToRead); } return numBytesToRead;} void BasePacket::adjustPayloadStartAndCapacity(qint64 headerSize, bool shouldDecreasePayloadSize) { _payloadStart += headerSize; _payloadCapacity -= headerSize; if (shouldDecreasePayloadSize) { _payloadSize -= headerSize; }}
//
// BasePacket.cpp
// libraries/networking/src/udt
//
// Created by Stephen Birarda on 2015-07-23.
// Copyright 2015 High Fidelity, Inc.
// Copyright 2021 Vircadia contributors.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "BasePacket.h"
#include "../NetworkLogging.h"
using namespace udt;
const qint64 BasePacket::PACKET_WRITE_ERROR = -1;
int BasePacket::localHeaderSize() {
return 0;
}
int BasePacket::totalHeaderSize() {
return 0;
}
int BasePacket::maxPayloadSize() {
return MAX_PACKET_SIZE;
}
std::unique_ptr<BasePacket> BasePacket::create(qint64 size) {
auto packet = std::unique_ptr<BasePacket>(new BasePacket(size));
packet->open(QIODevice::ReadWrite);
return packet;
}
std::unique_ptr<BasePacket> BasePacket::fromReceivedPacket(std::unique_ptr<char[]> data,
qint64 size, const SockAddr& senderSockAddr) {
// Fail with invalid size
Q_ASSERT(size >= 0);
// allocate memory
auto packet = std::unique_ptr<BasePacket>(new BasePacket(std::move(data), size, senderSockAddr));
packet->open(QIODevice::ReadOnly);
return packet;
}
BasePacket::BasePacket(qint64 size) {
auto maxPayload = BasePacket::maxPayloadSize();
if (size == -1) {
// default size of -1, means biggest packet possible
size = maxPayload;
}
// Sanity check
Q_ASSERT(size >= 0 && size <= maxPayload);
_packetSize = size;
_packet.reset(new char[_packetSize]());
_payloadCapacity = _packetSize;
_payloadSize = 0;
_payloadStart = _packet.get();
}
BasePacket::BasePacket(std::unique_ptr<char[]> data, qint64 size, const SockAddr& senderSockAddr) :
_packetSize(size),
_packet(std::move(data)),
_payloadStart(_packet.get()),
_payloadCapacity(size),
_payloadSize(size),
_senderSockAddr(senderSockAddr)
{
}
BasePacket& BasePacket::operator=(const BasePacket& other) {
_packetSize = other._packetSize;
_packet = std::unique_ptr<char[]>(new char[_packetSize]);
memcpy(_packet.get(), other._packet.get(), _packetSize);
_payloadStart = _packet.get() + (other._payloadStart - other._packet.get());
_payloadCapacity = other._payloadCapacity;
_payloadSize = other._payloadSize;
_senderSockAddr = other._senderSockAddr;
if (other.isOpen() && !isOpen()) {
open(other.openMode());
}
seek(other.pos());
return *this;
}
BasePacket::BasePacket(BasePacket&& other) {
*this = std::move(other);
}
BasePacket& BasePacket::operator=(BasePacket&& other) {
_packetSize = other._packetSize;
_packet = std::move(other._packet);
_payloadStart = other._payloadStart;
_payloadCapacity = other._payloadCapacity;
_payloadSize = other._payloadSize;
_senderSockAddr = std::move(other._senderSockAddr);
if (other.isOpen() && !isOpen()) {
open(other.openMode());
}
seek(other.pos());
return *this;
}
void BasePacket::setPayloadSize(qint64 payloadSize) {
if (isWritable()) {
Q_ASSERT(payloadSize <= _payloadCapacity);
_payloadSize = payloadSize;
} else {
qCDebug(networking) << "You can not call setPayloadSize for a non-writeable Packet.";
Q_ASSERT(false);
}
}
QByteArray BasePacket::read(qint64 maxSize) {
qint64 sizeToRead = std::min(size() - pos(), maxSize);
QByteArray data { getPayload() + pos(), (int) sizeToRead };
seek(pos() + sizeToRead);
return data;
}
QByteArray BasePacket::readWithoutCopy(qint64 maxSize) {
qint64 sizeToRead = std::min(size() - pos(), maxSize);
QByteArray data { QByteArray::fromRawData(getPayload() + pos(), sizeToRead) };
seek(pos() + sizeToRead);
return data;
}
qint64 BasePacket::writeString(const QString& string) {
QByteArray data = string.toUtf8();
uint32_t length = data.length();
writePrimitive(length);
write(data.constData(), data.length());
return length + sizeof(uint32_t);
}
QString BasePacket::readString() {
uint32_t size;
readPrimitive(&size);
auto string = QString::fromUtf8(getPayload() + pos(), size);
seek(pos() + size);
return string;
}
bool BasePacket::reset() {
if (isWritable()) {
_payloadSize = 0;
}
return QIODevice::reset();
}
qint64 BasePacket::writeData(const char* data, qint64 maxSize) {
Q_ASSERT_X(maxSize <= bytesAvailableForWrite(), "BasePacket::writeData", "not enough space for write");
// make sure we have the space required to write this block
if (maxSize <= bytesAvailableForWrite()) {
qint64 currentPos = pos();
// good to go - write the data
memcpy(_payloadStart + currentPos, data, maxSize);
// keep track of _payloadSize so we can just write the actual data when packet is about to be sent
_payloadSize = std::max(currentPos + maxSize, _payloadSize);
// return the number of bytes written
return maxSize;
} else {
// not enough space left for this write - return an error
return PACKET_WRITE_ERROR;
}
}
qint64 BasePacket::readData(char* dest, qint64 maxSize) {
// we're either reading what is left from the current position or what was asked to be read
qint64 numBytesToRead = std::min(bytesLeftToRead(), maxSize);
if (numBytesToRead > 0) {
int currentPosition = pos();
// read out the data
memcpy(dest, _payloadStart + currentPosition, numBytesToRead);
}
return numBytesToRead;
}
void BasePacket::adjustPayloadStartAndCapacity(qint64 headerSize, bool shouldDecreasePayloadSize) {
_payloadStart += headerSize;
_payloadCapacity -= headerSize;
if (shouldDecreasePayloadSize) {
_payloadSize -= headerSize;
}
}