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