1 // mqueue.h - originally written and placed in the public domain by Wei Dai
2 
3 /// \file
4 /// \brief Classes for an unlimited queue to store messages
5 
6 #ifndef CRYPTOPP_MQUEUE_H
7 #define CRYPTOPP_MQUEUE_H
8 
9 #include "cryptlib.h"
10 #include "queue.h"
11 #include "filters.h"
12 #include "misc.h"
13 
14 #include <deque>
15 
NAMESPACE_BEGIN(CryptoPP)16 NAMESPACE_BEGIN(CryptoPP)
17 
18 /// \brief Data structure used to store messages
19 /// \details The queue is implemented with a ByteQueue.
20 /// \sa <A HREF="https://www.cryptopp.com/wiki/MessageQueue">MessageQueue</A>
21 ///  on the Crypto++ wiki.
22 /// \since Crypto++ 2.0
23 class CRYPTOPP_DLL MessageQueue : public AutoSignaling<BufferedTransformation>
24 {
25 public:
26 	virtual ~MessageQueue() {}
27 
28 	/// \brief Construct a MessageQueue
29 	/// \param nodeSize the initial node size
30 	MessageQueue(unsigned int nodeSize=256);
31 
32 	// BufferedTransformation
33 	void IsolatedInitialize(const NameValuePairs &parameters)
34 		{m_queue.IsolatedInitialize(parameters); m_lengths.assign(1, 0U); m_messageCounts.assign(1, 0U);}
35 	size_t Put2(const byte *begin, size_t length, int messageEnd, bool blocking)
36 	{
37 		CRYPTOPP_UNUSED(blocking);
38 		m_queue.Put(begin, length);
39 		m_lengths.back() += length;
40 		if (messageEnd)
41 		{
42 			m_lengths.push_back(0);
43 			m_messageCounts.back()++;
44 		}
45 		return 0;
46 	}
47 	bool IsolatedFlush(bool hardFlush, bool blocking)
48 		{CRYPTOPP_UNUSED(hardFlush), CRYPTOPP_UNUSED(blocking); return false;}
49 	bool IsolatedMessageSeriesEnd(bool blocking)
50 		{CRYPTOPP_UNUSED(blocking); m_messageCounts.push_back(0); return false;}
51 
52 	lword MaxRetrievable() const
53 		{return m_lengths.front();}
54 	bool AnyRetrievable() const
55 		{return m_lengths.front() > 0;}
56 
57 	size_t TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true);
58 	size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const;
59 
60 	lword TotalBytesRetrievable() const
61 		{return m_queue.MaxRetrievable();}
62 	unsigned int NumberOfMessages() const
63 		{return (unsigned int)m_lengths.size()-1;}
64 	bool GetNextMessage();
65 
66 	unsigned int NumberOfMessagesInThisSeries() const
67 		{return m_messageCounts[0];}
68 	unsigned int NumberOfMessageSeries() const
69 		{return (unsigned int)m_messageCounts.size()-1;}
70 
71 	/// \brief Copy messages from this object to another BufferedTransformation.
72 	/// \param target the destination BufferedTransformation
73 	/// \param count the number of messages to copy
74 	/// \param channel the channel on which the transfer should occur
75 	/// \return the number of messages that remain in the copy (i.e., messages not copied)
76 	unsigned int CopyMessagesTo(BufferedTransformation &target, unsigned int count=UINT_MAX, const std::string &channel=DEFAULT_CHANNEL) const;
77 
78 	/// \brief Peek data in the queue
79 	/// \param contiguousSize the size of the data
80 	/// \details Spy() peeks at data at the head of the queue. Spy() does
81 	///  not remove data from the queue.
82 	/// \details The data's size is returned in <tt>contiguousSize</tt>.
83 	///  Spy() returns the size of the first message in the list.
84 	const byte * Spy(size_t &contiguousSize) const;
85 
86 	/// \brief Swap contents with another MessageQueue
87 	/// \param rhs the other MessageQueue
88 	void swap(MessageQueue &rhs);
89 
90 private:
91 	ByteQueue m_queue;
92 	std::deque<lword> m_lengths;
93 	std::deque<unsigned int> m_messageCounts;
94 };
95 
96 /// \brief Filter that checks messages on two channels for equality
97 class CRYPTOPP_DLL EqualityComparisonFilter : public Unflushable<Multichannel<Filter> >
98 {
99 public:
100 	/// \brief Different messages were detected
101 	struct MismatchDetected : public Exception
102 	{
103 		/// \brief Construct a MismatchDetected exception
MismatchDetectedMismatchDetected104 		MismatchDetected() : Exception(DATA_INTEGRITY_CHECK_FAILED, "EqualityComparisonFilter: did not receive the same data on two channels") {}
105 	};
106 
107 	/// \brief Construct an EqualityComparisonFilter
108 	/// \param attachment an attached transformation
109 	/// \param throwIfNotEqual flag indicating whether the objects throws
110 	/// \param firstChannel string naming the first channel
111 	/// \param secondChannel string naming the second channel
112 	/// \throw MismatchDetected if throwIfNotEqual is true and not equal
113 	/// \details If throwIfNotEqual is false, this filter will output a '\\0'
114 	///  byte when it detects a mismatch, '\\1' otherwise.
115 	EqualityComparisonFilter(BufferedTransformation *attachment=NULLPTR, bool throwIfNotEqual=true, const std::string &firstChannel="0", const std::string &secondChannel="1")
m_throwIfNotEqual(throwIfNotEqual)116 		: m_throwIfNotEqual(throwIfNotEqual), m_mismatchDetected(false)
117 		, m_firstChannel(firstChannel), m_secondChannel(secondChannel)
118 		{Detach(attachment);}
119 
120 	// BufferedTransformation
121 	size_t ChannelPut2(const std::string &channel, const byte *begin, size_t length, int messageEnd, bool blocking);
122 	bool ChannelMessageSeriesEnd(const std::string &channel, int propagation=-1, bool blocking=true);
123 
124 protected:
125 	unsigned int MapChannel(const std::string &channel) const;
126 	bool HandleMismatchDetected(bool blocking);
127 
128 private:
129 	bool m_throwIfNotEqual, m_mismatchDetected;
130 	std::string m_firstChannel, m_secondChannel;
131 	MessageQueue m_q[2];
132 };
133 
134 NAMESPACE_END
135 
136 #ifndef __BORLANDC__
NAMESPACE_BEGIN(std)137 NAMESPACE_BEGIN(std)
138 template<> inline void swap(CryptoPP::MessageQueue &a, CryptoPP::MessageQueue &b)
139 {
140 	a.swap(b);
141 }
142 NAMESPACE_END
143 #endif
144 
145 #endif
146