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