209 lines
5.5 KiB
C++
209 lines
5.5 KiB
C++
/*
|
|
* Net2Packet.cpp
|
|
*
|
|
* This source file is part of the FoundationDB open source project
|
|
*
|
|
* Copyright 2013-2018 Apple Inc. and the FoundationDB project authors
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "Net2Packet.h"
|
|
|
|
void PacketWriter::init(PacketBuffer* buf, ReliablePacket* reliable) {
|
|
this->buffer = buf;
|
|
this->reliable = reliable;
|
|
this->length = 0;
|
|
length -= buffer->bytes_written;
|
|
if (reliable) {
|
|
reliable->buffer = buffer; buffer->addref();
|
|
reliable->begin = buffer->bytes_written;
|
|
}
|
|
}
|
|
|
|
PacketBuffer* PacketWriter::finish() {
|
|
length += buffer->bytes_written;
|
|
if (reliable) {
|
|
reliable->cont = NULL;
|
|
reliable->end = buffer->bytes_written;
|
|
}
|
|
return buffer;
|
|
}
|
|
|
|
void PacketWriter::serializeBytesAcrossBoundary(const void* data, int bytes) {
|
|
while(true) {
|
|
int b = std::min( bytes, PacketBuffer::DATA_SIZE - buffer->bytes_written );
|
|
memcpy( buffer->data + buffer->bytes_written, data, b );
|
|
buffer->bytes_written += b;
|
|
bytes -= b;
|
|
if (!bytes) break;
|
|
|
|
data = (uint8_t*)data + b;
|
|
nextBuffer();
|
|
}
|
|
}
|
|
|
|
void PacketWriter::nextBuffer() {
|
|
ASSERT( buffer->bytes_written == PacketBuffer::DATA_SIZE );
|
|
length += PacketBuffer::DATA_SIZE;
|
|
buffer->next = new PacketBuffer;
|
|
buffer = buffer->nextPacketBuffer();
|
|
|
|
if (reliable) {
|
|
reliable->end = PacketBuffer::DATA_SIZE;
|
|
reliable->cont = new ReliablePacket;
|
|
reliable = reliable->cont;
|
|
reliable->buffer = buffer; buffer->addref();
|
|
reliable->begin = 0;
|
|
}
|
|
}
|
|
|
|
void PacketWriter::writeAhead( int bytes, struct SplitBuffer* buf ) {
|
|
if (bytes <= PacketBuffer::DATA_SIZE - buffer->bytes_written) {
|
|
buf->begin = buffer->data + buffer->bytes_written;
|
|
buf->first_length = bytes;
|
|
buffer->bytes_written += bytes;
|
|
buf->next = 0;
|
|
} else {
|
|
buf->begin = buffer->data + buffer->bytes_written;
|
|
buf->first_length = PacketBuffer::DATA_SIZE - buffer->bytes_written;
|
|
buffer->bytes_written = PacketBuffer::DATA_SIZE;
|
|
nextBuffer();
|
|
buf->next = buffer->data;
|
|
buffer->bytes_written = bytes - buf->first_length;
|
|
}
|
|
|
|
}
|
|
|
|
void SplitBuffer::write( const void* data, int len ) {
|
|
write(data, len, 0);
|
|
}
|
|
|
|
void SplitBuffer::write( const void* data, int len, int offset ) {
|
|
if (len + offset <= first_length)
|
|
memcpy( begin + offset, data, len );
|
|
else {
|
|
if (offset >= first_length) {
|
|
memcpy( next + offset - first_length, data, len );
|
|
} else {
|
|
memcpy( begin + offset, data, first_length - offset );
|
|
memcpy( next, (uint8_t*)data + first_length - offset, len - first_length + offset );
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
void SplitBuffer::writeAndShrink(const void* data, int len) {
|
|
if (len <= first_length) {
|
|
memcpy( begin, data, len );
|
|
begin += len;
|
|
first_length -= len;
|
|
}
|
|
else {
|
|
memcpy( begin, data, first_length );
|
|
int s = len - first_length;
|
|
memcpy( next, (uint8_t*)data + first_length, s);
|
|
next += s;
|
|
first_length = 0;
|
|
}
|
|
}
|
|
|
|
void ReliablePacket::insertBefore( ReliablePacket* p ) {
|
|
next = p;
|
|
prev = p->prev;
|
|
prev->next = next->prev = this;
|
|
}
|
|
|
|
void ReliablePacket::remove() {
|
|
next->prev = prev;
|
|
prev->next = next;
|
|
for(ReliablePacket* c = this; c; ) {
|
|
ReliablePacket* n = c->cont;
|
|
c->buffer->delref();
|
|
delete c;
|
|
c = n;
|
|
}
|
|
}
|
|
|
|
void UnsentPacketQueue::sent(int bytes) {
|
|
while (bytes) {
|
|
ASSERT( unsent_first );
|
|
PacketBuffer* b = unsent_first;
|
|
|
|
if (b->bytes_sent + bytes <= b->bytes_written && (b->bytes_sent + bytes != b->bytes_written || (!b->next && b->bytes_unwritten()))) {
|
|
b->bytes_sent += bytes;
|
|
ASSERT( b->bytes_sent <= PacketBuffer::DATA_SIZE );
|
|
break;
|
|
}
|
|
|
|
// We've sent an entire buffer
|
|
bytes -= b->bytes_written - b->bytes_sent;
|
|
b->bytes_sent = b->bytes_written;
|
|
ASSERT( b->bytes_written <= PacketBuffer::DATA_SIZE );
|
|
unsent_first = b->nextPacketBuffer();
|
|
if (!unsent_first) unsent_last = NULL;
|
|
b->delref();
|
|
}
|
|
}
|
|
|
|
void UnsentPacketQueue::discardAll() {
|
|
while (unsent_first) {
|
|
auto n = unsent_first->nextPacketBuffer();
|
|
unsent_first->delref();
|
|
unsent_first = n;
|
|
}
|
|
unsent_last = 0;
|
|
}
|
|
|
|
PacketBuffer* ReliablePacketList::compact(PacketBuffer* into, PacketBuffer* end) {
|
|
ReliablePacket* r = reliable.next;
|
|
while (r != &reliable) {
|
|
for(ReliablePacket* c = r; c; c = c->cont) {
|
|
if (c->buffer == end /*&& c->begin>=c->buffer->bytes_written*/) // quit when we hit the unsent range
|
|
return into;
|
|
if (into->bytes_written == PacketBuffer::DATA_SIZE) {
|
|
into->next = new PacketBuffer;
|
|
into = into->nextPacketBuffer();
|
|
}
|
|
|
|
uint8_t* data = &c->buffer->data[c->begin];
|
|
int len = c->end-c->begin;
|
|
|
|
if (len > into->bytes_unwritten()) {
|
|
// We have to split this ReliablePacket
|
|
len = into->bytes_unwritten();
|
|
ReliablePacket* e = new ReliablePacket;
|
|
e->cont = c->cont;
|
|
e->buffer = c->buffer; e->buffer->addref();
|
|
e->begin = c->begin + len;
|
|
e->end = c->end;
|
|
c->cont = e;
|
|
}
|
|
|
|
memcpy( into->data + into->bytes_written, data, len );
|
|
c->buffer->delref(); c->buffer = into; c->buffer->addref();
|
|
c->begin = into->bytes_written;
|
|
into->bytes_written += len;
|
|
c->end = into->bytes_written;
|
|
}
|
|
|
|
r = r->next;
|
|
}
|
|
return into;
|
|
}
|
|
|
|
void ReliablePacketList::discardAll() {
|
|
while (reliable.next != &reliable)
|
|
reliable.next->remove();
|
|
}
|