1#ifndef CRYPTOPP_NETWORK_H 2#define CRYPTOPP_NETWORK_H 3 4#include "config.h" 5 6#ifdef HIGHRES_TIMER_AVAILABLE 7 8#include "filters.h" 9#include "hrtimer.h" 10 11#include <deque> 12 13NAMESPACE_BEGIN(CryptoPP) 14 15class LimitedBandwidth 16{ 17public: 18 LimitedBandwidth(lword maxBytesPerSecond = 0) 19 : m_maxBytesPerSecond(maxBytesPerSecond), m_timer(Timer::MILLISECONDS) 20 , m_nextTransceiveTime(0) 21 { m_timer.StartTimer(); } 22 23 lword GetMaxBytesPerSecond() const 24 { return m_maxBytesPerSecond; } 25 26 void SetMaxBytesPerSecond(lword v) 27 { m_maxBytesPerSecond = v; } 28 29 lword ComputeCurrentTransceiveLimit(); 30 31 double TimeToNextTransceive(); 32 33 void NoteTransceive(lword size); 34 35public: 36 /*! GetWaitObjects() must be called despite the 0 return from GetMaxWaitObjectCount(); 37 the 0 is because the ScheduleEvent() method is used instead of adding a wait object */ 38 unsigned int GetMaxWaitObjectCount() const { return 0; } 39 void GetWaitObjects(WaitObjectContainer &container, const CallStack &callStack); 40 41private: 42 lword m_maxBytesPerSecond; 43 44 typedef std::deque<std::pair<double, lword> > OpQueue; 45 OpQueue m_ops; 46 47 Timer m_timer; 48 double m_nextTransceiveTime; 49 50 void ComputeNextTransceiveTime(); 51 double GetCurTimeAndCleanUp(); 52}; 53 54//! a Source class that can pump from a device for a specified amount of time. 55class CRYPTOPP_NO_VTABLE NonblockingSource : public AutoSignaling<Source>, public LimitedBandwidth 56{ 57public: 58 NonblockingSource(BufferedTransformation *attachment) 59 : m_messageEndSent(false) , m_doPumpBlocked(false), m_blockedBySpeedLimit(false) {Detach(attachment);} 60 61 //! \name NONBLOCKING SOURCE 62 //@{ 63 64 //! pump up to maxSize bytes using at most maxTime milliseconds 65 /*! If checkDelimiter is true, pump up to delimiter, which itself is not extracted or pumped. */ 66 size_t GeneralPump2(lword &byteCount, bool blockingOutput=true, unsigned long maxTime=INFINITE_TIME, bool checkDelimiter=false, byte delimiter='\n'); 67 68 lword GeneralPump(lword maxSize=LWORD_MAX, unsigned long maxTime=INFINITE_TIME, bool checkDelimiter=false, byte delimiter='\n') 69 { 70 GeneralPump2(maxSize, true, maxTime, checkDelimiter, delimiter); 71 return maxSize; 72 } 73 lword TimedPump(unsigned long maxTime) 74 {return GeneralPump(LWORD_MAX, maxTime);} 75 lword PumpLine(byte delimiter='\n', lword maxSize=1024) 76 {return GeneralPump(maxSize, INFINITE_TIME, true, delimiter);} 77 78 size_t Pump2(lword &byteCount, bool blocking=true) 79 {return GeneralPump2(byteCount, blocking, blocking ? INFINITE_TIME : 0);} 80 size_t PumpMessages2(unsigned int &messageCount, bool blocking=true); 81 //@} 82 83protected: 84 virtual size_t DoPump(lword &byteCount, bool blockingOutput, 85 unsigned long maxTime, bool checkDelimiter, byte delimiter) =0; 86 87 bool BlockedBySpeedLimit() const { return m_blockedBySpeedLimit; } 88 89private: 90 bool m_messageEndSent, m_doPumpBlocked, m_blockedBySpeedLimit; 91}; 92 93//! Network Receiver 94class CRYPTOPP_NO_VTABLE NetworkReceiver : public Waitable 95{ 96public: 97 virtual bool MustWaitToReceive() {return false;} 98 virtual bool MustWaitForResult() {return false;} 99 //! receive data from network source, returns whether result is immediately available 100 virtual bool Receive(byte* buf, size_t bufLen) =0; 101 virtual unsigned int GetReceiveResult() =0; 102 virtual bool EofReceived() const =0; 103}; 104 105class CRYPTOPP_NO_VTABLE NonblockingSinkInfo 106{ 107public: 108 virtual ~NonblockingSinkInfo() {} 109 virtual size_t GetMaxBufferSize() const =0; 110 virtual size_t GetCurrentBufferSize() const =0; 111 virtual bool EofPending() const =0; 112 //! compute the current speed of this sink in bytes per second 113 virtual float ComputeCurrentSpeed() =0; 114 //! get the maximum observed speed of this sink in bytes per second 115 virtual float GetMaxObservedSpeed() const =0; 116}; 117 118//! a Sink class that queues input and can flush to a device for a specified amount of time. 119class CRYPTOPP_NO_VTABLE NonblockingSink : public Sink, public NonblockingSinkInfo, public LimitedBandwidth 120{ 121public: 122 NonblockingSink() : m_blockedBySpeedLimit(false) {} 123 124 bool IsolatedFlush(bool hardFlush, bool blocking); 125 126 //! flush to device for no more than maxTime milliseconds 127 /*! This function will repeatedly attempt to flush data to some device, until 128 the queue is empty, or a total of maxTime milliseconds have elapsed. 129 If maxTime == 0, at least one attempt will be made to flush some data, but 130 it is likely that not all queued data will be flushed, even if the device 131 is ready to receive more data without waiting. If you want to flush as much data 132 as possible without waiting for the device, call this function in a loop. 133 For example: while (sink.TimedFlush(0) > 0) {} 134 \return number of bytes flushed 135 */ 136 lword TimedFlush(unsigned long maxTime, size_t targetSize = 0); 137 138 virtual void SetMaxBufferSize(size_t maxBufferSize) =0; 139 //! set a bound which will cause sink to flush if exceeded by GetCurrentBufferSize() 140 virtual void SetAutoFlushBound(size_t bound) =0; 141 142protected: 143 virtual lword DoFlush(unsigned long maxTime, size_t targetSize) = 0; 144 145 bool BlockedBySpeedLimit() const { return m_blockedBySpeedLimit; } 146 147private: 148 bool m_blockedBySpeedLimit; 149}; 150 151//! Network Sender 152class CRYPTOPP_NO_VTABLE NetworkSender : public Waitable 153{ 154public: 155 virtual bool MustWaitToSend() {return false;} 156 virtual bool MustWaitForResult() {return false;} 157 virtual void Send(const byte* buf, size_t bufLen) =0; 158 virtual unsigned int GetSendResult() =0; 159 virtual bool MustWaitForEof() {return false;} 160 virtual void SendEof() =0; 161 virtual bool EofSent() {return false;} // implement if MustWaitForEof() == true 162}; 163 164//! Network Source 165class CRYPTOPP_NO_VTABLE NetworkSource : public NonblockingSource 166{ 167public: 168 NetworkSource(BufferedTransformation *attachment); 169 170 unsigned int GetMaxWaitObjectCount() const; 171 void GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack); 172 173 bool SourceExhausted() const {return m_dataBegin == m_dataEnd && GetReceiver().EofReceived();} 174 175protected: 176 size_t DoPump(lword &byteCount, bool blockingOutput, unsigned long maxTime, bool checkDelimiter, byte delimiter); 177 178 virtual NetworkReceiver & AccessReceiver() =0; 179 const NetworkReceiver & GetReceiver() const {return const_cast<NetworkSource *>(this)->AccessReceiver();} 180 181private: 182 SecByteBlock m_buf; 183 size_t m_putSize, m_dataBegin, m_dataEnd; 184 bool m_waitingForResult, m_outputBlocked; 185}; 186 187//! Network Sink 188class CRYPTOPP_NO_VTABLE NetworkSink : public NonblockingSink 189{ 190public: 191 NetworkSink(unsigned int maxBufferSize, unsigned int autoFlushBound); 192 193 unsigned int GetMaxWaitObjectCount() const; 194 void GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack); 195 196 size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking); 197 198 void SetMaxBufferSize(size_t maxBufferSize) {m_maxBufferSize = maxBufferSize; m_buffer.SetNodeSize(UnsignedMin(maxBufferSize, 16U*1024U+256U));} 199 void SetAutoFlushBound(size_t bound) {m_autoFlushBound = bound;} 200 201 size_t GetMaxBufferSize() const {return m_maxBufferSize;} 202 size_t GetCurrentBufferSize() const {return (size_t)m_buffer.CurrentSize();} 203 204 void ClearBuffer() { m_buffer.Clear(); } 205 206 bool EofPending() const { return m_eofState > EOF_NONE && m_eofState < EOF_DONE; } 207 208 //! compute the current speed of this sink in bytes per second 209 float ComputeCurrentSpeed(); 210 //! get the maximum observed speed of this sink in bytes per second 211 float GetMaxObservedSpeed() const; 212 213protected: 214 lword DoFlush(unsigned long maxTime, size_t targetSize); 215 216 virtual NetworkSender & AccessSender() =0; 217 const NetworkSender & GetSender() const {return const_cast<NetworkSink *>(this)->AccessSender();} 218 219private: 220 enum EofState { EOF_NONE, EOF_PENDING_SEND, EOF_PENDING_DELIVERY, EOF_DONE }; 221 222 size_t m_maxBufferSize, m_autoFlushBound; 223 bool m_needSendResult, m_wasBlocked; 224 EofState m_eofState; 225 ByteQueue m_buffer; 226 size_t m_skipBytes; 227 Timer m_speedTimer; 228 float m_byteCountSinceLastTimerReset, m_currentSpeed, m_maxObservedSpeed; 229}; 230 231NAMESPACE_END 232 233#endif // #ifdef HIGHRES_TIMER_AVAILABLE 234 235#endif 236