Crypto++
network.h
00001 #ifndef CRYPTOPP_NETWORK_H
00002 #define CRYPTOPP_NETWORK_H
00003 
00004 #include "config.h"
00005 
00006 #ifdef HIGHRES_TIMER_AVAILABLE
00007 
00008 #include "filters.h"
00009 #include "hrtimer.h"
00010 
00011 #include <deque>
00012 
00013 NAMESPACE_BEGIN(CryptoPP)
00014 
00015 class LimitedBandwidth
00016 {
00017 public:
00018     LimitedBandwidth(lword maxBytesPerSecond = 0)
00019         : m_maxBytesPerSecond(maxBytesPerSecond), m_timer(Timer::MILLISECONDS)
00020         , m_nextTransceiveTime(0)
00021         { m_timer.StartTimer(); }
00022 
00023     lword GetMaxBytesPerSecond() const
00024         { return m_maxBytesPerSecond; }
00025 
00026     void SetMaxBytesPerSecond(lword v)
00027         { m_maxBytesPerSecond = v; }
00028 
00029     lword ComputeCurrentTransceiveLimit();
00030 
00031     double TimeToNextTransceive();
00032 
00033     void NoteTransceive(lword size);
00034 
00035 public:
00036     /*! GetWaitObjects() must be called despite the 0 return from GetMaxWaitObjectCount();
00037         the 0 is because the ScheduleEvent() method is used instead of adding a wait object */
00038     unsigned int GetMaxWaitObjectCount() const { return 0; }
00039     void GetWaitObjects(WaitObjectContainer &container, const CallStack &callStack);
00040 
00041 private:    
00042     lword m_maxBytesPerSecond;
00043 
00044     typedef std::deque<std::pair<double, lword> > OpQueue;
00045     OpQueue m_ops;
00046 
00047     Timer m_timer;
00048     double m_nextTransceiveTime;
00049 
00050     void ComputeNextTransceiveTime();
00051     double GetCurTimeAndCleanUp();
00052 };
00053 
00054 //! a Source class that can pump from a device for a specified amount of time.
00055 class CRYPTOPP_NO_VTABLE NonblockingSource : public AutoSignaling<Source>, public LimitedBandwidth
00056 {
00057 public:
00058     NonblockingSource(BufferedTransformation *attachment)
00059         : m_messageEndSent(false) , m_doPumpBlocked(false), m_blockedBySpeedLimit(false) {Detach(attachment);}
00060 
00061     //! \name NONBLOCKING SOURCE
00062     //@{
00063 
00064     //! pump up to maxSize bytes using at most maxTime milliseconds
00065     /*! If checkDelimiter is true, pump up to delimiter, which itself is not extracted or pumped. */
00066     size_t GeneralPump2(lword &byteCount, bool blockingOutput=true, unsigned long maxTime=INFINITE_TIME, bool checkDelimiter=false, byte delimiter='\n');
00067 
00068     lword GeneralPump(lword maxSize=LWORD_MAX, unsigned long maxTime=INFINITE_TIME, bool checkDelimiter=false, byte delimiter='\n')
00069     {
00070         GeneralPump2(maxSize, true, maxTime, checkDelimiter, delimiter);
00071         return maxSize;
00072     }
00073     lword TimedPump(unsigned long maxTime)
00074         {return GeneralPump(LWORD_MAX, maxTime);}
00075     lword PumpLine(byte delimiter='\n', lword maxSize=1024)
00076         {return GeneralPump(maxSize, INFINITE_TIME, true, delimiter);}
00077 
00078     size_t Pump2(lword &byteCount, bool blocking=true)
00079         {return GeneralPump2(byteCount, blocking, blocking ? INFINITE_TIME : 0);}
00080     size_t PumpMessages2(unsigned int &messageCount, bool blocking=true);
00081     //@}
00082 
00083 protected:
00084     virtual size_t DoPump(lword &byteCount, bool blockingOutput,
00085         unsigned long maxTime, bool checkDelimiter, byte delimiter) =0;
00086 
00087     bool BlockedBySpeedLimit() const { return m_blockedBySpeedLimit; }
00088 
00089 private:
00090     bool m_messageEndSent, m_doPumpBlocked, m_blockedBySpeedLimit;
00091 };
00092 
00093 //! Network Receiver
00094 class CRYPTOPP_NO_VTABLE NetworkReceiver : public Waitable
00095 {
00096 public:
00097     virtual bool MustWaitToReceive() {return false;}
00098     virtual bool MustWaitForResult() {return false;}
00099     //! receive data from network source, returns whether result is immediately available
00100     virtual bool Receive(byte* buf, size_t bufLen) =0;
00101     virtual unsigned int GetReceiveResult() =0;
00102     virtual bool EofReceived() const =0;
00103 };
00104 
00105 class CRYPTOPP_NO_VTABLE NonblockingSinkInfo
00106 {
00107 public:
00108     virtual ~NonblockingSinkInfo() {}
00109     virtual size_t GetMaxBufferSize() const =0;
00110     virtual size_t GetCurrentBufferSize() const =0;
00111     virtual bool EofPending() const =0;
00112     //! compute the current speed of this sink in bytes per second
00113     virtual float ComputeCurrentSpeed() =0;
00114     //! get the maximum observed speed of this sink in bytes per second
00115     virtual float GetMaxObservedSpeed() const =0;
00116 };
00117 
00118 //! a Sink class that queues input and can flush to a device for a specified amount of time.
00119 class CRYPTOPP_NO_VTABLE NonblockingSink : public Sink, public NonblockingSinkInfo, public LimitedBandwidth
00120 {
00121 public:
00122     NonblockingSink() : m_blockedBySpeedLimit(false) {}
00123 
00124     bool IsolatedFlush(bool hardFlush, bool blocking);
00125 
00126     //! flush to device for no more than maxTime milliseconds
00127     /*! This function will repeatedly attempt to flush data to some device, until
00128         the queue is empty, or a total of maxTime milliseconds have elapsed.
00129         If maxTime == 0, at least one attempt will be made to flush some data, but
00130         it is likely that not all queued data will be flushed, even if the device
00131         is ready to receive more data without waiting. If you want to flush as much data
00132         as possible without waiting for the device, call this function in a loop.
00133         For example: while (sink.TimedFlush(0) > 0) {}
00134         \return number of bytes flushed
00135     */
00136     lword TimedFlush(unsigned long maxTime, size_t targetSize = 0);
00137 
00138     virtual void SetMaxBufferSize(size_t maxBufferSize) =0;
00139     //! set a bound which will cause sink to flush if exceeded by GetCurrentBufferSize()
00140     virtual void SetAutoFlushBound(size_t bound) =0;
00141 
00142 protected:
00143     virtual lword DoFlush(unsigned long maxTime, size_t targetSize) = 0;
00144 
00145     bool BlockedBySpeedLimit() const { return m_blockedBySpeedLimit; }
00146 
00147 private:
00148     bool m_blockedBySpeedLimit;
00149 };
00150 
00151 //! Network Sender
00152 class CRYPTOPP_NO_VTABLE NetworkSender : public Waitable
00153 {
00154 public:
00155     virtual bool MustWaitToSend() {return false;}
00156     virtual bool MustWaitForResult() {return false;}
00157     virtual void Send(const byte* buf, size_t bufLen) =0;
00158     virtual unsigned int GetSendResult() =0;
00159     virtual bool MustWaitForEof() {return false;}
00160     virtual void SendEof() =0;
00161     virtual bool EofSent() {return false;}  // implement if MustWaitForEof() == true
00162 };
00163 
00164 //! Network Source
00165 class CRYPTOPP_NO_VTABLE NetworkSource : public NonblockingSource
00166 {
00167 public:
00168     NetworkSource(BufferedTransformation *attachment);
00169 
00170     unsigned int GetMaxWaitObjectCount() const;
00171     void GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack);
00172 
00173     bool SourceExhausted() const {return m_dataBegin == m_dataEnd && GetReceiver().EofReceived();}
00174 
00175 protected:
00176     size_t DoPump(lword &byteCount, bool blockingOutput, unsigned long maxTime, bool checkDelimiter, byte delimiter);
00177 
00178     virtual NetworkReceiver & AccessReceiver() =0;
00179     const NetworkReceiver & GetReceiver() const {return const_cast<NetworkSource *>(this)->AccessReceiver();}
00180 
00181 private:
00182     SecByteBlock m_buf;
00183     size_t m_putSize, m_dataBegin, m_dataEnd;
00184     bool m_waitingForResult, m_outputBlocked;
00185 };
00186 
00187 //! Network Sink
00188 class CRYPTOPP_NO_VTABLE NetworkSink : public NonblockingSink
00189 {
00190 public:
00191     NetworkSink(unsigned int maxBufferSize, unsigned int autoFlushBound);
00192 
00193     unsigned int GetMaxWaitObjectCount() const;
00194     void GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack);
00195 
00196     size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking);
00197 
00198     void SetMaxBufferSize(size_t maxBufferSize) {m_maxBufferSize = maxBufferSize; m_buffer.SetNodeSize(UnsignedMin(maxBufferSize, 16U*1024U+256U));}
00199     void SetAutoFlushBound(size_t bound) {m_autoFlushBound = bound;}
00200 
00201     size_t GetMaxBufferSize() const {return m_maxBufferSize;}
00202     size_t GetCurrentBufferSize() const {return (size_t)m_buffer.CurrentSize();}
00203 
00204     void ClearBuffer() { m_buffer.Clear(); }
00205 
00206     bool EofPending() const { return m_eofState > EOF_NONE && m_eofState < EOF_DONE; }
00207 
00208     //! compute the current speed of this sink in bytes per second
00209     float ComputeCurrentSpeed();
00210     //! get the maximum observed speed of this sink in bytes per second
00211     float GetMaxObservedSpeed() const;
00212 
00213 protected:
00214     lword DoFlush(unsigned long maxTime, size_t targetSize);
00215 
00216     virtual NetworkSender & AccessSender() =0;
00217     const NetworkSender & GetSender() const {return const_cast<NetworkSink *>(this)->AccessSender();}
00218 
00219 private:
00220     enum EofState { EOF_NONE, EOF_PENDING_SEND, EOF_PENDING_DELIVERY, EOF_DONE };
00221 
00222     size_t m_maxBufferSize, m_autoFlushBound;
00223     bool m_needSendResult, m_wasBlocked;
00224     EofState m_eofState;
00225     ByteQueue m_buffer;
00226     size_t m_skipBytes;
00227     Timer m_speedTimer;
00228     float m_byteCountSinceLastTimerReset, m_currentSpeed, m_maxObservedSpeed;
00229 };
00230 
00231 NAMESPACE_END
00232 
00233 #endif  // #ifdef HIGHRES_TIMER_AVAILABLE
00234 
00235 #endif