blob: 427cc0e7d6129846d90c2e32186d3076a647a1d7 [file] [log] [blame]
#ifndef _THRIFT_TRANSPORT_TTRANSPORTUTILS_H_
#define _THRIFT_TRANSPORT_TTRANSPORTUTILS_H_ 1
#include <transport/TTransport.h>
namespace facebook { namespace thrift { namespace transport {
/**
* The null transport is a dummy transport that doesn't actually do anything.
* It's sort of an analogy to /dev/null, you can never read anything from it
* and it will let you write anything you want to it, though it won't actually
* go anywhere.
*
* @author Mark Slee <mcslee@facebook.com>
*/
class TNullTransport : public TTransport {
public:
TNullTransport() {}
~TNullTransport() {}
bool isOpen() {
return true;
}
void open() {}
void write(const uint8_t* buf, uint32_t len) {
return;
}
};
/**
* Buffered transport. For reads it will read more data than is requested
* and will serve future data out of a local buffer. For writes, data is
* stored to an in memory buffer before being written out.
*
* @author Mark Slee <mcslee@facebook.com>
*/
class TBufferedTransport : public TTransport {
public:
TBufferedTransport(boost::shared_ptr<TTransport> transport) :
transport_(transport),
rBufSize_(512), rPos_(0), rLen_(0),
wBufSize_(512), wLen_(0) {
rBuf_ = new uint8_t[rBufSize_];
wBuf_ = new uint8_t[wBufSize_];
}
TBufferedTransport(boost::shared_ptr<TTransport> transport, uint32_t sz) :
transport_(transport),
rBufSize_(sz), rPos_(0), rLen_(0),
wBufSize_(sz), wLen_(0) {
rBuf_ = new uint8_t[rBufSize_];
wBuf_ = new uint8_t[wBufSize_];
}
TBufferedTransport(boost::shared_ptr<TTransport> transport, uint32_t rsz, uint32_t wsz) :
transport_(transport),
rBufSize_(rsz), rPos_(0), rLen_(0),
wBufSize_(wsz), wLen_(0) {
rBuf_ = new uint8_t[rBufSize_];
wBuf_ = new uint8_t[wBufSize_];
}
~TBufferedTransport() {
delete [] rBuf_;
delete [] wBuf_;
}
bool isOpen() {
return transport_->isOpen();
}
bool peek() {
if (rPos_ >= rLen_) {
rLen_ = transport_->read(rBuf_, rBufSize_);
rPos_ = 0;
}
return (rLen_ > rPos_);
}
void open() {
transport_->open();
}
void close() {
transport_->close();
}
uint32_t read(uint8_t* buf, uint32_t len);
void write(const uint8_t* buf, uint32_t len);
void flush();
protected:
boost::shared_ptr<TTransport> transport_;
uint8_t* rBuf_;
uint32_t rBufSize_;
uint32_t rPos_;
uint32_t rLen_;
uint8_t* wBuf_;
uint32_t wBufSize_;
uint32_t wLen_;
};
/**
* Wraps a transport into a buffered one.
*
* @author Mark Slee <mcslee@facebook.com>
*/
class TBufferedTransportFactory : public TTransportFactory {
public:
TBufferedTransportFactory() {}
virtual ~TBufferedTransportFactory() {}
/**
* Wraps the transport into a buffered one.
*/
virtual std::pair<boost::shared_ptr<TTransport>, boost::shared_ptr<TTransport> > getIOTransports(boost::shared_ptr<TTransport> trans) {
boost::shared_ptr<TTransport> buffered(new TBufferedTransport(trans));
return std::make_pair(buffered, buffered);
}
};
/**
* Framed transport. All writes go into an in-memory buffer until flush is
* called, at which point the transport writes the length of the entire
* binary chunk followed by the data payload. This allows the receiver on the
* other end to always do fixed-length reads.
*
* @author Mark Slee <mcslee@facebook.com>
*/
class TFramedTransport : public TTransport {
public:
TFramedTransport(boost::shared_ptr<TTransport> transport) :
transport_(transport),
rPos_(0),
rLen_(0),
read_(true),
wBufSize_(512),
wLen_(0),
write_(true) {
rBuf_ = NULL;
wBuf_ = new uint8_t[wBufSize_];
}
TFramedTransport(boost::shared_ptr<TTransport> transport, uint32_t sz) :
transport_(transport),
rPos_(0),
rLen_(0),
read_(true),
wBufSize_(sz),
wLen_(0),
write_(true) {
rBuf_ = NULL;
wBuf_ = new uint8_t[wBufSize_];
}
~TFramedTransport() {
if (rBuf_ != NULL) {
delete [] rBuf_;
}
if (wBuf_ != NULL) {
delete [] wBuf_;
}
}
void setRead(bool read) {
read_ = read;
}
void setWrite(bool write) {
write_ = write;
}
void open() {
transport_->open();
}
bool isOpen() {
return transport_->isOpen();
}
bool peek() {
if (rPos_ < rLen_) {
return true;
}
return transport_->peek();
}
void close() {
transport_->close();
}
uint32_t read(uint8_t* buf, uint32_t len);
void write(const uint8_t* buf, uint32_t len);
void flush();
protected:
boost::shared_ptr<TTransport> transport_;
uint8_t* rBuf_;
uint32_t rPos_;
uint32_t rLen_;
bool read_;
uint8_t* wBuf_;
uint32_t wBufSize_;
uint32_t wLen_;
bool write_;
/**
* Reads a frame of input from the underlying stream.
*/
void readFrame();
};
/**
* A memory buffer is a tranpsort that simply reads from and writes to an
* in memory buffer. Anytime you call write on it, the data is simply placed
* into a buffer, and anytime you call read, data is read from that buffer.
*
* The buffers are allocated using C constructs malloc,realloc, and the size
* doubles as necessary.
*
* @author Mark Slee <mcslee@facebook.com>
*/
class TMemoryBuffer : public TTransport {
public:
TMemoryBuffer() {
owner_ = true;
bufferSize_ = 1024;
buffer_ = (uint8_t*)malloc(bufferSize_);
if (buffer_ == NULL) {
throw TTransportException("Out of memory");
}
wPos_ = 0;
rPos_ = 0;
}
TMemoryBuffer(uint32_t sz) {
owner_ = true;
bufferSize_ = sz;
buffer_ = (uint8_t*)malloc(bufferSize_);
if (buffer_ == NULL) {
throw TTransportException("Out of memory");
}
wPos_ = 0;
rPos_ = 0;
}
TMemoryBuffer(uint8_t* buf, int sz) {
owner_ = false;
buffer_ = buf;
bufferSize_ = sz;
wPos_ = sz;
rPos_ = 0;
}
~TMemoryBuffer() {
if (owner_) {
if (buffer_ != NULL) {
free(buffer_);
buffer_ = NULL;
}
}
}
bool isOpen() {
return true;
}
bool peek() {
return (rPos_ < wPos_);
}
void open() {}
void close() {}
void getBuffer(uint8_t** bufPtr, uint32_t* sz) {
*bufPtr = buffer_;
*sz = wPos_;
}
void resetBuffer() {
wPos_ = 0;
rPos_ = 0;
}
void resetBuffer(uint8_t* buf, uint32_t sz) {
if (owner_) {
if (buffer_ != NULL) {
free(buffer_);
}
}
owner_ = false;
buffer_ = buf;
bufferSize_ = sz;
wPos_ = sz;
rPos_ = 0;
}
uint32_t read(uint8_t* buf, uint32_t len);
void write(const uint8_t* buf, uint32_t len);
private:
// Data buffer
uint8_t* buffer_;
// Allocated buffer size
uint32_t bufferSize_;
// Where the write is at
uint32_t wPos_;
// Where the reader is at
uint32_t rPos_;
// Is this object the owner of the buffer?
bool owner_;
};
}}} // facebook::thrift::transport
#endif // #ifndef _THRIFT_TRANSPORT_TTRANSPORTUTILS_H_