forked from Mirrorlandia_minetest/minetest
Network: Delete copy constructor and use std::move instead (#11642)
This is a follow-up change which disables class copies where possible to avoid unnecessary memory movements.
This commit is contained in:
parent
1dc1305ada
commit
57a59ae92d
@ -877,7 +877,7 @@ void Client::ProcessData(NetworkPacket *pkt)
|
|||||||
*/
|
*/
|
||||||
if(sender_peer_id != PEER_ID_SERVER) {
|
if(sender_peer_id != PEER_ID_SERVER) {
|
||||||
infostream << "Client::ProcessData(): Discarding data not "
|
infostream << "Client::ProcessData(): Discarding data not "
|
||||||
"coming from server: peer_id=" << sender_peer_id
|
"coming from server: peer_id=" << sender_peer_id << " command=" << pkt->getCommand()
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -62,18 +62,27 @@ namespace con
|
|||||||
|
|
||||||
#define PING_TIMEOUT 5.0
|
#define PING_TIMEOUT 5.0
|
||||||
|
|
||||||
BufferedPacket makePacket(Address &address, const SharedBuffer<u8> &data,
|
u16 BufferedPacket::getSeqnum() const
|
||||||
|
{
|
||||||
|
if (size() < BASE_HEADER_SIZE + 3)
|
||||||
|
return 0; // should never happen
|
||||||
|
|
||||||
|
return readU16(&data[BASE_HEADER_SIZE + 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
BufferedPacketPtr makePacket(Address &address, const SharedBuffer<u8> &data,
|
||||||
u32 protocol_id, session_t sender_peer_id, u8 channel)
|
u32 protocol_id, session_t sender_peer_id, u8 channel)
|
||||||
{
|
{
|
||||||
u32 packet_size = data.getSize() + BASE_HEADER_SIZE;
|
u32 packet_size = data.getSize() + BASE_HEADER_SIZE;
|
||||||
BufferedPacket p(packet_size);
|
|
||||||
p.address = address;
|
|
||||||
|
|
||||||
writeU32(&p.data[0], protocol_id);
|
BufferedPacketPtr p(new BufferedPacket(packet_size));
|
||||||
writeU16(&p.data[4], sender_peer_id);
|
p->address = address;
|
||||||
writeU8(&p.data[6], channel);
|
|
||||||
|
|
||||||
memcpy(&p.data[BASE_HEADER_SIZE], *data, data.getSize());
|
writeU32(&p->data[0], protocol_id);
|
||||||
|
writeU16(&p->data[4], sender_peer_id);
|
||||||
|
writeU8(&p->data[6], channel);
|
||||||
|
|
||||||
|
memcpy(&p->data[BASE_HEADER_SIZE], *data, data.getSize());
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
@ -169,9 +178,8 @@ void ReliablePacketBuffer::print()
|
|||||||
MutexAutoLock listlock(m_list_mutex);
|
MutexAutoLock listlock(m_list_mutex);
|
||||||
LOG(dout_con<<"Dump of ReliablePacketBuffer:" << std::endl);
|
LOG(dout_con<<"Dump of ReliablePacketBuffer:" << std::endl);
|
||||||
unsigned int index = 0;
|
unsigned int index = 0;
|
||||||
for (BufferedPacket &bufferedPacket : m_list) {
|
for (BufferedPacketPtr &packet : m_list) {
|
||||||
u16 s = readU16(&(bufferedPacket.data[BASE_HEADER_SIZE+1]));
|
LOG(dout_con<<index<< ":" << packet->getSeqnum() << std::endl);
|
||||||
LOG(dout_con<<index<< ":" << s << std::endl);
|
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -188,16 +196,13 @@ u32 ReliablePacketBuffer::size()
|
|||||||
return m_list.size();
|
return m_list.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
RPBSearchResult ReliablePacketBuffer::findPacket(u16 seqnum)
|
RPBSearchResult ReliablePacketBuffer::findPacketNoLock(u16 seqnum)
|
||||||
{
|
{
|
||||||
std::list<BufferedPacket>::iterator i = m_list.begin();
|
for (auto it = m_list.begin(); it != m_list.end(); ++it) {
|
||||||
for(; i != m_list.end(); ++i)
|
if ((*it)->getSeqnum() == seqnum)
|
||||||
{
|
return it;
|
||||||
u16 s = readU16(&(i->data[BASE_HEADER_SIZE+1]));
|
|
||||||
if (s == seqnum)
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
return i;
|
return m_list.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ReliablePacketBuffer::getFirstSeqnum(u16& result)
|
bool ReliablePacketBuffer::getFirstSeqnum(u16& result)
|
||||||
@ -205,54 +210,54 @@ bool ReliablePacketBuffer::getFirstSeqnum(u16& result)
|
|||||||
MutexAutoLock listlock(m_list_mutex);
|
MutexAutoLock listlock(m_list_mutex);
|
||||||
if (m_list.empty())
|
if (m_list.empty())
|
||||||
return false;
|
return false;
|
||||||
const BufferedPacket &p = m_list.front();
|
result = m_list.front()->getSeqnum();
|
||||||
result = readU16(&p.data[BASE_HEADER_SIZE + 1]);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
BufferedPacket ReliablePacketBuffer::popFirst()
|
BufferedPacketPtr ReliablePacketBuffer::popFirst()
|
||||||
{
|
{
|
||||||
MutexAutoLock listlock(m_list_mutex);
|
MutexAutoLock listlock(m_list_mutex);
|
||||||
if (m_list.empty())
|
if (m_list.empty())
|
||||||
throw NotFoundException("Buffer is empty");
|
throw NotFoundException("Buffer is empty");
|
||||||
BufferedPacket p = std::move(m_list.front());
|
|
||||||
|
BufferedPacketPtr p(m_list.front());
|
||||||
m_list.pop_front();
|
m_list.pop_front();
|
||||||
|
|
||||||
if (m_list.empty()) {
|
if (m_list.empty()) {
|
||||||
m_oldest_non_answered_ack = 0;
|
m_oldest_non_answered_ack = 0;
|
||||||
} else {
|
} else {
|
||||||
m_oldest_non_answered_ack =
|
m_oldest_non_answered_ack = m_list.front()->getSeqnum();
|
||||||
readU16(&m_list.front().data[BASE_HEADER_SIZE + 1]);
|
|
||||||
}
|
}
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
BufferedPacket ReliablePacketBuffer::popSeqnum(u16 seqnum)
|
BufferedPacketPtr ReliablePacketBuffer::popSeqnum(u16 seqnum)
|
||||||
{
|
{
|
||||||
MutexAutoLock listlock(m_list_mutex);
|
MutexAutoLock listlock(m_list_mutex);
|
||||||
RPBSearchResult r = findPacket(seqnum);
|
RPBSearchResult r = findPacketNoLock(seqnum);
|
||||||
if (r == notFound()) {
|
if (r == m_list.end()) {
|
||||||
LOG(dout_con<<"Sequence number: " << seqnum
|
LOG(dout_con<<"Sequence number: " << seqnum
|
||||||
<< " not found in reliable buffer"<<std::endl);
|
<< " not found in reliable buffer"<<std::endl);
|
||||||
throw NotFoundException("seqnum not found in buffer");
|
throw NotFoundException("seqnum not found in buffer");
|
||||||
}
|
}
|
||||||
BufferedPacket p = std::move(*r);
|
|
||||||
|
|
||||||
|
BufferedPacketPtr p(*r);
|
||||||
m_list.erase(r);
|
m_list.erase(r);
|
||||||
|
|
||||||
if (m_list.empty()) {
|
if (m_list.empty()) {
|
||||||
m_oldest_non_answered_ack = 0;
|
m_oldest_non_answered_ack = 0;
|
||||||
} else {
|
} else {
|
||||||
m_oldest_non_answered_ack =
|
m_oldest_non_answered_ack = m_list.front()->getSeqnum();
|
||||||
readU16(&m_list.front().data[BASE_HEADER_SIZE + 1]);
|
|
||||||
}
|
}
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReliablePacketBuffer::insert(const BufferedPacket &p, u16 next_expected)
|
void ReliablePacketBuffer::insert(BufferedPacketPtr &p_ptr, u16 next_expected)
|
||||||
{
|
{
|
||||||
MutexAutoLock listlock(m_list_mutex);
|
MutexAutoLock listlock(m_list_mutex);
|
||||||
if (p.data.getSize() < BASE_HEADER_SIZE + 3) {
|
const BufferedPacket &p = *p_ptr;
|
||||||
|
|
||||||
|
if (p.size() < BASE_HEADER_SIZE + 3) {
|
||||||
errorstream << "ReliablePacketBuffer::insert(): Invalid data size for "
|
errorstream << "ReliablePacketBuffer::insert(): Invalid data size for "
|
||||||
"reliable packet" << std::endl;
|
"reliable packet" << std::endl;
|
||||||
return;
|
return;
|
||||||
@ -263,7 +268,7 @@ void ReliablePacketBuffer::insert(const BufferedPacket &p, u16 next_expected)
|
|||||||
<< std::endl;
|
<< std::endl;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
u16 seqnum = readU16(&p.data[BASE_HEADER_SIZE + 1]);
|
const u16 seqnum = p.getSeqnum();
|
||||||
|
|
||||||
if (!seqnum_in_window(seqnum, next_expected, MAX_RELIABLE_WINDOW_SIZE)) {
|
if (!seqnum_in_window(seqnum, next_expected, MAX_RELIABLE_WINDOW_SIZE)) {
|
||||||
errorstream << "ReliablePacketBuffer::insert(): seqnum is outside of "
|
errorstream << "ReliablePacketBuffer::insert(): seqnum is outside of "
|
||||||
@ -280,44 +285,44 @@ void ReliablePacketBuffer::insert(const BufferedPacket &p, u16 next_expected)
|
|||||||
|
|
||||||
// Find the right place for the packet and insert it there
|
// Find the right place for the packet and insert it there
|
||||||
// If list is empty, just add it
|
// If list is empty, just add it
|
||||||
if (m_list.empty())
|
if (m_list.empty()) {
|
||||||
{
|
m_list.push_back(p_ptr);
|
||||||
m_list.push_back(p);
|
|
||||||
m_oldest_non_answered_ack = seqnum;
|
m_oldest_non_answered_ack = seqnum;
|
||||||
// Done.
|
// Done.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise find the right place
|
// Otherwise find the right place
|
||||||
std::list<BufferedPacket>::iterator i = m_list.begin();
|
auto it = m_list.begin();
|
||||||
// Find the first packet in the list which has a higher seqnum
|
// Find the first packet in the list which has a higher seqnum
|
||||||
u16 s = readU16(&(i->data[BASE_HEADER_SIZE+1]));
|
u16 s = (*it)->getSeqnum();
|
||||||
|
|
||||||
/* case seqnum is smaller then next_expected seqnum */
|
/* case seqnum is smaller then next_expected seqnum */
|
||||||
/* this is true e.g. on wrap around */
|
/* this is true e.g. on wrap around */
|
||||||
if (seqnum < next_expected) {
|
if (seqnum < next_expected) {
|
||||||
while(((s < seqnum) || (s >= next_expected)) && (i != m_list.end())) {
|
while(((s < seqnum) || (s >= next_expected)) && (it != m_list.end())) {
|
||||||
++i;
|
++it;
|
||||||
if (i != m_list.end())
|
if (it != m_list.end())
|
||||||
s = readU16(&(i->data[BASE_HEADER_SIZE+1]));
|
s = (*it)->getSeqnum();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* non wrap around case (at least for incoming and next_expected */
|
/* non wrap around case (at least for incoming and next_expected */
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
while(((s < seqnum) && (s >= next_expected)) && (i != m_list.end())) {
|
while(((s < seqnum) && (s >= next_expected)) && (it != m_list.end())) {
|
||||||
++i;
|
++it;
|
||||||
if (i != m_list.end())
|
if (it != m_list.end())
|
||||||
s = readU16(&(i->data[BASE_HEADER_SIZE+1]));
|
s = (*it)->getSeqnum();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s == seqnum) {
|
if (s == seqnum) {
|
||||||
/* nothing to do this seems to be a resent packet */
|
/* nothing to do this seems to be a resent packet */
|
||||||
/* for paranoia reason data should be compared */
|
/* for paranoia reason data should be compared */
|
||||||
|
auto &i = *it;
|
||||||
if (
|
if (
|
||||||
(readU16(&(i->data[BASE_HEADER_SIZE+1])) != seqnum) ||
|
(i->getSeqnum() != seqnum) ||
|
||||||
(i->data.getSize() != p.data.getSize()) ||
|
(i->size() != p.size()) ||
|
||||||
(i->address != p.address)
|
(i->address != p.address)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
@ -325,52 +330,53 @@ void ReliablePacketBuffer::insert(const BufferedPacket &p, u16 next_expected)
|
|||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Duplicated seqnum %d non matching packet detected:\n",
|
"Duplicated seqnum %d non matching packet detected:\n",
|
||||||
seqnum);
|
seqnum);
|
||||||
fprintf(stderr, "Old: seqnum: %05d size: %04d, address: %s\n",
|
fprintf(stderr, "Old: seqnum: %05d size: %04zu, address: %s\n",
|
||||||
readU16(&(i->data[BASE_HEADER_SIZE+1])),i->data.getSize(),
|
i->getSeqnum(), i->size(),
|
||||||
i->address.serializeString().c_str());
|
i->address.serializeString().c_str());
|
||||||
fprintf(stderr, "New: seqnum: %05d size: %04u, address: %s\n",
|
fprintf(stderr, "New: seqnum: %05d size: %04zu, address: %s\n",
|
||||||
readU16(&(p.data[BASE_HEADER_SIZE+1])),p.data.getSize(),
|
p.getSeqnum(), p.size(),
|
||||||
p.address.serializeString().c_str());
|
p.address.serializeString().c_str());
|
||||||
throw IncomingDataCorruption("duplicated packet isn't same as original one");
|
throw IncomingDataCorruption("duplicated packet isn't same as original one");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* insert or push back */
|
/* insert or push back */
|
||||||
else if (i != m_list.end()) {
|
else if (it != m_list.end()) {
|
||||||
m_list.insert(i, p);
|
m_list.insert(it, p_ptr);
|
||||||
} else {
|
} else {
|
||||||
m_list.push_back(p);
|
m_list.push_back(p_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* update last packet number */
|
/* update last packet number */
|
||||||
m_oldest_non_answered_ack = readU16(&m_list.front().data[BASE_HEADER_SIZE+1]);
|
m_oldest_non_answered_ack = m_list.front()->getSeqnum();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReliablePacketBuffer::incrementTimeouts(float dtime)
|
void ReliablePacketBuffer::incrementTimeouts(float dtime)
|
||||||
{
|
{
|
||||||
MutexAutoLock listlock(m_list_mutex);
|
MutexAutoLock listlock(m_list_mutex);
|
||||||
for (BufferedPacket &bufferedPacket : m_list) {
|
for (auto &packet : m_list) {
|
||||||
bufferedPacket.time += dtime;
|
packet->time += dtime;
|
||||||
bufferedPacket.totaltime += dtime;
|
packet->totaltime += dtime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::list<BufferedPacket>
|
std::list<ConstSharedPtr<BufferedPacket>>
|
||||||
ReliablePacketBuffer::getTimedOuts(float timeout, u32 max_packets)
|
ReliablePacketBuffer::getTimedOuts(float timeout, u32 max_packets)
|
||||||
{
|
{
|
||||||
MutexAutoLock listlock(m_list_mutex);
|
MutexAutoLock listlock(m_list_mutex);
|
||||||
std::list<BufferedPacket> timed_outs;
|
std::list<ConstSharedPtr<BufferedPacket>> timed_outs;
|
||||||
for (BufferedPacket &bufferedPacket : m_list) {
|
for (auto &packet : m_list) {
|
||||||
if (bufferedPacket.time >= timeout) {
|
if (packet->time < timeout)
|
||||||
// caller will resend packet so reset time and increase counter
|
continue;
|
||||||
bufferedPacket.time = 0.0f;
|
|
||||||
bufferedPacket.resend_count++;
|
|
||||||
|
|
||||||
timed_outs.push_back(bufferedPacket);
|
// caller will resend packet so reset time and increase counter
|
||||||
|
packet->time = 0.0f;
|
||||||
|
packet->resend_count++;
|
||||||
|
|
||||||
|
timed_outs.emplace_back(packet);
|
||||||
|
|
||||||
if (timed_outs.size() >= max_packets)
|
if (timed_outs.size() >= max_packets)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return timed_outs;
|
return timed_outs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -428,11 +434,13 @@ IncomingSplitBuffer::~IncomingSplitBuffer()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SharedBuffer<u8> IncomingSplitBuffer::insert(const BufferedPacket &p, bool reliable)
|
SharedBuffer<u8> IncomingSplitBuffer::insert(BufferedPacketPtr &p_ptr, bool reliable)
|
||||||
{
|
{
|
||||||
MutexAutoLock listlock(m_map_mutex);
|
MutexAutoLock listlock(m_map_mutex);
|
||||||
|
const BufferedPacket &p = *p_ptr;
|
||||||
|
|
||||||
u32 headersize = BASE_HEADER_SIZE + 7;
|
u32 headersize = BASE_HEADER_SIZE + 7;
|
||||||
if (p.data.getSize() < headersize) {
|
if (p.size() < headersize) {
|
||||||
errorstream << "Invalid data size for split packet" << std::endl;
|
errorstream << "Invalid data size for split packet" << std::endl;
|
||||||
return SharedBuffer<u8>();
|
return SharedBuffer<u8>();
|
||||||
}
|
}
|
||||||
@ -473,7 +481,7 @@ SharedBuffer<u8> IncomingSplitBuffer::insert(const BufferedPacket &p, bool relia
|
|||||||
<<std::endl);
|
<<std::endl);
|
||||||
|
|
||||||
// Cut chunk data out of packet
|
// Cut chunk data out of packet
|
||||||
u32 chunkdatasize = p.data.getSize() - headersize;
|
u32 chunkdatasize = p.size() - headersize;
|
||||||
SharedBuffer<u8> chunkdata(chunkdatasize);
|
SharedBuffer<u8> chunkdata(chunkdatasize);
|
||||||
memcpy(*chunkdata, &(p.data[headersize]), chunkdatasize);
|
memcpy(*chunkdata, &(p.data[headersize]), chunkdatasize);
|
||||||
|
|
||||||
@ -520,14 +528,67 @@ void IncomingSplitBuffer::removeUnreliableTimedOuts(float dtime, float timeout)
|
|||||||
ConnectionCommand
|
ConnectionCommand
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void ConnectionCommand::send(session_t peer_id_, u8 channelnum_, NetworkPacket *pkt,
|
ConnectionCommandPtr ConnectionCommand::create(ConnectionCommandType type)
|
||||||
bool reliable_)
|
|
||||||
{
|
{
|
||||||
type = CONNCMD_SEND;
|
return ConnectionCommandPtr(new ConnectionCommand(type));
|
||||||
peer_id = peer_id_;
|
}
|
||||||
channelnum = channelnum_;
|
|
||||||
data = pkt->oldForgePacket();
|
ConnectionCommandPtr ConnectionCommand::serve(Address address)
|
||||||
reliable = reliable_;
|
{
|
||||||
|
auto c = create(CONNCMD_SERVE);
|
||||||
|
c->address = address;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectionCommandPtr ConnectionCommand::connect(Address address)
|
||||||
|
{
|
||||||
|
auto c = create(CONNCMD_CONNECT);
|
||||||
|
c->address = address;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectionCommandPtr ConnectionCommand::disconnect()
|
||||||
|
{
|
||||||
|
return create(CONNCMD_DISCONNECT);
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectionCommandPtr ConnectionCommand::disconnect_peer(session_t peer_id)
|
||||||
|
{
|
||||||
|
auto c = create(CONNCMD_DISCONNECT_PEER);
|
||||||
|
c->peer_id = peer_id;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectionCommandPtr ConnectionCommand::send(session_t peer_id, u8 channelnum,
|
||||||
|
NetworkPacket *pkt, bool reliable)
|
||||||
|
{
|
||||||
|
auto c = create(CONNCMD_SEND);
|
||||||
|
c->peer_id = peer_id;
|
||||||
|
c->channelnum = channelnum;
|
||||||
|
c->reliable = reliable;
|
||||||
|
c->data = pkt->oldForgePacket();
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectionCommandPtr ConnectionCommand::ack(session_t peer_id, u8 channelnum, const Buffer<u8> &data)
|
||||||
|
{
|
||||||
|
auto c = create(CONCMD_ACK);
|
||||||
|
c->peer_id = peer_id;
|
||||||
|
c->channelnum = channelnum;
|
||||||
|
c->reliable = false;
|
||||||
|
data.copyTo(c->data);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectionCommandPtr ConnectionCommand::createPeer(session_t peer_id, const Buffer<u8> &data)
|
||||||
|
{
|
||||||
|
auto c = create(CONCMD_CREATE_PEER);
|
||||||
|
c->peer_id = peer_id;
|
||||||
|
c->channelnum = 0;
|
||||||
|
c->reliable = true;
|
||||||
|
c->raw = true;
|
||||||
|
data.copyTo(c->data);
|
||||||
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -562,39 +623,38 @@ void Channel::setNextSplitSeqNum(u16 seqnum)
|
|||||||
u16 Channel::getOutgoingSequenceNumber(bool& successful)
|
u16 Channel::getOutgoingSequenceNumber(bool& successful)
|
||||||
{
|
{
|
||||||
MutexAutoLock internal(m_internal_mutex);
|
MutexAutoLock internal(m_internal_mutex);
|
||||||
|
|
||||||
u16 retval = next_outgoing_seqnum;
|
u16 retval = next_outgoing_seqnum;
|
||||||
u16 lowest_unacked_seqnumber;
|
successful = false;
|
||||||
|
|
||||||
/* shortcut if there ain't any packet in outgoing list */
|
/* shortcut if there ain't any packet in outgoing list */
|
||||||
if (outgoing_reliables_sent.empty())
|
if (outgoing_reliables_sent.empty()) {
|
||||||
{
|
successful = true;
|
||||||
next_outgoing_seqnum++;
|
next_outgoing_seqnum++;
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (outgoing_reliables_sent.getFirstSeqnum(lowest_unacked_seqnumber))
|
u16 lowest_unacked_seqnumber;
|
||||||
{
|
if (outgoing_reliables_sent.getFirstSeqnum(lowest_unacked_seqnumber)) {
|
||||||
if (lowest_unacked_seqnumber < next_outgoing_seqnum) {
|
if (lowest_unacked_seqnumber < next_outgoing_seqnum) {
|
||||||
// ugly cast but this one is required in order to tell compiler we
|
// ugly cast but this one is required in order to tell compiler we
|
||||||
// know about difference of two unsigned may be negative in general
|
// know about difference of two unsigned may be negative in general
|
||||||
// but we already made sure it won't happen in this case
|
// but we already made sure it won't happen in this case
|
||||||
if (((u16)(next_outgoing_seqnum - lowest_unacked_seqnumber)) > m_window_size) {
|
if (((u16)(next_outgoing_seqnum - lowest_unacked_seqnumber)) > m_window_size) {
|
||||||
successful = false;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// ugly cast but this one is required in order to tell compiler we
|
// ugly cast but this one is required in order to tell compiler we
|
||||||
// know about difference of two unsigned may be negative in general
|
// know about difference of two unsigned may be negative in general
|
||||||
// but we already made sure it won't happen in this case
|
// but we already made sure it won't happen in this case
|
||||||
if ((next_outgoing_seqnum + (u16)(SEQNUM_MAX - lowest_unacked_seqnumber)) >
|
if ((next_outgoing_seqnum + (u16)(SEQNUM_MAX - lowest_unacked_seqnumber)) >
|
||||||
m_window_size) {
|
m_window_size) {
|
||||||
successful = false;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
successful = true;
|
||||||
next_outgoing_seqnum++;
|
next_outgoing_seqnum++;
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
@ -946,45 +1006,45 @@ bool UDPPeer::Ping(float dtime,SharedBuffer<u8>& data)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UDPPeer::PutReliableSendCommand(ConnectionCommand &c,
|
void UDPPeer::PutReliableSendCommand(ConnectionCommandPtr &c,
|
||||||
unsigned int max_packet_size)
|
unsigned int max_packet_size)
|
||||||
{
|
{
|
||||||
if (m_pending_disconnect)
|
if (m_pending_disconnect)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Channel &chan = channels[c.channelnum];
|
Channel &chan = channels[c->channelnum];
|
||||||
|
|
||||||
if (chan.queued_commands.empty() &&
|
if (chan.queued_commands.empty() &&
|
||||||
/* don't queue more packets then window size */
|
/* don't queue more packets then window size */
|
||||||
(chan.queued_reliables.size() < chan.getWindowSize() / 2)) {
|
(chan.queued_reliables.size() + 1 < chan.getWindowSize() / 2)) {
|
||||||
LOG(dout_con<<m_connection->getDesc()
|
LOG(dout_con<<m_connection->getDesc()
|
||||||
<<" processing reliable command for peer id: " << c.peer_id
|
<<" processing reliable command for peer id: " << c->peer_id
|
||||||
<<" data size: " << c.data.getSize() << std::endl);
|
<<" data size: " << c->data.getSize() << std::endl);
|
||||||
if (!processReliableSendCommand(c,max_packet_size)) {
|
if (processReliableSendCommand(c, max_packet_size))
|
||||||
chan.queued_commands.push_back(c);
|
return;
|
||||||
}
|
} else {
|
||||||
}
|
|
||||||
else {
|
|
||||||
LOG(dout_con<<m_connection->getDesc()
|
LOG(dout_con<<m_connection->getDesc()
|
||||||
<<" Queueing reliable command for peer id: " << c.peer_id
|
<<" Queueing reliable command for peer id: " << c->peer_id
|
||||||
<<" data size: " << c.data.getSize() <<std::endl);
|
<<" data size: " << c->data.getSize() <<std::endl);
|
||||||
chan.queued_commands.push_back(c);
|
|
||||||
if (chan.queued_commands.size() >= chan.getWindowSize() / 2) {
|
if (chan.queued_commands.size() + 1 >= chan.getWindowSize() / 2) {
|
||||||
LOG(derr_con << m_connection->getDesc()
|
LOG(derr_con << m_connection->getDesc()
|
||||||
<< "Possible packet stall to peer id: " << c.peer_id
|
<< "Possible packet stall to peer id: " << c->peer_id
|
||||||
<< " queued_commands=" << chan.queued_commands.size()
|
<< " queued_commands=" << chan.queued_commands.size()
|
||||||
<< std::endl);
|
<< std::endl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
chan.queued_commands.push_back(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UDPPeer::processReliableSendCommand(
|
bool UDPPeer::processReliableSendCommand(
|
||||||
ConnectionCommand &c,
|
ConnectionCommandPtr &c_ptr,
|
||||||
unsigned int max_packet_size)
|
unsigned int max_packet_size)
|
||||||
{
|
{
|
||||||
if (m_pending_disconnect)
|
if (m_pending_disconnect)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
const auto &c = *c_ptr;
|
||||||
Channel &chan = channels[c.channelnum];
|
Channel &chan = channels[c.channelnum];
|
||||||
|
|
||||||
u32 chunksize_max = max_packet_size
|
u32 chunksize_max = max_packet_size
|
||||||
@ -1003,9 +1063,9 @@ bool UDPPeer::processReliableSendCommand(
|
|||||||
chan.setNextSplitSeqNum(split_sequence_number);
|
chan.setNextSplitSeqNum(split_sequence_number);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool have_sequence_number = true;
|
bool have_sequence_number = false;
|
||||||
bool have_initial_sequence_number = false;
|
bool have_initial_sequence_number = false;
|
||||||
std::queue<BufferedPacket> toadd;
|
std::queue<BufferedPacketPtr> toadd;
|
||||||
volatile u16 initial_sequence_number = 0;
|
volatile u16 initial_sequence_number = 0;
|
||||||
|
|
||||||
for (SharedBuffer<u8> &original : originals) {
|
for (SharedBuffer<u8> &original : originals) {
|
||||||
@ -1024,25 +1084,23 @@ bool UDPPeer::processReliableSendCommand(
|
|||||||
SharedBuffer<u8> reliable = makeReliablePacket(original, seqnum);
|
SharedBuffer<u8> reliable = makeReliablePacket(original, seqnum);
|
||||||
|
|
||||||
// Add base headers and make a packet
|
// Add base headers and make a packet
|
||||||
BufferedPacket p = con::makePacket(address, reliable,
|
BufferedPacketPtr p = con::makePacket(address, reliable,
|
||||||
m_connection->GetProtocolID(), m_connection->GetPeerID(),
|
m_connection->GetProtocolID(), m_connection->GetPeerID(),
|
||||||
c.channelnum);
|
c.channelnum);
|
||||||
|
|
||||||
toadd.push(std::move(p));
|
toadd.push(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (have_sequence_number) {
|
if (have_sequence_number) {
|
||||||
volatile u16 pcount = 0;
|
|
||||||
while (!toadd.empty()) {
|
while (!toadd.empty()) {
|
||||||
BufferedPacket p = std::move(toadd.front());
|
BufferedPacketPtr p = toadd.front();
|
||||||
toadd.pop();
|
toadd.pop();
|
||||||
// LOG(dout_con<<connection->getDesc()
|
// LOG(dout_con<<connection->getDesc()
|
||||||
// << " queuing reliable packet for peer_id: " << c.peer_id
|
// << " queuing reliable packet for peer_id: " << c.peer_id
|
||||||
// << " channel: " << (c.channelnum&0xFF)
|
// << " channel: " << (c.channelnum&0xFF)
|
||||||
// << " seqnum: " << readU16(&p.data[BASE_HEADER_SIZE+1])
|
// << " seqnum: " << readU16(&p.data[BASE_HEADER_SIZE+1])
|
||||||
// << std::endl)
|
// << std::endl)
|
||||||
chan.queued_reliables.push(std::move(p));
|
chan.queued_reliables.push(p);
|
||||||
pcount++;
|
|
||||||
}
|
}
|
||||||
sanity_check(chan.queued_reliables.size() < 0xFFFF);
|
sanity_check(chan.queued_reliables.size() < 0xFFFF);
|
||||||
return true;
|
return true;
|
||||||
@ -1051,6 +1109,7 @@ bool UDPPeer::processReliableSendCommand(
|
|||||||
volatile u16 packets_available = toadd.size();
|
volatile u16 packets_available = toadd.size();
|
||||||
/* we didn't get a single sequence number no need to fill queue */
|
/* we didn't get a single sequence number no need to fill queue */
|
||||||
if (!have_initial_sequence_number) {
|
if (!have_initial_sequence_number) {
|
||||||
|
LOG(derr_con << m_connection->getDesc() << "Ran out of sequence numbers!" << std::endl);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1096,7 +1155,7 @@ void UDPPeer::RunCommandQueues(
|
|||||||
(channel.queued_reliables.size() < maxtransfer) &&
|
(channel.queued_reliables.size() < maxtransfer) &&
|
||||||
(commands_processed < maxcommands)) {
|
(commands_processed < maxcommands)) {
|
||||||
try {
|
try {
|
||||||
ConnectionCommand c = channel.queued_commands.front();
|
ConnectionCommandPtr c = channel.queued_commands.front();
|
||||||
|
|
||||||
LOG(dout_con << m_connection->getDesc()
|
LOG(dout_con << m_connection->getDesc()
|
||||||
<< " processing queued reliable command " << std::endl);
|
<< " processing queued reliable command " << std::endl);
|
||||||
@ -1106,8 +1165,8 @@ void UDPPeer::RunCommandQueues(
|
|||||||
channel.queued_commands.pop_front();
|
channel.queued_commands.pop_front();
|
||||||
} else {
|
} else {
|
||||||
LOG(dout_con << m_connection->getDesc()
|
LOG(dout_con << m_connection->getDesc()
|
||||||
<< " Failed to queue packets for peer_id: " << c.peer_id
|
<< " Failed to queue packets for peer_id: " << c->peer_id
|
||||||
<< ", delaying sending of " << c.data.getSize()
|
<< ", delaying sending of " << c->data.getSize()
|
||||||
<< " bytes" << std::endl);
|
<< " bytes" << std::endl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1130,13 +1189,70 @@ void UDPPeer::setNextSplitSequenceNumber(u8 channel, u16 seqnum)
|
|||||||
channels[channel].setNextSplitSeqNum(seqnum);
|
channels[channel].setNextSplitSeqNum(seqnum);
|
||||||
}
|
}
|
||||||
|
|
||||||
SharedBuffer<u8> UDPPeer::addSplitPacket(u8 channel, const BufferedPacket &toadd,
|
SharedBuffer<u8> UDPPeer::addSplitPacket(u8 channel, BufferedPacketPtr &toadd,
|
||||||
bool reliable)
|
bool reliable)
|
||||||
{
|
{
|
||||||
assert(channel < CHANNEL_COUNT); // Pre-condition
|
assert(channel < CHANNEL_COUNT); // Pre-condition
|
||||||
return channels[channel].incoming_splits.insert(toadd, reliable);
|
return channels[channel].incoming_splits.insert(toadd, reliable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
ConnectionEvent
|
||||||
|
*/
|
||||||
|
|
||||||
|
const char *ConnectionEvent::describe() const
|
||||||
|
{
|
||||||
|
switch(type) {
|
||||||
|
case CONNEVENT_NONE:
|
||||||
|
return "CONNEVENT_NONE";
|
||||||
|
case CONNEVENT_DATA_RECEIVED:
|
||||||
|
return "CONNEVENT_DATA_RECEIVED";
|
||||||
|
case CONNEVENT_PEER_ADDED:
|
||||||
|
return "CONNEVENT_PEER_ADDED";
|
||||||
|
case CONNEVENT_PEER_REMOVED:
|
||||||
|
return "CONNEVENT_PEER_REMOVED";
|
||||||
|
case CONNEVENT_BIND_FAILED:
|
||||||
|
return "CONNEVENT_BIND_FAILED";
|
||||||
|
}
|
||||||
|
return "Invalid ConnectionEvent";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ConnectionEventPtr ConnectionEvent::create(ConnectionEventType type)
|
||||||
|
{
|
||||||
|
return std::shared_ptr<ConnectionEvent>(new ConnectionEvent(type));
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectionEventPtr ConnectionEvent::dataReceived(session_t peer_id, const Buffer<u8> &data)
|
||||||
|
{
|
||||||
|
auto e = create(CONNEVENT_DATA_RECEIVED);
|
||||||
|
e->peer_id = peer_id;
|
||||||
|
data.copyTo(e->data);
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectionEventPtr ConnectionEvent::peerAdded(session_t peer_id, Address address)
|
||||||
|
{
|
||||||
|
auto e = create(CONNEVENT_PEER_ADDED);
|
||||||
|
e->peer_id = peer_id;
|
||||||
|
e->address = address;
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectionEventPtr ConnectionEvent::peerRemoved(session_t peer_id, bool is_timeout, Address address)
|
||||||
|
{
|
||||||
|
auto e = create(CONNEVENT_PEER_REMOVED);
|
||||||
|
e->peer_id = peer_id;
|
||||||
|
e->timeout = is_timeout;
|
||||||
|
e->address = address;
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectionEventPtr ConnectionEvent::bindFailed()
|
||||||
|
{
|
||||||
|
return create(CONNEVENT_BIND_FAILED);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Connection
|
Connection
|
||||||
*/
|
*/
|
||||||
@ -1186,18 +1302,12 @@ Connection::~Connection()
|
|||||||
|
|
||||||
/* Internal stuff */
|
/* Internal stuff */
|
||||||
|
|
||||||
void Connection::putEvent(const ConnectionEvent &e)
|
void Connection::putEvent(ConnectionEventPtr e)
|
||||||
{
|
{
|
||||||
assert(e.type != CONNEVENT_NONE); // Pre-condition
|
assert(e->type != CONNEVENT_NONE); // Pre-condition
|
||||||
m_event_queue.push_back(e);
|
m_event_queue.push_back(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Connection::putEvent(ConnectionEvent &&e)
|
|
||||||
{
|
|
||||||
assert(e.type != CONNEVENT_NONE); // Pre-condition
|
|
||||||
m_event_queue.push_back(std::move(e));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Connection::TriggerSend()
|
void Connection::TriggerSend()
|
||||||
{
|
{
|
||||||
m_sendThread->Trigger();
|
m_sendThread->Trigger();
|
||||||
@ -1260,11 +1370,9 @@ bool Connection::deletePeer(session_t peer_id, bool timeout)
|
|||||||
Address peer_address;
|
Address peer_address;
|
||||||
//any peer has a primary address this never fails!
|
//any peer has a primary address this never fails!
|
||||||
peer->getAddress(MTP_PRIMARY, peer_address);
|
peer->getAddress(MTP_PRIMARY, peer_address);
|
||||||
// Create event
|
|
||||||
ConnectionEvent e;
|
|
||||||
e.peerRemoved(peer_id, timeout, peer_address);
|
|
||||||
putEvent(e);
|
|
||||||
|
|
||||||
|
// Create event
|
||||||
|
putEvent(ConnectionEvent::peerRemoved(peer_id, timeout, peer_address));
|
||||||
|
|
||||||
peer->Drop();
|
peer->Drop();
|
||||||
return true;
|
return true;
|
||||||
@ -1272,18 +1380,16 @@ bool Connection::deletePeer(session_t peer_id, bool timeout)
|
|||||||
|
|
||||||
/* Interface */
|
/* Interface */
|
||||||
|
|
||||||
ConnectionEvent Connection::waitEvent(u32 timeout_ms)
|
ConnectionEventPtr Connection::waitEvent(u32 timeout_ms)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
return m_event_queue.pop_front(timeout_ms);
|
return m_event_queue.pop_front(timeout_ms);
|
||||||
} catch(ItemNotFoundException &ex) {
|
} catch(ItemNotFoundException &ex) {
|
||||||
ConnectionEvent e;
|
return ConnectionEvent::create(CONNEVENT_NONE);
|
||||||
e.type = CONNEVENT_NONE;
|
|
||||||
return e;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Connection::putCommand(const ConnectionCommand &c)
|
void Connection::putCommand(ConnectionCommandPtr c)
|
||||||
{
|
{
|
||||||
if (!m_shutting_down) {
|
if (!m_shutting_down) {
|
||||||
m_command_queue.push_back(c);
|
m_command_queue.push_back(c);
|
||||||
@ -1291,26 +1397,14 @@ void Connection::putCommand(const ConnectionCommand &c)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Connection::putCommand(ConnectionCommand &&c)
|
|
||||||
{
|
|
||||||
if (!m_shutting_down) {
|
|
||||||
m_command_queue.push_back(std::move(c));
|
|
||||||
m_sendThread->Trigger();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Connection::Serve(Address bind_addr)
|
void Connection::Serve(Address bind_addr)
|
||||||
{
|
{
|
||||||
ConnectionCommand c;
|
putCommand(ConnectionCommand::serve(bind_addr));
|
||||||
c.serve(bind_addr);
|
|
||||||
putCommand(c);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Connection::Connect(Address address)
|
void Connection::Connect(Address address)
|
||||||
{
|
{
|
||||||
ConnectionCommand c;
|
putCommand(ConnectionCommand::connect(address));
|
||||||
c.connect(address);
|
|
||||||
putCommand(c);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Connection::Connected()
|
bool Connection::Connected()
|
||||||
@ -1332,9 +1426,7 @@ bool Connection::Connected()
|
|||||||
|
|
||||||
void Connection::Disconnect()
|
void Connection::Disconnect()
|
||||||
{
|
{
|
||||||
ConnectionCommand c;
|
putCommand(ConnectionCommand::disconnect());
|
||||||
c.disconnect();
|
|
||||||
putCommand(c);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Connection::Receive(NetworkPacket *pkt, u32 timeout)
|
bool Connection::Receive(NetworkPacket *pkt, u32 timeout)
|
||||||
@ -1345,10 +1437,14 @@ bool Connection::Receive(NetworkPacket *pkt, u32 timeout)
|
|||||||
This is not considered to be a problem (is it?)
|
This is not considered to be a problem (is it?)
|
||||||
*/
|
*/
|
||||||
for(;;) {
|
for(;;) {
|
||||||
ConnectionEvent e = waitEvent(timeout);
|
ConnectionEventPtr e_ptr = waitEvent(timeout);
|
||||||
if (e.type != CONNEVENT_NONE)
|
const ConnectionEvent &e = *e_ptr;
|
||||||
|
|
||||||
|
if (e.type != CONNEVENT_NONE) {
|
||||||
LOG(dout_con << getDesc() << ": Receive: got event: "
|
LOG(dout_con << getDesc() << ": Receive: got event: "
|
||||||
<< e.describe() << std::endl);
|
<< e.describe() << std::endl);
|
||||||
|
}
|
||||||
|
|
||||||
switch (e.type) {
|
switch (e.type) {
|
||||||
case CONNEVENT_NONE:
|
case CONNEVENT_NONE:
|
||||||
return false;
|
return false;
|
||||||
@ -1397,10 +1493,7 @@ void Connection::Send(session_t peer_id, u8 channelnum,
|
|||||||
{
|
{
|
||||||
assert(channelnum < CHANNEL_COUNT); // Pre-condition
|
assert(channelnum < CHANNEL_COUNT); // Pre-condition
|
||||||
|
|
||||||
ConnectionCommand c;
|
putCommand(ConnectionCommand::send(peer_id, channelnum, pkt, reliable));
|
||||||
|
|
||||||
c.send(peer_id, channelnum, pkt, reliable);
|
|
||||||
putCommand(std::move(c));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Address Connection::GetPeerAddress(session_t peer_id)
|
Address Connection::GetPeerAddress(session_t peer_id)
|
||||||
@ -1499,41 +1592,31 @@ u16 Connection::createPeer(Address& sender, MTProtocols protocol, int fd)
|
|||||||
LOG(dout_con << getDesc()
|
LOG(dout_con << getDesc()
|
||||||
<< "createPeer(): giving peer_id=" << peer_id_new << std::endl);
|
<< "createPeer(): giving peer_id=" << peer_id_new << std::endl);
|
||||||
|
|
||||||
ConnectionCommand cmd;
|
{
|
||||||
Buffer<u8> reply(4);
|
Buffer<u8> reply(4);
|
||||||
writeU8(&reply[0], PACKET_TYPE_CONTROL);
|
writeU8(&reply[0], PACKET_TYPE_CONTROL);
|
||||||
writeU8(&reply[1], CONTROLTYPE_SET_PEER_ID);
|
writeU8(&reply[1], CONTROLTYPE_SET_PEER_ID);
|
||||||
writeU16(&reply[2], peer_id_new);
|
writeU16(&reply[2], peer_id_new);
|
||||||
cmd.createPeer(peer_id_new,reply);
|
putCommand(ConnectionCommand::createPeer(peer_id_new, reply));
|
||||||
putCommand(std::move(cmd));
|
}
|
||||||
|
|
||||||
// Create peer addition event
|
// Create peer addition event
|
||||||
ConnectionEvent e;
|
putEvent(ConnectionEvent::peerAdded(peer_id_new, sender));
|
||||||
e.peerAdded(peer_id_new, sender);
|
|
||||||
putEvent(e);
|
|
||||||
|
|
||||||
// We're now talking to a valid peer_id
|
// We're now talking to a valid peer_id
|
||||||
return peer_id_new;
|
return peer_id_new;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Connection::PrintInfo(std::ostream &out)
|
|
||||||
{
|
|
||||||
m_info_mutex.lock();
|
|
||||||
out<<getDesc()<<": ";
|
|
||||||
m_info_mutex.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string Connection::getDesc()
|
const std::string Connection::getDesc()
|
||||||
{
|
{
|
||||||
|
MutexAutoLock _(m_info_mutex);
|
||||||
return std::string("con(")+
|
return std::string("con(")+
|
||||||
itos(m_udpSocket.GetHandle())+"/"+itos(m_peer_id)+")";
|
itos(m_udpSocket.GetHandle())+"/"+itos(m_peer_id)+")";
|
||||||
}
|
}
|
||||||
|
|
||||||
void Connection::DisconnectPeer(session_t peer_id)
|
void Connection::DisconnectPeer(session_t peer_id)
|
||||||
{
|
{
|
||||||
ConnectionCommand discon;
|
putCommand(ConnectionCommand::disconnect_peer(peer_id));
|
||||||
discon.disconnect_peer(peer_id);
|
|
||||||
putCommand(discon);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Connection::sendAck(session_t peer_id, u8 channelnum, u16 seqnum)
|
void Connection::sendAck(session_t peer_id, u8 channelnum, u16 seqnum)
|
||||||
@ -1545,14 +1628,12 @@ void Connection::sendAck(session_t peer_id, u8 channelnum, u16 seqnum)
|
|||||||
" channel: " << (channelnum & 0xFF) <<
|
" channel: " << (channelnum & 0xFF) <<
|
||||||
" seqnum: " << seqnum << std::endl);
|
" seqnum: " << seqnum << std::endl);
|
||||||
|
|
||||||
ConnectionCommand c;
|
|
||||||
SharedBuffer<u8> ack(4);
|
SharedBuffer<u8> ack(4);
|
||||||
writeU8(&ack[0], PACKET_TYPE_CONTROL);
|
writeU8(&ack[0], PACKET_TYPE_CONTROL);
|
||||||
writeU8(&ack[1], CONTROLTYPE_ACK);
|
writeU8(&ack[1], CONTROLTYPE_ACK);
|
||||||
writeU16(&ack[2], seqnum);
|
writeU16(&ack[2], seqnum);
|
||||||
|
|
||||||
c.ack(peer_id, channelnum, ack);
|
putCommand(ConnectionCommand::ack(peer_id, channelnum, ack));
|
||||||
putCommand(std::move(c));
|
|
||||||
m_sendThread->Trigger();
|
m_sendThread->Trigger();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,6 +32,95 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
|
#define MAX_UDP_PEERS 65535
|
||||||
|
|
||||||
|
/*
|
||||||
|
=== NOTES ===
|
||||||
|
|
||||||
|
A packet is sent through a channel to a peer with a basic header:
|
||||||
|
Header (7 bytes):
|
||||||
|
[0] u32 protocol_id
|
||||||
|
[4] session_t sender_peer_id
|
||||||
|
[6] u8 channel
|
||||||
|
sender_peer_id:
|
||||||
|
Unique to each peer.
|
||||||
|
value 0 (PEER_ID_INEXISTENT) is reserved for making new connections
|
||||||
|
value 1 (PEER_ID_SERVER) is reserved for server
|
||||||
|
these constants are defined in constants.h
|
||||||
|
channel:
|
||||||
|
Channel numbers have no intrinsic meaning. Currently only 0, 1, 2 exist.
|
||||||
|
*/
|
||||||
|
#define BASE_HEADER_SIZE 7
|
||||||
|
#define CHANNEL_COUNT 3
|
||||||
|
|
||||||
|
/*
|
||||||
|
Packet types:
|
||||||
|
|
||||||
|
CONTROL: This is a packet used by the protocol.
|
||||||
|
- When this is processed, nothing is handed to the user.
|
||||||
|
Header (2 byte):
|
||||||
|
[0] u8 type
|
||||||
|
[1] u8 controltype
|
||||||
|
controltype and data description:
|
||||||
|
CONTROLTYPE_ACK
|
||||||
|
[2] u16 seqnum
|
||||||
|
CONTROLTYPE_SET_PEER_ID
|
||||||
|
[2] session_t peer_id_new
|
||||||
|
CONTROLTYPE_PING
|
||||||
|
- There is no actual reply, but this can be sent in a reliable
|
||||||
|
packet to get a reply
|
||||||
|
CONTROLTYPE_DISCO
|
||||||
|
*/
|
||||||
|
enum ControlType : u8 {
|
||||||
|
CONTROLTYPE_ACK = 0,
|
||||||
|
CONTROLTYPE_SET_PEER_ID = 1,
|
||||||
|
CONTROLTYPE_PING = 2,
|
||||||
|
CONTROLTYPE_DISCO = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
ORIGINAL: This is a plain packet with no control and no error
|
||||||
|
checking at all.
|
||||||
|
- When this is processed, it is directly handed to the user.
|
||||||
|
Header (1 byte):
|
||||||
|
[0] u8 type
|
||||||
|
*/
|
||||||
|
//#define TYPE_ORIGINAL 1
|
||||||
|
#define ORIGINAL_HEADER_SIZE 1
|
||||||
|
|
||||||
|
/*
|
||||||
|
SPLIT: These are sequences of packets forming one bigger piece of
|
||||||
|
data.
|
||||||
|
- When processed and all the packet_nums 0...packet_count-1 are
|
||||||
|
present (this should be buffered), the resulting data shall be
|
||||||
|
directly handed to the user.
|
||||||
|
- If the data fails to come up in a reasonable time, the buffer shall
|
||||||
|
be silently discarded.
|
||||||
|
- These can be sent as-is or atop of a RELIABLE packet stream.
|
||||||
|
Header (7 bytes):
|
||||||
|
[0] u8 type
|
||||||
|
[1] u16 seqnum
|
||||||
|
[3] u16 chunk_count
|
||||||
|
[5] u16 chunk_num
|
||||||
|
*/
|
||||||
|
//#define TYPE_SPLIT 2
|
||||||
|
|
||||||
|
/*
|
||||||
|
RELIABLE: Delivery of all RELIABLE packets shall be forced by ACKs,
|
||||||
|
and they shall be delivered in the same order as sent. This is done
|
||||||
|
with a buffer in the receiving and transmitting end.
|
||||||
|
- When this is processed, the contents of each packet is recursively
|
||||||
|
processed as packets.
|
||||||
|
Header (3 bytes):
|
||||||
|
[0] u8 type
|
||||||
|
[1] u16 seqnum
|
||||||
|
|
||||||
|
*/
|
||||||
|
//#define TYPE_RELIABLE 3
|
||||||
|
#define RELIABLE_HEADER_SIZE 3
|
||||||
|
#define SEQNUM_INITIAL 65500
|
||||||
|
#define SEQNUM_MAX 65535
|
||||||
|
|
||||||
class NetworkPacket;
|
class NetworkPacket;
|
||||||
|
|
||||||
namespace con
|
namespace con
|
||||||
@ -46,9 +135,13 @@ typedef enum MTProtocols {
|
|||||||
MTP_MINETEST_RELIABLE_UDP
|
MTP_MINETEST_RELIABLE_UDP
|
||||||
} MTProtocols;
|
} MTProtocols;
|
||||||
|
|
||||||
#define MAX_UDP_PEERS 65535
|
enum PacketType : u8 {
|
||||||
|
PACKET_TYPE_CONTROL = 0,
|
||||||
#define SEQNUM_MAX 65535
|
PACKET_TYPE_ORIGINAL = 1,
|
||||||
|
PACKET_TYPE_SPLIT = 2,
|
||||||
|
PACKET_TYPE_RELIABLE = 3,
|
||||||
|
PACKET_TYPE_MAX
|
||||||
|
};
|
||||||
|
|
||||||
inline bool seqnum_higher(u16 totest, u16 base)
|
inline bool seqnum_higher(u16 totest, u16 base)
|
||||||
{
|
{
|
||||||
@ -85,24 +178,40 @@ static inline float CALC_DTIME(u64 lasttime, u64 curtime)
|
|||||||
return MYMAX(MYMIN(value,0.1),0.0);
|
return MYMAX(MYMIN(value,0.1),0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct BufferedPacket
|
/*
|
||||||
|
Struct for all kinds of packets. Includes following data:
|
||||||
|
BASE_HEADER
|
||||||
|
u8[] packet data (usually copied from SharedBuffer<u8>)
|
||||||
|
*/
|
||||||
|
struct BufferedPacket {
|
||||||
|
BufferedPacket(u32 a_size)
|
||||||
{
|
{
|
||||||
BufferedPacket(u8 *a_data, u32 a_size):
|
m_data.resize(a_size);
|
||||||
data(a_data, a_size)
|
data = &m_data[0];
|
||||||
{}
|
}
|
||||||
BufferedPacket(u32 a_size):
|
|
||||||
data(a_size)
|
DISABLE_CLASS_COPY(BufferedPacket)
|
||||||
{}
|
|
||||||
Buffer<u8> data; // Data of the packet, including headers
|
u16 getSeqnum() const;
|
||||||
|
|
||||||
|
inline const size_t size() const { return m_data.size(); }
|
||||||
|
|
||||||
|
u8 *data; // Direct memory access
|
||||||
float time = 0.0f; // Seconds from buffering the packet or re-sending
|
float time = 0.0f; // Seconds from buffering the packet or re-sending
|
||||||
float totaltime = 0.0f; // Seconds from buffering the packet
|
float totaltime = 0.0f; // Seconds from buffering the packet
|
||||||
u64 absolute_send_time = -1;
|
u64 absolute_send_time = -1;
|
||||||
Address address; // Sender or destination
|
Address address; // Sender or destination
|
||||||
unsigned int resend_count = 0;
|
unsigned int resend_count = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<u8> m_data; // Data of the packet, including headers
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef std::shared_ptr<BufferedPacket> BufferedPacketPtr;
|
||||||
|
|
||||||
|
|
||||||
// This adds the base headers to the data and makes a packet out of it
|
// This adds the base headers to the data and makes a packet out of it
|
||||||
BufferedPacket makePacket(Address &address, const SharedBuffer<u8> &data,
|
BufferedPacketPtr makePacket(Address &address, const SharedBuffer<u8> &data,
|
||||||
u32 protocol_id, session_t sender_peer_id, u8 channel);
|
u32 protocol_id, session_t sender_peer_id, u8 channel);
|
||||||
|
|
||||||
// Depending on size, make a TYPE_ORIGINAL or TYPE_SPLIT packet
|
// Depending on size, make a TYPE_ORIGINAL or TYPE_SPLIT packet
|
||||||
@ -136,101 +245,12 @@ private:
|
|||||||
std::map<u16, SharedBuffer<u8>> chunks;
|
std::map<u16, SharedBuffer<u8>> chunks;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
=== NOTES ===
|
|
||||||
|
|
||||||
A packet is sent through a channel to a peer with a basic header:
|
|
||||||
Header (7 bytes):
|
|
||||||
[0] u32 protocol_id
|
|
||||||
[4] session_t sender_peer_id
|
|
||||||
[6] u8 channel
|
|
||||||
sender_peer_id:
|
|
||||||
Unique to each peer.
|
|
||||||
value 0 (PEER_ID_INEXISTENT) is reserved for making new connections
|
|
||||||
value 1 (PEER_ID_SERVER) is reserved for server
|
|
||||||
these constants are defined in constants.h
|
|
||||||
channel:
|
|
||||||
Channel numbers have no intrinsic meaning. Currently only 0, 1, 2 exist.
|
|
||||||
*/
|
|
||||||
#define BASE_HEADER_SIZE 7
|
|
||||||
#define CHANNEL_COUNT 3
|
|
||||||
/*
|
|
||||||
Packet types:
|
|
||||||
|
|
||||||
CONTROL: This is a packet used by the protocol.
|
|
||||||
- When this is processed, nothing is handed to the user.
|
|
||||||
Header (2 byte):
|
|
||||||
[0] u8 type
|
|
||||||
[1] u8 controltype
|
|
||||||
controltype and data description:
|
|
||||||
CONTROLTYPE_ACK
|
|
||||||
[2] u16 seqnum
|
|
||||||
CONTROLTYPE_SET_PEER_ID
|
|
||||||
[2] session_t peer_id_new
|
|
||||||
CONTROLTYPE_PING
|
|
||||||
- There is no actual reply, but this can be sent in a reliable
|
|
||||||
packet to get a reply
|
|
||||||
CONTROLTYPE_DISCO
|
|
||||||
*/
|
|
||||||
//#define TYPE_CONTROL 0
|
|
||||||
#define CONTROLTYPE_ACK 0
|
|
||||||
#define CONTROLTYPE_SET_PEER_ID 1
|
|
||||||
#define CONTROLTYPE_PING 2
|
|
||||||
#define CONTROLTYPE_DISCO 3
|
|
||||||
|
|
||||||
/*
|
|
||||||
ORIGINAL: This is a plain packet with no control and no error
|
|
||||||
checking at all.
|
|
||||||
- When this is processed, it is directly handed to the user.
|
|
||||||
Header (1 byte):
|
|
||||||
[0] u8 type
|
|
||||||
*/
|
|
||||||
//#define TYPE_ORIGINAL 1
|
|
||||||
#define ORIGINAL_HEADER_SIZE 1
|
|
||||||
/*
|
|
||||||
SPLIT: These are sequences of packets forming one bigger piece of
|
|
||||||
data.
|
|
||||||
- When processed and all the packet_nums 0...packet_count-1 are
|
|
||||||
present (this should be buffered), the resulting data shall be
|
|
||||||
directly handed to the user.
|
|
||||||
- If the data fails to come up in a reasonable time, the buffer shall
|
|
||||||
be silently discarded.
|
|
||||||
- These can be sent as-is or atop of a RELIABLE packet stream.
|
|
||||||
Header (7 bytes):
|
|
||||||
[0] u8 type
|
|
||||||
[1] u16 seqnum
|
|
||||||
[3] u16 chunk_count
|
|
||||||
[5] u16 chunk_num
|
|
||||||
*/
|
|
||||||
//#define TYPE_SPLIT 2
|
|
||||||
/*
|
|
||||||
RELIABLE: Delivery of all RELIABLE packets shall be forced by ACKs,
|
|
||||||
and they shall be delivered in the same order as sent. This is done
|
|
||||||
with a buffer in the receiving and transmitting end.
|
|
||||||
- When this is processed, the contents of each packet is recursively
|
|
||||||
processed as packets.
|
|
||||||
Header (3 bytes):
|
|
||||||
[0] u8 type
|
|
||||||
[1] u16 seqnum
|
|
||||||
|
|
||||||
*/
|
|
||||||
//#define TYPE_RELIABLE 3
|
|
||||||
#define RELIABLE_HEADER_SIZE 3
|
|
||||||
#define SEQNUM_INITIAL 65500
|
|
||||||
|
|
||||||
enum PacketType: u8 {
|
|
||||||
PACKET_TYPE_CONTROL = 0,
|
|
||||||
PACKET_TYPE_ORIGINAL = 1,
|
|
||||||
PACKET_TYPE_SPLIT = 2,
|
|
||||||
PACKET_TYPE_RELIABLE = 3,
|
|
||||||
PACKET_TYPE_MAX
|
|
||||||
};
|
|
||||||
/*
|
/*
|
||||||
A buffer which stores reliable packets and sorts them internally
|
A buffer which stores reliable packets and sorts them internally
|
||||||
for fast access to the smallest one.
|
for fast access to the smallest one.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef std::list<BufferedPacket>::iterator RPBSearchResult;
|
typedef std::list<BufferedPacketPtr>::iterator RPBSearchResult;
|
||||||
|
|
||||||
class ReliablePacketBuffer
|
class ReliablePacketBuffer
|
||||||
{
|
{
|
||||||
@ -239,12 +259,12 @@ public:
|
|||||||
|
|
||||||
bool getFirstSeqnum(u16& result);
|
bool getFirstSeqnum(u16& result);
|
||||||
|
|
||||||
BufferedPacket popFirst();
|
BufferedPacketPtr popFirst();
|
||||||
BufferedPacket popSeqnum(u16 seqnum);
|
BufferedPacketPtr popSeqnum(u16 seqnum);
|
||||||
void insert(const BufferedPacket &p, u16 next_expected);
|
void insert(BufferedPacketPtr &p_ptr, u16 next_expected);
|
||||||
|
|
||||||
void incrementTimeouts(float dtime);
|
void incrementTimeouts(float dtime);
|
||||||
std::list<BufferedPacket> getTimedOuts(float timeout, u32 max_packets);
|
std::list<ConstSharedPtr<BufferedPacket>> getTimedOuts(float timeout, u32 max_packets);
|
||||||
|
|
||||||
void print();
|
void print();
|
||||||
bool empty();
|
bool empty();
|
||||||
@ -252,10 +272,9 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RPBSearchResult findPacket(u16 seqnum); // does not perform locking
|
RPBSearchResult findPacketNoLock(u16 seqnum);
|
||||||
inline RPBSearchResult notFound() { return m_list.end(); }
|
|
||||||
|
|
||||||
std::list<BufferedPacket> m_list;
|
std::list<BufferedPacketPtr> m_list;
|
||||||
|
|
||||||
u16 m_oldest_non_answered_ack;
|
u16 m_oldest_non_answered_ack;
|
||||||
|
|
||||||
@ -274,7 +293,7 @@ public:
|
|||||||
Returns a reference counted buffer of length != 0 when a full split
|
Returns a reference counted buffer of length != 0 when a full split
|
||||||
packet is constructed. If not, returns one of length 0.
|
packet is constructed. If not, returns one of length 0.
|
||||||
*/
|
*/
|
||||||
SharedBuffer<u8> insert(const BufferedPacket &p, bool reliable);
|
SharedBuffer<u8> insert(BufferedPacketPtr &p_ptr, bool reliable);
|
||||||
|
|
||||||
void removeUnreliableTimedOuts(float dtime, float timeout);
|
void removeUnreliableTimedOuts(float dtime, float timeout);
|
||||||
|
|
||||||
@ -285,25 +304,6 @@ private:
|
|||||||
std::mutex m_map_mutex;
|
std::mutex m_map_mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct OutgoingPacket
|
|
||||||
{
|
|
||||||
session_t peer_id;
|
|
||||||
u8 channelnum;
|
|
||||||
SharedBuffer<u8> data;
|
|
||||||
bool reliable;
|
|
||||||
bool ack;
|
|
||||||
|
|
||||||
OutgoingPacket(session_t peer_id_, u8 channelnum_, const SharedBuffer<u8> &data_,
|
|
||||||
bool reliable_,bool ack_=false):
|
|
||||||
peer_id(peer_id_),
|
|
||||||
channelnum(channelnum_),
|
|
||||||
data(data_),
|
|
||||||
reliable(reliable_),
|
|
||||||
ack(ack_)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
enum ConnectionCommandType{
|
enum ConnectionCommandType{
|
||||||
CONNCMD_NONE,
|
CONNCMD_NONE,
|
||||||
CONNCMD_SERVE,
|
CONNCMD_SERVE,
|
||||||
@ -316,9 +316,13 @@ enum ConnectionCommandType{
|
|||||||
CONCMD_CREATE_PEER
|
CONCMD_CREATE_PEER
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ConnectionCommand;
|
||||||
|
typedef std::shared_ptr<ConnectionCommand> ConnectionCommandPtr;
|
||||||
|
|
||||||
|
// This is very similar to ConnectionEvent
|
||||||
struct ConnectionCommand
|
struct ConnectionCommand
|
||||||
{
|
{
|
||||||
enum ConnectionCommandType type = CONNCMD_NONE;
|
const ConnectionCommandType type;
|
||||||
Address address;
|
Address address;
|
||||||
session_t peer_id = PEER_ID_INEXISTENT;
|
session_t peer_id = PEER_ID_INEXISTENT;
|
||||||
u8 channelnum = 0;
|
u8 channelnum = 0;
|
||||||
@ -326,48 +330,21 @@ struct ConnectionCommand
|
|||||||
bool reliable = false;
|
bool reliable = false;
|
||||||
bool raw = false;
|
bool raw = false;
|
||||||
|
|
||||||
ConnectionCommand() = default;
|
DISABLE_CLASS_COPY(ConnectionCommand);
|
||||||
|
|
||||||
void serve(Address address_)
|
static ConnectionCommandPtr serve(Address address);
|
||||||
{
|
static ConnectionCommandPtr connect(Address address);
|
||||||
type = CONNCMD_SERVE;
|
static ConnectionCommandPtr disconnect();
|
||||||
address = address_;
|
static ConnectionCommandPtr disconnect_peer(session_t peer_id);
|
||||||
}
|
static ConnectionCommandPtr send(session_t peer_id, u8 channelnum, NetworkPacket *pkt, bool reliable);
|
||||||
void connect(Address address_)
|
static ConnectionCommandPtr ack(session_t peer_id, u8 channelnum, const Buffer<u8> &data);
|
||||||
{
|
static ConnectionCommandPtr createPeer(session_t peer_id, const Buffer<u8> &data);
|
||||||
type = CONNCMD_CONNECT;
|
|
||||||
address = address_;
|
|
||||||
}
|
|
||||||
void disconnect()
|
|
||||||
{
|
|
||||||
type = CONNCMD_DISCONNECT;
|
|
||||||
}
|
|
||||||
void disconnect_peer(session_t peer_id_)
|
|
||||||
{
|
|
||||||
type = CONNCMD_DISCONNECT_PEER;
|
|
||||||
peer_id = peer_id_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void send(session_t peer_id_, u8 channelnum_, NetworkPacket *pkt, bool reliable_);
|
private:
|
||||||
|
ConnectionCommand(ConnectionCommandType type_) :
|
||||||
|
type(type_) {}
|
||||||
|
|
||||||
void ack(session_t peer_id_, u8 channelnum_, const Buffer<u8> &data_)
|
static ConnectionCommandPtr create(ConnectionCommandType type);
|
||||||
{
|
|
||||||
type = CONCMD_ACK;
|
|
||||||
peer_id = peer_id_;
|
|
||||||
channelnum = channelnum_;
|
|
||||||
data = data_;
|
|
||||||
reliable = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void createPeer(session_t peer_id_, const Buffer<u8> &data_)
|
|
||||||
{
|
|
||||||
type = CONCMD_CREATE_PEER;
|
|
||||||
peer_id = peer_id_;
|
|
||||||
data = data_;
|
|
||||||
channelnum = 0;
|
|
||||||
reliable = true;
|
|
||||||
raw = true;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* maximum window size to use, 0xFFFF is theoretical maximum. don't think about
|
/* maximum window size to use, 0xFFFF is theoretical maximum. don't think about
|
||||||
@ -402,10 +379,10 @@ public:
|
|||||||
ReliablePacketBuffer outgoing_reliables_sent;
|
ReliablePacketBuffer outgoing_reliables_sent;
|
||||||
|
|
||||||
//queued reliable packets
|
//queued reliable packets
|
||||||
std::queue<BufferedPacket> queued_reliables;
|
std::queue<BufferedPacketPtr> queued_reliables;
|
||||||
|
|
||||||
//queue commands prior splitting to packets
|
//queue commands prior splitting to packets
|
||||||
std::deque<ConnectionCommand> queued_commands;
|
std::deque<ConnectionCommandPtr> queued_commands;
|
||||||
|
|
||||||
IncomingSplitBuffer incoming_splits;
|
IncomingSplitBuffer incoming_splits;
|
||||||
|
|
||||||
@ -514,7 +491,7 @@ class Peer {
|
|||||||
public:
|
public:
|
||||||
friend class PeerHelper;
|
friend class PeerHelper;
|
||||||
|
|
||||||
Peer(Address address_,u16 id_,Connection* connection) :
|
Peer(Address address_,session_t id_,Connection* connection) :
|
||||||
id(id_),
|
id(id_),
|
||||||
m_connection(connection),
|
m_connection(connection),
|
||||||
address(address_),
|
address(address_),
|
||||||
@ -528,11 +505,11 @@ class Peer {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Unique id of the peer
|
// Unique id of the peer
|
||||||
u16 id;
|
const session_t id;
|
||||||
|
|
||||||
void Drop();
|
void Drop();
|
||||||
|
|
||||||
virtual void PutReliableSendCommand(ConnectionCommand &c,
|
virtual void PutReliableSendCommand(ConnectionCommandPtr &c,
|
||||||
unsigned int max_packet_size) {};
|
unsigned int max_packet_size) {};
|
||||||
|
|
||||||
virtual bool getAddress(MTProtocols type, Address& toset) = 0;
|
virtual bool getAddress(MTProtocols type, Address& toset) = 0;
|
||||||
@ -549,7 +526,7 @@ class Peer {
|
|||||||
|
|
||||||
virtual u16 getNextSplitSequenceNumber(u8 channel) { return 0; };
|
virtual u16 getNextSplitSequenceNumber(u8 channel) { return 0; };
|
||||||
virtual void setNextSplitSequenceNumber(u8 channel, u16 seqnum) {};
|
virtual void setNextSplitSequenceNumber(u8 channel, u16 seqnum) {};
|
||||||
virtual SharedBuffer<u8> addSplitPacket(u8 channel, const BufferedPacket &toadd,
|
virtual SharedBuffer<u8> addSplitPacket(u8 channel, BufferedPacketPtr &toadd,
|
||||||
bool reliable)
|
bool reliable)
|
||||||
{
|
{
|
||||||
errorstream << "Peer::addSplitPacket called,"
|
errorstream << "Peer::addSplitPacket called,"
|
||||||
@ -586,7 +563,7 @@ class Peer {
|
|||||||
bool IncUseCount();
|
bool IncUseCount();
|
||||||
void DecUseCount();
|
void DecUseCount();
|
||||||
|
|
||||||
std::mutex m_exclusive_access_mutex;
|
mutable std::mutex m_exclusive_access_mutex;
|
||||||
|
|
||||||
bool m_pending_deletion = false;
|
bool m_pending_deletion = false;
|
||||||
|
|
||||||
@ -634,7 +611,7 @@ public:
|
|||||||
UDPPeer(u16 a_id, Address a_address, Connection* connection);
|
UDPPeer(u16 a_id, Address a_address, Connection* connection);
|
||||||
virtual ~UDPPeer() = default;
|
virtual ~UDPPeer() = default;
|
||||||
|
|
||||||
void PutReliableSendCommand(ConnectionCommand &c,
|
void PutReliableSendCommand(ConnectionCommandPtr &c,
|
||||||
unsigned int max_packet_size);
|
unsigned int max_packet_size);
|
||||||
|
|
||||||
bool getAddress(MTProtocols type, Address& toset);
|
bool getAddress(MTProtocols type, Address& toset);
|
||||||
@ -642,7 +619,7 @@ public:
|
|||||||
u16 getNextSplitSequenceNumber(u8 channel);
|
u16 getNextSplitSequenceNumber(u8 channel);
|
||||||
void setNextSplitSequenceNumber(u8 channel, u16 seqnum);
|
void setNextSplitSequenceNumber(u8 channel, u16 seqnum);
|
||||||
|
|
||||||
SharedBuffer<u8> addSplitPacket(u8 channel, const BufferedPacket &toadd,
|
SharedBuffer<u8> addSplitPacket(u8 channel, BufferedPacketPtr &toadd,
|
||||||
bool reliable);
|
bool reliable);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -671,7 +648,7 @@ private:
|
|||||||
float resend_timeout = 0.5;
|
float resend_timeout = 0.5;
|
||||||
|
|
||||||
bool processReliableSendCommand(
|
bool processReliableSendCommand(
|
||||||
ConnectionCommand &c,
|
ConnectionCommandPtr &c_ptr,
|
||||||
unsigned int max_packet_size);
|
unsigned int max_packet_size);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -687,56 +664,32 @@ enum ConnectionEventType{
|
|||||||
CONNEVENT_BIND_FAILED,
|
CONNEVENT_BIND_FAILED,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ConnectionEvent;
|
||||||
|
typedef std::shared_ptr<ConnectionEvent> ConnectionEventPtr;
|
||||||
|
|
||||||
|
// This is very similar to ConnectionCommand
|
||||||
struct ConnectionEvent
|
struct ConnectionEvent
|
||||||
{
|
{
|
||||||
enum ConnectionEventType type = CONNEVENT_NONE;
|
const ConnectionEventType type;
|
||||||
session_t peer_id = 0;
|
session_t peer_id = 0;
|
||||||
Buffer<u8> data;
|
Buffer<u8> data;
|
||||||
bool timeout = false;
|
bool timeout = false;
|
||||||
Address address;
|
Address address;
|
||||||
|
|
||||||
ConnectionEvent() = default;
|
// We don't want to copy "data"
|
||||||
|
DISABLE_CLASS_COPY(ConnectionEvent);
|
||||||
|
|
||||||
const char *describe() const
|
static ConnectionEventPtr create(ConnectionEventType type);
|
||||||
{
|
static ConnectionEventPtr dataReceived(session_t peer_id, const Buffer<u8> &data);
|
||||||
switch(type) {
|
static ConnectionEventPtr peerAdded(session_t peer_id, Address address);
|
||||||
case CONNEVENT_NONE:
|
static ConnectionEventPtr peerRemoved(session_t peer_id, bool is_timeout, Address address);
|
||||||
return "CONNEVENT_NONE";
|
static ConnectionEventPtr bindFailed();
|
||||||
case CONNEVENT_DATA_RECEIVED:
|
|
||||||
return "CONNEVENT_DATA_RECEIVED";
|
|
||||||
case CONNEVENT_PEER_ADDED:
|
|
||||||
return "CONNEVENT_PEER_ADDED";
|
|
||||||
case CONNEVENT_PEER_REMOVED:
|
|
||||||
return "CONNEVENT_PEER_REMOVED";
|
|
||||||
case CONNEVENT_BIND_FAILED:
|
|
||||||
return "CONNEVENT_BIND_FAILED";
|
|
||||||
}
|
|
||||||
return "Invalid ConnectionEvent";
|
|
||||||
}
|
|
||||||
|
|
||||||
void dataReceived(session_t peer_id_, const Buffer<u8> &data_)
|
const char *describe() const;
|
||||||
{
|
|
||||||
type = CONNEVENT_DATA_RECEIVED;
|
private:
|
||||||
peer_id = peer_id_;
|
ConnectionEvent(ConnectionEventType type_) :
|
||||||
data = data_;
|
type(type_) {}
|
||||||
}
|
|
||||||
void peerAdded(session_t peer_id_, Address address_)
|
|
||||||
{
|
|
||||||
type = CONNEVENT_PEER_ADDED;
|
|
||||||
peer_id = peer_id_;
|
|
||||||
address = address_;
|
|
||||||
}
|
|
||||||
void peerRemoved(session_t peer_id_, bool timeout_, Address address_)
|
|
||||||
{
|
|
||||||
type = CONNEVENT_PEER_REMOVED;
|
|
||||||
peer_id = peer_id_;
|
|
||||||
timeout = timeout_;
|
|
||||||
address = address_;
|
|
||||||
}
|
|
||||||
void bindFailed()
|
|
||||||
{
|
|
||||||
type = CONNEVENT_BIND_FAILED;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class PeerHandler;
|
class PeerHandler;
|
||||||
@ -752,10 +705,9 @@ public:
|
|||||||
~Connection();
|
~Connection();
|
||||||
|
|
||||||
/* Interface */
|
/* Interface */
|
||||||
ConnectionEvent waitEvent(u32 timeout_ms);
|
ConnectionEventPtr waitEvent(u32 timeout_ms);
|
||||||
// Warning: creates an unnecessary copy, prefer putCommand(T&&) if possible
|
|
||||||
void putCommand(const ConnectionCommand &c);
|
void putCommand(ConnectionCommandPtr c);
|
||||||
void putCommand(ConnectionCommand &&c);
|
|
||||||
|
|
||||||
void SetTimeoutMs(u32 timeout) { m_bc_receive_timeout = timeout; }
|
void SetTimeoutMs(u32 timeout) { m_bc_receive_timeout = timeout; }
|
||||||
void Serve(Address bind_addr);
|
void Serve(Address bind_addr);
|
||||||
@ -785,8 +737,6 @@ protected:
|
|||||||
|
|
||||||
void sendAck(session_t peer_id, u8 channelnum, u16 seqnum);
|
void sendAck(session_t peer_id, u8 channelnum, u16 seqnum);
|
||||||
|
|
||||||
void PrintInfo(std::ostream &out);
|
|
||||||
|
|
||||||
std::vector<session_t> getPeerIDs()
|
std::vector<session_t> getPeerIDs()
|
||||||
{
|
{
|
||||||
MutexAutoLock peerlock(m_peers_mutex);
|
MutexAutoLock peerlock(m_peers_mutex);
|
||||||
@ -795,13 +745,11 @@ protected:
|
|||||||
|
|
||||||
UDPSocket m_udpSocket;
|
UDPSocket m_udpSocket;
|
||||||
// Command queue: user -> SendThread
|
// Command queue: user -> SendThread
|
||||||
MutexedQueue<ConnectionCommand> m_command_queue;
|
MutexedQueue<ConnectionCommandPtr> m_command_queue;
|
||||||
|
|
||||||
bool Receive(NetworkPacket *pkt, u32 timeout);
|
bool Receive(NetworkPacket *pkt, u32 timeout);
|
||||||
|
|
||||||
// Warning: creates an unnecessary copy, prefer putEvent(T&&) if possible
|
void putEvent(ConnectionEventPtr e);
|
||||||
void putEvent(const ConnectionEvent &e);
|
|
||||||
void putEvent(ConnectionEvent &&e);
|
|
||||||
|
|
||||||
void TriggerSend();
|
void TriggerSend();
|
||||||
|
|
||||||
@ -811,7 +759,7 @@ protected:
|
|||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
// Event queue: ReceiveThread -> user
|
// Event queue: ReceiveThread -> user
|
||||||
MutexedQueue<ConnectionEvent> m_event_queue;
|
MutexedQueue<ConnectionEventPtr> m_event_queue;
|
||||||
|
|
||||||
session_t m_peer_id = 0;
|
session_t m_peer_id = 0;
|
||||||
u32 m_protocol_id;
|
u32 m_protocol_id;
|
||||||
@ -823,7 +771,7 @@ private:
|
|||||||
std::unique_ptr<ConnectionSendThread> m_sendThread;
|
std::unique_ptr<ConnectionSendThread> m_sendThread;
|
||||||
std::unique_ptr<ConnectionReceiveThread> m_receiveThread;
|
std::unique_ptr<ConnectionReceiveThread> m_receiveThread;
|
||||||
|
|
||||||
std::mutex m_info_mutex;
|
mutable std::mutex m_info_mutex;
|
||||||
|
|
||||||
// Backwards compatibility
|
// Backwards compatibility
|
||||||
PeerHandler *m_bc_peerhandler;
|
PeerHandler *m_bc_peerhandler;
|
||||||
|
@ -50,11 +50,11 @@ std::mutex log_conthread_mutex;
|
|||||||
|
|
||||||
#define WINDOW_SIZE 5
|
#define WINDOW_SIZE 5
|
||||||
|
|
||||||
static session_t readPeerId(u8 *packetdata)
|
static session_t readPeerId(const u8 *packetdata)
|
||||||
{
|
{
|
||||||
return readU16(&packetdata[4]);
|
return readU16(&packetdata[4]);
|
||||||
}
|
}
|
||||||
static u8 readChannel(u8 *packetdata)
|
static u8 readChannel(const u8 *packetdata)
|
||||||
{
|
{
|
||||||
return readU8(&packetdata[6]);
|
return readU8(&packetdata[6]);
|
||||||
}
|
}
|
||||||
@ -114,9 +114,9 @@ void *ConnectionSendThread::run()
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* translate commands to packets */
|
/* translate commands to packets */
|
||||||
ConnectionCommand c = m_connection->m_command_queue.pop_frontNoEx(0);
|
auto c = m_connection->m_command_queue.pop_frontNoEx(0);
|
||||||
while (c.type != CONNCMD_NONE) {
|
while (c && c->type != CONNCMD_NONE) {
|
||||||
if (c.reliable)
|
if (c->reliable)
|
||||||
processReliableCommand(c);
|
processReliableCommand(c);
|
||||||
else
|
else
|
||||||
processNonReliableCommand(c);
|
processNonReliableCommand(c);
|
||||||
@ -227,21 +227,21 @@ void ConnectionSendThread::runTimeouts(float dtime)
|
|||||||
m_iteration_packets_avaialble -= timed_outs.size();
|
m_iteration_packets_avaialble -= timed_outs.size();
|
||||||
|
|
||||||
for (const auto &k : timed_outs) {
|
for (const auto &k : timed_outs) {
|
||||||
u8 channelnum = readChannel(*k.data);
|
u8 channelnum = readChannel(k->data);
|
||||||
u16 seqnum = readU16(&(k.data[BASE_HEADER_SIZE + 1]));
|
u16 seqnum = k->getSeqnum();
|
||||||
|
|
||||||
channel.UpdateBytesLost(k.data.getSize());
|
channel.UpdateBytesLost(k->size());
|
||||||
|
|
||||||
LOG(derr_con << m_connection->getDesc()
|
LOG(derr_con << m_connection->getDesc()
|
||||||
<< "RE-SENDING timed-out RELIABLE to "
|
<< "RE-SENDING timed-out RELIABLE to "
|
||||||
<< k.address.serializeString()
|
<< k->address.serializeString()
|
||||||
<< "(t/o=" << resend_timeout << "): "
|
<< "(t/o=" << resend_timeout << "): "
|
||||||
<< "count=" << k.resend_count
|
<< "count=" << k->resend_count
|
||||||
<< ", channel=" << ((int) channelnum & 0xff)
|
<< ", channel=" << ((int) channelnum & 0xff)
|
||||||
<< ", seqnum=" << seqnum
|
<< ", seqnum=" << seqnum
|
||||||
<< std::endl);
|
<< std::endl);
|
||||||
|
|
||||||
rawSend(k);
|
rawSend(k.get());
|
||||||
|
|
||||||
// do not handle rtt here as we can't decide if this packet was
|
// do not handle rtt here as we can't decide if this packet was
|
||||||
// lost or really takes more time to transmit
|
// lost or really takes more time to transmit
|
||||||
@ -274,25 +274,24 @@ void ConnectionSendThread::runTimeouts(float dtime)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConnectionSendThread::rawSend(const BufferedPacket &packet)
|
void ConnectionSendThread::rawSend(const BufferedPacket *p)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
m_connection->m_udpSocket.Send(packet.address, *packet.data,
|
m_connection->m_udpSocket.Send(p->address, p->data, p->size());
|
||||||
packet.data.getSize());
|
|
||||||
LOG(dout_con << m_connection->getDesc()
|
LOG(dout_con << m_connection->getDesc()
|
||||||
<< " rawSend: " << packet.data.getSize()
|
<< " rawSend: " << p->size()
|
||||||
<< " bytes sent" << std::endl);
|
<< " bytes sent" << std::endl);
|
||||||
} catch (SendFailedException &e) {
|
} catch (SendFailedException &e) {
|
||||||
LOG(derr_con << m_connection->getDesc()
|
LOG(derr_con << m_connection->getDesc()
|
||||||
<< "Connection::rawSend(): SendFailedException: "
|
<< "Connection::rawSend(): SendFailedException: "
|
||||||
<< packet.address.serializeString() << std::endl);
|
<< p->address.serializeString() << std::endl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConnectionSendThread::sendAsPacketReliable(BufferedPacket &p, Channel *channel)
|
void ConnectionSendThread::sendAsPacketReliable(BufferedPacketPtr &p, Channel *channel)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
p.absolute_send_time = porting::getTimeMs();
|
p->absolute_send_time = porting::getTimeMs();
|
||||||
// Buffer the packet
|
// Buffer the packet
|
||||||
channel->outgoing_reliables_sent.insert(p,
|
channel->outgoing_reliables_sent.insert(p,
|
||||||
(channel->readOutgoingSequenceNumber() - MAX_RELIABLE_WINDOW_SIZE)
|
(channel->readOutgoingSequenceNumber() - MAX_RELIABLE_WINDOW_SIZE)
|
||||||
@ -305,7 +304,7 @@ void ConnectionSendThread::sendAsPacketReliable(BufferedPacket &p, Channel *chan
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Send the packet
|
// Send the packet
|
||||||
rawSend(p);
|
rawSend(p.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ConnectionSendThread::rawSendAsPacket(session_t peer_id, u8 channelnum,
|
bool ConnectionSendThread::rawSendAsPacket(session_t peer_id, u8 channelnum,
|
||||||
@ -321,11 +320,10 @@ bool ConnectionSendThread::rawSendAsPacket(session_t peer_id, u8 channelnum,
|
|||||||
Channel *channel = &(dynamic_cast<UDPPeer *>(&peer)->channels[channelnum]);
|
Channel *channel = &(dynamic_cast<UDPPeer *>(&peer)->channels[channelnum]);
|
||||||
|
|
||||||
if (reliable) {
|
if (reliable) {
|
||||||
bool have_sequence_number_for_raw_packet = true;
|
bool have_seqnum = false;
|
||||||
u16 seqnum =
|
const u16 seqnum = channel->getOutgoingSequenceNumber(have_seqnum);
|
||||||
channel->getOutgoingSequenceNumber(have_sequence_number_for_raw_packet);
|
|
||||||
|
|
||||||
if (!have_sequence_number_for_raw_packet)
|
if (!have_seqnum)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
SharedBuffer<u8> reliable = makeReliablePacket(data, seqnum);
|
SharedBuffer<u8> reliable = makeReliablePacket(data, seqnum);
|
||||||
@ -333,13 +331,12 @@ bool ConnectionSendThread::rawSendAsPacket(session_t peer_id, u8 channelnum,
|
|||||||
peer->getAddress(MTP_MINETEST_RELIABLE_UDP, peer_address);
|
peer->getAddress(MTP_MINETEST_RELIABLE_UDP, peer_address);
|
||||||
|
|
||||||
// Add base headers and make a packet
|
// Add base headers and make a packet
|
||||||
BufferedPacket p = con::makePacket(peer_address, reliable,
|
BufferedPacketPtr p = con::makePacket(peer_address, reliable,
|
||||||
m_connection->GetProtocolID(), m_connection->GetPeerID(),
|
m_connection->GetProtocolID(), m_connection->GetPeerID(),
|
||||||
channelnum);
|
channelnum);
|
||||||
|
|
||||||
// first check if our send window is already maxed out
|
// first check if our send window is already maxed out
|
||||||
if (channel->outgoing_reliables_sent.size()
|
if (channel->outgoing_reliables_sent.size() < channel->getWindowSize()) {
|
||||||
< channel->getWindowSize()) {
|
|
||||||
LOG(dout_con << m_connection->getDesc()
|
LOG(dout_con << m_connection->getDesc()
|
||||||
<< " INFO: sending a reliable packet to peer_id " << peer_id
|
<< " INFO: sending a reliable packet to peer_id " << peer_id
|
||||||
<< " channel: " << (u32)channelnum
|
<< " channel: " << (u32)channelnum
|
||||||
@ -352,19 +349,19 @@ bool ConnectionSendThread::rawSendAsPacket(session_t peer_id, u8 channelnum,
|
|||||||
<< " INFO: queueing reliable packet for peer_id: " << peer_id
|
<< " INFO: queueing reliable packet for peer_id: " << peer_id
|
||||||
<< " channel: " << (u32)channelnum
|
<< " channel: " << (u32)channelnum
|
||||||
<< " seqnum: " << seqnum << std::endl);
|
<< " seqnum: " << seqnum << std::endl);
|
||||||
channel->queued_reliables.push(std::move(p));
|
channel->queued_reliables.push(p);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Address peer_address;
|
Address peer_address;
|
||||||
if (peer->getAddress(MTP_UDP, peer_address)) {
|
if (peer->getAddress(MTP_UDP, peer_address)) {
|
||||||
// Add base headers and make a packet
|
// Add base headers and make a packet
|
||||||
BufferedPacket p = con::makePacket(peer_address, data,
|
BufferedPacketPtr p = con::makePacket(peer_address, data,
|
||||||
m_connection->GetProtocolID(), m_connection->GetPeerID(),
|
m_connection->GetProtocolID(), m_connection->GetPeerID(),
|
||||||
channelnum);
|
channelnum);
|
||||||
|
|
||||||
// Send the packet
|
// Send the packet
|
||||||
rawSend(p);
|
rawSend(p.get());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -374,11 +371,11 @@ bool ConnectionSendThread::rawSendAsPacket(session_t peer_id, u8 channelnum,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConnectionSendThread::processReliableCommand(ConnectionCommand &c)
|
void ConnectionSendThread::processReliableCommand(ConnectionCommandPtr &c)
|
||||||
{
|
{
|
||||||
assert(c.reliable); // Pre-condition
|
assert(c->reliable); // Pre-condition
|
||||||
|
|
||||||
switch (c.type) {
|
switch (c->type) {
|
||||||
case CONNCMD_NONE:
|
case CONNCMD_NONE:
|
||||||
LOG(dout_con << m_connection->getDesc()
|
LOG(dout_con << m_connection->getDesc()
|
||||||
<< "UDP processing reliable CONNCMD_NONE" << std::endl);
|
<< "UDP processing reliable CONNCMD_NONE" << std::endl);
|
||||||
@ -399,7 +396,7 @@ void ConnectionSendThread::processReliableCommand(ConnectionCommand &c)
|
|||||||
case CONCMD_CREATE_PEER:
|
case CONCMD_CREATE_PEER:
|
||||||
LOG(dout_con << m_connection->getDesc()
|
LOG(dout_con << m_connection->getDesc()
|
||||||
<< "UDP processing reliable CONCMD_CREATE_PEER" << std::endl);
|
<< "UDP processing reliable CONCMD_CREATE_PEER" << std::endl);
|
||||||
if (!rawSendAsPacket(c.peer_id, c.channelnum, c.data, c.reliable)) {
|
if (!rawSendAsPacket(c->peer_id, c->channelnum, c->data, c->reliable)) {
|
||||||
/* put to queue if we couldn't send it immediately */
|
/* put to queue if we couldn't send it immediately */
|
||||||
sendReliable(c);
|
sendReliable(c);
|
||||||
}
|
}
|
||||||
@ -412,13 +409,14 @@ void ConnectionSendThread::processReliableCommand(ConnectionCommand &c)
|
|||||||
FATAL_ERROR("Got command that shouldn't be reliable as reliable command");
|
FATAL_ERROR("Got command that shouldn't be reliable as reliable command");
|
||||||
default:
|
default:
|
||||||
LOG(dout_con << m_connection->getDesc()
|
LOG(dout_con << m_connection->getDesc()
|
||||||
<< " Invalid reliable command type: " << c.type << std::endl);
|
<< " Invalid reliable command type: " << c->type << std::endl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ConnectionSendThread::processNonReliableCommand(ConnectionCommand &c)
|
void ConnectionSendThread::processNonReliableCommand(ConnectionCommandPtr &c_ptr)
|
||||||
{
|
{
|
||||||
|
const ConnectionCommand &c = *c_ptr;
|
||||||
assert(!c.reliable); // Pre-condition
|
assert(!c.reliable); // Pre-condition
|
||||||
|
|
||||||
switch (c.type) {
|
switch (c.type) {
|
||||||
@ -480,9 +478,7 @@ void ConnectionSendThread::serve(Address bind_address)
|
|||||||
}
|
}
|
||||||
catch (SocketException &e) {
|
catch (SocketException &e) {
|
||||||
// Create event
|
// Create event
|
||||||
ConnectionEvent ce;
|
m_connection->putEvent(ConnectionEvent::bindFailed());
|
||||||
ce.bindFailed();
|
|
||||||
m_connection->putEvent(ce);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -495,9 +491,7 @@ void ConnectionSendThread::connect(Address address)
|
|||||||
UDPPeer *peer = m_connection->createServerPeer(address);
|
UDPPeer *peer = m_connection->createServerPeer(address);
|
||||||
|
|
||||||
// Create event
|
// Create event
|
||||||
ConnectionEvent e;
|
m_connection->putEvent(ConnectionEvent::peerAdded(peer->id, peer->address));
|
||||||
e.peerAdded(peer->id, peer->address);
|
|
||||||
m_connection->putEvent(e);
|
|
||||||
|
|
||||||
Address bind_addr;
|
Address bind_addr;
|
||||||
|
|
||||||
@ -586,9 +580,9 @@ void ConnectionSendThread::send(session_t peer_id, u8 channelnum,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConnectionSendThread::sendReliable(ConnectionCommand &c)
|
void ConnectionSendThread::sendReliable(ConnectionCommandPtr &c)
|
||||||
{
|
{
|
||||||
PeerHelper peer = m_connection->getPeerNoEx(c.peer_id);
|
PeerHelper peer = m_connection->getPeerNoEx(c->peer_id);
|
||||||
if (!peer)
|
if (!peer)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -604,7 +598,7 @@ void ConnectionSendThread::sendToAll(u8 channelnum, const SharedBuffer<u8> &data
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConnectionSendThread::sendToAllReliable(ConnectionCommand &c)
|
void ConnectionSendThread::sendToAllReliable(ConnectionCommandPtr &c)
|
||||||
{
|
{
|
||||||
std::vector<session_t> peerids = m_connection->getPeerIDs();
|
std::vector<session_t> peerids = m_connection->getPeerIDs();
|
||||||
|
|
||||||
@ -663,8 +657,12 @@ void ConnectionSendThread::sendPackets(float dtime)
|
|||||||
// first send queued reliable packets for all peers (if possible)
|
// first send queued reliable packets for all peers (if possible)
|
||||||
for (unsigned int i = 0; i < CHANNEL_COUNT; i++) {
|
for (unsigned int i = 0; i < CHANNEL_COUNT; i++) {
|
||||||
Channel &channel = udpPeer->channels[i];
|
Channel &channel = udpPeer->channels[i];
|
||||||
u16 next_to_ack = 0;
|
|
||||||
|
|
||||||
|
// Reduces logging verbosity
|
||||||
|
if (channel.queued_reliables.empty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
u16 next_to_ack = 0;
|
||||||
channel.outgoing_reliables_sent.getFirstSeqnum(next_to_ack);
|
channel.outgoing_reliables_sent.getFirstSeqnum(next_to_ack);
|
||||||
u16 next_to_receive = 0;
|
u16 next_to_receive = 0;
|
||||||
channel.incoming_reliables.getFirstSeqnum(next_to_receive);
|
channel.incoming_reliables.getFirstSeqnum(next_to_receive);
|
||||||
@ -694,13 +692,13 @@ void ConnectionSendThread::sendPackets(float dtime)
|
|||||||
channel.outgoing_reliables_sent.size()
|
channel.outgoing_reliables_sent.size()
|
||||||
< channel.getWindowSize() &&
|
< channel.getWindowSize() &&
|
||||||
peer->m_increment_packets_remaining > 0) {
|
peer->m_increment_packets_remaining > 0) {
|
||||||
BufferedPacket p = std::move(channel.queued_reliables.front());
|
BufferedPacketPtr p = channel.queued_reliables.front();
|
||||||
channel.queued_reliables.pop();
|
channel.queued_reliables.pop();
|
||||||
|
|
||||||
LOG(dout_con << m_connection->getDesc()
|
LOG(dout_con << m_connection->getDesc()
|
||||||
<< " INFO: sending a queued reliable packet "
|
<< " INFO: sending a queued reliable packet "
|
||||||
<< " channel: " << i
|
<< " channel: " << i
|
||||||
<< ", seqnum: " << readU16(&p.data[BASE_HEADER_SIZE + 1])
|
<< ", seqnum: " << p->getSeqnum()
|
||||||
<< std::endl);
|
<< std::endl);
|
||||||
|
|
||||||
sendAsPacketReliable(p, &channel);
|
sendAsPacketReliable(p, &channel);
|
||||||
@ -881,17 +879,14 @@ void ConnectionReceiveThread::receive(SharedBuffer<u8> &packetdata,
|
|||||||
try {
|
try {
|
||||||
// First, see if there any buffered packets we can process now
|
// First, see if there any buffered packets we can process now
|
||||||
if (packet_queued) {
|
if (packet_queued) {
|
||||||
bool data_left = true;
|
|
||||||
session_t peer_id;
|
session_t peer_id;
|
||||||
SharedBuffer<u8> resultdata;
|
SharedBuffer<u8> resultdata;
|
||||||
while (data_left) {
|
while (true) {
|
||||||
try {
|
try {
|
||||||
data_left = getFromBuffers(peer_id, resultdata);
|
if (!getFromBuffers(peer_id, resultdata))
|
||||||
if (data_left) {
|
break;
|
||||||
ConnectionEvent e;
|
|
||||||
e.dataReceived(peer_id, resultdata);
|
m_connection->putEvent(ConnectionEvent::dataReceived(peer_id, resultdata));
|
||||||
m_connection->putEvent(std::move(e));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (ProcessedSilentlyException &e) {
|
catch (ProcessedSilentlyException &e) {
|
||||||
/* try reading again */
|
/* try reading again */
|
||||||
@ -999,9 +994,7 @@ void ConnectionReceiveThread::receive(SharedBuffer<u8> &packetdata,
|
|||||||
<< ", channel: " << (u32)channelnum << ", returned "
|
<< ", channel: " << (u32)channelnum << ", returned "
|
||||||
<< resultdata.getSize() << " bytes" << std::endl);
|
<< resultdata.getSize() << " bytes" << std::endl);
|
||||||
|
|
||||||
ConnectionEvent e;
|
m_connection->putEvent(ConnectionEvent::dataReceived(peer_id, resultdata));
|
||||||
e.dataReceived(peer_id, resultdata);
|
|
||||||
m_connection->putEvent(std::move(e));
|
|
||||||
}
|
}
|
||||||
catch (ProcessedSilentlyException &e) {
|
catch (ProcessedSilentlyException &e) {
|
||||||
}
|
}
|
||||||
@ -1026,10 +1019,11 @@ bool ConnectionReceiveThread::getFromBuffers(session_t &peer_id, SharedBuffer<u8
|
|||||||
if (!peer)
|
if (!peer)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (dynamic_cast<UDPPeer *>(&peer) == 0)
|
UDPPeer *p = dynamic_cast<UDPPeer *>(&peer);
|
||||||
|
if (!p)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (Channel &channel : (dynamic_cast<UDPPeer *>(&peer))->channels) {
|
for (Channel &channel : p->channels) {
|
||||||
if (checkIncomingBuffers(&channel, peer_id, dst)) {
|
if (checkIncomingBuffers(&channel, peer_id, dst)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1042,12 +1036,17 @@ bool ConnectionReceiveThread::checkIncomingBuffers(Channel *channel,
|
|||||||
session_t &peer_id, SharedBuffer<u8> &dst)
|
session_t &peer_id, SharedBuffer<u8> &dst)
|
||||||
{
|
{
|
||||||
u16 firstseqnum = 0;
|
u16 firstseqnum = 0;
|
||||||
if (channel->incoming_reliables.getFirstSeqnum(firstseqnum)) {
|
if (!channel->incoming_reliables.getFirstSeqnum(firstseqnum))
|
||||||
if (firstseqnum == channel->readNextIncomingSeqNum()) {
|
return false;
|
||||||
BufferedPacket p = channel->incoming_reliables.popFirst();
|
|
||||||
peer_id = readPeerId(*p.data);
|
if (firstseqnum != channel->readNextIncomingSeqNum())
|
||||||
u8 channelnum = readChannel(*p.data);
|
return false;
|
||||||
u16 seqnum = readU16(&p.data[BASE_HEADER_SIZE + 1]);
|
|
||||||
|
BufferedPacketPtr p = channel->incoming_reliables.popFirst();
|
||||||
|
|
||||||
|
peer_id = readPeerId(p->data); // Carried over to caller function
|
||||||
|
u8 channelnum = readChannel(p->data);
|
||||||
|
u16 seqnum = p->getSeqnum();
|
||||||
|
|
||||||
LOG(dout_con << m_connection->getDesc()
|
LOG(dout_con << m_connection->getDesc()
|
||||||
<< "UNBUFFERING TYPE_RELIABLE"
|
<< "UNBUFFERING TYPE_RELIABLE"
|
||||||
@ -1060,15 +1059,12 @@ bool ConnectionReceiveThread::checkIncomingBuffers(Channel *channel,
|
|||||||
|
|
||||||
u32 headers_size = BASE_HEADER_SIZE + RELIABLE_HEADER_SIZE;
|
u32 headers_size = BASE_HEADER_SIZE + RELIABLE_HEADER_SIZE;
|
||||||
// Get out the inside packet and re-process it
|
// Get out the inside packet and re-process it
|
||||||
SharedBuffer<u8> payload(p.data.getSize() - headers_size);
|
SharedBuffer<u8> payload(p->size() - headers_size);
|
||||||
memcpy(*payload, &p.data[headers_size], payload.getSize());
|
memcpy(*payload, &p->data[headers_size], payload.getSize());
|
||||||
|
|
||||||
dst = processPacket(channel, payload, peer_id, channelnum, true);
|
dst = processPacket(channel, payload, peer_id, channelnum, true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
SharedBuffer<u8> ConnectionReceiveThread::processPacket(Channel *channel,
|
SharedBuffer<u8> ConnectionReceiveThread::processPacket(Channel *channel,
|
||||||
const SharedBuffer<u8> &packetdata, session_t peer_id, u8 channelnum, bool reliable)
|
const SharedBuffer<u8> &packetdata, session_t peer_id, u8 channelnum, bool reliable)
|
||||||
@ -1115,7 +1111,7 @@ SharedBuffer<u8> ConnectionReceiveThread::handlePacketType_Control(Channel *chan
|
|||||||
if (packetdata.getSize() < 2)
|
if (packetdata.getSize() < 2)
|
||||||
throw InvalidIncomingDataException("packetdata.getSize() < 2");
|
throw InvalidIncomingDataException("packetdata.getSize() < 2");
|
||||||
|
|
||||||
u8 controltype = readU8(&(packetdata[1]));
|
ControlType controltype = (ControlType)readU8(&(packetdata[1]));
|
||||||
|
|
||||||
if (controltype == CONTROLTYPE_ACK) {
|
if (controltype == CONTROLTYPE_ACK) {
|
||||||
assert(channel != NULL);
|
assert(channel != NULL);
|
||||||
@ -1131,7 +1127,7 @@ SharedBuffer<u8> ConnectionReceiveThread::handlePacketType_Control(Channel *chan
|
|||||||
<< seqnum << " ]" << std::endl);
|
<< seqnum << " ]" << std::endl);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
BufferedPacket p = channel->outgoing_reliables_sent.popSeqnum(seqnum);
|
BufferedPacketPtr p = channel->outgoing_reliables_sent.popSeqnum(seqnum);
|
||||||
|
|
||||||
// the rtt calculation will be a bit off for re-sent packets but that's okay
|
// the rtt calculation will be a bit off for re-sent packets but that's okay
|
||||||
{
|
{
|
||||||
@ -1140,14 +1136,14 @@ SharedBuffer<u8> ConnectionReceiveThread::handlePacketType_Control(Channel *chan
|
|||||||
|
|
||||||
// a overflow is quite unlikely but as it'd result in major
|
// a overflow is quite unlikely but as it'd result in major
|
||||||
// rtt miscalculation we handle it here
|
// rtt miscalculation we handle it here
|
||||||
if (current_time > p.absolute_send_time) {
|
if (current_time > p->absolute_send_time) {
|
||||||
float rtt = (current_time - p.absolute_send_time) / 1000.0;
|
float rtt = (current_time - p->absolute_send_time) / 1000.0;
|
||||||
|
|
||||||
// Let peer calculate stuff according to it
|
// Let peer calculate stuff according to it
|
||||||
// (avg_rtt and resend_timeout)
|
// (avg_rtt and resend_timeout)
|
||||||
dynamic_cast<UDPPeer *>(peer)->reportRTT(rtt);
|
dynamic_cast<UDPPeer *>(peer)->reportRTT(rtt);
|
||||||
} else if (p.totaltime > 0) {
|
} else if (p->totaltime > 0) {
|
||||||
float rtt = p.totaltime;
|
float rtt = p->totaltime;
|
||||||
|
|
||||||
// Let peer calculate stuff according to it
|
// Let peer calculate stuff according to it
|
||||||
// (avg_rtt and resend_timeout)
|
// (avg_rtt and resend_timeout)
|
||||||
@ -1156,7 +1152,7 @@ SharedBuffer<u8> ConnectionReceiveThread::handlePacketType_Control(Channel *chan
|
|||||||
}
|
}
|
||||||
|
|
||||||
// put bytes for max bandwidth calculation
|
// put bytes for max bandwidth calculation
|
||||||
channel->UpdateBytesSent(p.data.getSize(), 1);
|
channel->UpdateBytesSent(p->size(), 1);
|
||||||
if (channel->outgoing_reliables_sent.size() == 0)
|
if (channel->outgoing_reliables_sent.size() == 0)
|
||||||
m_connection->TriggerSend();
|
m_connection->TriggerSend();
|
||||||
} catch (NotFoundException &e) {
|
} catch (NotFoundException &e) {
|
||||||
@ -1204,7 +1200,7 @@ SharedBuffer<u8> ConnectionReceiveThread::handlePacketType_Control(Channel *chan
|
|||||||
throw ProcessedSilentlyException("Got a DISCO");
|
throw ProcessedSilentlyException("Got a DISCO");
|
||||||
} else {
|
} else {
|
||||||
LOG(derr_con << m_connection->getDesc()
|
LOG(derr_con << m_connection->getDesc()
|
||||||
<< "INVALID TYPE_CONTROL: invalid controltype="
|
<< "INVALID controltype="
|
||||||
<< ((int) controltype & 0xff) << std::endl);
|
<< ((int) controltype & 0xff) << std::endl);
|
||||||
throw InvalidIncomingDataException("Invalid control type");
|
throw InvalidIncomingDataException("Invalid control type");
|
||||||
}
|
}
|
||||||
@ -1232,7 +1228,7 @@ SharedBuffer<u8> ConnectionReceiveThread::handlePacketType_Split(Channel *channe
|
|||||||
if (peer->getAddress(MTP_UDP, peer_address)) {
|
if (peer->getAddress(MTP_UDP, peer_address)) {
|
||||||
// We have to create a packet again for buffering
|
// We have to create a packet again for buffering
|
||||||
// This isn't actually too bad an idea.
|
// This isn't actually too bad an idea.
|
||||||
BufferedPacket packet = makePacket(peer_address,
|
BufferedPacketPtr packet = con::makePacket(peer_address,
|
||||||
packetdata,
|
packetdata,
|
||||||
m_connection->GetProtocolID(),
|
m_connection->GetProtocolID(),
|
||||||
peer->id,
|
peer->id,
|
||||||
@ -1267,7 +1263,7 @@ SharedBuffer<u8> ConnectionReceiveThread::handlePacketType_Reliable(Channel *cha
|
|||||||
if (packetdata.getSize() < RELIABLE_HEADER_SIZE)
|
if (packetdata.getSize() < RELIABLE_HEADER_SIZE)
|
||||||
throw InvalidIncomingDataException("packetdata.getSize() < RELIABLE_HEADER_SIZE");
|
throw InvalidIncomingDataException("packetdata.getSize() < RELIABLE_HEADER_SIZE");
|
||||||
|
|
||||||
u16 seqnum = readU16(&packetdata[1]);
|
const u16 seqnum = readU16(&packetdata[1]);
|
||||||
bool is_future_packet = false;
|
bool is_future_packet = false;
|
||||||
bool is_old_packet = false;
|
bool is_old_packet = false;
|
||||||
|
|
||||||
@ -1311,7 +1307,7 @@ SharedBuffer<u8> ConnectionReceiveThread::handlePacketType_Reliable(Channel *cha
|
|||||||
// This one comes later, buffer it.
|
// This one comes later, buffer it.
|
||||||
// Actually we have to make a packet to buffer one.
|
// Actually we have to make a packet to buffer one.
|
||||||
// Well, we have all the ingredients, so just do it.
|
// Well, we have all the ingredients, so just do it.
|
||||||
BufferedPacket packet = con::makePacket(
|
BufferedPacketPtr packet = con::makePacket(
|
||||||
peer_address,
|
peer_address,
|
||||||
packetdata,
|
packetdata,
|
||||||
m_connection->GetProtocolID(),
|
m_connection->GetProtocolID(),
|
||||||
@ -1328,9 +1324,7 @@ SharedBuffer<u8> ConnectionReceiveThread::handlePacketType_Reliable(Channel *cha
|
|||||||
throw ProcessedQueued("Buffered future reliable packet");
|
throw ProcessedQueued("Buffered future reliable packet");
|
||||||
} catch (AlreadyExistsException &e) {
|
} catch (AlreadyExistsException &e) {
|
||||||
} catch (IncomingDataCorruption &e) {
|
} catch (IncomingDataCorruption &e) {
|
||||||
ConnectionCommand discon;
|
m_connection->putCommand(ConnectionCommand::disconnect_peer(peer->id));
|
||||||
discon.disconnect_peer(peer->id);
|
|
||||||
m_connection->putCommand(discon);
|
|
||||||
|
|
||||||
LOG(derr_con << m_connection->getDesc()
|
LOG(derr_con << m_connection->getDesc()
|
||||||
<< "INVALID, TYPE_RELIABLE peer_id: " << peer->id
|
<< "INVALID, TYPE_RELIABLE peer_id: " << peer->id
|
||||||
@ -1351,7 +1345,7 @@ SharedBuffer<u8> ConnectionReceiveThread::handlePacketType_Reliable(Channel *cha
|
|||||||
u16 queued_seqnum = 0;
|
u16 queued_seqnum = 0;
|
||||||
if (channel->incoming_reliables.getFirstSeqnum(queued_seqnum)) {
|
if (channel->incoming_reliables.getFirstSeqnum(queued_seqnum)) {
|
||||||
if (queued_seqnum == seqnum) {
|
if (queued_seqnum == seqnum) {
|
||||||
BufferedPacket queued_packet = channel->incoming_reliables.popFirst();
|
BufferedPacketPtr queued_packet = channel->incoming_reliables.popFirst();
|
||||||
/** TODO find a way to verify the new against the old packet */
|
/** TODO find a way to verify the new against the old packet */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,25 @@ namespace con
|
|||||||
|
|
||||||
class Connection;
|
class Connection;
|
||||||
|
|
||||||
|
struct OutgoingPacket
|
||||||
|
{
|
||||||
|
session_t peer_id;
|
||||||
|
u8 channelnum;
|
||||||
|
SharedBuffer<u8> data;
|
||||||
|
bool reliable;
|
||||||
|
bool ack;
|
||||||
|
|
||||||
|
OutgoingPacket(session_t peer_id_, u8 channelnum_, const SharedBuffer<u8> &data_,
|
||||||
|
bool reliable_,bool ack_=false):
|
||||||
|
peer_id(peer_id_),
|
||||||
|
channelnum(channelnum_),
|
||||||
|
data(data_),
|
||||||
|
reliable(reliable_),
|
||||||
|
ack(ack_)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class ConnectionSendThread : public Thread
|
class ConnectionSendThread : public Thread
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -51,27 +70,27 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void runTimeouts(float dtime);
|
void runTimeouts(float dtime);
|
||||||
void rawSend(const BufferedPacket &packet);
|
void rawSend(const BufferedPacket *p);
|
||||||
bool rawSendAsPacket(session_t peer_id, u8 channelnum,
|
bool rawSendAsPacket(session_t peer_id, u8 channelnum,
|
||||||
const SharedBuffer<u8> &data, bool reliable);
|
const SharedBuffer<u8> &data, bool reliable);
|
||||||
|
|
||||||
void processReliableCommand(ConnectionCommand &c);
|
void processReliableCommand(ConnectionCommandPtr &c);
|
||||||
void processNonReliableCommand(ConnectionCommand &c);
|
void processNonReliableCommand(ConnectionCommandPtr &c);
|
||||||
void serve(Address bind_address);
|
void serve(Address bind_address);
|
||||||
void connect(Address address);
|
void connect(Address address);
|
||||||
void disconnect();
|
void disconnect();
|
||||||
void disconnect_peer(session_t peer_id);
|
void disconnect_peer(session_t peer_id);
|
||||||
void send(session_t peer_id, u8 channelnum, const SharedBuffer<u8> &data);
|
void send(session_t peer_id, u8 channelnum, const SharedBuffer<u8> &data);
|
||||||
void sendReliable(ConnectionCommand &c);
|
void sendReliable(ConnectionCommandPtr &c);
|
||||||
void sendToAll(u8 channelnum, const SharedBuffer<u8> &data);
|
void sendToAll(u8 channelnum, const SharedBuffer<u8> &data);
|
||||||
void sendToAllReliable(ConnectionCommand &c);
|
void sendToAllReliable(ConnectionCommandPtr &c);
|
||||||
|
|
||||||
void sendPackets(float dtime);
|
void sendPackets(float dtime);
|
||||||
|
|
||||||
void sendAsPacket(session_t peer_id, u8 channelnum, const SharedBuffer<u8> &data,
|
void sendAsPacket(session_t peer_id, u8 channelnum, const SharedBuffer<u8> &data,
|
||||||
bool ack = false);
|
bool ack = false);
|
||||||
|
|
||||||
void sendAsPacketReliable(BufferedPacket &p, Channel *channel);
|
void sendAsPacketReliable(BufferedPacketPtr &p, Channel *channel);
|
||||||
|
|
||||||
bool packetsQueued();
|
bool packetsQueued();
|
||||||
|
|
||||||
|
@ -124,7 +124,7 @@ void TestConnection::testHelpers()
|
|||||||
Address a(127,0,0,1, 10);
|
Address a(127,0,0,1, 10);
|
||||||
const u16 seqnum = 34352;
|
const u16 seqnum = 34352;
|
||||||
|
|
||||||
con::BufferedPacket p1 = con::makePacket(a, data1,
|
con::BufferedPacketPtr p1 = con::makePacket(a, data1,
|
||||||
proto_id, peer_id, channel);
|
proto_id, peer_id, channel);
|
||||||
/*
|
/*
|
||||||
We should now have a packet with this data:
|
We should now have a packet with this data:
|
||||||
@ -135,10 +135,10 @@ void TestConnection::testHelpers()
|
|||||||
Data:
|
Data:
|
||||||
[7] u8 data1[0]
|
[7] u8 data1[0]
|
||||||
*/
|
*/
|
||||||
UASSERT(readU32(&p1.data[0]) == proto_id);
|
UASSERT(readU32(&p1->data[0]) == proto_id);
|
||||||
UASSERT(readU16(&p1.data[4]) == peer_id);
|
UASSERT(readU16(&p1->data[4]) == peer_id);
|
||||||
UASSERT(readU8(&p1.data[6]) == channel);
|
UASSERT(readU8(&p1->data[6]) == channel);
|
||||||
UASSERT(readU8(&p1.data[7]) == data1[0]);
|
UASSERT(readU8(&p1->data[7]) == data1[0]);
|
||||||
|
|
||||||
//infostream<<"initial data1[0]="<<((u32)data1[0]&0xff)<<std::endl;
|
//infostream<<"initial data1[0]="<<((u32)data1[0]&0xff)<<std::endl;
|
||||||
|
|
||||||
|
@ -22,6 +22,21 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "irrlichttypes.h"
|
#include "irrlichttypes.h"
|
||||||
#include "debug.h" // For assert()
|
#include "debug.h" // For assert()
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <memory> // std::shared_ptr
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T> class ConstSharedPtr {
|
||||||
|
public:
|
||||||
|
ConstSharedPtr(T *ptr) : ptr(ptr) {}
|
||||||
|
ConstSharedPtr(const std::shared_ptr<T> &ptr) : ptr(ptr) {}
|
||||||
|
|
||||||
|
const T* get() const noexcept { return ptr.get(); }
|
||||||
|
const T& operator*() const noexcept { return *ptr.get(); }
|
||||||
|
const T* operator->() const noexcept { return ptr.get(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<T> ptr;
|
||||||
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class Buffer
|
class Buffer
|
||||||
@ -40,17 +55,11 @@ public:
|
|||||||
else
|
else
|
||||||
data = NULL;
|
data = NULL;
|
||||||
}
|
}
|
||||||
Buffer(const Buffer &buffer)
|
|
||||||
{
|
// Disable class copy
|
||||||
m_size = buffer.m_size;
|
Buffer(const Buffer &) = delete;
|
||||||
if(m_size != 0)
|
Buffer &operator=(const Buffer &) = delete;
|
||||||
{
|
|
||||||
data = new T[buffer.m_size];
|
|
||||||
memcpy(data, buffer.data, buffer.m_size);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
data = NULL;
|
|
||||||
}
|
|
||||||
Buffer(Buffer &&buffer)
|
Buffer(Buffer &&buffer)
|
||||||
{
|
{
|
||||||
m_size = buffer.m_size;
|
m_size = buffer.m_size;
|
||||||
@ -81,21 +90,6 @@ public:
|
|||||||
drop();
|
drop();
|
||||||
}
|
}
|
||||||
|
|
||||||
Buffer& operator=(const Buffer &buffer)
|
|
||||||
{
|
|
||||||
if(this == &buffer)
|
|
||||||
return *this;
|
|
||||||
drop();
|
|
||||||
m_size = buffer.m_size;
|
|
||||||
if(m_size != 0)
|
|
||||||
{
|
|
||||||
data = new T[buffer.m_size];
|
|
||||||
memcpy(data, buffer.data, buffer.m_size);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
data = NULL;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
Buffer& operator=(Buffer &&buffer)
|
Buffer& operator=(Buffer &&buffer)
|
||||||
{
|
{
|
||||||
if(this == &buffer)
|
if(this == &buffer)
|
||||||
@ -113,6 +107,18 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void copyTo(Buffer &buffer) const
|
||||||
|
{
|
||||||
|
buffer.drop();
|
||||||
|
buffer.m_size = m_size;
|
||||||
|
if (m_size != 0) {
|
||||||
|
buffer.data = new T[m_size];
|
||||||
|
memcpy(buffer.data, data, m_size);
|
||||||
|
} else {
|
||||||
|
buffer.data = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
T & operator[](unsigned int i) const
|
T & operator[](unsigned int i) const
|
||||||
{
|
{
|
||||||
return data[i];
|
return data[i];
|
||||||
|
Loading…
Reference in New Issue
Block a user