1
/**************************************************************************/
3
/* Copyright (c) 2001, 2007 NoMachine, http://www.nomachine.com/. */
5
/* NXCOMP, NX protocol compression and NX extensions to this software */
6
/* are copyright of NoMachine. Redistribution and use of the present */
7
/* software is allowed according to terms specified in the file LICENSE */
8
/* which comes in the source distribution. */
10
/* Check http://www.nomachine.com/licensing.html for applicability. */
12
/* NX and NoMachine are trademarks of NoMachine S.r.l. */
14
/* All rights reserved. */
16
/**************************************************************************/
18
#include "ReadBuffer.h"
20
#include "Transport.h"
23
// Set the verbosity level.
31
ReadBuffer::ReadBuffer(Transport *transport)
33
: transport_(transport)
36
// The read buffer will grow until
37
// reaching the maximum buffer size
38
// and then will remain stable at
42
initialReadSize_ = READ_BUFFER_DEFAULT_SIZE;
43
maximumBufferSize_ = READ_BUFFER_DEFAULT_SIZE;
55
ReadBuffer::~ReadBuffer()
63
void ReadBuffer::readMessage(const unsigned char *message, unsigned int length)
66
// To be here we must be the real owner
67
// of the buffer and there must not be
68
// pending bytes in the transport.
75
*logofs << "ReadBuffer: PANIC! Class for FD#"
76
<< transport_ -> fd() << " doesn't "
77
<< "appear to be the owner of the buffer "
78
<< "while borrowing from the caller.\n"
87
// Be sure that any outstanding data from
88
// the transport is appended to our own
92
if (transport_ -> pending() != 0)
95
*logofs << "ReadBuffer: WARNING! Class for FD#"
96
<< transport_ -> fd() << " has pending "
97
<< "data in the transport while "
98
<< "borrowing from the caller.\n"
111
// Can't borrow the buffer if there is data
112
// from a partial message. In this case add
113
// the new data to the end of our buffer.
119
*logofs << "ReadBuffer: Borrowing " << length
120
<< " bytes from the caller for FD#"
121
<< transport_ -> fd() << " with "
122
<< length_ << " bytes in the buffer.\n"
128
buffer_ = (unsigned char *) message;
139
*logofs << "ReadBuffer: Appending " << length
140
<< " bytes from the caller for FD#"
141
<< transport_ -> fd() << " with "
142
<< length_ << " bytes in the buffer.\n"
146
appendBuffer(message, length);
150
int ReadBuffer::readMessage()
152
int pendingLength = transport_ -> pending();
154
if (pendingLength > 0)
157
// Can't move the data in the borrowed buffer,
158
// so use the tansport buffer only if we don't
159
// have any partial message. This can happen
160
// with the proxy where we need to deflate the
166
unsigned char *newBuffer;
168
length_ = transport_ -> getPending(newBuffer);
170
if (newBuffer == NULL)
173
*logofs << "ReadBuffer: PANIC! Failed to borrow "
174
<< length_ << " bytes of memory for buffer "
175
<< "in context [A].\n" << logofs_flush;
178
cerr << "Error" << ": Failed to borrow memory for "
179
<< "read buffer in context [A].\n";
193
*logofs << "ReadBuffer: Borrowed " << length_
194
<< " pending bytes for FD#" << transport_ ->
195
fd() << ".\n" << logofs_flush;
203
*logofs << "ReadBuffer: WARNING! Cannot borrow "
204
<< pendingLength << " bytes for FD#"
205
<< transport_ -> fd() << " with "
206
<< length_ << " bytes in the buffer.\n"
212
unsigned int readLength = suggestedLength(pendingLength);
215
*logofs << "ReadBuffer: Requested " << readLength
216
<< " bytes for FD#" << transport_ -> fd()
217
<< " with readable " << transport_ -> readable()
218
<< " remaining " << remaining_ << " pending "
219
<< transport_ -> pending() << ".\n"
223
if (readLength < initialReadSize_)
225
readLength = initialReadSize_;
229
*logofs << "ReadBuffer: Buffer size is " << size_
230
<< " length " << length_ << " and start "
231
<< start_ << ".\n" << logofs_flush;
235
// We can't use the transport buffer
236
// to read our own data in it.
243
*logofs << "ReadBuffer: PANIC! Class for FD#"
244
<< transport_ -> fd() << " doesn't "
245
<< "appear to be the owner of the buffer "
246
<< "while reading.\n" << logofs_flush;
254
// Be sure that we have enough space
255
// to store all the requested data.
258
if (buffer_ == NULL || length_ + readLength > size_)
260
unsigned int newSize = length_ + readLength;
263
*logofs << "ReadBuffer: Resizing buffer for FD#"
264
<< transport_ -> fd() << " in read from "
265
<< size_ << " to " << newSize << " bytes.\n"
269
unsigned char *newBuffer = allocateBuffer(newSize);
271
memcpy(newBuffer, buffer_ + start_, length_);
278
transport_ -> pendingReset();
282
else if (start_ != 0 && length_ != 0)
285
// If any bytes are left due to a partial
286
// message, shift them to the beginning
291
*logofs << "ReadBuffer: Moving " << length_
292
<< " bytes of data " << "at beginning of "
293
<< "the buffer for FD#" << transport_ -> fd()
294
<< ".\n" << logofs_flush;
297
memmove(buffer_, buffer_ + start_, length_);
303
*logofs << "ReadBuffer: Buffer size is now " << size_
304
<< " length is " << length_ << " and start is "
305
<< start_ << ".\n" << logofs_flush;
308
unsigned char *readData = buffer_ + length_;
311
*logofs << "ReadBuffer: Going to read " << readLength
312
<< " bytes from FD#" << transport_ -> fd() << ".\n"
316
int bytesRead = transport_ -> read(readData, readLength);
321
*logofs << "ReadBuffer: Read " << bytesRead
322
<< " bytes from FD#" << transport_ -> fd()
323
<< ".\n" << logofs_flush;
326
length_ += bytesRead;
328
else if (bytesRead < 0)
331
// Check if there is more data pending than the
332
// size of the provided buffer. After reading
333
// the requested amount, in fact, the transport
334
// may have decompressed the data and produced
335
// more input. This trick allows us to always
336
// borrow the buffer from the transport, even
337
// when the partial read would have prevented
341
if (transport_ -> pending() > 0)
344
*logofs << "ReadBuffer: WARNING! Trying to read some "
345
<< "more with " << transport_ -> pending()
346
<< " bytes pending for FD#" << transport_ ->
347
fd() << ".\n" << logofs_flush;
350
return readMessage();
354
*logofs << "ReadBuffer: Error detected reading "
355
<< "from FD#" << transport_ -> fd()
356
<< ".\n" << logofs_flush;
364
*logofs << "ReadBuffer: No data read from FD#"
365
<< transport_ -> fd() << " with remaining "
366
<< remaining_ << ".\n" << logofs_flush;
373
const unsigned char *ReadBuffer::getMessage(unsigned int &controlLength,
374
unsigned int &dataLength)
378
if (transport_ -> pending() > 0)
380
*logofs << "ReadBuffer: PANIC! The transport "
381
<< "appears to have data pending.\n"
392
*logofs << "ReadBuffer: No message can be located "
393
<< "for FD#" << transport_ -> fd() << ".\n"
402
transport_ -> pendingReset();
411
unsigned int trailerLength;
414
*logofs << "ReadBuffer: Going to locate message with "
415
<< "start at " << start_ << " and length "
416
<< length_ << " for FD#" << transport_ -> fd()
417
<< ".\n" << logofs_flush;
420
int located = locateMessage(buffer_ + start_, buffer_ + start_ + length_,
421
controlLength, dataLength, trailerLength);
426
// No more complete messages are in
431
*logofs << "ReadBuffer: No message was located "
432
<< "for FD#" << transport_ -> fd()
433
<< ".\n" << logofs_flush;
439
// Must move the remaining bytes in
450
const unsigned char *result = buffer_ + start_;
455
// Message contains data, so go to the
456
// first byte of payload.
459
result += trailerLength;
461
start_ += (dataLength + trailerLength);
462
length_ -= (dataLength + trailerLength);
467
// It is a control message.
470
start_ += (controlLength + trailerLength);
471
length_ -= (controlLength + trailerLength);
475
*logofs << "ReadBuffer: Located message for FD#"
476
<< transport_ -> fd() << " with control length "
477
<< controlLength << " and data length "
478
<< dataLength << ".\n" << logofs_flush;
487
int ReadBuffer::setSize(int initialReadSize, int maximumBufferSize)
489
initialReadSize_ = initialReadSize;
490
maximumBufferSize_ = maximumBufferSize;
493
*logofs << "ReadBuffer: WARNING! Set buffer parameters to "
494
<< initialReadSize_ << "/" << maximumBufferSize_
495
<< " for object at "<< this << ".\n"
502
void ReadBuffer::fullReset()
508
*logofs << "ReadBuffer: PANIC! Class for FD#"
509
<< transport_ -> fd() << " doesn't "
510
<< "appear to be the owner of the buffer "
511
<< "in reset.\n" << logofs_flush;
518
if (length_ == 0 && size_ > maximumBufferSize_)
521
*logofs << "ReadBuffer: Resizing buffer for FD#"
522
<< transport_ -> fd() << " in reset from "
523
<< size_ << " to " << maximumBufferSize_
524
<< " bytes.\n" << logofs_flush;
529
int newSize = maximumBufferSize_;
531
unsigned char *newBuffer = allocateBuffer(newSize);
536
transport_ -> pendingReset();
543
unsigned char *ReadBuffer::allocateBuffer(unsigned int newSize)
545
unsigned char *newBuffer = new unsigned char[newSize];
547
if (newBuffer == NULL)
550
*logofs << "ReadBuffer: PANIC! Can't allocate "
551
<< newSize << " bytes of memory for buffer "
552
<< "in context [B].\n" << logofs_flush;
555
cerr << "Error" << ": Can't allocate memory for "
556
<< "read buffer in context [B].\n";
563
memset(newBuffer, '\0', newSize);
570
void ReadBuffer::appendBuffer(const unsigned char *message, unsigned int length)
572
if (start_ + length_ + length > size_)
574
unsigned int newSize = length_ + length + initialReadSize_;
577
*logofs << "ReadBuffer: WARNING! Resizing buffer "
578
<< "for FD#" << transport_ -> fd()
579
<< " from " << size_ << " to " << newSize
580
<< " bytes.\n" << logofs_flush;
583
unsigned char *newBuffer = allocateBuffer(newSize);
585
memcpy(newBuffer, buffer_ + start_, length_);
595
memcpy(buffer_ + start_ + length_, message, length);
599
transport_ -> pendingReset();
604
void ReadBuffer::convertBuffer()
606
unsigned int newSize = length_ + initialReadSize_;
609
*logofs << "ReadBuffer: WARNING! Converting "
610
<< length_ << " bytes to own buffer "
611
<< "for FD#" << transport_ -> fd()
612
<< " with new size " << newSize
613
<< " bytes.\n" << logofs_flush;
616
unsigned char *newBuffer = allocateBuffer(newSize);
618
memcpy(newBuffer, buffer_ + start_, length_);
623
transport_ -> pendingReset();