source: box/trunk/lib/server/Protocol.cpp @ 3069

Revision 3069, 26.8 KB checked in by chris, 4 months ago (diff)

Catch trying to send a zero-length stream, which will cause an assertion failure on the other side.

  • Property svn:eol-style set to native
Line 
1// --------------------------------------------------------------------------
2//
3// File
4//              Name:    Protocol.cpp
5//              Purpose: Generic protocol support
6//              Created: 2003/08/19
7//
8// --------------------------------------------------------------------------
9
10#include "Box.h"
11
12#include <sys/types.h>
13
14#include <cstdlib>
15#include <cstring>
16#include <cstdio>
17
18#include <new>
19
20#include "Protocol.h"
21#include "ProtocolWire.h"
22#include "IOStream.h"
23#include "ServerException.h"
24#include "PartialReadStream.h"
25#include "ProtocolUncertainStream.h"
26#include "Logging.h"
27
28#include "MemLeakFindOn.h"
29
30#ifdef BOX_RELEASE_BUILD
31        #define PROTOCOL_ALLOCATE_SEND_BLOCK_CHUNK      1024
32#else
33//      #define PROTOCOL_ALLOCATE_SEND_BLOCK_CHUNK      1024
34        #define PROTOCOL_ALLOCATE_SEND_BLOCK_CHUNK      4
35#endif
36
37#define UNCERTAIN_STREAM_SIZE_BLOCK     (64*1024)
38
39// --------------------------------------------------------------------------
40//
41// Function
42//              Name:    Protocol::Protocol(IOStream &rStream)
43//              Purpose: Constructor
44//              Created: 2003/08/19
45//
46// --------------------------------------------------------------------------
47Protocol::Protocol(IOStream &rStream)
48: mrStream(rStream),
49  mHandshakeDone(false),
50  mMaxObjectSize(PROTOCOL_DEFAULT_MAXOBJSIZE),
51  mTimeout(PROTOCOL_DEFAULT_TIMEOUT),
52  mpBuffer(0),
53  mBufferSize(0),
54  mReadOffset(-1),
55  mWriteOffset(-1),
56  mValidDataSize(-1),
57  mLogToSysLog(false),
58  mLogToFile(NULL) 
59{
60        BOX_TRACE("Send block allocation size is " << 
61                PROTOCOL_ALLOCATE_SEND_BLOCK_CHUNK);
62}
63
64// --------------------------------------------------------------------------
65//
66// Function
67//              Name:    Protocol::~Protocol()
68//              Purpose: Destructor
69//              Created: 2003/08/19
70//
71// --------------------------------------------------------------------------
72Protocol::~Protocol()
73{
74        // Free buffer?
75        if(mpBuffer != 0)
76        {
77                free(mpBuffer);
78                mpBuffer = 0;
79        }
80}
81
82
83// --------------------------------------------------------------------------
84//
85// Function
86//              Name:    Protocol::Handshake()
87//              Purpose: Handshake with peer (exchange ident strings)
88//              Created: 2003/08/20
89//
90// --------------------------------------------------------------------------
91void Protocol::Handshake()
92{
93        // Already done?
94        if(mHandshakeDone)
95        {
96                THROW_EXCEPTION(CommonException, Internal)
97        }
98
99        // Make handshake block
100        PW_Handshake hsSend;
101        ::memset(&hsSend, 0, sizeof(hsSend));
102        // Copy in ident string
103        ::strncpy(hsSend.mIdent, GetProtocolIdentString(), sizeof(hsSend.mIdent));
104       
105        // Send it
106        mrStream.Write(&hsSend, sizeof(hsSend));
107        mrStream.WriteAllBuffered();
108
109        // Receive a handshake from the peer
110        PW_Handshake hsReceive;
111        ::memset(&hsReceive, 0, sizeof(hsReceive));
112        char *readInto = (char*)&hsReceive;
113        int bytesToRead = sizeof(hsReceive);
114        while(bytesToRead > 0)
115        {
116                // Get some data from the stream
117                int bytesRead = mrStream.Read(readInto, bytesToRead, mTimeout);
118                if(bytesRead == 0)
119                {
120                        THROW_EXCEPTION(ConnectionException, Conn_Protocol_Timeout)
121                }
122                readInto += bytesRead;
123                bytesToRead -= bytesRead;
124        }
125        ASSERT(bytesToRead == 0);
126       
127        // Are they the same?
128        if(::memcmp(&hsSend, &hsReceive, sizeof(hsSend)) != 0)
129        {
130                THROW_EXCEPTION(ConnectionException, Conn_Protocol_HandshakeFailed)
131        }
132
133        // Mark as done
134        mHandshakeDone = true;
135}
136
137// --------------------------------------------------------------------------
138//
139// Function
140//              Name:    Protocol::CheckAndReadHdr(void *)
141//              Purpose: Check read for recieve call and get object header from stream.
142//                               Don't use type here to avoid dependency in .h file.
143//              Created: 2003/08/26
144//
145// --------------------------------------------------------------------------
146void Protocol::CheckAndReadHdr(void *hdr)
147{
148        // Check usage
149        if(mValidDataSize != -1 || mWriteOffset != -1 || mReadOffset != -1)
150        {
151                THROW_EXCEPTION(ServerException, Protocol_BadUsage)
152        }
153       
154        // Handshake done?
155        if(!mHandshakeDone)
156        {
157                Handshake();
158        }
159
160        // Get some data into this header
161        if(!mrStream.ReadFullBuffer(hdr, sizeof(PW_ObjectHeader), 0 /* not interested in bytes read if this fails */, mTimeout))
162        {
163                THROW_EXCEPTION(ConnectionException, Conn_Protocol_Timeout)
164        }
165}
166
167
168// --------------------------------------------------------------------------
169//
170// Function
171//              Name:    Protocol::Recieve()
172//              Purpose: Recieves an object from the stream, creating it from the factory object type
173//              Created: 2003/08/19
174//
175// --------------------------------------------------------------------------
176std::auto_ptr<Message> Protocol::ReceiveInternal()
177{
178        // Get object header
179        PW_ObjectHeader objHeader;
180        CheckAndReadHdr(&objHeader);
181       
182        // Hope it's not a stream
183        if(ntohl(objHeader.mObjType) == SPECIAL_STREAM_OBJECT_TYPE)
184        {
185                THROW_EXCEPTION(ConnectionException, Conn_Protocol_StreamWhenObjExpected)
186        }
187       
188        // Check the object size
189        u_int32_t objSize = ntohl(objHeader.mObjSize);
190        if(objSize < sizeof(objHeader) || objSize > mMaxObjectSize)
191        {
192                THROW_EXCEPTION(ConnectionException, Conn_Protocol_ObjTooBig)
193        }
194
195        // Create a blank object
196        std::auto_ptr<Message> obj(MakeMessage(ntohl(objHeader.mObjType)));
197
198        // Make sure memory is allocated to read it into
199        EnsureBufferAllocated(objSize);
200       
201        // Read data
202        if(!mrStream.ReadFullBuffer(mpBuffer, objSize - sizeof(objHeader), 0 /* not interested in bytes read if this fails */, mTimeout))
203        {
204                THROW_EXCEPTION(ConnectionException, Conn_Protocol_Timeout)
205        }
206
207        // Setup ready to read out data from the buffer
208        mValidDataSize = objSize - sizeof(objHeader);
209        mReadOffset = 0;
210
211        // Get the object to read its properties from the data recieved
212        try
213        {
214                obj->SetPropertiesFromStreamData(*this);
215        }
216        catch(...)
217        {
218                // Make sure state is reset!
219                mValidDataSize = -1;
220                mReadOffset = -1;
221                throw;
222        }
223       
224        // Any data left over?
225        bool dataLeftOver = (mValidDataSize != mReadOffset);
226       
227        // Unset read state, so future read calls don't fail
228        mValidDataSize = -1;
229        mReadOffset = -1;
230       
231        // Exception if not all the data was consumed
232        if(dataLeftOver)
233        {
234                THROW_EXCEPTION(ConnectionException, Conn_Protocol_BadCommandRecieved)
235        }
236
237        return obj;
238}
239
240// --------------------------------------------------------------------------
241//
242// Function
243//              Name:    Protocol::Send()
244//              Purpose: Send an object to the other side of the connection.
245//              Created: 2003/08/19
246//
247// --------------------------------------------------------------------------
248void Protocol::SendInternal(const Message &rObject)
249{
250        // Check usage
251        if(mValidDataSize != -1 || mWriteOffset != -1 || mReadOffset != -1)
252        {
253                THROW_EXCEPTION(ServerException, Protocol_BadUsage)
254        }
255
256        // Handshake done?
257        if(!mHandshakeDone)
258        {
259                Handshake();
260        }
261
262        // Make sure there's a little bit of space allocated
263        EnsureBufferAllocated(((sizeof(PW_ObjectHeader) + PROTOCOL_ALLOCATE_SEND_BLOCK_CHUNK - 1) / PROTOCOL_ALLOCATE_SEND_BLOCK_CHUNK) * PROTOCOL_ALLOCATE_SEND_BLOCK_CHUNK);
264        ASSERT(mBufferSize >= (int)sizeof(PW_ObjectHeader));
265       
266        // Setup for write operation
267        mValidDataSize = 0;             // Not used, but must not be -1
268        mWriteOffset = sizeof(PW_ObjectHeader);
269       
270        try
271        {
272                rObject.WritePropertiesToStreamData(*this);
273        }
274        catch(...)
275        {
276                // Make sure state is reset!
277                mValidDataSize = -1;
278                mWriteOffset = -1;
279                throw;
280        }
281
282        // How big?
283        int writtenSize = mWriteOffset;
284
285        // Reset write state
286        mValidDataSize = -1;
287        mWriteOffset = -1;     
288       
289        // Make header in the existing block
290        PW_ObjectHeader *pobjHeader = (PW_ObjectHeader*)(mpBuffer);
291        pobjHeader->mObjSize = htonl(writtenSize);
292        pobjHeader->mObjType = htonl(rObject.GetType());
293
294        // Write data
295        mrStream.Write(mpBuffer, writtenSize);
296        mrStream.WriteAllBuffered();
297}
298
299// --------------------------------------------------------------------------
300//
301// Function
302//              Name:    Protocol::EnsureBufferAllocated(int)
303//              Purpose: Private. Ensures the buffer is at least the size requested.
304//              Created: 2003/08/19
305//
306// --------------------------------------------------------------------------
307void Protocol::EnsureBufferAllocated(int Size)
308{
309        if(mpBuffer != 0 && mBufferSize >= Size)
310        {
311                // Nothing to do!
312                return;
313        }
314       
315        // Need to allocate, or reallocate, the block
316        if(mpBuffer != 0)
317        {
318                // Reallocate
319                void *b = realloc(mpBuffer, Size);
320                if(b == 0)
321                {
322                        throw std::bad_alloc();
323                }
324                mpBuffer = (char*)b;
325                mBufferSize = Size;
326        }
327        else
328        {
329                // Just allocate
330                mpBuffer = (char*)malloc(Size);
331                if(mpBuffer == 0)
332                {
333                        throw std::bad_alloc();
334                }
335                mBufferSize = Size;
336        }
337}
338
339
340#define READ_START_CHECK                                                                                                                \
341        if(mValidDataSize == -1 || mWriteOffset != -1 || mReadOffset == -1)                     \
342        {                                                                                                                                                       \
343                THROW_EXCEPTION(ServerException, Protocol_BadUsage)                                             \
344        }
345
346#define READ_CHECK_BYTES_AVAILABLE(bytesRequired)                                                               \
347        if((mReadOffset + (int)(bytesRequired)) > mValidDataSize)                                       \
348        {                                                                                                                                                       \
349                THROW_EXCEPTION(ConnectionException, Conn_Protocol_BadCommandRecieved)  \
350        }
351
352// --------------------------------------------------------------------------
353//
354// Function
355//              Name:    Protocol::Read(void *, int)
356//              Purpose: Read raw data from the stream (buffered)
357//              Created: 2003/08/19
358//
359// --------------------------------------------------------------------------
360void Protocol::Read(void *Buffer, int Size)
361{
362        READ_START_CHECK
363        READ_CHECK_BYTES_AVAILABLE(Size)
364       
365        // Copy data out
366        ::memmove(Buffer, mpBuffer + mReadOffset, Size);
367        mReadOffset += Size;
368}
369
370// --------------------------------------------------------------------------
371//
372// Function
373//              Name:    Protocol::Read(std::string &, int)
374//              Purpose: Read raw data from the stream (buffered), into a std::string
375//              Created: 2003/08/26
376//
377// --------------------------------------------------------------------------
378void Protocol::Read(std::string &rOut, int Size)
379{
380        READ_START_CHECK
381        READ_CHECK_BYTES_AVAILABLE(Size)
382       
383        rOut.assign(mpBuffer + mReadOffset, Size);
384        mReadOffset += Size;
385}
386
387
388// --------------------------------------------------------------------------
389//
390// Function
391//              Name:    Protocol::Read(int64_t &)
392//              Purpose: Read a value from the stream (buffered)
393//              Created: 2003/08/19
394//
395// --------------------------------------------------------------------------
396void Protocol::Read(int64_t &rOut)
397{
398        READ_START_CHECK
399        READ_CHECK_BYTES_AVAILABLE(sizeof(int64_t))
400       
401#ifdef HAVE_ALIGNED_ONLY_INT64
402        int64_t nvalue;
403        memcpy(&nvalue, mpBuffer + mReadOffset, sizeof(int64_t));
404#else
405        int64_t nvalue = *((int64_t*)(mpBuffer + mReadOffset));
406#endif
407        rOut = box_ntoh64(nvalue);
408
409        mReadOffset += sizeof(int64_t);
410}
411
412// --------------------------------------------------------------------------
413//
414// Function
415//              Name:    Protocol::Read(int32_t &)
416//              Purpose: Read a value from the stream (buffered)
417//              Created: 2003/08/19
418//
419// --------------------------------------------------------------------------
420void Protocol::Read(int32_t &rOut)
421{
422        READ_START_CHECK
423        READ_CHECK_BYTES_AVAILABLE(sizeof(int32_t))
424       
425#ifdef HAVE_ALIGNED_ONLY_INT32
426        int32_t nvalue;
427        memcpy(&nvalue, mpBuffer + mReadOffset, sizeof(int32_t));
428#else
429        int32_t nvalue = *((int32_t*)(mpBuffer + mReadOffset));
430#endif
431        rOut = ntohl(nvalue);
432        mReadOffset += sizeof(int32_t);
433}
434
435// --------------------------------------------------------------------------
436//
437// Function
438//              Name:    Protocol::Read(int16_t &)
439//              Purpose: Read a value from the stream (buffered)
440//              Created: 2003/08/19
441//
442// --------------------------------------------------------------------------
443void Protocol::Read(int16_t &rOut)
444{
445        READ_START_CHECK
446        READ_CHECK_BYTES_AVAILABLE(sizeof(int16_t))
447
448        rOut = ntohs(*((int16_t*)(mpBuffer + mReadOffset)));
449        mReadOffset += sizeof(int16_t);
450}
451
452// --------------------------------------------------------------------------
453//
454// Function
455//              Name:    Protocol::Read(int8_t &)
456//              Purpose: Read a value from the stream (buffered)
457//              Created: 2003/08/19
458//
459// --------------------------------------------------------------------------
460void Protocol::Read(int8_t &rOut)
461{
462        READ_START_CHECK
463        READ_CHECK_BYTES_AVAILABLE(sizeof(int8_t))
464
465        rOut = *((int8_t*)(mpBuffer + mReadOffset));
466        mReadOffset += sizeof(int8_t);
467}
468
469// --------------------------------------------------------------------------
470//
471// Function
472//              Name:    Protocol::Read(std::string &)
473//              Purpose: Read a value from the stream (buffered)
474//              Created: 2003/08/19
475//
476// --------------------------------------------------------------------------
477void Protocol::Read(std::string &rOut)
478{
479        // READ_START_CHECK implied
480        int32_t size;
481        Read(size);
482       
483        READ_CHECK_BYTES_AVAILABLE(size)
484       
485        // initialise string
486        rOut.assign(mpBuffer + mReadOffset, size);
487        mReadOffset += size;
488}
489
490
491
492
493#define WRITE_START_CHECK                                                                                                               \
494        if(mValidDataSize == -1 || mWriteOffset == -1 || mReadOffset != -1)                     \
495        {                                                                                                                                                       \
496                THROW_EXCEPTION(ServerException, Protocol_BadUsage)                                             \
497        }
498
499#define WRITE_ENSURE_BYTES_AVAILABLE(bytesToWrite)                                                              \
500        if(mWriteOffset + (int)(bytesToWrite) > mBufferSize)                                            \
501        {                                                                                                                                                       \
502                EnsureBufferAllocated((((mWriteOffset + (int)(bytesToWrite)) + PROTOCOL_ALLOCATE_SEND_BLOCK_CHUNK - 1) / PROTOCOL_ALLOCATE_SEND_BLOCK_CHUNK) * PROTOCOL_ALLOCATE_SEND_BLOCK_CHUNK); \
503                ASSERT(mWriteOffset + (int)(bytesToWrite) <= mBufferSize);                      \
504        }
505
506// --------------------------------------------------------------------------
507//
508// Function
509//              Name:    Protocol::Write(const void *, int)
510//              Purpose: Writes the contents of a buffer to the stream
511//              Created: 2003/08/19
512//
513// --------------------------------------------------------------------------
514void Protocol::Write(const void *Buffer, int Size)
515{
516        WRITE_START_CHECK
517        WRITE_ENSURE_BYTES_AVAILABLE(Size)
518       
519        ::memmove(mpBuffer + mWriteOffset, Buffer, Size);
520        mWriteOffset += Size;
521}
522
523// --------------------------------------------------------------------------
524//
525// Function
526//              Name:    Protocol::Write(int64_t)
527//              Purpose: Writes a value to the stream
528//              Created: 2003/08/19
529//
530// --------------------------------------------------------------------------
531void Protocol::Write(int64_t Value)
532{
533        WRITE_START_CHECK
534        WRITE_ENSURE_BYTES_AVAILABLE(sizeof(int64_t))
535
536        int64_t nvalue = box_hton64(Value);
537#ifdef HAVE_ALIGNED_ONLY_INT64
538        memcpy(mpBuffer + mWriteOffset, &nvalue, sizeof(int64_t));
539#else
540        *((int64_t*)(mpBuffer + mWriteOffset)) = nvalue;
541#endif
542        mWriteOffset += sizeof(int64_t);
543}
544
545
546// --------------------------------------------------------------------------
547//
548// Function
549//              Name:    Protocol::Write(int32_t)
550//              Purpose: Writes a value to the stream
551//              Created: 2003/08/19
552//
553// --------------------------------------------------------------------------
554void Protocol::Write(int32_t Value)
555{
556        WRITE_START_CHECK
557        WRITE_ENSURE_BYTES_AVAILABLE(sizeof(int32_t))
558
559        int32_t nvalue = htonl(Value);
560#ifdef HAVE_ALIGNED_ONLY_INT32
561        memcpy(mpBuffer + mWriteOffset, &nvalue, sizeof(int32_t));
562#else
563        *((int32_t*)(mpBuffer + mWriteOffset)) = nvalue;
564#endif
565        mWriteOffset += sizeof(int32_t);
566}
567
568// --------------------------------------------------------------------------
569//
570// Function
571//              Name:    Protocol::Write(int16_t)
572//              Purpose: Writes a value to the stream
573//              Created: 2003/08/19
574//
575// --------------------------------------------------------------------------
576void Protocol::Write(int16_t Value)
577{
578        WRITE_START_CHECK
579        WRITE_ENSURE_BYTES_AVAILABLE(sizeof(int16_t))
580
581        *((int16_t*)(mpBuffer + mWriteOffset)) = htons(Value);
582        mWriteOffset += sizeof(int16_t);
583}
584
585// --------------------------------------------------------------------------
586//
587// Function
588//              Name:    Protocol::Write(int8_t)
589//              Purpose: Writes a value to the stream
590//              Created: 2003/08/19
591//
592// --------------------------------------------------------------------------
593void Protocol::Write(int8_t Value)
594{
595        WRITE_START_CHECK
596        WRITE_ENSURE_BYTES_AVAILABLE(sizeof(int8_t))
597
598        *((int8_t*)(mpBuffer + mWriteOffset)) = Value;
599        mWriteOffset += sizeof(int8_t);
600}
601
602// --------------------------------------------------------------------------
603//
604// Function
605//              Name:    Protocol::Write(const std::string &)
606//              Purpose: Writes a value to the stream
607//              Created: 2003/08/19
608//
609// --------------------------------------------------------------------------
610void Protocol::Write(const std::string &rValue)
611{
612        // WRITE_START_CHECK implied
613        Write((int32_t)(rValue.size()));
614       
615        WRITE_ENSURE_BYTES_AVAILABLE(rValue.size())
616        Write(rValue.c_str(), rValue.size());
617}
618
619// --------------------------------------------------------------------------
620//
621// Function
622//              Name:    Protocol::ReceieveStream()
623//              Purpose: Receive a stream from the remote side
624//              Created: 2003/08/26
625//
626// --------------------------------------------------------------------------
627std::auto_ptr<IOStream> Protocol::ReceiveStream()
628{
629        // Get object header
630        PW_ObjectHeader objHeader;
631        CheckAndReadHdr(&objHeader);
632       
633        // Hope it's not an object
634        if(ntohl(objHeader.mObjType) != SPECIAL_STREAM_OBJECT_TYPE)
635        {
636                THROW_EXCEPTION(ConnectionException, Conn_Protocol_ObjWhenStreamExpected)
637        }
638       
639        // Get the stream size
640        u_int32_t streamSize = ntohl(objHeader.mObjSize);
641
642        // Inform sub class
643        InformStreamReceiving(streamSize);
644
645        // Return a stream object
646        if(streamSize == ProtocolStream_SizeUncertain)
647        {
648                BOX_TRACE("Receiving stream, size uncertain");
649                return std::auto_ptr<IOStream>(
650                        new ProtocolUncertainStream(mrStream));
651        }
652        else
653        {
654                BOX_TRACE("Receiving stream, size " << streamSize << " bytes");
655                return std::auto_ptr<IOStream>(
656                        new PartialReadStream(mrStream, streamSize));
657        }
658}
659
660// --------------------------------------------------------------------------
661//
662// Function
663//              Name:    Protocol::SendStream(IOStream &)
664//              Purpose: Send a stream to the remote side
665//              Created: 2003/08/26
666//
667// --------------------------------------------------------------------------
668void Protocol::SendStream(IOStream &rStream)
669{
670        // Check usage
671        if(mValidDataSize != -1 || mWriteOffset != -1 || mReadOffset != -1)
672        {
673                THROW_EXCEPTION(ServerException, Protocol_BadUsage)
674        }
675
676        // Handshake done?
677        if(!mHandshakeDone)
678        {
679                Handshake();
680        }
681
682        // How should this be streamed?
683        bool uncertainSize = false;
684        IOStream::pos_type streamSize = rStream.BytesLeftToRead();
685        if(streamSize == IOStream::SizeOfStreamUnknown
686                || streamSize > 0x7fffffff)
687        {
688                // Can't send this using the fixed size header
689                uncertainSize = true;
690        }
691
692        if(streamSize == 0)
693        {
694                // Server protocol will throw an assertion failure if we
695                // try to send a stream whose size is definitely zero:
696                // ASSERT FAILED: [BytesToRead > 0] at PartialReadStream.cpp:31
697                // so catch this on the client side to help debugging
698                THROW_EXCEPTION_MESSAGE(ServerException, Protocol_BadUsage,
699                        "Sending a stream with a definite size of zero "
700                        "is not allowed in the protocol");
701        }
702       
703        // Inform sub class
704        InformStreamSending(streamSize);
705       
706        // Make header
707        PW_ObjectHeader objHeader;
708        objHeader.mObjSize = htonl(uncertainSize?(ProtocolStream_SizeUncertain):streamSize);
709        objHeader.mObjType = htonl(SPECIAL_STREAM_OBJECT_TYPE);
710
711        // Write header
712        mrStream.Write(&objHeader, sizeof(objHeader));
713        // Could be sent in one of two ways
714        if(uncertainSize)
715        {
716                // Don't know how big this is going to be -- so send it in chunks
717               
718                // Allocate memory
719                uint8_t *blockA = (uint8_t *)malloc(UNCERTAIN_STREAM_SIZE_BLOCK + sizeof(int));
720                if(blockA == 0)
721                {
722                        throw std::bad_alloc();
723                }
724                uint8_t *block = blockA + sizeof(int);  // so that everything is word aligned for reading, but can put the one byte header before it
725               
726                try
727                {
728                        int bytesInBlock = 0;
729                        while(rStream.StreamDataLeft())
730                        {
731                                // Read some of it
732                                bytesInBlock += rStream.Read(block + bytesInBlock, UNCERTAIN_STREAM_SIZE_BLOCK - bytesInBlock);
733                               
734                                // Send as much as we can out
735                                bytesInBlock -= SendStreamSendBlock(block, bytesInBlock);
736                        }
737
738                        // Everything recieved from stream, but need to send whatevers left in the block
739                        while(bytesInBlock > 0)
740                        {
741                                bytesInBlock -= SendStreamSendBlock(block, bytesInBlock);
742                        }
743                       
744                        // Send final byte to finish the stream
745                        BOX_TRACE("Sending end of stream byte");
746                        uint8_t endOfStream = ProtocolStreamHeader_EndOfStream;
747                        mrStream.Write(&endOfStream, 1);
748                        BOX_TRACE("Sent end of stream byte");
749                }
750                catch(...)
751                {
752                        free(blockA);
753                        throw;
754                }
755               
756                // Clean up
757                free(blockA);
758        }
759        else
760        {
761                // Fixed size stream, send it all in one go
762                if(!rStream.CopyStreamTo(mrStream, mTimeout, 4096 /* slightly larger buffer */))
763                {
764                        THROW_EXCEPTION(ConnectionException, Conn_Protocol_TimeOutWhenSendingStream)
765                }
766        }
767        // Make sure everything is written
768        mrStream.WriteAllBuffered();
769       
770}
771
772// --------------------------------------------------------------------------
773//
774// Function
775//              Name:    Protocol::SendStreamSendBlock(uint8_t *, int)
776//              Purpose: Sends as much of the block as can be sent, moves the remainer down to the beginning,
777//                               and returns the number of bytes sent. WARNING: Will write to Block[-1]
778//              Created: 5/12/03
779//
780// --------------------------------------------------------------------------
781int Protocol::SendStreamSendBlock(uint8_t *Block, int BytesInBlock)
782{
783        // Quick sanity check
784        if(BytesInBlock == 0)
785        {
786                BOX_TRACE("Zero size block, not sending anything");
787                return 0;
788        }
789       
790        // Work out the header byte
791        uint8_t header = 0;
792        int writeSize = 0;
793        if(BytesInBlock >= (64*1024))
794        {
795                header = ProtocolStreamHeader_SizeIs64k;
796                writeSize = (64*1024);
797        }
798        else
799        {
800                // Scan the table to find the most that can be written
801                for(int s = ProtocolStreamHeader_MaxEncodedSizeValue; s > 0; --s)
802                {
803                        if(sProtocolStreamHeaderLengths[s] <= BytesInBlock)
804                        {
805                                header = s;
806                                writeSize = sProtocolStreamHeaderLengths[s];
807                                break;
808                        }
809                }
810        }
811        ASSERT(header > 0);
812        BOX_TRACE("Sending header byte " << (int)header << " plus " <<
813                writeSize << " bytes to stream");
814       
815        // Store the header
816        Block[-1] = header;
817       
818        // Write everything out
819        mrStream.Write(Block - 1, writeSize + 1);
820       
821        BOX_TRACE("Sent " << (writeSize+1) << " bytes to stream");
822        // move the remainer to the beginning of the block for the next time round
823        if(writeSize != BytesInBlock)
824        {
825                ::memmove(Block, Block + writeSize, BytesInBlock - writeSize);
826        }
827       
828        return writeSize;
829}
830
831// --------------------------------------------------------------------------
832//
833// Function
834//              Name:    Protocol::InformStreamReceiving(u_int32_t)
835//              Purpose: Informs sub classes about streams being received
836//              Created: 2003/10/27
837//
838// --------------------------------------------------------------------------
839void Protocol::InformStreamReceiving(u_int32_t Size)
840{
841        if(GetLogToSysLog())
842        {
843                if(Size == Protocol::ProtocolStream_SizeUncertain)
844                {
845                        BOX_TRACE("Receiving stream, size uncertain");
846                }
847                else
848                {
849                        BOX_TRACE("Receiving stream, size " << Size);
850                }
851        }
852
853        if(GetLogToFile())
854        {
855                ::fprintf(GetLogToFile(),
856                        (Size == Protocol::ProtocolStream_SizeUncertain)
857                        ? "Receiving stream, size uncertain\n"
858                        : "Receiving stream, size %d\n", Size);
859                ::fflush(GetLogToFile());
860        }
861}
862
863// --------------------------------------------------------------------------
864//
865// Function
866//              Name:    Protocol::InformStreamSending(u_int32_t)
867//              Purpose: Informs sub classes about streams being sent
868//              Created: 2003/10/27
869//
870// --------------------------------------------------------------------------
871void Protocol::InformStreamSending(u_int32_t Size)
872{
873        if(GetLogToSysLog())
874        {
875                if(Size == Protocol::ProtocolStream_SizeUncertain)
876                {
877                        BOX_TRACE("Sending stream, size uncertain");
878                }
879                else
880                {
881                        BOX_TRACE("Sending stream, size " << Size);
882                }
883        }
884       
885        if(GetLogToFile())
886        {
887                ::fprintf(GetLogToFile(),
888                        (Size == Protocol::ProtocolStream_SizeUncertain)
889                        ? "Sending stream, size uncertain\n"
890                        : "Sending stream, size %d\n", Size);
891                ::fflush(GetLogToFile());
892        }
893}
894
895
896/*
897perl code to generate the table below
898
899#!/usr/bin/perl
900use strict;
901open OUT,">protolengths.txt";
902my $len = 0;
903for(0 .. 255)
904{
905        print OUT "\t$len,\t// $_\n";
906        my $inc = 1;
907        $inc = 8 if $_ >= 64;
908        $inc = 16 if $_ >= 96;
909        $inc = 32 if $_ >= 112;
910        $inc = 64 if $_ >= 128;
911        $inc = 128 if $_ >= 135;
912        $inc = 256 if $_ >= 147;
913        $inc = 512 if $_ >= 159;
914        $inc = 1024 if $_ >= 231;
915        $len += $inc;
916}
917close OUT;
918
919*/
920const uint16_t Protocol::sProtocolStreamHeaderLengths[256] =
921{
922        0,      // 0
923        1,      // 1
924        2,      // 2
925        3,      // 3
926        4,      // 4
927        5,      // 5
928        6,      // 6
929        7,      // 7
930        8,      // 8
931        9,      // 9
932        10,     // 10
933        11,     // 11
934        12,     // 12
935        13,     // 13
936        14,     // 14
937        15,     // 15
938        16,     // 16
939        17,     // 17
940        18,     // 18
941        19,     // 19
942        20,     // 20
943        21,     // 21
944        22,     // 22
945        23,     // 23
946        24,     // 24
947        25,     // 25
948        26,     // 26
949        27,     // 27
950        28,     // 28
951        29,     // 29
952        30,     // 30
953        31,     // 31
954        32,     // 32
955        33,     // 33
956        34,     // 34
957        35,     // 35
958        36,     // 36
959        37,     // 37
960        38,     // 38
961        39,     // 39
962        40,     // 40
963        41,     // 41
964        42,     // 42
965        43,     // 43
966        44,     // 44
967        45,     // 45
968        46,     // 46
969        47,     // 47
970        48,     // 48
971        49,     // 49
972        50,     // 50
973        51,     // 51
974        52,     // 52
975        53,     // 53
976        54,     // 54
977        55,     // 55
978        56,     // 56
979        57,     // 57
980        58,     // 58
981        59,     // 59
982        60,     // 60
983        61,     // 61
984        62,     // 62
985        63,     // 63
986        64,     // 64
987        72,     // 65
988        80,     // 66
989        88,     // 67
990        96,     // 68
991        104,    // 69
992        112,    // 70
993        120,    // 71
994        128,    // 72
995        136,    // 73
996        144,    // 74
997        152,    // 75
998        160,    // 76
999        168,    // 77
1000        176,    // 78
1001        184,    // 79
1002        192,    // 80
1003        200,    // 81
1004        208,    // 82
1005        216,    // 83
1006        224,    // 84
1007        232,    // 85
1008        240,    // 86
1009        248,    // 87
1010        256,    // 88
1011        264,    // 89
1012        272,    // 90
1013        280,    // 91
1014        288,    // 92
1015        296,    // 93
1016        304,    // 94
1017        312,    // 95
1018        320,    // 96
1019        336,    // 97
1020        352,    // 98
1021        368,    // 99
1022        384,    // 100
1023        400,    // 101
1024        416,    // 102
1025        432,    // 103
1026        448,    // 104
1027        464,    // 105
1028        480,    // 106
1029        496,    // 107
1030        512,    // 108
1031        528,    // 109
1032        544,    // 110
1033        560,    // 111
1034        576,    // 112
1035        608,    // 113
1036        640,    // 114
1037        672,    // 115
1038        704,    // 116
1039        736,    // 117
1040        768,    // 118
1041        800,    // 119
1042        832,    // 120
1043        864,    // 121
1044        896,    // 122
1045        928,    // 123
1046        960,    // 124
1047        992,    // 125
1048        1024,   // 126
1049        1056,   // 127
1050        1088,   // 128
1051        1152,   // 129
1052        1216,   // 130
1053        1280,   // 131
1054        1344,   // 132
1055        1408,   // 133
1056        1472,   // 134
1057        1536,   // 135
1058        1664,   // 136
1059        1792,   // 137
1060        1920,   // 138
1061        2048,   // 139
1062        2176,   // 140
1063        2304,   // 141
1064        2432,   // 142
1065        2560,   // 143
1066        2688,   // 144
1067        2816,   // 145
1068        2944,   // 146
1069        3072,   // 147
1070        3328,   // 148
1071        3584,   // 149
1072        3840,   // 150
1073        4096,   // 151
1074        4352,   // 152
1075        4608,   // 153
1076        4864,   // 154
1077        5120,   // 155
1078        5376,   // 156
1079        5632,   // 157
1080        5888,   // 158
1081        6144,   // 159
1082        6656,   // 160
1083        7168,   // 161
1084        7680,   // 162
1085        8192,   // 163
1086        8704,   // 164
1087        9216,   // 165
1088        9728,   // 166
1089        10240,  // 167
1090        10752,  // 168
1091        11264,  // 169
1092        11776,  // 170
1093        12288,  // 171
1094        12800,  // 172
1095        13312,  // 173
1096        13824,  // 174
1097        14336,  // 175
1098        14848,  // 176
1099        15360,  // 177
1100        15872,  // 178
1101        16384,  // 179
1102        16896,  // 180
1103        17408,  // 181
1104        17920,  // 182
1105        18432,  // 183
1106        18944,  // 184
1107        19456,  // 185
1108        19968,  // 186
1109        20480,  // 187
1110        20992,  // 188
1111        21504,  // 189
1112        22016,  // 190
1113        22528,  // 191
1114        23040,  // 192
1115        23552,  // 193
1116        24064,  // 194
1117        24576,  // 195
1118        25088,  // 196
1119        25600,  // 197
1120        26112,  // 198
1121        26624,  // 199
1122        27136,  // 200
1123        27648,  // 201
1124        28160,  // 202
1125        28672,  // 203
1126        29184,  // 204
1127        29696,  // 205
1128        30208,  // 206
1129        30720,  // 207
1130        31232,  // 208
1131        31744,  // 209
1132        32256,  // 210
1133        32768,  // 211
1134        33280,  // 212
1135        33792,  // 213
1136        34304,  // 214
1137        34816,  // 215
1138        35328,  // 216
1139        35840,  // 217
1140        36352,  // 218
1141        36864,  // 219
1142        37376,  // 220
1143        37888,  // 221
1144        38400,  // 222
1145        38912,  // 223
1146        39424,  // 224
1147        39936,  // 225
1148        40448,  // 226
1149        40960,  // 227
1150        41472,  // 228
1151        41984,  // 229
1152        42496,  // 230
1153        43008,  // 231
1154        44032,  // 232
1155        45056,  // 233
1156        46080,  // 234
1157        47104,  // 235
1158        48128,  // 236
1159        49152,  // 237
1160        50176,  // 238
1161        51200,  // 239
1162        52224,  // 240
1163        53248,  // 241
1164        54272,  // 242
1165        55296,  // 243
1166        56320,  // 244
1167        57344,  // 245
1168        58368,  // 246
1169        59392,  // 247
1170        60416,  // 248
1171        61440,  // 249
1172        62464,  // 250
1173        63488,  // 251
1174        64512,  // 252
1175        0,              // 253 = 65536 / 64k
1176        0,              // 254 = special (reserved)
1177        0               // 255 = special (reserved)
1178};
1179
1180
1181
1182
Note: See TracBrowser for help on using the repository browser.