#ifndef ReceiveBuffer_hh #define ReceiveBuffer_hh #include #if CHAR_BIT != 8 #error Only 8 bit char supported #endif #if defined(_MSC_VER) || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) #define WIN32_LEAN_AND_MEAN #include #else #include #include #include #endif #include #include #include #include #include #include #include #include template class ReceiveBuffer { unsigned int bufsize_; unsigned int vsize_; unsigned int recIndex_; #if defined(_MSC_VER) || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) DWORD minBytesAvailable_; #else unsigned int minBytesAvailable_; #endif unsigned int bytesRemainingInMsg_; unsigned char* buf_; R reader_; public: #if defined(_MSC_VER) || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) #ifdef EE_FILEIO HANDLE sock_; #else SOCKET sock_; #endif #else int sock_; #endif explicit ReceiveBuffer(unsigned int bufsize) : bufsize_(bufsize), vsize_(0), recIndex_(0), minBytesAvailable_(0), bytesRemainingInMsg_(0) { if (bufsize_ < 8) { throw failure("buffer size too small"); } buf_ = new unsigned char[bufsize_]; } ~ReceiveBuffer() { delete [] buf_; } void Give(uint8_t& val) { val = Get(); } void Give(uint16_t& val) { reader_.Read(*this, val); } void Give(uint32_t& val) { reader_.Read(*this, val); } void Give(uint64_t& val) { reader_.Read(*this, val); } void Give(int8_t& value) { value = Get(); } void Give(int16_t& value) { uint16_t tmp; reader_.Read(*this, tmp); value = tmp; } void Give(int32_t& value) { uint32_t tmp; reader_.Read(*this, tmp); value = tmp; } void Give(int64_t& value) { uint64_t tmp; reader_.Read(*this, tmp); value = tmp; } void Give(float& value) { reader_.Read(*this, value); } void Give(double& value) { reader_.Read(*this, value); } template void Give(std::complex cmplx) { T value; Give(value); cmplx.real(value); Give(value); cmplx.imag(value); } #if defined(_MSC_VER) || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) void Give(void* address, unsigned int len) { using std::min; if (len > bytesRemainingInMsg_) { throw failure("ReceiveBuffer::Give -- len > bytesRemainingInMsg_"); } char * addr = static_cast (address); if (vsize_ > recIndex_) { if (len <= (vsize_ - recIndex_)) { memcpy(addr, buf_ + recIndex_, len); recIndex_ += len; } else { memcpy(addr, buf_ + recIndex_, vsize_ - recIndex_); addr += (vsize_ - recIndex_); len -= (vsize_ - recIndex_); bytesRemainingInMsg_ -= (vsize_ - recIndex_); recIndex_ = vsize_; goto pull; } } else { pull: int rc = 0; if (minBytesAvailable_ < len) { #ifdef EE_FILEIO minBytesAvailable_ = bufsize_; #else if ((rc = ioctlsocket(sock_, FIONREAD, &minBytesAvailable_)) == SOCKET_ERROR) { throw failure("ReceiveBuffer::Give -- ioctl"); } #endif } if (len > bufsize_ || len > minBytesAvailable_) { PersistentRead(sock_, addr, len); minBytesAvailable_ = 0; } else { vsize_ = min(min(bufsize_, bytesRemainingInMsg_), minBytesAvailable_); minBytesAvailable_ -= vsize_; #ifdef EE_FILEIO PersistentRead(sock_, buf_, vsize_); #else if ((rc = recv(sock_, reinterpret_cast (buf_), vsize_, 0)) != vsize_) { throw failure("ReceiveBuffer::Give -- recv"); } #endif memcpy(addr, buf_, len); recIndex_ = len; } } bytesRemainingInMsg_ -= len; } #else void Give(void* address, unsigned int len) { using std::min; if (len > bytesRemainingInMsg_) { throw failure("ReceiveBuffer::Give -- len > bytesRemainingInMsg_"); } char * addr = static_cast (address); if (vsize_ > recIndex_) { if (len <= (vsize_ - recIndex_)) { memcpy(addr, buf_ + recIndex_, len); recIndex_ += len; } else { memcpy(addr, buf_ + recIndex_, vsize_ - recIndex_); addr += (vsize_ - recIndex_); len -= (vsize_ - recIndex_); bytesRemainingInMsg_ -= (vsize_ - recIndex_); recIndex_ = vsize_; goto pull; } } else { pull: int rc = 0; if (minBytesAvailable_ < len) { if ((rc = ioctl(sock_, FIONREAD, &minBytesAvailable_)) == -1) { throw failure("ReceiveBuffer::Give -- ioctl"); } } if (len > bufsize_ || len > minBytesAvailable_) { PersistentRead(sock_, addr, len); minBytesAvailable_ = 0; } else { vsize_ = min(min(bufsize_, bytesRemainingInMsg_), minBytesAvailable_); minBytesAvailable_ -= vsize_; if ((rc = read(sock_, buf_, vsize_)) != vsize_) { throw failure("ReceiveBuffer::Give -- read"); } memcpy(addr, buf_, len); recIndex_ = len; } } bytesRemainingInMsg_ -= len; } #endif unsigned char Get() { unsigned char byte; if (minBytesAvailable_ > 0) { byte = buf_[recIndex_]; ++recIndex_; --minBytesAvailable_; --bytesRemainingInMsg_; } else { Give(&byte, 1); } return byte; } void Reset() { recIndex_ = 0; vsize_ = 0; minBytesAvailable_ = 0; bytesRemainingInMsg_ = 0; } void SetMsgLength(unsigned int newMsgLength) { bytesRemainingInMsg_ = newMsgLength; } private: ReceiveBuffer(ReceiveBuffer const&); ReceiveBuffer& operator=(ReceiveBuffer const&); }; #endif