1#ifndef CRYPTOPP_WAIT_H
2#define CRYPTOPP_WAIT_H
3
4#include "config.h"
5
6#ifdef SOCKETS_AVAILABLE
7
8#include "misc.h"
9#include "cryptlib.h"
10#include <vector>
11
12#ifdef USE_WINDOWS_STYLE_SOCKETS
13#include <winsock2.h>
14#else
15#include <sys/types.h>
16#endif
17
18#include "hrtimer.h"
19
20NAMESPACE_BEGIN(CryptoPP)
21
22class Tracer
23{
24public:
25	Tracer(unsigned int level) : m_level(level) {}
26	virtual ~Tracer() {}
27
28protected:
29	//! Override this in your most-derived tracer to do the actual tracing.
30	virtual void Trace(unsigned int n, std::string const& s) = 0;
31
32	/*! By default, tracers will decide which trace messages to trace according to a trace level
33		mechanism. If your most-derived tracer uses a different mechanism, override this to
34		return false. If this method returns false, the default TraceXxxx(void) methods will all
35		return 0 and must be overridden explicitly by your tracer for trace messages you want. */
36	virtual bool UsingDefaults() const { return true; }
37
38protected:
39	unsigned int m_level;
40
41	void TraceIf(unsigned int n, std::string const&s)
42		{ if (n) Trace(n, s); }
43
44	/*! Returns nr if, according to the default log settings mechanism (using log levels),
45	    the message should be traced. Returns 0 if the default trace level mechanism is not
46		in use, or if it is in use but the event should not be traced. Provided as a utility
47		method for easier and shorter coding of default TraceXxxx(void) implementations. */
48	unsigned int Tracing(unsigned int nr, unsigned int minLevel) const
49		{ return (UsingDefaults() && m_level >= minLevel) ? nr : 0; }
50};
51
52// Your Tracer-derived class should inherit as virtual public from Tracer or another
53// Tracer-derived class, and should pass the log level in its constructor. You can use the
54// following methods to begin and end your Tracer definition.
55
56// This constructor macro initializes Tracer directly even if not derived directly from it;
57// this is intended, virtual base classes are always initialized by the most derived class.
58#define CRYPTOPP_TRACER_CONSTRUCTOR(DERIVED) \
59	public: DERIVED(unsigned int level = 0) : Tracer(level) {}
60
61#define CRYPTOPP_BEGIN_TRACER_CLASS_1(DERIVED, BASE1) \
62	class DERIVED : virtual public BASE1 { CRYPTOPP_TRACER_CONSTRUCTOR(DERIVED)
63
64#define CRYPTOPP_BEGIN_TRACER_CLASS_2(DERIVED, BASE1, BASE2) \
65	class DERIVED : virtual public BASE1, virtual public BASE2 { CRYPTOPP_TRACER_CONSTRUCTOR(DERIVED)
66
67#define CRYPTOPP_END_TRACER_CLASS };
68
69// In your Tracer-derived class, you should define a globally unique event number for each
70// new event defined. This can be done using the following macros.
71
72#define CRYPTOPP_BEGIN_TRACER_EVENTS(UNIQUENR)	enum { EVENTBASE = UNIQUENR,
73#define CRYPTOPP_TRACER_EVENT(EVENTNAME)				EventNr_##EVENTNAME,
74#define CRYPTOPP_END_TRACER_EVENTS				};
75
76// In your own Tracer-derived class, you must define two methods per new trace event type:
77// - unsigned int TraceXxxx() const
78//   Your default implementation of this method should return the event number if according
79//   to the default trace level system the event should be traced, or 0 if it should not.
80// - void TraceXxxx(string const& s)
81//   This method should call TraceIf(TraceXxxx(), s); to do the tracing.
82// For your convenience, a macro to define these two types of methods are defined below.
83// If you use this macro, you should also use the TRACER_EVENTS macros above to associate
84// event names with numbers.
85
86#define CRYPTOPP_TRACER_EVENT_METHODS(EVENTNAME, LOGLEVEL) \
87	virtual unsigned int Trace##EVENTNAME() const { return Tracing(EventNr_##EVENTNAME, LOGLEVEL); } \
88	virtual void Trace##EVENTNAME(std::string const& s) { TraceIf(Trace##EVENTNAME(), s); }
89
90
91/*! A simple unidirectional linked list with m_prev == 0 to indicate the final entry.
92    The aim of this implementation is to provide a very lightweight and practical
93	tracing mechanism with a low performance impact. Functions and methods supporting
94	this call-stack mechanism would take a parameter of the form "CallStack const& callStack",
95	and would pass this parameter to subsequent functions they call using the construct:
96
97	SubFunc(arg1, arg2, CallStack("my func at place such and such", &callStack));
98
99	The advantage of this approach is that it is easy to use and should be very efficient,
100	involving no allocation from the heap, just a linked list of stack objects containing
101	pointers to static ASCIIZ strings (or possibly additional but simple data if derived). */
102class CallStack
103{
104public:
105	CallStack(char const* i, CallStack const* p) : m_info(i), m_prev(p) {}
106	CallStack const* Prev() const { return m_prev; }
107	virtual std::string Format() const;
108
109protected:
110	char const* m_info;
111	CallStack const* m_prev;
112};
113
114/*! An extended CallStack entry type with an additional numeric parameter. */
115class CallStackWithNr : public CallStack
116{
117public:
118	CallStackWithNr(char const* i, word32 n, CallStack const* p) : CallStack(i, p), m_nr(n) {}
119	std::string Format() const;
120
121protected:
122	word32 m_nr;
123};
124
125/*! An extended CallStack entry type with an additional string parameter. */
126class CallStackWithStr : public CallStack
127{
128public:
129	CallStackWithStr(char const* i, char const* z, CallStack const* p) : CallStack(i, p), m_z(z) {}
130	std::string Format() const;
131
132protected:
133	char const* m_z;
134};
135
136CRYPTOPP_BEGIN_TRACER_CLASS_1(WaitObjectsTracer, Tracer)
137	CRYPTOPP_BEGIN_TRACER_EVENTS(0x48752841)
138		CRYPTOPP_TRACER_EVENT(NoWaitLoop)
139	CRYPTOPP_END_TRACER_EVENTS
140	CRYPTOPP_TRACER_EVENT_METHODS(NoWaitLoop, 1)
141CRYPTOPP_END_TRACER_CLASS
142
143struct WaitingThreadData;
144
145//! container of wait objects
146class WaitObjectContainer : public NotCopyable
147{
148public:
149	//! exception thrown by WaitObjectContainer
150	class Err : public Exception
151	{
152	public:
153		Err(const std::string& s) : Exception(IO_ERROR, s) {}
154	};
155
156	static unsigned int MaxWaitObjects();
157
158	WaitObjectContainer(WaitObjectsTracer* tracer = 0);
159
160	void Clear();
161	void SetNoWait(CallStack const& callStack);
162	void ScheduleEvent(double milliseconds, CallStack const& callStack);
163	// returns false if timed out
164	bool Wait(unsigned long milliseconds);
165
166#ifdef USE_WINDOWS_STYLE_SOCKETS
167	~WaitObjectContainer();
168	void AddHandle(HANDLE handle, CallStack const& callStack);
169#else
170	void AddReadFd(int fd, CallStack const& callStack);
171	void AddWriteFd(int fd, CallStack const& callStack);
172#endif
173
174private:
175	WaitObjectsTracer* m_tracer;
176
177#ifdef USE_WINDOWS_STYLE_SOCKETS
178	void CreateThreads(unsigned int count);
179	std::vector<HANDLE> m_handles;
180	std::vector<WaitingThreadData *> m_threads;
181	HANDLE m_startWaiting;
182	HANDLE m_stopWaiting;
183#else
184	fd_set m_readfds, m_writefds;
185	int m_maxFd;
186#endif
187	bool m_noWait;
188	double m_firstEventTime;
189	Timer m_eventTimer;
190
191#ifdef USE_WINDOWS_STYLE_SOCKETS
192	typedef size_t LastResultType;
193#else
194	typedef int LastResultType;
195#endif
196	enum { LASTRESULT_NOWAIT = -1, LASTRESULT_SCHEDULED = -2, LASTRESULT_TIMEOUT = -3 };
197	LastResultType m_lastResult;
198	unsigned int m_sameResultCount;
199	Timer m_noWaitTimer;
200	void SetLastResult(LastResultType result);
201	void DetectNoWait(LastResultType result, CallStack const& callStack);
202};
203
204NAMESPACE_END
205
206#endif
207
208#endif
209