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