// distribution boxbackup-0.10 (svn version: 494)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// 3. All use of this software and associated advertising materials must
// display the following acknowledgment:
// This product includes software developed by Ben Summers.
// 4. The names of the Authors may not be used to endorse or promote
// products derived from this software without specific prior written
// permission.
//
// [Where legally impermissible the Authors do not disclaim liability for
// direct physical injury or death caused solely by defects in the software
// unless it is modified by a third party.]
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
//
//
// --------------------------------------------------------------------------
//
// File
// Name: Protocol.cpp
// Purpose: Generic protocol support
// Created: 2003/08/19
//
// --------------------------------------------------------------------------
#include "Box.h"
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <new>
#include "Protocol.h"
#include "ProtocolWire.h"
#include "IOStream.h"
#include "ServerException.h"
#include "PartialReadStream.h"
#include "ProtocolUncertainStream.h"
#include "MemLeakFindOn.h"
#ifdef NDEBUG
#define PROTOCOL_ALLOCATE_SEND_BLOCK_CHUNK 1024
#else
// #define PROTOCOL_ALLOCATE_SEND_BLOCK_CHUNK 1024
#define PROTOCOL_ALLOCATE_SEND_BLOCK_CHUNK 4
#endif
#define UNCERTAIN_STREAM_SIZE_BLOCK (64*1024)
// --------------------------------------------------------------------------
//
// Function
// Name: Protocol::Protocol(IOStream &rStream)
// Purpose: Constructor
// Created: 2003/08/19
//
// --------------------------------------------------------------------------
Protocol::Protocol(IOStream &rStream)
: mrStream(rStream),
mHandshakeDone(false),
mMaxObjectSize(PROTOCOL_DEFAULT_MAXOBJSIZE),
mTimeout(PROTOCOL_DEFAULT_TIMEOUT),
mpBuffer(0),
mBufferSize(0),
mReadOffset(-1),
mWriteOffset(-1),
mValidDataSize(-1),
mLastErrorType(NoError),
mLastErrorSubType(NoError)
{
TRACE1("Send block allocation size is %d\n", PROTOCOL_ALLOCATE_SEND_BLOCK_CHUNK);
}
// --------------------------------------------------------------------------
//
// Function
// Name: Protocol::~Protocol()
// Purpose: Destructor
// Created: 2003/08/19
//
// --------------------------------------------------------------------------
Protocol::~Protocol()
{
// Free buffer?
if(mpBuffer != 0)
{
free(mpBuffer);
mpBuffer = 0;
}
}
// --------------------------------------------------------------------------
//
// Function
// Name: Protocol::GetLastError(int &, int &)
// Purpose: Returns true if there was an error, and type and subtype if there was.
// Created: 2003/08/19
//
// --------------------------------------------------------------------------
bool Protocol::GetLastError(int &rTypeOut, int &rSubTypeOut)
{
if(mLastErrorType == NoError)
{
// no error.
return false;
}
// Return type and subtype in args
rTypeOut = mLastErrorType;
rSubTypeOut = mLastErrorSubType;
// and unset them
mLastErrorType = NoError;
mLastErrorSubType = NoError;
return true;
}
// --------------------------------------------------------------------------
//
// Function
// Name: Protocol::Handshake()
// Purpose: Handshake with peer (exchange ident strings)
// Created: 2003/08/20
//
// --------------------------------------------------------------------------
void Protocol::Handshake()
{
// Already done?
if(mHandshakeDone)
{
THROW_EXCEPTION(CommonException, Internal)
}
// Make handshake block
PW_Handshake hsSend;
::memset(&hsSend, 0, sizeof(hsSend));
// Copy in ident string
::strncpy(hsSend.mIdent, GetIdentString(), sizeof(hsSend.mIdent));
// Send it
mrStream.Write(&hsSend, sizeof(hsSend));
mrStream.WriteAllBuffered();
// Receive a handshake from the peer
PW_Handshake hsReceive;
::memset(&hsReceive, 0, sizeof(hsReceive));
char *readInto = (char*)&hsReceive;
int bytesToRead = sizeof(hsReceive);
while(bytesToRead > 0)
{
// Get some data from the stream
int bytesRead = mrStream.Read(readInto, bytesToRead, mTimeout);
if(bytesRead == 0)
{
THROW_EXCEPTION(ConnectionException, Conn_Protocol_Timeout)
}
readInto += bytesRead;
bytesToRead -= bytesRead;
}
ASSERT(bytesToRead == 0);
// Are they the same?
if(::memcmp(&hsSend, &hsReceive, sizeof(hsSend)) != 0)
{
THROW_EXCEPTION(ConnectionException, Conn_Protocol_HandshakeFailed)
}
// Mark as done
mHandshakeDone = true;
}
// --------------------------------------------------------------------------
//
// Function
// Name: Protocol::CheckAndReadHdr(void *)
// Purpose: Check read for recieve call and get object header from stream.
// Don't use type here to avoid dependency in .h file.
// Created: 2003/08/26
//
// --------------------------------------------------------------------------
void Protocol::CheckAndReadHdr(void *hdr)
{
// Check usage
if(mValidDataSize != -1 || mWriteOffset != -1 || mReadOffset != -1)
{
THROW_EXCEPTION(ServerException, Protocol_BadUsage)
}
// Handshake done?
if(!mHandshakeDone)
{
Handshake();
}
// Get some data into this header
if(!mrStream.ReadFullBuffer(hdr, sizeof(PW_ObjectHeader), 0 /* not interested in bytes read if this fails */, mTimeout))
{
THROW_EXCEPTION(ConnectionException, Conn_Protocol_Timeout)
}
}
// --------------------------------------------------------------------------
//
// Function
// Name: Protocol::Recieve()
// Purpose: Recieves an object from the stream, creating it from the factory object type
// Created: 2003/08/19
//
// --------------------------------------------------------------------------
std::auto_ptr<ProtocolObject> Protocol::Receive()
{
// Get object header
PW_ObjectHeader objHeader;
CheckAndReadHdr(&objHeader);
// Hope it's not a stream
if(ntohl(objHeader.mObjType) == SPECIAL_STREAM_OBJECT_TYPE)
{
THROW_EXCEPTION(ConnectionException, Conn_Protocol_StreamWhenObjExpected)
}
// Check the object size
u_int32_t objSize = ntohl(objHeader.mObjSize);
if(objSize < sizeof(objHeader) || objSize > mMaxObjectSize)
{
THROW_EXCEPTION(ConnectionException, Conn_Protocol_ObjTooBig)
}
// Create a blank object
std::auto_ptr<ProtocolObject> obj(MakeProtocolObject(ntohl(objHeader.mObjType)));
// Make sure memory is allocated to read it into
EnsureBufferAllocated(objSize);
// Read data
if(!mrStream.ReadFullBuffer(mpBuffer, objSize - sizeof(objHeader), 0 /* not interested in bytes read if this fails */, mTimeout))
{
THROW_EXCEPTION(ConnectionException, Conn_Protocol_Timeout)
}
// Setup ready to read out data from the buffer
mValidDataSize = objSize - sizeof(objHeader);
mReadOffset = 0;
// Get the object to read its properties from the data recieved
try
{
obj->SetPropertiesFromStreamData(*this);
}
catch(...)
{
// Make sure state is reset!
mValidDataSize = -1;
mReadOffset = -1;
throw;
}
// Any data left over?
bool dataLeftOver = (mValidDataSize != mReadOffset);
// Unset read state, so future read calls don't fail
mValidDataSize = -1;
mReadOffset = -1;
// Exception if not all the data was consumed
if(dataLeftOver)
{
THROW_EXCEPTION(ConnectionException, Conn_Protocol_BadCommandRecieved)
}
return obj;
}
// --------------------------------------------------------------------------
//
// Function
// Name: Protocol::Send()
// Purpose: Send an object to the other side of the connection.
// Created: 2003/08/19
//
// --------------------------------------------------------------------------
void Protocol::Send(const ProtocolObject &rObject)
{
// Check usage
if(mValidDataSize != -1 || mWriteOffset != -1 || mReadOffset != -1)
{
THROW_EXCEPTION(ServerException, Protocol_BadUsage)
}
// Handshake done?
if(!mHandshakeDone)
{
Handshake();
}
// Make sure there's a little bit of space allocated
EnsureBufferAllocated(((sizeof(PW_ObjectHeader) + PROTOCOL_ALLOCATE_SEND_BLOCK_CHUNK - 1) / PROTOCOL_ALLOCATE_SEND_BLOCK_CHUNK) * PROTOCOL_ALLOCATE_SEND_BLOCK_CHUNK);
ASSERT(mBufferSize >= (int)sizeof(PW_ObjectHeader));
// Setup for write operation
mValidDataSize = 0; // Not used, but must not be -1
mWriteOffset = sizeof(PW_ObjectHeader);
try
{
rObject.WritePropertiesToStreamData(*this);
}
catch(...)
{
// Make sure state is reset!
mValidDataSize = -1;
mWriteOffset = -1;
throw;
}
// How big?
int writtenSize = mWriteOffset;
// Reset write state
mValidDataSize = -1;
mWriteOffset = -1;
// Make header in the existing block
PW_ObjectHeader *pobjHeader = (PW_ObjectHeader*)(mpBuffer);
pobjHeader->mObjSize = htonl(writtenSize);
pobjHeader->mObjType = htonl(rObject.GetType());
// Write data
mrStream.Write(mpBuffer, writtenSize);
mrStream.WriteAllBuffered();
}
// --------------------------------------------------------------------------
//
// Function
// Name: Protocol::EnsureBufferAllocated(int)
// Purpose: Private. Ensures the buffer is at least the size requested.
// Created: 2003/08/19
//
// --------------------------------------------------------------------------
void Protocol::EnsureBufferAllocated(int Size)
{
if(mpBuffer != 0 && mBufferSize >= Size)
{
// Nothing to do!
return;
}
// Need to allocate, or reallocate, the block
if(mpBuffer != 0)
{
// Reallocate
void *b = realloc(mpBuffer, Size);
if(b == 0)
{
throw std::bad_alloc();
}
mpBuffer = (char*)b;
mBufferSize = Size;
}
else
{
// Just allocate
mpBuffer = (char*)malloc(Size);
if(mpBuffer == 0)
{
throw std::bad_alloc();
}
mBufferSize = Size;
}
}
#define READ_START_CHECK \
if(mValidDataSize == -1 || mWriteOffset != -1 || mReadOffset == -1) \
{ \
THROW_EXCEPTION(ServerException, Protocol_BadUsage) \
}
#define READ_CHECK_BYTES_AVAILABLE(bytesRequired) \
if((mReadOffset + (int)(bytesRequired)) > mValidDataSize) \
{ \
THROW_EXCEPTION(ConnectionException, Conn_Protocol_BadCommandRecieved) \
}
// --------------------------------------------------------------------------
//
// Function
// Name: Protocol::Read(void *, int)
// Purpose: Read raw data from the stream (buffered)
// Created: 2003/08/19
//
// --------------------------------------------------------------------------
void Protocol::Read(void *Buffer, int Size)
{
READ_START_CHECK
READ_CHECK_BYTES_AVAILABLE(Size)
// Copy data out
::memmove(Buffer, mpBuffer + mReadOffset, Size);
mReadOffset += Size;
}
// --------------------------------------------------------------------------
//
// Function
// Name: Protocol::Read(std::string &, int)
// Purpose: Read raw data from the stream (buffered), into a std::string
// Created: 2003/08/26
//
// --------------------------------------------------------------------------
void Protocol::Read(std::string &rOut, int Size)
{
READ_START_CHECK
READ_CHECK_BYTES_AVAILABLE(Size)
rOut.assign(mpBuffer + mReadOffset, Size);
mReadOffset += Size;
}
// --------------------------------------------------------------------------
//
// Function
// Name: Protocol::Read(int64_t &)
// Purpose: Read a value from the stream (buffered)
// Created: 2003/08/19
//
// --------------------------------------------------------------------------
void Protocol::Read(int64_t &rOut)
{
READ_START_CHECK
READ_CHECK_BYTES_AVAILABLE(sizeof(int64_t))
#ifdef HAVE_ALIGNED_ONLY_INT64
int64_t nvalue;
memcpy(&nvalue, mpBuffer + mReadOffset, sizeof(int64_t));
#else
int64_t nvalue = *((int64_t*)(mpBuffer + mReadOffset));
#endif
rOut = box_ntoh64(nvalue);
mReadOffset += sizeof(int64_t);
}
// --------------------------------------------------------------------------
//
// Function
// Name: Protocol::Read(int32_t &)
// Purpose: Read a value from the stream (buffered)
// Created: 2003/08/19
//
// --------------------------------------------------------------------------
void Protocol::Read(int32_t &rOut)
{
READ_START_CHECK
READ_CHECK_BYTES_AVAILABLE(sizeof(int32_t))
#ifdef HAVE_ALIGNED_ONLY_INT32
int32_t nvalue;
memcpy(&nvalue, mpBuffer + mReadOffset, sizeof(int32_t));
#else
int32_t nvalue = *((int32_t*)(mpBuffer + mReadOffset));
#endif
rOut = ntohl(nvalue);
mReadOffset += sizeof(int32_t);
}
// --------------------------------------------------------------------------
//
// Function
// Name: Protocol::Read(int16_t &)
// Purpose: Read a value from the stream (buffered)
// Created: 2003/08/19
//
// --------------------------------------------------------------------------
void Protocol::Read(int16_t &rOut)
{
READ_START_CHECK
READ_CHECK_BYTES_AVAILABLE(sizeof(int16_t))
rOut = ntohs(*((int16_t*)(mpBuffer + mReadOffset)));
mReadOffset += sizeof(int16_t);
}
// --------------------------------------------------------------------------
//
// Function
// Name: Protocol::Read(int8_t &)
// Purpose: Read a value from the stream (buffered)
// Created: 2003/08/19
//
// --------------------------------------------------------------------------
void Protocol::Read(int8_t &rOut)
{
READ_START_CHECK
READ_CHECK_BYTES_AVAILABLE(sizeof(int8_t))
rOut = *((int8_t*)(mpBuffer + mReadOffset));
mReadOffset += sizeof(int8_t);
}
// --------------------------------------------------------------------------
//
// Function
// Name: Protocol::Read(std::string &)
// Purpose: Read a value from the stream (buffered)
// Created: 2003/08/19
//
// --------------------------------------------------------------------------
void Protocol::Read(std::string &rOut)
{
// READ_START_CHECK implied
int32_t size;
Read(size);
READ_CHECK_BYTES_AVAILABLE(size)
// initialise string
rOut.assign(mpBuffer + mReadOffset, size);
mReadOffset += size;
}
#define WRITE_START_CHECK \
if(mValidDataSize == -1 || mWriteOffset == -1 || mReadOffset != -1) \
{ \
THROW_EXCEPTION(ServerException, Protocol_BadUsage) \
}
#define WRITE_ENSURE_BYTES_AVAILABLE(bytesToWrite) \
if(mWriteOffset + (int)(bytesToWrite) > mBufferSize) \
{ \
EnsureBufferAllocated((((mWriteOffset + (int)(bytesToWrite)) + PROTOCOL_ALLOCATE_SEND_BLOCK_CHUNK - 1) / PROTOCOL_ALLOCATE_SEND_BLOCK_CHUNK) * PROTOCOL_ALLOCATE_SEND_BLOCK_CHUNK); \
ASSERT(mWriteOffset + (int)(bytesToWrite) <= mBufferSize); \
}
// --------------------------------------------------------------------------
//
// Function
// Name: Protocol::Write(const void *, int)
// Purpose: Writes the contents of a buffer to the stream
// Created: 2003/08/19
//
// --------------------------------------------------------------------------
void Protocol::Write(const void *Buffer, int Size)
{
WRITE_START_CHECK
WRITE_ENSURE_BYTES_AVAILABLE(Size)
::memmove(mpBuffer + mWriteOffset, Buffer, Size);
mWriteOffset += Size;
}
// --------------------------------------------------------------------------
//
// Function
// Name: Protocol::Write(int64_t)
// Purpose: Writes a value to the stream
// Created: 2003/08/19
//
// --------------------------------------------------------------------------
void Protocol::Write(int64_t Value)
{
WRITE_START_CHECK
WRITE_ENSURE_BYTES_AVAILABLE(sizeof(int64_t))
int64_t nvalue = box_hton64(Value);
#ifdef HAVE_ALIGNED_ONLY_INT64
memcpy(mpBuffer + mWriteOffset, &nvalue, sizeof(int64_t));
#else
*((int64_t*)(mpBuffer + mWriteOffset)) = nvalue;
#endif
mWriteOffset += sizeof(int64_t);
}
// --------------------------------------------------------------------------
//
// Function
// Name: Protocol::Write(int32_t)
// Purpose: Writes a value to the stream
// Created: 2003/08/19
//
// --------------------------------------------------------------------------
void Protocol::Write(int32_t Value)
{
WRITE_START_CHECK
WRITE_ENSURE_BYTES_AVAILABLE(sizeof(int32_t))
int32_t nvalue = htonl(Value);
#ifdef HAVE_ALIGNED_ONLY_INT32
memcpy(mpBuffer + mWriteOffset, &nvalue, sizeof(int32_t));
#else
*((int32_t*)(mpBuffer + mWriteOffset)) = nvalue;
#endif
mWriteOffset += sizeof(int32_t);
}
// --------------------------------------------------------------------------
//
// Function
// Name: Protocol::Write(int16_t)
// Purpose: Writes a value to the stream
// Created: 2003/08/19
//
// --------------------------------------------------------------------------
void Protocol::Write(int16_t Value)
{
WRITE_START_CHECK
WRITE_ENSURE_BYTES_AVAILABLE(sizeof(int16_t))
*((int16_t*)(mpBuffer + mWriteOffset)) = htons(Value);
mWriteOffset += sizeof(int16_t);
}
// --------------------------------------------------------------------------
//
// Function
// Name: Protocol::Write(int8_t)
// Purpose: Writes a value to the stream
// Created: 2003/08/19
//
// --------------------------------------------------------------------------
void Protocol::Write(int8_t Value)
{
WRITE_START_CHECK
WRITE_ENSURE_BYTES_AVAILABLE(sizeof(int8_t))
*((int8_t*)(mpBuffer + mWriteOffset)) = Value;
mWriteOffset += sizeof(int8_t);
}
// --------------------------------------------------------------------------
//
// Function
// Name: Protocol::Write(const std::string &)
// Purpose: Writes a value to the stream
// Created: 2003/08/19
//
// --------------------------------------------------------------------------
void Protocol::Write(const std::string &rValue)
{
// WRITE_START_CHECK implied
Write((int32_t)(rValue.size()));
WRITE_ENSURE_BYTES_AVAILABLE(rValue.size())
Write(rValue.c_str(), rValue.size());
}
// --------------------------------------------------------------------------
//
// Function
// Name: Protocol::ReceieveStream()
// Purpose: Receive a stream from the remote side
// Created: 2003/08/26
//
// --------------------------------------------------------------------------
std::auto_ptr<IOStream> Protocol::ReceiveStream()
{
// Get object header
PW_ObjectHeader objHeader;
CheckAndReadHdr(&objHeader);
// Hope it's not an object
if(ntohl(objHeader.mObjType) != SPECIAL_STREAM_OBJECT_TYPE)
{
THROW_EXCEPTION(ConnectionException, Conn_Protocol_ObjWhenStreamExpected)
}
// Get the stream size
u_int32_t streamSize = ntohl(objHeader.mObjSize);
// Inform sub class
InformStreamReceiving(streamSize);
// Return a stream object
return std::auto_ptr<IOStream>((streamSize == ProtocolStream_SizeUncertain)?
((IOStream*)(new ProtocolUncertainStream(mrStream)))
:((IOStream*)(new PartialReadStream(mrStream, streamSize))));
}
// --------------------------------------------------------------------------
//
// Function
// Name: Protocol::SendStream(IOStream &)
// Purpose: Send a stream to the remote side
// Created: 2003/08/26
//
// --------------------------------------------------------------------------
void Protocol::SendStream(IOStream &rStream)
{
// Check usage
if(mValidDataSize != -1 || mWriteOffset != -1 || mReadOffset != -1)
{
THROW_EXCEPTION(ServerException, Protocol_BadUsage)
}
// Handshake done?
if(!mHandshakeDone)
{
Handshake();
}
// How should this be streamed?
bool uncertainSize = false;
IOStream::pos_type streamSize = rStream.BytesLeftToRead();
if(streamSize == IOStream::SizeOfStreamUnknown
|| streamSize > 0x7fffffff)
{
// Can't send this using the fixed size header
uncertainSize = true;
}
// Inform sub class
InformStreamSending(streamSize);
// Make header
PW_ObjectHeader objHeader;
objHeader.mObjSize = htonl(uncertainSize?(ProtocolStream_SizeUncertain):streamSize);
objHeader.mObjType = htonl(SPECIAL_STREAM_OBJECT_TYPE);
// Write header
mrStream.Write(&objHeader, sizeof(objHeader));
// Could be sent in one of two ways
if(uncertainSize)
{
// Don't know how big this is going to be -- so send it in chunks
// Allocate memory
uint8_t *blockA = (uint8_t *)malloc(UNCERTAIN_STREAM_SIZE_BLOCK + sizeof(int));
if(blockA == 0)
{
throw std::bad_alloc();
}
uint8_t *block = blockA + sizeof(int); // so that everything is word aligned for reading, but can put the one byte header before it
try
{
int bytesInBlock = 0;
while(rStream.StreamDataLeft())
{
// Read some of it
bytesInBlock += rStream.Read(block + bytesInBlock, UNCERTAIN_STREAM_SIZE_BLOCK - bytesInBlock);
// Send as much as we can out
bytesInBlock -= SendStreamSendBlock(block, bytesInBlock);
}
// Everything recieved from stream, but need to send whatevers left in the block
while(bytesInBlock > 0)
{
bytesInBlock -= SendStreamSendBlock(block, bytesInBlock);
}
// Send final byte to finish the stream
uint8_t endOfStream = ProtocolStreamHeader_EndOfStream;
mrStream.Write(&endOfStream, 1);
}
catch(...)
{
free(blockA);
throw;
}
// Clean up
free(blockA);
}
else
{
// Fixed size stream, send it all in one go
if(!rStream.CopyStreamTo(mrStream, mTimeout, 4096 /* slightly larger buffer */))
{
THROW_EXCEPTION(ConnectionException, Conn_Protocol_TimeOutWhenSendingStream)
}
}
// Make sure everything is written
mrStream.WriteAllBuffered();
}
// --------------------------------------------------------------------------
//
// Function
// Name: Protocol::SendStreamSendBlock(uint8_t *, int)
// Purpose: Sends as much of the block as can be sent, moves the remainer down to the beginning,
// and returns the number of bytes sent. WARNING: Will write to Block[-1]
// Created: 5/12/03
//
// --------------------------------------------------------------------------
int Protocol::SendStreamSendBlock(uint8_t *Block, int BytesInBlock)
{
// Quick sanity check
if(BytesInBlock == 0)
{
return 0;
}
// Work out the header byte
uint8_t header = 0;
int writeSize = 0;
if(BytesInBlock >= (64*1024))
{
header = ProtocolStreamHeader_SizeIs64k;
writeSize = (64*1024);
}
else
{
// Scan the table to find the most that can be written
for(int s = ProtocolStreamHeader_MaxEncodedSizeValue; s > 0; --s)
{
if(sProtocolStreamHeaderLengths[s] <= BytesInBlock)
{
header = s;
writeSize = sProtocolStreamHeaderLengths[s];
break;
}
}
}
ASSERT(header > 0);
// Store the header
Block[-1] = header;
// Write everything out
mrStream.Write(Block - 1, writeSize + 1);
// move the remainer to the beginning of the block for the next time round
if(writeSize != BytesInBlock)
{
::memmove(Block, Block + writeSize, BytesInBlock - writeSize);
}
return writeSize;
}
// --------------------------------------------------------------------------
//
// Function
// Name: Protocol::InformStreamReceiving(u_int32_t)
// Purpose: Informs sub classes about streams being received
// Created: 2003/10/27
//
// --------------------------------------------------------------------------
void Protocol::InformStreamReceiving(u_int32_t Size)
{
// Do nothing
}
// --------------------------------------------------------------------------
//
// Function
// Name: Protocol::InformStreamSending(u_int32_t)
// Purpose: Informs sub classes about streams being sent
// Created: 2003/10/27
//
// --------------------------------------------------------------------------
void Protocol::InformStreamSending(u_int32_t Size)
{
// Do nothing
}
/*
perl code to generate the table below
#!/usr/bin/perl
use strict;
open OUT,">protolengths.txt";
my $len = 0;
for(0 .. 255)
{
print OUT "\t$len,\t// $_\n";
my $inc = 1;
$inc = 8 if $_ >= 64;
$inc = 16 if $_ >= 96;
$inc = 32 if $_ >= 112;
$inc = 64 if $_ >= 128;
$inc = 128 if $_ >= 135;
$inc = 256 if $_ >= 147;
$inc = 512 if $_ >= 159;
$inc = 1024 if $_ >= 231;
$len += $inc;
}
close OUT;
*/
const uint16_t Protocol::sProtocolStreamHeaderLengths[256] =
{
0, // 0
1, // 1
2, // 2
3, // 3
4, // 4
5, // 5
6, // 6
7, // 7
8, // 8
9, // 9
10, // 10
11, // 11
12, // 12
13, // 13
14, // 14
15, // 15
16, // 16
17, // 17
18, // 18
19, // 19
20, // 20
21, // 21
22, // 22
23, // 23
24, // 24
25, // 25
26, // 26
27, // 27
28, // 28
29, // 29
30, // 30
31, // 31
32, // 32
33, // 33
34, // 34
35, // 35
36, // 36
37, // 37
38, // 38
39, // 39
40, // 40
41, // 41
42, // 42
43, // 43
44, // 44
45, // 45
46, // 46
47, // 47
48, // 48
49, // 49
50, // 50
51, // 51
52, // 52
53, // 53
54, // 54
55, // 55
56, // 56
57, // 57
58, // 58
59, // 59
60, // 60
61, // 61
62, // 62
63, // 63
64, // 64
72, // 65
80, // 66
88, // 67
96, // 68
104, // 69
112, // 70
120, // 71
128, // 72
136, // 73
144, // 74
152, // 75
160, // 76
168, // 77
176, // 78
184, // 79
192, // 80
200, // 81
208, // 82
216, // 83
224, // 84
232, // 85
240, // 86
248, // 87
256, // 88
264, // 89
272, // 90
280, // 91
288, // 92
296, // 93
304, // 94
312, // 95
320, // 96
336, // 97
352, // 98
368, // 99
384, // 100
400, // 101
416, // 102
432, // 103
448, // 104
464, // 105
480, // 106
496, // 107
512, // 108
528, // 109
544, // 110
560, // 111
576, // 112
608, // 113
640, // 114
672, // 115
704, // 116
736, // 117
768, // 118
800, // 119
832, // 120
864, // 121
896, // 122
928, // 123
960, // 124
992, // 125
1024, // 126
1056, // 127
1088, // 128
1152, // 129
1216, // 130
1280, // 131
1344, // 132
1408, // 133
1472, // 134
1536, // 135
1664, // 136
1792, // 137
1920, // 138
2048, // 139
2176, // 140
2304, // 141
2432, // 142
2560, // 143
2688, // 144
2816, // 145
2944, // 146
3072, // 147
3328, // 148
3584, // 149
3840, // 150
4096, // 151
4352, // 152
4608, // 153
4864, // 154
5120, // 155
5376, // 156
5632, // 157
5888, // 158
6144, // 159
6656, // 160
7168, // 161
7680, // 162
8192, // 163
8704, // 164
9216, // 165
9728, // 166
10240, // 167
10752, // 168
11264, // 169
11776, // 170
12288, // 171
12800, // 172
13312, // 173
13824, // 174
14336, // 175
14848, // 176
15360, // 177
15872, // 178
16384, // 179
16896, // 180
17408, // 181
17920, // 182
18432, // 183
18944, // 184
19456, // 185
19968, // 186
20480, // 187
20992, // 188
21504, // 189
22016, // 190
22528, // 191
23040, // 192
23552, // 193
24064, // 194
24576, // 195
25088, // 196
25600, // 197
26112, // 198
26624, // 199
27136, // 200
27648, // 201
28160, // 202
28672, // 203
29184, // 204
29696, // 205
30208, // 206
30720, // 207
31232, // 208
31744, // 209
32256, // 210
32768, // 211
33280, // 212
33792, // 213
34304, // 214
34816, // 215
35328, // 216
35840, // 217
36352, // 218
36864, // 219
37376, // 220
37888, // 221
38400, // 222
38912, // 223
39424, // 224
39936, // 225
40448, // 226
40960, // 227
41472, // 228
41984, // 229
42496, // 230
43008, // 231
44032, // 232
45056, // 233
46080, // 234
47104, // 235
48128, // 236
49152, // 237
50176, // 238
51200, // 239
52224, // 240
53248, // 241
54272, // 242
55296, // 243
56320, // 244
57344, // 245
58368, // 246
59392, // 247
60416, // 248
61440, // 249
62464, // 250
63488, // 251
64512, // 252
0, // 253 = 65536 / 64k
0, // 254 = special (reserved)
0 // 255 = special (reserved)
};
syntax highlighted by Code2HTML, v. 0.9.1