/** * yateclass.h * This file is part of the YATE Project http://YATE.null.ro * * Base classes and types, not related to the engine or telephony * * Yet Another Telephony Engine - a fully featured software PBX and IVR * Copyright (C) 2004-2014 Null Team * * This software is distributed under multiple licenses; * see the COPYING file in the main directory for licensing * information for this specific distribution. * * This use of this software may be subject to additional restrictions. * See the LEGAL file in the main directory for details. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ #ifndef __YATECLASS_H #define __YATECLASS_H #ifndef __cplusplus #error C++ is required #endif #include #include #include #include #include #include #ifndef _WORDSIZE #if defined(__arch64__) || defined(__x86_64__) \ || defined(__amd64__) || defined(__ia64__) \ || defined(__alpha__) || defined(__sparcv9) || defined(__mips64) #define _WORDSIZE 64 #else #define _WORDSIZE 32 #endif #endif #ifndef _WINDOWS #if defined(WIN32) || defined(_WIN32) #define _WINDOWS #endif #endif #ifdef _WINDOWS #include #include #include /** * Windows definitions for commonly used types */ typedef signed __int8 int8_t; typedef unsigned __int8 u_int8_t; typedef unsigned __int8 uint8_t; typedef signed __int16 int16_t; typedef unsigned __int16 u_int16_t; typedef unsigned __int16 uint16_t; typedef signed __int32 int32_t; typedef unsigned __int32 u_int32_t; typedef unsigned __int32 uint32_t; typedef signed __int64 int64_t; typedef unsigned __int64 u_int64_t; typedef unsigned __int64 uint64_t; typedef int pid_t; typedef int socklen_t; typedef unsigned long in_addr_t; #ifndef strcasecmp #define strcasecmp _stricmp #endif #ifndef strncasecmp #define strncasecmp _strnicmp #endif #define vsnprintf _vsnprintf #define snprintf _snprintf #define strdup _strdup #define strtoll _strtoi64 #define strtoull _strtoui64 #define open _open #define dup2 _dup2 #define read _read #define write _write #define close _close #define getpid _getpid #define chdir _chdir #define mkdir(p,m) _mkdir(p) #define unlink _unlink #define llabs _abs64 #define O_RDWR _O_RDWR #define O_RDONLY _O_RDONLY #define O_WRONLY _O_WRONLY #define O_APPEND _O_APPEND #define O_BINARY _O_BINARY #define O_EXCL _O_EXCL #define O_CREAT _O_CREAT #define O_TRUNC _O_TRUNC #define O_NOCTTY 0 #define S_IRUSR _S_IREAD #define S_IWUSR _S_IWRITE #define S_IXUSR 0 #define S_IRWXU (_S_IREAD|_S_IWRITE) #ifdef LIBYATE_EXPORTS #define YATE_API __declspec(dllexport) #else #ifndef LIBYATE_STATIC #define YATE_API __declspec(dllimport) #endif #endif #define FMT64 "%I64d" #define FMT64U "%I64u" #else /* _WINDOWS */ #include #include #if defined(__FreeBSD__) #include #endif #include #include #include #include #include /** * Non-Windows definitions for commonly used types */ #ifndef SOCKET typedef int SOCKET; #endif #ifndef HANDLE typedef int HANDLE; #endif #ifndef O_BINARY #define O_BINARY 0 #endif #if _WORDSIZE == 64 && !defined(__APPLE__) #define FMT64 "%ld" #define FMT64U "%lu" #else #define FMT64 "%lld" #define FMT64U "%llu" #endif #endif /* ! _WINDOWS */ #ifndef LLONG_MAX #ifdef _I64_MAX #define LLONG_MAX _I64_MAX #else #define LLONG_MAX 9223372036854775807LL #endif #endif #ifndef LLONG_MIN #ifdef _I64_MIN #define LLONG_MIN _I64_MIN #else #define LLONG_MIN (-LLONG_MAX - 1LL) #endif #endif #ifndef ULLONG_MAX #ifdef _UI64_MAX #define ULLONG_MAX _UI64_MAX #else #define ULLONG_MAX 18446744073709551615ULL #endif #endif #ifndef O_LARGEFILE #define O_LARGEFILE 0 #endif #ifndef IPTOS_LOWDELAY #define IPTOS_LOWDELAY 0x10 #define IPTOS_THROUGHPUT 0x08 #define IPTOS_RELIABILITY 0x04 #endif #ifndef IPTOS_MINCOST #define IPTOS_MINCOST 0x02 #endif #ifndef IPPROTO_SCTP #define IPPROTO_SCTP 132 #endif #ifndef YATE_API #define YATE_API #endif #ifdef _WINDOWS #undef RAND_MAX #define RAND_MAX 2147483647 #endif /** * Holds all Telephony Engine related classes. */ namespace TelEngine { #ifdef HAVE_GCC_FORMAT_CHECK #define FORMAT_CHECK(f) __attribute__((format(printf,(f),(f)+1))) #else #define FORMAT_CHECK(f) #endif #define YIGNORE(v) while (v) { break; } #ifdef HAVE_BLOCK_RETURN #define YSTRING(s) (*({static const String str("" s);&str;})) #define YATOM(s) (*({static const String* str(0);str ? str : String::atom(str,"" s);})) #else #define YSTRING(s) ("" s) #define YATOM(s) ("" s) #endif #define YSTRING_INIT_HASH ((unsigned) -1) /** * Abort execution (and coredump if allowed) if the abort flag is set. * This function may not return. */ YATE_API void abortOnBug(); /** * Set the abort on bug flag. The default flag state is false. * @return The old state of the flag. */ YATE_API bool abortOnBug(bool doAbort); /** * Standard debugging levels. * The DebugFail level is special - it is always displayed and may abort * the program if @ref abortOnBug() is set. */ enum DebugLevel { DebugFail = 0, DebugTest = 1, DebugCrit = 2, DebugGoOn = DebugCrit, DebugConf = 3, DebugStub = 4, DebugWarn = 5, DebugMild = 6, DebugNote = 7, DebugCall = 8, DebugInfo = 9, DebugAll = 10 }; /** * Retrieve the current global debug level * @return The current global debug level */ YATE_API int debugLevel(); /** * Set the current global debug level. * @param level The desired debug level * @return The new global debug level (may be different) */ YATE_API int debugLevel(int level); /** * Check if debugging output should be generated * @param level The global debug level we are testing * @return True if messages should be output, false otherwise */ YATE_API bool debugAt(int level); /** * Get an ANSI string to colorize debugging output * @param level The debug level who's color is requested. * Negative or out of range will reset to the default color * @return ANSI string that sets color corresponding to level */ YATE_API const char* debugColor(int level); /** * Get the name of a debugging or alarm level * @param level The debug level * @return Short C string describing the level */ YATE_API const char* debugLevelName(int level); /** * Holds a local debugging level that can be modified separately from the * global debugging * @short A holder for a debug level */ class YATE_API DebugEnabler { public: /** * Constructor * @param level The initial local debug level * @param enabled Enable debugging on this object */ inline DebugEnabler(int level = TelEngine::debugLevel(), bool enabled = true) : m_level(DebugFail), m_enabled(enabled), m_chain(0), m_name(0) { debugLevel(level); } inline ~DebugEnabler() { m_name = 0; m_chain = 0; } /** * Retrieve the current local debug level * @return The current local debug level */ inline int debugLevel() const { return m_chain ? m_chain->debugLevel() : m_level; } /** * Set the current local debug level. * @param level The desired debug level * @return The new debug level (may be different) */ int debugLevel(int level); /** * Retrieve the current debug activation status * @return True if local debugging is enabled */ inline bool debugEnabled() const { return m_chain ? m_chain->debugEnabled() : m_enabled; } /** * Set the current debug activation status * @param enable The new debug activation status, true to enable */ inline void debugEnabled(bool enable) { m_enabled = enable; m_chain = 0; } /** * Get the current debug name * @return Name of the debug activation if set or NULL */ inline const char* debugName() const { return m_name; } /** * Check if debugging output should be generated * @param level The debug level we are testing * @return True if messages should be output, false otherwise */ bool debugAt(int level) const; /** * Check if this enabler is chained to another one * @return True if local debugging is chained to other enabler */ inline bool debugChained() const { return m_chain != 0; } /** * Chain this debug holder to a parent or detach from existing one * @param chain Pointer to parent debug level, NULL to detach */ inline void debugChain(const DebugEnabler* chain = 0) { m_chain = (chain != this) ? chain : 0; } /** * Copy debug settings from another object or from engine globals * @param original Pointer to a DebugEnabler to copy settings from */ void debugCopy(const DebugEnabler* original = 0); protected: /** * Set the current debug name * @param name Static debug name or NULL */ inline void debugName(const char* name) { m_name = name; } private: int m_level; bool m_enabled; const DebugEnabler* m_chain; const char* m_name; }; #if 0 /* for documentation generator */ /** * Convenience macro. * Does the same as @ref Debug if DEBUG is \#defined (compiling for debugging) * else it does not get compiled at all. */ void DDebug(int level, const char* format, ...); /** * Convenience macro. * Does the same as @ref Debug if DEBUG is \#defined (compiling for debugging) * else it does not get compiled at all. */ void DDebug(const char* facility, int level, const char* format, ...); /** * Convenience macro. * Does the same as @ref Debug if DEBUG is \#defined (compiling for debugging) * else it does not get compiled at all. */ void DDebug(const DebugEnabler* local, int level, const char* format, ...); /** * Convenience macro. * Does the same as @ref Debug if XDEBUG is \#defined (compiling for extra * debugging) else it does not get compiled at all. */ void XDebug(int level, const char* format, ...); /** * Convenience macro. * Does the same as @ref Debug if XDEBUG is \#defined (compiling for extra * debugging) else it does not get compiled at all. */ void XDebug(const char* facility, int level, const char* format, ...); /** * Convenience macro. * Does the same as @ref Debug if XDEBUG is \#defined (compiling for extra * debugging) else it does not get compiled at all. */ void XDebug(const DebugEnabler* local, int level, const char* format, ...); /** * Convenience macro. * Does the same as @ref Debug if NDEBUG is not \#defined * else it does not get compiled at all (compiling for mature release). */ void NDebug(int level, const char* format, ...); /** * Convenience macro. * Does the same as @ref Debug if NDEBUG is not \#defined * else it does not get compiled at all (compiling for mature release). */ void NDebug(const char* facility, int level, const char* format, ...); /** * Convenience macro. * Does the same as @ref Debug if NDEBUG is not \#defined * else it does not get compiled at all (compiling for mature release). */ void NDebug(const DebugEnabler* local, int level, const char* format, ...); #endif #if defined(_DEBUG) || defined(DEBUG) || defined(XDEBUG) #undef DEBUG #define DEBUG 1 #endif #ifdef DEBUG #define DDebug Debug #else #ifdef _WINDOWS #define DDebug do { break; } while #else #define DDebug(arg...) #endif #endif #ifdef XDEBUG #define XDebug Debug #else #ifdef _WINDOWS #define XDebug do { break; } while #else #define XDebug(arg...) #endif #endif #ifndef NDEBUG #define NDebug Debug #else #ifdef _WINDOWS #define NDebug do { break; } while #else #define NDebug(arg...) #endif #endif /** * Outputs a debug string. * @param level The level of the message * @param format A printf() style format string */ YATE_API void Debug(int level, const char* format, ...) FORMAT_CHECK(2); /** * Outputs a debug string for a specific facility. * @param facility Facility that outputs the message * @param level The level of the message * @param format A printf() style format string */ YATE_API void Debug(const char* facility, int level, const char* format, ...) FORMAT_CHECK(3); /** * Outputs a debug string for a specific facility. * @param local Pointer to a DebugEnabler holding current debugging settings * @param level The level of the message * @param format A printf() style format string */ YATE_API void Debug(const DebugEnabler* local, int level, const char* format, ...) FORMAT_CHECK(3); /** * Outputs a debug string and emits an alarm if a callback is installed * @param component Component that emits the alarm * @param level The level of the alarm * @param format A printf() style format string */ YATE_API void Alarm(const char* component, int level, const char* format, ...) FORMAT_CHECK(3); /** * Outputs a debug string and emits an alarm if a callback is installed * @param component Pointer to a DebugEnabler holding component name and debugging settings * @param level The level of the alarm * @param format A printf() style format string */ YATE_API void Alarm(const DebugEnabler* component, int level, const char* format, ...) FORMAT_CHECK(3); /** * Outputs a debug string and emits an alarm if a callback is installed * @param component Component that emits the alarm * @param info Extra alarm information * @param level The level of the alarm * @param format A printf() style format string */ YATE_API void Alarm(const char* component, const char* info, int level, const char* format, ...) FORMAT_CHECK(4); /** * Outputs a debug string and emits an alarm if a callback is installed * @param component Pointer to a DebugEnabler holding component name and debugging settings * @param info Extra alarm information * @param level The level of the alarm * @param format A printf() style format string */ YATE_API void Alarm(const DebugEnabler* component, const char* info, int level, const char* format, ...) FORMAT_CHECK(4); /** * Outputs a string to the debug console with formatting * @param format A printf() style format string */ YATE_API void Output(const char* format, ...) FORMAT_CHECK(1); /** * Outputs a debug string with a trace ID. * @param traceId The trace ID associated with this message * @param level The level of the message * @param format A printf() style format string */ YATE_API void TraceDebug(const char* traceId, int level, const char* format, ...) FORMAT_CHECK(3); /** * Outputs a debug string with a trace ID. * @param traceId The trace ID associated with this message * @param facility Facility that outputs the message * @param level The level of the message * @param format A printf() style format string */ YATE_API void TraceDebug(const char* traceId, const char* facility, int level, const char* format, ...) FORMAT_CHECK(4); /** * Outputs a debug string with a trace ID. * @param traceId The trace ID associated with this message * @param local Pointer to a DebugEnabler holding current debugging settings * @param level The level of the message * @param format A printf() style format string */ YATE_API void TraceDebug(const char* traceId, const DebugEnabler* local, int level, const char* format, ...) FORMAT_CHECK(4); #if 0 /* for documentation generator */ /** * Outputs a debug string with a trace ID. * @param obj Object from where to get trace ID * @param level The level of the message * @param format A printf() style format string */ void TraceDebugObj(GenObject* obj, int level, const char* format, ...); /** * Outputs a debug string with a trace ID. * @param obj Object from where to get trace ID * @param facility Facility that outputs the message * @param level The level of the message * @param format A printf() style format string */ void TraceDebugObj(GenObject* obj, const char* facility, int level, const char* format, ...); /** * Outputs a debug string with a trace ID. * @param obj Object from where to get trace ID * @param local Pointer to a DebugEnabler holding current debugging settings * @param level The level of the message * @param format A printf() style format string */ void TraceDebugObj(GenObject* obj, const DebugEnabler* local, int level, const char* format, ...); /** * Outputs a debug string only if trace ID is valid. * @param obj Object from where to get trace ID * @param level The level of the message * @param format A printf() style format string */ void Trace(GenObject* obj, int level, const char* format, ...); /** * Outputs a debug string only if trace ID is valid. * @param obj Object from where to get trace ID * @param facility Facility that outputs the message * @param level The level of the message * @param format A printf() style format string */ void Trace(GenObject* obj, const char* facility, int level, const char* format, ...); /** * Outputs a debug string only if trace ID is valid. * @param obj Object from where to get trace ID * @param local Pointer to a DebugEnabler holding current debugging settings * @param level The level of the message * @param format A printf() style format string */ void Trace(GenObject* obj, const DebugEnabler* local, int level, const char* format, ...); /** * Outputs a debug string only if trace ID is valid. * @param obj Object from where to get trace ID * @param level The level of the message * @param format A printf() style format string */ void TraceObj(GenObject* obj, int level, const char* format, ...); /** * Outputs a debug string only if trace ID is valid. * @param obj Object from where to get trace ID * @param facility Facility that outputs the message * @param level The level of the message * @param format A printf() style format string */ void TraceObj(GenObject* obj, const char* facility, int level, const char* format, ...); /** * Outputs a debug string only if trace ID is valid. * @param obj Object from where to get trace ID * @param local Pointer to a DebugEnabler holding current debugging settings * @param level The level of the message * @param format A printf() style format string */ void TraceObj(GenObject* obj, const DebugEnabler* local, int level, const char* format, ...); #endif #define TraceDebugObj(pGenObj,...) \ TraceDebug((!!(pGenObj)) ? (pGenObj)->traceId() : "",##__VA_ARGS__) #define Trace(traceId,...) \ do { if (!TelEngine::null(traceId)) TraceDebug(traceId,##__VA_ARGS__); } while(false) #define TraceObj(pGenObj,...) \ do { if (!!(pGenObj) && (pGenObj)->traceId()) TraceDebug((pGenObj)->traceId(),##__VA_ARGS__); } while (false) /** * Outputs a debug string with trace ID and emits an alarm if a callback is installed * @param traceId The trace ID associated with this message * @param component Component that emits the alarm * @param info Extra alarm information * @param level The level of the alarm * @param format A printf() style format string */ YATE_API void TraceAlarm(const char* traceId, const char* component, int level, const char* format, ...) FORMAT_CHECK(4); /** * Outputs a debug string with trace ID and emits an alarm if a callback is installed * @param traceId The trace ID associated with this message * @param component Pointer to a DebugEnabler holding component name and debugging settings * @param level The level of the alarm * @param format A printf() style format string */ YATE_API void TraceAlarm(const char* traceId, const DebugEnabler* component, int level, const char* format, ...) FORMAT_CHECK(4); /** * Outputs a debug string with trace ID and emits an alarm if a callback is installed * @param traceId The trace ID associated with this message * @param component Component that emits the alarm * @param info Extra alarm information * @param level The level of the alarm * @param format A printf() style format string */ YATE_API void TraceAlarm(const char* traceId, const char* component, const char* info, int level, const char* format, ...) FORMAT_CHECK(5); /** * Outputs a debug string with trace ID and emits an alarm if a callback is installed * @param traceId The trace ID associated with this message * @param component Pointer to a DebugEnabler holding component name and debugging settings * @param info Extra alarm information * @param level The level of the alarm * @param format A printf() style format string */ YATE_API void TraceAlarm(const char* traceId, const DebugEnabler* component, const char* info, int level, const char* format, ...) FORMAT_CHECK(5); /** * This class is used as an automatic variable that logs messages on creation * and destruction (when the instruction block is left or function returns). * IMPORTANT: the name is not copied so it should best be static. * @short An object that logs messages on creation and destruction */ class YATE_API Debugger { public: /** * Timestamp formatting */ enum Formatting { None = 0, Relative, // from program start Absolute, // from EPOCH (1-1-1970) Textual, // absolute GMT in YYYYMMDDhhmmss.uuuuuu format TextLocal, // local time in YYYYMMDDhhmmss.uuuuuu format TextSep, // absolute GMT in YYYY-MM-DD_hh:mm:ss.uuuuuu format TextLSep, // local time in YYYY-MM-DD_hh:mm:ss.uuuuuu format }; /** * The constructor prints the method entry message and indents. * @param name Name of the function or block entered, must be static * @param format printf() style format string */ explicit Debugger(const char* name, const char* format = 0, ...); /** * The constructor prints the method entry message and indents. * @param level The level of the message * @param name Name of the function or block entered, must be static * @param format printf() style format string */ Debugger(int level, const char* name, const char* format = 0, ...); /** * The destructor prints the method leave message and deindents. */ ~Debugger(); /** * Set the output callback * @param outFunc Pointer to the output function, NULL to use stderr */ static void setOutput(void (*outFunc)(const char*,int) = 0); /** * Set the interactive output callback * @param outFunc Pointer to the output function, NULL to disable */ static void setIntOut(void (*outFunc)(const char*,int) = 0); /** * Set the alarm hook callback * @param alarmFunc Pointer to the alarm callback function, NULL to disable */ static void setAlarmHook(void (*alarmFunc)(const char*,int,const char*,const char*) = 0); /** * Set the relay hook callback that will process all Output, Debug and Alarm * @param relayFunc Pointer to the relay callback function, NULL to disable */ static void setRelayHook(void (*relayFunc)(int,const char*,const char*,const char*) = 0); /** * Enable or disable the debug output * @param enable Set to true to globally enable output * @param colorize Enable ANSI colorization of output */ static void enableOutput(bool enable = true, bool colorize = false); /** * Retrieve the start timestamp * @return Start timestamp value in seconds */ static uint32_t getStartTimeSec(); /** * Retrieve the format of timestamps * @return The current formatting type for timestamps */ static Formatting getFormatting(); /** * Set the format of timestamps on output messages and set the time start reference * @param format Desired timestamp formatting * @param startTimeSec Optional start timestamp (in seconds) */ static void setFormatting(Formatting format, uint32_t startTimeSec = 0); /** * Fill a buffer with a current timestamp prefix * @param buf Buffer to fill, must be at least 28 characters long * @param format Desired timestamp formatting * @return Length of the prefix written in buffer excluding final NUL */ static unsigned int formatTime(char* buf, Formatting format = getFormatting()); /** * Processes a preformatted string as Output, Debug or Alarm. * This method is intended to relay messages from other processes, DO NOT USE! * @param level The level of the debug or alarm, negative for an output * @param buffer Preformatted text buffer, MUST HAVE SPACE for at least strlen + 2 * @param component Component that emits the alarm if applicable * @param info Extra alarm information if applicable */ static void relayOutput(int level, char* buffer, const char* component = 0, const char* info = 0); private: const char* m_name; int m_level; }; /** * A structure to build (mainly static) Token-to-ID translation tables. * A table of such structures must end with an entry with a null token */ struct TokenDict { /** * Token to match */ const char* token; /** * Value the token translates to */ int value; }; /** * A structure to build (mainly static) Token-to-ID translation tables. * Value is 64bit integer. * A table of such structures must end with an entry with a null token */ struct TokenDict64 { /** * Token to match */ const char* token; /** * Value the token translates to */ int64_t value; }; class String; class DataBlock; class Mutex; class ObjList; class NamedCounter; #if 0 /* for documentation generator */ /** * Macro to ignore the result of a function * @param value Returned value to be ignored, must be interpretable as boolean */ void YIGNORE(primitive value); /** * Macro to create a local static String if supported by compiler, use with caution * @param string Literal constant string * @return A const String& if supported, literal string if not supported */ constant YSTRING(const char* string); /** * Macro to create a shared static String if supported by compiler, use with caution * @param string Literal constant string * @return A const String& if supported, literal string if not supported */ constant YATOM(const char* string); /** * Macro to create a GenObject class from a base class and implement @ref GenObject::getObject * @param type Class that is declared * @param base Base class that is inherited */ void YCLASS(class type,class base); /** * Macro to create a GenObject class from two base classes and implement @ref GenObject::getObject * @param type Class that is declared * @param base1 First base class that is inherited * @param base2 Second base class that is inherited */ void YCLASS2(class type,class base1,class base2); /** * Macro to create a GenObject class from three base classes and implement @ref GenObject::getObject * @param type Class that is declared * @param base1 First base class that is inherited * @param base2 Second base class that is inherited * @param base3 Third base class that is inherited */ void YCLASS3(class type,class base1,class base2,class base3); /** * Macro to implement @ref GenObject::getObject in a derived class * @param type Class that is declared * @param base Base class that is inherited */ void YCLASSIMP(class type,class base); /** * Macro to implement @ref GenObject::getObject in a derived class * @param type Class that is declared * @param base1 First base class that is inherited * @param base2 Second base class that is inherited */ void YCLASSIMP2(class type,class base1,class base2); /** * Macro to implement @ref GenObject::getObject in a derived class * @param type Class that is declared * @param base1 First base class that is inherited * @param base2 Second base class that is inherited * @param base3 Third base class that is inherited */ void YCLASSIMP3(class type,class base1,class base2,class base3); /** * Macro to retrieve a typed pointer to an interface from an object * @param type Class we want to return * @param pntr Pointer to the object we want to get the interface from * @return Pointer to the class we want or NULL */ class* YOBJECT(class type,GenObject* pntr); /** * Macro to disable automatic copy and assignment operators * @param type Class that is declared */ void YNOCOPY(class type); #endif #define YCLASS(type,base) \ public: virtual void* getObject(const String& name) const \ { return (name == YATOM(#type)) ? const_cast(this) : base::getObject(name); } #define YCLASS2(type,base1,base2) \ public: virtual void* getObject(const String& name) const \ { if (name == YATOM(#type)) return const_cast(this); \ void* tmp = base1::getObject(name); \ return tmp ? tmp : base2::getObject(name); } #define YCLASS3(type,base1,base2,base3) \ public: virtual void* getObject(const String& name) const \ { if (name == YATOM(#type)) return const_cast(this); \ void* tmp = base1::getObject(name); \ if (tmp) return tmp; \ tmp = base2::getObject(name); \ return tmp ? tmp : base3::getObject(name); } #define YCLASSIMP(type,base) \ void* type::getObject(const String& name) const \ { return (name == YATOM(#type)) ? const_cast(this) : base::getObject(name); } #define YCLASSIMP2(type,base1,base2) \ void* type::getObject(const String& name) const \ { if (name == YATOM(#type)) return const_cast(this); \ void* tmp = base1::getObject(name); \ return tmp ? tmp : base2::getObject(name); } #define YCLASSIMP3(type,base1,base2,base3) \ void* type::getObject(const String& name) const \ { if (name == YATOM(#type)) return const_cast(this); \ void* tmp = base1::getObject(name); \ if (tmp) return tmp; \ tmp = base2::getObject(name); \ return tmp ? tmp : base3::getObject(name); } #define YOBJECT(type,pntr) (static_cast(GenObject::getObject(YATOM(#type),pntr))) #define YNOCOPY(type) private: \ type(const type&); \ void operator=(const type&) /** * Compute a hash for a 64-bit unsigned integer * @param val Integer value to hash * @return Hash value */ YATE_API inline uint32_t hashInt64(uint64_t val) { return (uint32_t)(((val ^ (val >> 48)) ^ (val >> 32)) ^ (val >> 16)); } /** * Compute a hash for a 32-bit unsigned integer * @param val Integer value to hash * @return Hash value */ YATE_API inline uint32_t hashInt32(uint32_t val) { return (uint32_t)((val ^ (val >> 16)) ^ (val << 16)); } /** * Compute a hash for a pointer * @param val Pointer to hash * @return Hash value */ YATE_API inline uint32_t hashPtr(const void* ptr) { #if (_WORDSIZE == 64) return hashInt64((uintptr_t)ptr); #else return hashInt32((uintptr_t)ptr); #endif } /** * An object with just a public virtual destructor */ class YATE_API GenObject { YNOCOPY(GenObject); // no automatic copies please public: /** * Default constructor */ GenObject(); /** * Destructor. */ virtual ~GenObject() { setObjCounter(0); } /** * Check if the object is still valid and safe to access. * Note that you should not trust this result unless the object is locked * by other means. * @return True if the object is still useable */ virtual bool alive() const; /** * Destroys the object, disposes the memory. */ virtual void destruct(); /** * Get a string representation of this object * @return A reference to a String representing this object * which is either null, the object itself (for objects derived from * String) or some form of identification */ virtual const String& toString() const; /** * Get the trace ID associated with this object * @return The trace ID or an empty string */ virtual const String& traceId() const; /** * Get a pointer to a derived class given that class name * @param name Name of the class we are asking for * @return Pointer to the requested class or NULL if this object doesn't implement it */ virtual void* getObject(const String& name) const; /** * Helper method to get the pointer to a derived class * @param name Name of the class we are asking for * @param obj Pointer to the object to get derived class from * @return Pointer to the requested class or NULL if this object doesn't implement it */ static inline void* getObject(const String& name, const GenObject* obj) { return obj ? obj->getObject(name) : 0; } /** * Get the global state of object counting * @return True if object counting is enabled */ static inline bool getObjCounting() { return s_counting; } /** * Set the global state of object counting * @param enable True to enable object counting, false to disable */ static inline void setObjCounting(bool enable) { s_counting = enable; } /** * Get the counter of this object * @return Pointer to current counter object */ inline NamedCounter* getObjCounter() const { return m_counter; } /** * Set the counter of this object * @param counter New counter object or NULL * @return Pointer to old counter object */ NamedCounter* setObjCounter(NamedCounter* counter); /** * Retrieve or allocate an object counter * @param name Name of the counter * @param create True to create a new counter if needed * @return Pointer to existing or new counter object */ static NamedCounter* getObjCounter(const String& name, bool create = true); /** * Access the object counters list * @return Reference to the global object counters list */ static ObjList& getObjCounters(); private: NamedCounter* m_counter; static bool s_counting; }; /** * Helper function that destroys a GenObject only if the pointer is non-NULL. * Use it instead of the delete operator. * @param obj Pointer (rvalue) to the object to destroy */ inline void destruct(GenObject* obj) { if (obj) obj->destruct(); } /** * Helper template function that destroys a GenObject descendant if the pointer * is non-NULL and also zeros out the pointer. * Use it instead of the delete operator. * @param obj Reference to pointer (lvalue) to the object to destroy */ template void destruct(Obj*& obj) { if (obj) { obj->destruct(); obj = 0; } } /** * A reference counted object. * Whenever using multiple inheritance you should inherit this class virtually. */ class YATE_API RefObject : public GenObject { YNOCOPY(RefObject); // no automatic copies please public: /** * The constructor initializes the reference counter to 1! * Use deref() to destruct the object when safe */ RefObject(); /** * Destructor. */ virtual ~RefObject(); /** * Get a pointer to a derived class given that class name * @param name Name of the class we are asking for * @return Pointer to the requested class or NULL if this object doesn't implement it */ virtual void* getObject(const String& name) const; /** * Check if the object is still referenced and safe to access. * Note that you should not trust this result unless the object is locked * by other means. * @return True if the object is referenced and safe to access */ virtual bool alive() const; /** * Increments the reference counter if not already zero * @return True if the object was successfully referenced and is safe to access */ bool ref(); /** * Decrements the reference counter, destroys the object if it reaches zero *
     * // Deref this object, return quickly if the object was deleted
     * if (deref()) return;
     * 
* @return True if the object may have been deleted, false if it still exists and is safe to access */ bool deref(); /** * Get the current value of the reference counter * @return The value of the reference counter */ inline int refcount() const { return m_refcount; } /** * Refcounted objects should just have the counter decremented. * That will destroy them only when the refcount reaches zero. */ virtual void destruct(); /** * Check if a refcounted object is still alive * @param obj Pointer to the object to check * @return True if the pointer is not null and the object is referenced */ inline static bool alive(const RefObject* obj) { return obj && (obj->refcount() > 0); } /** * Check if reference counter manipulations are efficient on this platform. * If platform does not support atomic operations a mutex pool is used. * @return True if refcount uses atomic integer operations */ static bool efficientIncDec(); protected: /** * This method is called when the reference count reaches zero after * unlocking the mutex if the call to zeroRefsTest() returned true. * The default behaviour is to delete the object. */ virtual void zeroRefs(); /** * Bring the object back alive by setting the reference counter to one. * Note that it works only if the counter was zero previously * @return True if the object was resurrected - its name may be Lazarus ;-) */ bool resurrect(); /** * Pre-destruction notification, called just before the object is deleted. * Unlike in the destructor it is safe to call virtual methods here. * Reimplementing this method allows to perform any object cleanups. */ virtual void destroyed(); private: int m_refcount; Mutex* m_mutex; }; /** * Internal helper class providing a non-inline method to RefPointer. * Please don't use this class directly, use @ref RefPointer instead. * @short Internal helper class */ class YATE_API RefPointerBase { protected: /** * Default constructor, initialize to null pointer */ inline RefPointerBase() : m_pointer(0) { } /** * Set a new stored pointer * @param oldptr Pointer to the RefObject of the old stored object * @param newptr Pointer to the RefObject of the new stored object * @param pointer A void pointer to the derived class */ void assign(RefObject* oldptr, RefObject* newptr, void* pointer); /** * The untyped stored pointer that should be casted to a @ref RefObject derived class */ void* m_pointer; }; /** * @short Templated smart pointer class */ template class RefPointer : public RefPointerBase { protected: /** * Retrieve the stored pointer * @return A typed pointer */ inline Obj* pointer() const { return static_cast(m_pointer); } /** * Set a new stored pointer * @param object Pointer to the new stored object */ inline void assign(Obj* object = 0) { RefPointerBase::assign(pointer(),object,object); } public: /** * Default constructor - creates a null smart pointer */ inline RefPointer() { } /** * Copy constructor, references the object * @param value Original RefPointer */ inline RefPointer(const RefPointer& value) : RefPointerBase() { assign(value); } /** * Constructs an initialized smart pointer, references the object * @param object Pointer to object */ inline RefPointer(Obj* object) { assign(object); } /** * Destructs the pointer and dereferences the object */ inline ~RefPointer() { assign(); } /** * Assignment from smart pointer */ inline RefPointer& operator=(const RefPointer& value) { assign(value.pointer()); return *this; } /** * Assignment from regular pointer */ inline RefPointer& operator=(Obj* object) { assign(object); return *this; } /** * Conversion to regular pointer operator * @return The stored pointer */ inline operator Obj*() const { return pointer(); } /** * Member access operator */ inline Obj* operator->() const { return pointer(); } /** * Dereferencing operator */ inline Obj& operator*() const { return *pointer(); } }; /** * @short Templated pointer that can be inserted in a list */ template class GenPointer : public GenObject { private: /** * The stored pointer */ Obj* m_pointer; public: /** * Default constructor - creates a null pointer */ inline GenPointer() : m_pointer(0) { } /** * Copy constructor * @param value Original GenPointer */ inline GenPointer(const GenPointer& value) : m_pointer(value) { } /** * Constructs an initialized pointer * @param object Pointer to object */ inline GenPointer(Obj* object) : m_pointer(object) { } /** * Assignment from another GenPointer */ inline GenPointer& operator=(const GenPointer& value) { m_pointer = value; return *this; } /** * Assignment from regular pointer */ inline GenPointer& operator=(Obj* object) { m_pointer = object; return *this; } /** * Conversion to regular pointer operator * @return The stored pointer */ inline operator Obj*() const { return m_pointer; } /** * Member access operator */ inline Obj* operator->() const { return m_pointer; } /** * Dereferencing operator */ inline Obj& operator*() const { return *m_pointer; } }; /** * A simple single-linked object list handling class * @short An object list class */ class YATE_API ObjList : public GenObject { YNOCOPY(ObjList); // no automatic copies please public: /** * Creates a new, empty list. */ ObjList(); /** * Destroys the list and everything in it. */ virtual ~ObjList(); /** * Get a pointer to a derived class given that class name * @param name Name of the class we are asking for * @return Pointer to the requested class or NULL if this object doesn't implement it */ virtual void* getObject(const String& name) const; /** * Get the number of elements in the list * @return Count of items */ unsigned int length() const; /** * Get the number of non-null objects in the list * @return Count of items */ unsigned int count() const; /** * Get the object associated to this list item * @return Pointer to the object or NULL */ inline GenObject* get() const { return m_obj; } /** * Set the object associated to this list item * @param obj Pointer to the new object to set * @param delold True to delete the old object (default) * @return Pointer to the old object if not destroyed */ GenObject* set(const GenObject* obj, bool delold = true); /** * Get the next item in the list * @return Pointer to the next item in list or NULL */ inline ObjList* next() const { return m_next; } /** * Get the last item in the list * @return Pointer to the last item in list */ ObjList* last() const; /** * Skip over NULL holding items in the list * @return Pointer to the first non NULL holding item in list or NULL */ ObjList* skipNull() const; /** * Advance in the list skipping over NULL holding items * @return Pointer to the next non NULL holding item in list or NULL */ ObjList* skipNext() const; /** * Get the object at a specific index in list * @param index Index of the object to retrieve * @return Pointer to the object or NULL */ GenObject* at(int index) const; /** * Pointer-like indexing operator * @param index Index of the list item to retrieve * @return Pointer to the list item or NULL */ ObjList* operator+(int index) const; /** * Array-like indexing operator with signed parameter * @param index Index of the object to retrieve * @return Pointer to the object or NULL */ inline GenObject* operator[](signed int index) const { return at(index); } /** * Array-like indexing operator with unsigned parameter * @param index Index of the object to retrieve * @return Pointer to the object or NULL */ inline GenObject* operator[](unsigned int index) const { return at(index); } /** * Array-like indexing operator * @param str String value of the object to locate * @return Pointer to the object or NULL */ GenObject* operator[](const String& str) const; /** * Get the item in the list that holds an object * @param obj Pointer to the object to search for * @return Pointer to the found item or NULL */ ObjList* find(const GenObject* obj) const; /** * Get the item in the list that holds an object by String value * @param str String value (toString) of the object to search for * @return Pointer to the found item or NULL */ ObjList* find(const String& str) const; /** * Get the position in list of a GenObject by a pointer to it * @param obj Pointer to the object to search for * @return Index of object in list, -1 if not found */ int index(const GenObject* obj) const; /** * Get the position in list of the first GenObject with a given value * @param str String value (toString) of the object to search for * @return Index of object in list, -1 if not found */ int index(const String& str) const; /** * Insert an object at this point * @param obj Pointer to the object to insert * @param compact True to replace NULL values in list if possible * @return A pointer to the inserted list item */ ObjList* insert(const GenObject* obj, bool compact = true); /** * Append an object to the end of the list * @param obj Pointer to the object to append * @param compact True to replace NULL values in list if possible * @return A pointer to the inserted list item */ ObjList* append(const GenObject* obj, bool compact = true); /** * Set unique entry in this list. If not found, append it to the list * @param obj Pointer to the object to uniquely set in the list * @param compact True to replace NULL values in list if possible * @return A pointer to the set list item */ ObjList* setUnique(const GenObject* obj, bool compact = true); /** * Delete this list item * @param delobj True to delete the object (default) * @return Pointer to the object if not destroyed */ GenObject* remove(bool delobj = true); /** * Delete the list item that holds a given object * @param obj Object to search in the list * @param delobj True to delete the object (default) * @return Pointer to the object if not destroyed */ GenObject* remove(GenObject* obj, bool delobj = true); /** * Delete the first list item that holds an object with a iven value * @param str String value (toString) of the object to remove * @param delobj True to delete the object (default) * @return Pointer to the object if not destroyed */ GenObject* remove(const String& str, bool delobj = true); /** * Clear the list and optionally delete all contained objects */ void clear(); /** * Remove all empty objects in the list */ void compact(); /** * Get the automatic delete flag * @return True if will delete on destruct, false otherwise */ inline bool autoDelete() { return m_delete; } /** * Set the automatic delete flag * @param autodelete True to delete on destruct, false otherwise */ inline void setDelete(bool autodelete) { m_delete = autodelete; } /** * A static empty object list * @return Reference to a static empty list */ static const ObjList& empty(); /** * Sort this list * @param callbackCompare pointer to a callback function that should compare two objects. *
     *     obj1 First object of the comparation
     *     obj2 Second object of the comparation
     *     context Data context
     *     return 0 if the objects are equal; positive value if obj2 > obj1; negative value if obj1 > obj2
     *     Note: the function should expect receiving null pointers
     * 
* @param context Context data. */ void sort(int (*callbackCompare)(GenObject* obj1, GenObject* obj2, void* context), void* context = 0); private: ObjList* m_next; GenObject* m_obj; bool m_delete; }; /** * Simple vector class that holds objects derived from GenObject * @short A vector holding GenObjects */ class YATE_API ObjVector : public GenObject { YNOCOPY(ObjVector); // no automatic copies please public: /** * Constructor of a zero capacity vector * @param autodelete True to delete objects on destruct, false otherwise */ inline explicit ObjVector(bool autodelete = true) : m_length(0), m_objects(0), m_delete(autodelete) { } /** * Constructor of an empty vector * @param maxLen Maximum number of objects the vector can hold * @param autodelete True to delete objects on destruct, false otherwise */ ObjVector(unsigned int maxLen, bool autodelete = true); /** * Constructor from an object list * @param list List of objects to store in vector * @param move True to move elements from list, false to just copy the pointer * @param maxLen Maximum number of objects to put in vector, zero to put all * @param autodelete True to delete objects on destruct, false otherwise */ ObjVector(ObjList& list, bool move = true, unsigned int maxLen = 0, bool autodelete = true); /** * Destroys the vector and the objects if automatic delete is set */ virtual ~ObjVector(); /** * Get a pointer to a derived class given that class name * @param name Name of the class we are asking for * @return Pointer to the requested class or NULL if this object doesn't implement it */ virtual void* getObject(const String& name) const; /** * Get the capacity of the vector * @return Number of items the vector can hold */ inline unsigned int length() const { return m_length; } /** * Get the number of non-null objects in the vector * @return Count of items */ unsigned int count() const; /** * Check if the vector is empty * @return True if the vector contains no objects */ bool null() const; /** * Get the object at a specific index in vector * @param index Index of the object to retrieve * @return Pointer to the object or NULL */ inline GenObject* at(int index) const { return (index >= 0 && index < (int)m_length) ? m_objects[index] : 0; } /** * Indexing operator with signed parameter * @param index Index of the object to retrieve * @return Pointer to the object or NULL */ inline GenObject* operator[](signed int index) const { return at(index); } /** * Indexing operator with unsigned parameter * @param index Index of the object to retrieve * @return Pointer to the object or NULL */ inline GenObject* operator[](unsigned int index) const { return at(index); } /** * Clear the vector and assign objects from a list * @param list List of objects to store in vector * @param move True to move elements from list, false to just copy the pointer * @param maxLen Maximum number of objects to put in vector, zero to put all * @return Capacity of the vector */ unsigned int assign(ObjList& list, bool move = true, unsigned int maxLen = 0); /** * Retrieve and remove an object from the vector * @param index Index of the object to retrieve * @return Pointer to the stored object, NULL for out of bound index */ GenObject* take(unsigned int index); /** * Store an object in the vector * @param obj Object to store in vector * @param index Index of the object to store * @return True for success, false if index was out of bounds */ bool set(GenObject* obj, unsigned int index); /** * Get the position in vector of a GenObject by a pointer to it * @param obj Pointer to the object to search for * @return Index of object in vector, -1 if not found */ int index(const GenObject* obj) const; /** * Get the position in vector of the first GenObject with a given value * @param str String value (toString) of the object to search for * @return Index of object in vector, -1 if not found */ int index(const String& str) const; /** * Clear the vector and optionally delete all contained objects */ void clear(); /** * Get the automatic delete flag * @return True if will delete objects on destruct, false otherwise */ inline bool autoDelete() { return m_delete; } /** * Set the automatic delete flag * @param autodelete True to delete objects on destruct, false otherwise */ inline void setDelete(bool autodelete) { m_delete = autodelete; } private: unsigned int m_length; GenObject** m_objects; bool m_delete; }; /** * A simple Array class derivated from RefObject * It uses one ObjList to keep the pointers to other ObjList's. * Data is organized in columns - the main ObjList holds pointers to one * ObjList for each column. * This class has been written by Diana * @short A list based Array */ class YATE_API Array : public RefObject { public: /** * Creates a new empty array. * @param columns Initial number of columns * @param rows Initial number of rows */ explicit Array(int columns = 0, int rows = 0); /** * Destructor. Destructs all objects in the array */ virtual ~Array(); /** * Get a pointer to a derived class given that class name * @param name Name of the class we are asking for * @return Pointer to the requested class or NULL if this object doesn't implement it */ virtual void* getObject(const String& name) const; /** * Insert a row of objects * @param row List of objects to insert or NULL * @param index Number of the row to insert before, negative to append * @return True for success, false if index was larger than the array */ bool addRow(ObjList* row = 0, int index = -1); /** * Insert a column of objects * @param column List of objects to insert or NULL * @param index Number of the column to insert before, negative to append * @return True for success, false if index was larger than the array */ bool addColumn(ObjList* column = 0, int index = -1); /** * Delete an entire row of objects * @param index Number of the row to delete * @return True for success, false if index was out of bounds */ bool delRow(int index); /** * Delete an entire column of objects * @param index Number of the column to delete * @return True for success, false if index was out of bounds */ bool delColumn(int index); /** * Retrieve an object from the array * @param column Number of the column in the array * @param row Number of the row in the array * @return Pointer to the stored object, NULL for out of bound indexes */ GenObject* get(int column, int row) const; /** * Retrieve and remove an object from the array * @param column Number of the column in the array * @param row Number of the row in the array * @return Pointer to the stored object, NULL for out of bound indexes */ GenObject* take(int column, int row); /** * Store an object in the array * @param obj Object to store in the array * @param column Number of the column in the array * @param row Number of the row in the array * @return True for success, false if indexes were out of bounds */ bool set(GenObject* obj, int column, int row); /** * Get the number of rows in the array * @return Total number of rows */ inline int getRows() const { return m_rows; } /** * Get the number of columns in the array * @return Total number of columns */ inline int getColumns() const { return m_columns; } /** * Retrieve a column. * Note: Use the returned list only to get or set data. * List items must not be removed or appended * @param column Column to retrieve * @return Pointer to column list, NULL for out of bound indexes */ inline ObjList* getColumn(int column) const { if (column >= 0 || column < m_columns) return static_cast(m_obj[column]); return 0; } private: int m_rows; int m_columns; ObjList m_obj; }; class Regexp; class StringMatchPrivate; /** * A simple class to hold a single Unicode character and convert it to / from UTF-8 * @short A single Unicode character */ class YATE_API UChar { public: enum Endianness { LE = 0, BE = 1, Native = 2, }; /** * Constructor from unsigned numeric code * @param code Code of the Unicode character */ inline explicit UChar(uint32_t code = 0) : m_chr(code) { encode(); } /** * Constructor from signed numeric code * @param code Code of the Unicode character */ inline explicit UChar(int32_t code) : m_chr((code < 0) ? 0 : code) { encode(); } /** * Constructor from signed character * @param code Character to construct from */ inline explicit UChar(signed char code) : m_chr((unsigned char)code) { encode(); } /** * Constructor from unsigned character * @param code Character to construct from */ inline explicit UChar(unsigned char code) : m_chr(code) { encode(); } /** * Assignment operator from a character code * @param code Character code to assign * @return Reference to this object */ inline UChar& operator=(uint32_t code) { m_chr = code; encode(); return *this; } /** * Assignment operator from a character * @param code Character to assign * @return Reference to this object */ inline UChar& operator=(char code) { m_chr = (unsigned char)code; encode(); return *this; } /** * Get the Unicode value of the character * @return Code of the character as defined by Unicode */ inline uint32_t code() const { return m_chr; } /** * Get the value of the character as UTF-8 string. * @return The character as UTF-8 C string */ inline const char* c_str() const { return m_str; } /** * Conversion to "const char *" operator. * @return Pointer to the internally stored UTF-8 string */ inline operator const char*() const { return m_str; }; /** * Decode the first Unicode character from an UTF-8 C string * @param str String to extract from, will be advanced past the character * @param maxChar Maximum accepted Unicode character code * @param overlong Accept overlong UTF-8 sequences (dangerous!) * @return True if an Unicode character was decoded from string */ bool decode(const char*& str, uint32_t maxChar = 0x10ffff, bool overlong = false); /** * Decode the first Unicode character from an UTF-16 string * @param buff Input buffer, advanced if decoding succeeds * @param len Length of input buffer, updated if decoding succeeds * @param order Endianness to use for decoding the character * @param maxChar Maximum accepted Unicode character code * @return True if decoding succeeded, false otherwise */ bool decode(uint16_t*& buff, unsigned int& len, Endianness order, uint32_t maxChar = 0x10ffff); /** * Decode the first Unicode character from an UTF-16 string * @param buff Input buffer from which to decode the character * @param order Endianness to use for decoding the character * @param maxChar Maximum accepted Unicode character code * @return True if decoding succeeded, false otherwise */ bool decode(DataBlock& buff, Endianness order, uint32_t maxChar = 0x10ffff); /** * Encode the Unicode character to UTF-16 into a given buffer * @param buff Buffer where to put encoded character, advanced after encoding * @param len Available space in given buffer, updated after encoding * @param order Endianness to use for encoding the character * @return True if decoding succeeded, false otherwise */ bool encode(uint16_t*& buff, unsigned int& len, Endianness order); /** * Encode the Unicode character to UTF-16 into a DataBlock * @param buff DataBlock to which the encoded character is to be appended * @param order Endianness to use for encoding the character * @return True if decoding succeeded, false otherwise */ bool encode(DataBlock& buff, Endianness order); /** * Decode a UTF-16 encoded string * @param out String to append the decoded characters to * @param buff Input buffer to decode, advanced as decoding occurs * @param len Length of input buffer, decremented as decoding occurs * @param order Endianness to use for decoding * @param checkBOM Check for presence of BOM and interpret accordingly if present * @param maxChar Maximum accepted Unicode character code * @return True if decoding succeeded, false otherwise */ static bool decode(String& out, uint16_t*& buff, unsigned int& len, Endianness order, bool checkBOM = false, uint32_t maxChar = 0x10ffff); /** * Encode a string to UTF-16 * @param out DataBlock to which encoded data is to be appended * @param str String to be encoded * @param order Endianness to use for encoding the character * @param addBOM True to add BOM to the resulting encoding * @return True if encoding succeeded, false otherwise */ static bool encode(DataBlock& out, const char*& str, Endianness order, bool addBOM = false); /** * Encode a string to UTF-16 into a given buffer * @param buff Buffer where to put encoded character, advanced after encoding * @param len Available space in given buffer, updated after encoding * @param str String to be encoded * @param order Endianness to use for encoding the character * @param addBOM True to add BOM to the resulting encoding * @return True if encoding succeeded, false otherwise */ static bool encode(uint16_t*& buff, unsigned int& len, const char*& str, Endianness order, bool addBOM = false); private: void encode(); uint32_t m_chr; char m_str[8]; }; /** * A simple string handling class for C style (one byte) strings. * For simplicity and read speed no copy-on-write is performed. * Strings have hash capabilities and comparations are using the hash * for fast inequality check. * @short A C-style string handling class */ class YATE_API String : public GenObject { public: enum Align { Left = 0, Center, Right }; /** * Creates a new, empty string. */ String(); /** * Creates a new initialized string. * @param value Initial value of the string * @param len Length of the data to copy, -1 for full string */ String(const char* value, int len = -1); /** * Creates a new initialized string. * @param value Character to fill the string * @param repeat How many copies of the character to use */ explicit String(char value, unsigned int repeat = 1); /** * Creates a new initialized string from a 32 bit integer. * @param value Value to convert to string */ explicit String(int32_t value); /** * Creates a new initialized string from a 32 bit unsigned int. * @param value Value to convert to string */ explicit String(uint32_t value); /** * Creates a new initialized string from a 64 bit integer. * @param value Value to convert to string */ explicit String(int64_t value); /** * Creates a new initialized string from a 64 bit unsigned int. * @param value Value to convert to string */ explicit String(uint64_t value); /** * Creates a new initialized string from a boolean. * @param value Value to convert to string */ explicit String(bool value); /** * Creates a new initialized string from a double value. * @param value Value to convert to string */ explicit String(double value); /** * Copy constructor. * @param value Initial value of the string */ String(const String& value); /** * Constructor from String pointer. * @param value Initial value of the string */ String(const String* value); /** * Destroys the string, disposes the memory. */ virtual ~String(); /** * Get a pointer to a derived class given that class name * @param name Name of the class we are asking for * @return Pointer to the requested class or NULL if this object doesn't implement it */ virtual void* getObject(const String& name) const; /** * A static null String * @return Reference to a static empty String */ static const String& empty(); /** * A standard text representation of boolean values * @param value Boolean value to convert * @return Pointer to a text representation of the value */ inline static const char* boolText(bool value) { return value ? "true" : "false"; } /** * Get the value of the stored string. * @return The stored C string which may be NULL. */ inline const char* c_str() const { return m_string; } /** * Get a valid non-NULL C string. * @return The stored C string or a static "". */ inline const char* safe() const { return m_string ? m_string : ""; } /** * Get a valid non-NULL C string with a provided default. * @param defStr Default C string to return if stored is NULL * @return The stored C string, the default or a static "". */ inline const char* safe(const char* defStr) const { return m_string ? m_string : (defStr ? defStr : ""); } /** * Get the length of the stored string. * @return The length of the stored string, zero for NULL. */ inline unsigned int length() const { return m_length; } /** * Checks if the string holds a NULL pointer. * @return True if the string holds NULL, false otherwise. */ inline bool null() const { return !m_string; } /** * Get the number of characters in a string assuming UTF-8 encoding * @param value C string to compute Unicode length * @param maxChar Maximum accepted Unicode character code * @param overlong Accept overlong UTF-8 sequences (dangerous!) * @return Count of Unicode characters, -1 if not valid UTF-8 */ static int lenUtf8(const char* value, uint32_t maxChar = 0x10ffff, bool overlong = false); /** * Get the number of characters in the string assuming UTF-8 encoding * @param maxChar Maximum accepted Unicode character code * @param overlong Accept overlong UTF-8 sequences (dangerous!) * @return Count of Unicode characters, -1 if not valid UTF-8 */ inline int lenUtf8(uint32_t maxChar = 0x10ffff, bool overlong = false) const { return lenUtf8(m_string,maxChar,overlong); } /** * Fix an UTF-8 encoded string by replacing invalid sequences * @param replace String to replace invalid sequences, use U+FFFD if null * @param maxChar Maximum accepted Unicode character code * @param overlong Accept overlong UTF-8 sequences (dangerous!) * @return Count of invalid UTF-8 sequences that were replaced */ int fixUtf8(const char* replace = 0, uint32_t maxChar = 0x10ffff, bool overlong = false); /** * Encode flags from dictionary values * @param tokens The dictionary containing the flags * @return Encoded flags */ unsigned int encodeFlags(const TokenDict* tokens) const; /** * Encode flags from dictionary values * @param tokens The dictionary containing the flags * @return Encoded flags */ uint64_t encodeFlags(const TokenDict64* tokens) const; /** * Decodoe flags from dictionary values * @param flags The flags * @param tokens The dictionary containing the flags * @param unknownflag True (default) to add unknown flags * @return Decoded flags */ const String& decodeFlags(unsigned int flags, const TokenDict* tokens, bool unknownflag = true); /** * Decode flags from dictionary values * @param flags The flags * @param tokens The dictionary containing the flags * @param unknownflag True (default) to add unknown flags * @return Decoded flags */ const String& decodeFlags(uint64_t flags, const TokenDict64* tokens, bool unknownflag = true); /** * Check if a string starts with UTF-8 Byte Order Mark * @param str String to check for BOM * @return True if the string starts with UTF-8 BOM */ inline static bool checkBOM(const char* str) { return str && (str[0] == '\357') && (str[1] == '\273') && (str[2] == '\277'); } /** * Check if this string starts with UTF-8 Byte Order Mark * @return True if the string starts with UTF-8 BOM */ inline bool checkBOM() const { return checkBOM(c_str()); } /** * Advance a const string past an UTF-8 Byte Order Mark * @param str String to check for and strip BOM * @return True if the string started with UTF-8 BOM */ inline static bool stripBOM(const char*& str) { return checkBOM(str) && (str += 3); } /** * Advance a string past an UTF-8 Byte Order Mark * @param str String to check for and strip BOM * @return True if the string started with UTF-8 BOM */ inline static bool stripBOM(char*& str) { return checkBOM(str) && (str += 3); } /** * Strip an UTF-8 Byte Order Mark from the start of this string * @return True if the string started with UTF-8 BOM */ inline bool stripBOM() { return checkBOM(c_str()) && &(*this = c_str() + 3); } /** * Get the hash of the contained string. * @return The hash of the string. */ inline unsigned int hash() const { if (m_hash == YSTRING_INIT_HASH) m_hash = hash(m_string); return m_hash; } /** * Get the hash of an arbitrary string. * @param value C string to hash * @param h Old hash value for incremental hashing * @return The hash of the string. */ static unsigned int hash(const char* value, unsigned int h = 0); /** * Clear the string and free the memory */ void clear(); /** * Extract the caracter at a given index * @param index Index of character in string * @return Character at given index or 0 if out of range */ char at(int index) const; /** * Substring extraction * @param offs Offset of the substring, negative to count from end * @param len Length of the substring, -1 for everything possible * @return A copy of the requested substring */ String substr(int offs, int len = -1) const; /** * Strip off leading and trailing blank characters */ String& trimBlanks(); /** * Strip off leading and trailing whitespace characters * (blank, tabs, form-feed, newlines) */ String& trimSpaces(); /** * Override GenObject's method to return this String * @return A reference to this String */ virtual const String& toString() const; /** * Convert the string to an integer value. * @param defvalue Default to return if the string is not a number * @param base Numeration base, 0 to autodetect * @param minvalue Minimum value allowed * @param maxvalue Maximum value allowed * @param clamp Control the out of bound values: true to adjust to the nearest * bound, false to return the default value * @return The integer interpretation or defvalue. */ int toInteger(int defvalue = 0, int base = 0, int minvalue = INT_MIN, int maxvalue = INT_MAX, bool clamp = true) const; /** * Convert the string to an integer value looking up first a token table. * @param tokens Pointer to an array of tokens to lookup first * @param defvalue Default to return if the string is not a token or number * @param base Numeration base, 0 to autodetect * @return The integer interpretation or defvalue. */ int toInteger(const TokenDict* tokens, int defvalue = 0, int base = 0) const; /** * Convert the string to an long integer value. * @param defvalue Default to return if the string is not a number * @param base Numeration base, 0 to autodetect * @param minvalue Minimum value allowed * @param maxvalue Maximum value allowed * @param clamp Control the out of bound values: true to adjust to the nearest * bound, false to return the default value * @return The long integer interpretation or defvalue. */ long int toLong(long int defvalue = 0, int base = 0, long int minvalue = LONG_MIN, long int maxvalue = LONG_MAX, bool clamp = true) const; /** * Convert the string to an 64 bit integer value. * @param defvalue Default to return if the string is not a number * @param base Numeration base, 0 to autodetect * @param minvalue Minimum value allowed * @param maxvalue Maximum value allowed * @param clamp Control the out of bound values: true to adjust to the nearest * bound, false to return the default value * @return The 64 bit integer interpretation or defvalue. */ int64_t toInt64(int64_t defvalue = 0, int base = 0, int64_t minvalue = LLONG_MIN, int64_t maxvalue = LLONG_MAX, bool clamp = true) const; /** * Convert the string to an unsigned 64 bit integer value. * @param defvalue Default to return if the string is not a number * @param base Numeration base, 0 to autodetect * @param minvalue Minimum value allowed * @param maxvalue Maximum value allowed * @param clamp Control the out of bound values: true to adjust to the nearest * bound, false to return the default value * @return The unsigned 64 bit integer interpretation or defvalue. */ uint64_t toUInt64(uint64_t defvalue = 0, int base = 0, uint64_t minvalue = 0, uint64_t maxvalue = ULLONG_MAX, bool clamp = true) const; /** * Convert the string to a floating point value. * @param defvalue Default to return if the string is not a number * @return The floating-point interpretation or defvalue. */ double toDouble(double defvalue = 0.0) const; /** * Convert the string to a boolean value. * @param defvalue Default to return if the string is not a bool * @return The boolean interpretation or defvalue. */ bool toBoolean(bool defvalue = false) const; /** * Check if the string can be converted to a boolean value. * @return True if the string is a valid boolean. */ bool isBoolean() const; /** * Turn the string to an all-uppercase string * @return A reference to this String */ String& toUpper(); /** * Turn the string to an all-lowercase string * @return A reference to this String */ String& toLower(); /** * Indexing operator with signed int * @param index Index of character in string * @return Character at given index or 0 if out of range */ inline char operator[](signed int index) const { return at(index); } /** * Indexing operator with unsigned int * @param index Index of character in string * @return Character at given index or 0 if out of range */ inline char operator[](unsigned int index) const { return at(index); } /** * Conversion to "const char *" operator. * @return Pointer to the internally stored string */ inline operator const char*() const { return m_string; }; /** * Assigns a new value to the string from a character block. * @param value New value of the string * @param len Length of the data to copy, -1 for full string * @return Reference to the String */ String& assign(const char* value, int len = -1); /** * Assigns a new value by filling with a repeated character * @param value Character to fill the string * @param repeat How many copies of the character to use * @return Reference to the String */ String& assign(char value, unsigned int repeat = 1); /** * Build a hexadecimal representation of a buffer of data * @param data Pointer to data to dump * @param len Length of the data buffer * @param sep Separator character to use between octets * @param upCase Set to true to use upper case characters in hexa * @return Reference to the String */ String& hexify(void* data, unsigned int len, char sep = 0, bool upCase = false); /** * Assignment operator. * @param value Value to assign to the string */ inline String& operator=(const String& value) { return operator=(value.c_str()); } /** * Assignment from String* operator. * @param value Value to assign to the string * @see TelEngine::strcpy */ inline String& operator=(const String* value) { return operator=(value ? value->c_str() : ""); } /** * Assignment from char* operator. * @param value Value to assign to the string * @see TelEngine::strcpy */ String& operator=(const char* value); /** * Assignment operator for single characters. * @param value Value to assign to the string */ String& operator=(char value); /** * Assignment operator for 32 bit integers. * @param value Value to assign to the string */ String& operator=(int32_t value); /** * Assignment operator for 32 bit unsigned integers. * @param value Value to assign to the string */ String& operator=(uint32_t value); /** * Assignment operator for 64 bit integers. * @param value Value to assign to the string */ String& operator=(int64_t value); /** * Assignment operator for 64 bit unsigned integers. * @param value Value to assign to the string */ String& operator=(uint64_t value); /** * Assignment operator for booleans. * @param value Value to assign to the string */ inline String& operator=(bool value) { return operator=(boolText(value)); } /** * Assignment operator for double. * @param value Value to assign to the string */ String& operator=(double value); /** * Appending operator for strings. * @param value Value to assign to the string * @see TelEngine::strcat */ inline String& operator+=(const char* value) { return append(value,-1); } /** * Appending operator for single characters. * @param value Value to append to the string */ String& operator+=(char value); /** * Appending operator for 32 bit integers. * @param value Value to append to the string */ String& operator+=(int32_t value); /** * Appending operator for 32 bit unsigned integers. * @param value Value to append to the string */ String& operator+=(uint32_t value); /** * Appending operator for 64 bit integers. * @param value Value to append to the string */ String& operator+=(int64_t value); /** * Appending operator for 64 bit unsigned integers. * @param value Value to append to the string */ String& operator+=(uint64_t value); /** * Appending operator for booleans. * @param value Value to append to the string */ inline String& operator+=(bool value) { return operator+=(boolText(value)); } /** * Appending operator for double. * @param value Value to append to the string */ String& operator+=(double value); /** * Equality operator. */ bool operator==(const char* value) const; /** * Inequality operator. */ bool operator!=(const char* value) const; /** * Fast equality operator. */ inline bool operator==(const String& value) const { return (this == &value) || ((hash() == value.hash()) && operator==(value.c_str())); } /** * Fast inequality operator. */ inline bool operator!=(const String& value) const { return (this != &value) && ((hash() != value.hash()) || operator!=(value.c_str())); } /** * Case-insensitive equality operator. */ bool operator&=(const char* value) const; /** * Case-insensitive inequality operator. */ bool operator|=(const char* value) const; /** * Stream style appending operator for C strings */ inline String& operator<<(const char* value) { return operator+=(value); } /** * Stream style appending operator for single characters */ inline String& operator<<(char value) { return operator+=(value); } /** * Stream style appending operator for 32 bit integers */ inline String& operator<<(int32_t value) { return operator+=(value); } /** * Stream style appending operator for 32 bit unsigned integers */ inline String& operator<<(uint32_t value) { return operator+=(value); } /** * Stream style appending operator for 64 bit integers */ inline String& operator<<(int64_t value) { return operator+=(value); } /** * Stream style appending operator for 64 bit unsigned integers */ inline String& operator<<(uint64_t value) { return operator+=(value); } /** * Stream style appending operator for booleans */ inline String& operator<<(bool value) { return operator+=(value); } /** * Stream style appending operator for double */ inline String& operator<<(double value) { return operator+=(value); } /** * Stream style substring skipping operator. * It eats all characters up to and including the skip string */ String& operator>>(const char* skip); /** * Stream style extraction operator for single characters */ String& operator>>(char& store); /** * Stream style extraction operator for single Unicode characters */ String& operator>>(UChar& store); /** * Stream style extraction operator for integers */ String& operator>>(int& store); /** * Stream style extraction operator for unsigned integers */ String& operator>>(unsigned int& store); /** * Stream style extraction operator for booleans */ String& operator>>(bool& store); /** * Append a string to the current string * @param value String from which to append * @param len Length of the data to copy, -1 for full string * @return Reference to the String */ String& append(const char* value, int len); /** * Conditional appending with a separator * @param value String to append * @param separator Separator to insert before the value * @param force True to allow appending empty strings */ String& append(const char* value, const char* separator = 0, bool force = false); /** * List members appending with a separator * @param list Pointer to ObjList whose @ref GenObject::toString() of the items will be appended * @param separator Separator to insert before each item in list * @param force True to allow appending empty strings */ String& append(const ObjList* list, const char* separator = 0, bool force = false); /** * List members appending with a separator * @param list Reference of ObjList whose @ref GenObject::toString() of the items will be appended * @param separator Separator to insert before each item in list * @param force True to allow appending empty strings */ inline String& append(const ObjList& list, const char* separator = 0, bool force = false) { return append(&list,separator,force); } /** * Explicit double append * @param value Value to append * @param decimals Number of decimals */ String& append(double value, unsigned int decimals = 3); /** * Insert a string into current string * @param pos Position to insert. String will be appended if position is greater than curent length * @param value String to insert * @param len Length of the data to copy, -1 for full string * @return Reference to the String */ String& insert(unsigned int pos, const char* value, int len = -1); /** * Insert a character into current string * @param pos Position to insert. The character will be appended if position is greater than curent length * @param value Character to insert. NUL character will be ignored * @return Reference to the String */ inline String& insert(unsigned int pos, char value) { if (!value) return *this; char s[] = {value}; return insert(pos,s,1); } /** * Build a String in a printf style. * @param format The output format. * NOTE: The length of the resulting string will be at most 128 + length of format */ String& printf(const char* format, ...) FORMAT_CHECK(2); /** * Build a String in a printf style. * @param length maximum length of the resulting string * @param format The output format. */ String& printf(unsigned int length, const char* format, ...) FORMAT_CHECK(3); /** * Build a fixed aligned string from str and append it. * @param fixedLength The fixed length in which the 'str' will be aligned. * @param str The string to align * @param len The number of characters to use from str. * @param fill Character to fill the empty space. * @param align The alignment mode. */ String& appendFixed(unsigned int fixedLength, const char* str, unsigned int len = -1, char fill = ' ', int align = Left); /** * Build a fixed aligned string from str and append it. * @param fixedLength The fixed length in which the 'str' will be aligned. * @param str The string to align * @param fill Character to fill the empty space. * @param align The alignment mode. */ inline String& appendFixed(unsigned int fixedLength, const String& str, char fill = ' ', int align = Left) { return appendFixed(fixedLength,str.c_str(),str.length(),fill,align); } /** * Locate the first instance of a character in the string * @param what Character to search for * @param offs Offset in string to start searching from * @return Offset of character or -1 if not found */ int find(char what, unsigned int offs = 0) const; /** * Locate the first instance of a substring in the string * @param what Substring to search for * @param offs Offset in string to start searching from * @return Offset of substring or -1 if not found */ int find(const char* what, unsigned int offs = 0) const; /** * Locate the last instance of a character in the string * @param what Character to search for * @return Offset of character or -1 if not found */ int rfind(char what) const; /** * Locate the last instance of a substring in the string * @param what Substring to search for * @return Offset of substring or -1 if not found */ int rfind(const char* what) const; /** * Checks if the string starts with a substring * @param what Substring to search for * @param wordBreak Check if a word boundary follows the substring * @param caseInsensitive Compare case-insensitive if set * @return True if the substring occurs at the beginning of the string */ bool startsWith(const char* what, bool wordBreak = false, bool caseInsensitive = false) const; /** * Checks if the string ends with a substring * @param what Substring to search for * @param wordBreak Check if a word boundary precedes the substring * @param caseInsensitive Compare case-insensitive if set * @return True if the substring occurs at the end of the string */ bool endsWith(const char* what, bool wordBreak = false, bool caseInsensitive = false) const; /** * Checks if the string starts with a substring and removes it * @param what Substring to search for * @param wordBreak Check if a word boundary follows the substring; * this parameter defaults to True because the intended use of this * method is to separate commands from their parameters * @param caseInsensitive Compare case-insensitive if set * @return True if the substring occurs at the beginning of the string * and also removes the substring; if wordBreak is True any word * breaking characters are also removed */ bool startSkip(const char* what, bool wordBreak = true, bool caseInsensitive = false); /** * Extract a substring up to a separator * @param sep Separator string to match after extracted fragment * @param store Reference to String variable to store extracted fragment * @return Reference to this string */ String& extractTo(const char* sep, String& store); /** * Extract a boolean substring up to a separator * @param sep Separator string to match after extracted fragment * @param store Reference to boolean variable to store extracted fragment * @return Reference to this string */ String& extractTo(const char* sep, bool& store); /** * Extract an integer value substring up to a separator * @param sep Separator string to match after extracted fragment * @param store Reference to integer variable to store extracted fragment * @param base Numeration base, 0 to autodetect * @return Reference to this string */ String& extractTo(const char* sep, int& store, int base = 0); /** * Extract an integer or token value substring up to a separator * @param sep Separator string to match after extracted fragment * @param store Reference to integer variable to store extracted fragment * @param tokens Pointer to an array of tokens to lookup first * @param base Numeration base, 0 to autodetect * @return Reference to this string */ String& extractTo(const char* sep, int& store, const TokenDict* tokens, int base = 0); /** * Extract a double value substring up to a separator * @param sep Separator string to match after extracted fragment * @param store Reference to double variable to store extracted fragment * @return Reference to this string */ String& extractTo(const char* sep, double& store); /** * Checks if matches another string * @param value String to check for match * @return True if matches, false otherwise */ virtual bool matches(const String& value) const { return operator==(value); } /** * Checks if matches a regular expression and fill the match substrings * @param rexp Regular expression to check for match * @return True if matches, false otherwise */ bool matches(const Regexp& rexp); /** * Get the offset of the last match * @param index Index of the submatch to return, 0 for full match * @return Offset of the last match, -1 if no match or not in range */ int matchOffset(int index = 0) const; /** * Get the length of the last match * @param index Index of the submatch to return, 0 for full match * @return Length of the last match, 0 if no match or out of range */ int matchLength(int index = 0) const; /** * Get a copy of a matched (sub)string * @param index Index of the submatch to return, 0 for full match * @return Copy of the matched substring */ inline String matchString(int index = 0) const { return substr(matchOffset(index),matchLength(index)); } /** * Create a string by replacing matched strings in a template * @param templ Template of the string to generate * @return Copy of template with "\0" - "\9" replaced with submatches */ String replaceMatches(const String& templ) const; /** * Get the total number of submatches from the last match, 0 if no match * @return Number of matching subexpressions */ int matchCount() const; /** * Splits the string at a delimiter character * @param separator Character where to split the string * @param emptyOK True if empty strings should be inserted in list * @return A newly allocated list of strings, must be deleted after use */ ObjList* split(char separator, bool emptyOK = true) const; /** * Splits the string at Regexp delimiter * @param reg Regexp describing the delimiter * @param emptyOK True if empty strings should be inserted in list * @return A newly allocated list of strings, must be deleted after use */ ObjList* split(const Regexp& reg, bool emptyOK = true) const; /** * Create an escaped string suitable for use in messages * @param str String to convert to escaped format * @param extraEsc Character to escape other than the default ones * @return The string with special characters escaped */ static String msgEscape(const char* str, char extraEsc = 0); /** * Create an escaped string suitable for use in messages * @param extraEsc Character to escape other than the default ones * @return The string with special characters escaped */ inline String msgEscape(char extraEsc = 0) const { return msgEscape(c_str(),extraEsc); } /** * Decode an escaped string back to its raw form * @param str String to convert to unescaped format * @param errptr Pointer to an integer to receive the place of 1st error * @param extraEsc Character to unescape other than the default ones * @return The string with special characters unescaped */ static String msgUnescape(const char* str, int* errptr = 0, char extraEsc = 0); /** * Decode an escaped string back to its raw form * @param errptr Pointer to an integer to receive the place of 1st error * @param extraEsc Character to unescape other than the default ones * @return The string with special characters unescaped */ inline String msgUnescape(int* errptr = 0, char extraEsc = 0) const { return msgUnescape(c_str(),errptr,extraEsc); } /** * Create an escaped string suitable for use in SQL queries * @param str String to convert to escaped format * @param extraEsc Character to escape other than the default ones * @return The string with special characters escaped */ static String sqlEscape(const char* str, char extraEsc = 0); /** * Create an escaped string suitable for use in SQL queries * @param extraEsc Character to escape other than the default ones * @return The string with special characters escaped */ inline String sqlEscape(char extraEsc = 0) const { return sqlEscape(c_str(),extraEsc); } /** * Create an escaped string suitable for use in URIs * @param str String to convert to escaped format * @param extraEsc Character to escape other than the default ones * @param noEsc Optional pointer to string of characters that shouldn't be escaped * @return The string with special characters escaped */ static String uriEscape(const char* str, char extraEsc = 0, const char* noEsc = 0); /** * Create an escaped string suitable for use in URIs * @param str String to convert to escaped format * @param extraEsc Pointer to string of characters to escape other than the defaults * @param noEsc Optional pointer to string of characters that shouldn't be escaped * @return The string with special characters escaped */ static String uriEscape(const char* str, const char* extraEsc, const char* noEsc = 0); /** * Create an escaped string suitable for use in URI * @param extraEsc Character to escape other than the default ones * @param noEsc Optional pointer to string of characters that shouldn't be escaped * @return The string with special characters escaped */ inline String uriEscape(char extraEsc = 0, const char* noEsc = 0) const { return uriEscape(c_str(),extraEsc,noEsc); } /** * Decode an URI escaped string back to its raw form * @param str String to convert to unescaped format * @param errptr Pointer to an integer to receive the place of 1st error * @return The string with special characters unescaped */ static String uriUnescape(const char* str, int* errptr = 0); /** * Decode an URI escaped string back to its raw form * @param errptr Pointer to an integer to receive the place of 1st error * @return The string with special characters unescaped */ inline String uriUnescape(int* errptr = 0) const { return uriUnescape(c_str(),errptr); } /** * Atom string support helper * @param str Reference to variable to hold the atom string * @param val String value to allocate to the atom * @return Pointer to shared atom string */ static const String* atom(const String*& str, const char* val); protected: /** * Called whenever the value changed (except in constructors). */ virtual void changed(); private: void clearMatches(); char* m_string; unsigned int m_length; // I hope every C++ compiler now knows about mutable... mutable unsigned int m_hash; StringMatchPrivate* m_matches; }; /** * Utility function to retrieve a C string from a possibly NULL String pointer * @param str Pointer to a String that may be NULL * @return String data pointer or NULL */ inline const char* c_str(const String* str) { return str ? str->c_str() : (const char*)0; } /** * Utility function to replace NULL C string pointers with an empty C string * @param str Pointer to a C string that may be NULL * @return Original pointer or pointer to an empty C string */ inline const char* c_safe(const char* str) { return str ? str : ""; } /** * Utility function to replace NULL String pointers with an empty C string * @param str Pointer to a String that may be NULL * @return String data pointer or pointer to an empty C string */ inline const char* c_safe(const String* str) { return str ? str->safe() : ""; } /** * Utility function to check if a C string is null or empty * @param str Pointer to a C string * @return True if str is NULL or starts with a NUL character */ inline bool null(const char* str) { return !(str && *str); } /** * Utility function to check if a String is null or empty * @param str Pointer to a String * @return True if str is NULL or is empty */ inline bool null(const String* str) { return !str || str->null(); } /** * Concatenation operator for strings. */ YATE_API String operator+(const String& s1, const String& s2); /** * Concatenation operator for strings. */ YATE_API String operator+(const String& s1, const char* s2); /** * Concatenation operator for strings. */ YATE_API String operator+(const char* s1, const String& s2); /** * Prevent careless programmers from overwriting the string * @see TelEngine::String::operator= */ inline const char *strcpy(String& dest, const char* src) { dest = src; return dest.c_str(); } /** * Prevent careless programmers from overwriting the string * @see TelEngine::String::operator+= */ inline const char *strcat(String& dest, const char* src) { dest += src; return dest.c_str(); } /** * Utility function to look up a string in a token table, * interpret as number if it fails * @param str String to look up * @param tokens Pointer to the token table * @param defvalue Value to return if lookup and conversion fail * @param base Default base to use to convert to number */ YATE_API int lookup(const char* str, const TokenDict* tokens, int defvalue = 0, int base = 0); /** * Utility function to look up a number in a token table * @param value Value to search for * @param tokens Pointer to the token table * @param defvalue Value to return if lookup fails */ YATE_API const char* lookup(int value, const TokenDict* tokens, const char* defvalue = 0); /** * Utility function to look up a string in a 64bit token table, * interpret as number if it fails * @param str String to look up * @param tokens Pointer to the token table * @param defvalue Value to return if lookup and conversion fail * @param base Default base to use to convert to number */ YATE_API int64_t lookup(const char* str, const TokenDict64* tokens, int64_t defvalue = 0, int base = 0); /** * Utility function to look up a 64bit number in a token table * @param value Value to search for * @param tokens Pointer to the token table * @param defvalue Value to return if lookup fails */ YATE_API const char* lookup(int64_t value, const TokenDict64* tokens, const char* defvalue = 0); class NamedList; /** * Utility method to return from a chan.control handler * @param params The parameters list * @param ret The return value * @param retVal The error message * @return ret if the message was not generated from rmanager. */ YATE_API bool controlReturn(NamedList* params, bool ret, const char* retVal = 0); /** * A regular expression matching class. * @short A regexp matching class */ class YATE_API Regexp : public String { YCLASS(Regexp,String) friend class String; public: /** * Creates a new, empty regexp. */ Regexp(); /** * Creates a new initialized regexp. * @param value Initial value of the regexp. * @param extended True to use POSIX Extended Regular Expression syntax * @param insensitive True to not differentiate case */ explicit Regexp(const char* value, bool extended = false, bool insensitive = false); /** * Copy constructor. * @param value Initial value of the regexp. */ Regexp(const Regexp& value); /** * Destroys the regexp, disposes the memory. */ virtual ~Regexp(); /** * Assignment from char* operator. */ inline Regexp& operator=(const char* value) { String::operator=(value); return *this; } /** * Makes sure the regular expression is compiled * @return True if successfully compiled, false on error */ inline bool compile() const { return m_regexp || (m_compile && doCompile()); } /** * Checks if the pattern matches a given value * @param value String to check for match * @return True if matches, false otherwise */ bool matches(const char* value) const; /** * Checks if the pattern matches a string * @param value String to check for match * @return True if matches, false otherwise */ virtual bool matches(const String& value) const { return Regexp::matches(value.safe()); } /** * Change the expression matching flags * @param extended True to use POSIX Extended Regular Expression syntax * @param insensitive True to not differentiate case */ void setFlags(bool extended, bool insensitive); /** * Return the POSIX Extended syntax flag * @return True if using POSIX Extended Regular Expression syntax */ bool isExtended() const; /** * Return the Case Insensitive flag * @return True if not differentiating case */ bool isCaseInsensitive() const; protected: /** * Called whenever the value changed (except in constructors) to recompile. */ virtual void changed(); /** * Compile the regular expression * @return True if successfully compiled, false on error */ bool doCompile() const; private: void cleanup(); bool matches(const char* value, StringMatchPrivate* matchlist) const; mutable void* m_regexp; mutable bool m_compile; int m_flags; }; /** * Indirected shared string offering access to atom strings * @short Atom string holder */ class Atom { public: /** * Constructor * @param value Atom's string value */ inline explicit Atom(const char* value) : m_atom(0) { String::atom(m_atom,value); } /** * Conversion to "const String &" operator * @return Pointer to the atom String */ inline operator const String&() const { return *m_atom; } /** * String method call operator * @return Pointer to the atom String */ inline const String* operator->() const { return m_atom; } private: const String* m_atom; }; /** * Holder for an event (output, debug or alarm) message * @short A captured event string with a debug level */ class YATE_API CapturedEvent : public String { friend class Engine; YCLASS(CapturedEvent,String) public: /** * Constructor * @param level Debugging level associated with the event * @param text Text description of the event */ inline CapturedEvent(int level, const char* text) : String(text), m_level(level) { } /** * Copy constructor * @param original Captured event to copy */ inline CapturedEvent(const CapturedEvent& original) : String(original), m_level(original.level()) { } /** * Get the debugging level of the event * @return Debugging level associated with the event */ inline int level() const { return m_level; } /** * Get the capturing state of the output and debug messages * @return True if output and debug messages are being captured */ inline static bool capturing() { return s_capturing; } /** * Get the list of captured events * @return List of events captured from output and debugging */ inline static const ObjList& events() { return s_events; } /** * Add an event to the captured events list * @param level Debugging level associated with the event * @param text Text description of the event, must not be empty */ inline static void append(int level, const char* text) { if (text && *text) s_events.append(new CapturedEvent(level,text)); } protected: /** * Get a writable list of captured events * @return List of events captured from output and debugging */ inline static ObjList& eventsRw() { return s_events; } /** * Enable or disable capturing of output and debug messages * @param capture True to capture internally the debugging messages */ inline static void capturing(bool capture) { s_capturing = capture; } private: int m_level; static ObjList s_events; static bool s_capturing; }; /** * A string class with a hashed string name * @short A named string class. */ class YATE_API NamedString : public String { YNOCOPY(NamedString); // no automatic copies please public: /** * Creates a new named string. * @param name Name of this string * @param value Initial value of the string */ explicit NamedString(const char* name, const char* value = 0); /** * Retrieve the name of this string. * @return A hashed string with the name of the string */ inline const String& name() const { return m_name; } /** * Get a string representation of this object * @return A reference to the name of this object */ virtual const String& toString() const; /** * Get a pointer to a derived class given that class name * @param name Name of the class we are asking for * @return Pointer to the requested class or NULL if this object doesn't implement it */ virtual void* getObject(const String& name) const; /** * Value assignment operator */ inline NamedString& operator=(const char* value) { String::operator=(value); return *this; } private: NamedString(); // no default constructor please String m_name; }; /** * A named string holding a pointer to arbitrary data. * The pointer is owned by the object: it will be released when the object is * destroyed or the string value changed * @short A named pointer class. */ class YATE_API NamedPointer : public NamedString { public: /** * Creates a new named pointer * @param name Name of this pointer * @param data Initial pointer value. The pointer will be owned by this object * @param value Initial string value */ explicit NamedPointer(const char* name, GenObject* data = 0, const char* value = 0); /** * Destructor. Release the pointer */ virtual ~NamedPointer(); /** * Retrieve the pointer carried by this object * @return Pointer to arbitrary user GenObject */ inline GenObject* userData() const { return m_data; } /** * Retrieve the pointer carried by this object and release ownership. * The caller will own the returned pointer * @return Pointer to arbitrary user GenObject */ GenObject* takeData(); /** * Set obscure data carried by this object. * Note that a RefObject's reference counter should be increased before adding it to this named pointer * @param data Pointer to arbitrary user data */ void userData(GenObject* data); /** * Get a pointer to a derived class of user data given that class name * @param name Name of the class we are asking for * @return Pointer to the requested class or NULL if user object id NULL or doesn't implement it */ inline void* userObject(const String& name) const { return m_data ? m_data->getObject(name) : 0; } /** * String value assignment operator */ inline NamedPointer& operator=(const char* value) { NamedString::operator=(value); return *this; } /** * Get a pointer to a derived class given that class name * @param name Name of the class we are asking for * @return Pointer to the requested class or NULL if this object doesn't implement it */ virtual void* getObject(const String& name) const; protected: /** * Called whenever the string value changed. Release the pointer */ virtual void changed(); private: NamedPointer(); // no default constructor please GenObject* m_data; }; /** * An atomic counter with an associated name * @short Atomic counter with name */ class YATE_API NamedCounter : public String { YNOCOPY(NamedCounter); // no automatic copies please public: /** * Constructor * @param name Name of the counter */ explicit NamedCounter(const String& name); /** * Check if the counter is enabled * @return True if the counter is enabled */ inline bool enabled() const { return m_enabled; } /** * Enable or disable the counter * @param val True to enable counter, false to disable */ inline void enable(bool val) { m_enabled = val; } /** * Increment the counter * @return Post-increment value of the counter */ int inc(); /** * Decrement the counter * @return Post-decrement value of the counter */ int dec(); /** * Add a specific value to the counter * @param val Value to add */ int add(int val); /** * Get the current value of the counter * @return Value of the counter */ inline int count() const { return m_count; } private: int m_count; bool m_enabled; Mutex* m_mutex; }; /** * A hashed object list handling class. Objects placed in the list are * distributed according to their String hash resulting in faster searches. * On the other hand an object placed in a hashed list must never change * its String value or it becomes unfindable. * @short A hashed object list class */ class YATE_API HashList : public GenObject { YNOCOPY(HashList); // no automatic copies please public: /** * Creates a new, empty list. * @param size Number of classes to divide the objects */ explicit HashList(unsigned int size = 17); /** * Destroys the list and everything in it. */ virtual ~HashList(); /** * Get a pointer to a derived class given that class name * @param name Name of the class we are asking for * @return Pointer to the requested class or NULL if this object doesn't implement it */ virtual void* getObject(const String& name) const; /** * Get the number of hash entries * @return Count of hash entries */ inline unsigned int length() const { return m_size; } /** * Get the number of non-null objects in the list * @return Count of items */ unsigned int count() const; /** * Retrieve one of the internal object lists. This method should be used * only to iterate all objects in the list. * @param index Index of the internal list to retrieve * @return Pointer to the list or NULL */ inline ObjList* getList(unsigned int index) const { return (index < m_size) ? m_lists[index] : 0; } /** * Retrieve one of the internal object lists knowing the hash value. * @param hash Hash of the internal list to retrieve * @return Pointer to the list or NULL if never filled */ inline ObjList* getHashList(unsigned int hash) const { return getList(hash % m_size); } /** * Retrieve one of the internal object lists knowing the String value. * @param str String whose hash internal list is to retrieve * @return Pointer to the list or NULL if never filled */ inline ObjList* getHashList(const String& str) const { return getHashList(str.hash()); } /** * Array-like indexing operator * @param str String value of the object to locate * @return Pointer to the first object or NULL */ GenObject* operator[](const String& str) const; /** * Get the item in the list that holds an object. * The item is searched sequentially in the lists, not using it's String hash * @param obj Pointer to the object to search for * @return Pointer to the found item or NULL */ ObjList* find(const GenObject* obj) const; /** * Get the item in the list that holds an object * @param obj Pointer to the object to search for * @param hash Object hash used to identify the list it belongs to * @return Pointer to the found item or NULL */ ObjList* find(const GenObject* obj, unsigned int hash) const; /** * Get the item in the list that holds an object by String value * @param str String value (toString) of the object to search for * @return Pointer to the first found item or NULL */ ObjList* find(const String& str) const; /** * Appends an object to the hashed list * @param obj Pointer to the object to append * @return A pointer to the inserted list item */ ObjList* append(const GenObject* obj); /** * Appends an object to the hashed list * @param obj Pointer to the object to append * @param hash Object hash used to identify the list into which this object should be inserted * @return A pointer to the inserted list item */ ObjList* append(const GenObject* obj, unsigned int hash); /** * Delete the list item that holds a given object * @param obj Object to search in the list * @param delobj True to delete the object (default) * @param useHash True to use object hash to identify the list it belongs to * @return Pointer to the object if not destroyed */ GenObject* remove(GenObject* obj, bool delobj = true, bool useHash = false); /** * Delete the item in the list that holds an object by String value * @param str String value (toString) of the object to remove * @param delobj True to delete the object (default) * @return Pointer to the object if not destroyed */ inline GenObject* remove(const String& str, bool delobj = true) { ObjList* n = find(str); return n ? n->remove(delobj) : 0; } /** * Delete the item in the list that has the associated hash * @param obj Object to search in the list * @param hash Object hash used to identify the list from which to remove the object * @param delobj True to delete the object (default) * @return Pointer to the object if not destroyed */ inline GenObject* remove(GenObject* obj, unsigned int hash, bool delobj = true) { ObjList* n = find(obj,hash); return n ? n->remove(delobj) : 0; } /** * Clear the list and optionally delete all contained objects */ void clear(); /** * Resync the list by checking if a stored object belongs to the list * according to its hash * @param obj Object to resync in the list * @return True if object was in the wrong list and had to be moved */ bool resync(GenObject* obj); /** * Resync the list by checking if all stored objects belong to the list * according to their hash * @return True if at least one object had to be moved */ bool resync(); private: unsigned int m_size; ObjList** m_lists; }; /** * An ObjList or HashList iterator that can be used even when list elements * are changed while iterating. Note that it will not detect that an item was * removed and another with the same address was inserted back in list. * @short Class used to iterate the items of a list */ class YATE_API ListIterator { YNOCOPY(ListIterator); // no automatic copies please public: /** * Constructor used to iterate through an ObjList. * The image of the list is frozen at the time the constructor executes * @param list List to get the objects from * @param offset First list element to iterate, will wrap around */ ListIterator(ObjList& list, int offset = 0); /** * Constructor used to iterate through a HashList. * The image of the list is frozen at the time the constructor executes * @param list List to get the objects from * @param offset First list element to iterate, will wrap around */ ListIterator(HashList& list, int offset = 0); /** * Destructor - frees the allocated memory */ ~ListIterator(); /** * Get the number of elements in the list * @return Count of items in the internal list */ inline unsigned int length() const { return m_length; } /** * Clear the iterator, disconnect from any list */ void clear(); /** * Assign an ObjList to the iterator, build a frozen image of the list * @param list List to get the objects from * @param offset First list element to iterate, will wrap around */ void assign(ObjList& list, int offset = 0); /** * Assign a HashList to the iterator, build a frozen image of the list * @param list List to get the objects from * @param offset First list element to iterate, will wrap around */ void assign(HashList& list, int offset = 0); /** * Get an arbitrary element in the iterator's list image. * Items that were removed from list or are not alive are not returned. * @param index Position to get the item from * @return Pointer to the list item or NULL if out of range or item removed */ GenObject* get(unsigned int index) const; /** * Get the current element and advance the current index. * Items that were removed from list or are not alive are skipped over. * An example of typical usage: *
     * ListIterator iter(list);
     * while (GenObject* obj = iter.get()) {
     *     do_something_with(obj);
     * }
     * 
* @return Pointer to a list item or NULL if advanced past end (eof) */ GenObject* get(); /** * Check if the current pointer is past the end of the list * @return True if there are no more entries left */ inline bool eof() const { return m_current >= m_length; } /** * Reset the iterator index to the first position in the list */ inline void reset() { m_current = 0; } private: ObjList* m_objList; HashList* m_hashList; GenObject** m_objects; unsigned int* m_hashes; unsigned int m_length; unsigned int m_current; }; /** * The Time class holds a time moment with microsecond accuracy * @short A time holding class */ class YATE_API Time { public: /** * Constructs a Time object from the current time */ inline Time() : m_time(now()) { } /** * Constructs a Time object from a given time * @param usec Time in microseconds */ inline Time(u_int64_t usec) : m_time(usec) { } /** * Constructs a Time object from a timeval structure pointer * @param tv Pointer to the timeval structure */ inline explicit Time(const struct timeval* tv) : m_time(fromTimeval(tv)) { } /** * Constructs a Time object from a timeval structure * @param tv Reference of the timeval structure */ inline explicit Time(const struct timeval& tv) : m_time(fromTimeval(tv)) { } /** * Do-nothing destructor that keeps the compiler from complaining * about inlining derivates or members of Time type */ inline ~Time() { } /** * Get time in seconds * @return Time in seconds since the Epoch */ inline u_int32_t sec() const { return (u_int32_t)((m_time+500000) / 1000000); } /** * Get time in milliseconds * @return Time in milliseconds since the Epoch */ inline u_int64_t msec() const { return (m_time+500) / 1000; } /** * Get time in microseconds * @return Time in microseconds since the Epoch */ inline u_int64_t usec() const { return m_time; } /** * Conversion to microseconds operator */ inline operator u_int64_t() const { return m_time; } /** * Assignment operator. */ inline Time& operator=(u_int64_t usec) { m_time = usec; return *this; } /** * Offsetting operator. */ inline Time& operator+=(int64_t delta) { m_time += delta; return *this; } /** * Offsetting operator. */ inline Time& operator-=(int64_t delta) { m_time -= delta; return *this; } /** * Fill in a timeval struct from a value in microseconds * @param tv Pointer to the timeval structure */ inline void toTimeval(struct timeval* tv) const { toTimeval(tv, m_time); } /** * Fill in a timeval struct from a value in microseconds * @param tv Pointer to the timeval structure * @param usec Time to convert to timeval */ static void toTimeval(struct timeval* tv, u_int64_t usec); /** * Convert time in a timeval struct to microseconds * @param tv Pointer to the timeval structure * @return Corresponding time in microseconds or zero if tv is NULL */ static u_int64_t fromTimeval(const struct timeval* tv); /** * Convert time in a timeval struct to microseconds * @param tv Reference of the timeval structure * @return Corresponding time in microseconds */ inline static u_int64_t fromTimeval(const struct timeval& tv) { return fromTimeval(&tv); } /** * Get the current system time in microseconds * @return Time in microseconds since the Epoch */ static u_int64_t now(); /** * Get the current system time in milliseconds * @return Time in milliseconds since the Epoch */ static u_int64_t msecNow(); /** * Get the current system time in seconds * @return Time in seconds since the Epoch */ static u_int32_t secNow(); /** * Build EPOCH time from date/time components * @param year The year component of the date. Must be greater then 1969 * @param month The month component of the date (1 to 12) * @param day The day component of the date (1 to 31) * @param hour The hour component of the time (0 to 23). The hour can be 24 * if minute and sec are 0 * @param minute The minute component of the time (0 to 59) * @param sec The seconds component of the time (0 to 59) * @param offset Optional number of seconds to be added/substracted * to/from result. It can't exceed the number of seconds in a day * @return EPOCH time in seconds, -1 on failure */ static unsigned int toEpoch(int year, unsigned int month, unsigned int day, unsigned int hour, unsigned int minute, unsigned int sec, int offset = 0); /** * Split a given EPOCH time into its date/time components * @param epochTimeSec EPOCH time in seconds * @param year The year component of the date * @param month The month component of the date (1 to 12) * @param day The day component of the date (1 to 31) * @param hour The hour component of the time (0 to 23) * @param minute The minute component of the time (0 to 59) * @param sec The seconds component of the time (0 to 59) * @param wDay The day of the week (optional) * @return True on succes, false if conversion failed */ static bool toDateTime(unsigned int epochTimeSec, int& year, unsigned int& month, unsigned int& day, unsigned int& hour, unsigned int& minute, unsigned int& sec, unsigned int* wDay = 0); /** * Convert system time to 32bit NTP (seconds since 1900) * @param sec Time in seconds * @param over Optional destination for overflow value. Must be reset before calling this method * @param rfc2030 Use time extension as specified in RFC 2030 Section 3 * @return NTP time value in seconds */ static uint32_t toNtp(uint32_t sec, uint32_t* over = 0, bool rfc2030 = true); /** * Convert this time to 32bit NTP (seconds since 1900) * @param over Optional destination for overflow value. Must be reset before calling this method * @param rfc2030 Use time extension as specified in RFC 2030 Section 3 * @return NTP time value in seconds */ inline uint32_t toNtp(uint32_t* over = 0, bool rfc2030 = true) { return toNtp(sec(),over,rfc2030); } /** * Convert 32bit NTP (seconds since 1900) to system time * @param val NTP time in seconds * @param under Optional destination for underflow value (given time is before EPOCH). * Must be reset before calling this method * @param rfc2030 Handle time extension as specified in RFC 2030 Section 3 * @return System time value in seconds. 0 if underflow */ static uint32_t fromNtp(uint32_t val, uint32_t* under = 0, bool rfc2030 = true); /** * Convert EPOCH time to a string representation. Does not add a NUL char at end * Minimal representation is yyyy-mm-ddThh:mm:ssZ * Destination buffer length must be at least 20 if no fractions are going to be filled * For milliseconds fractions extra 4 bytes must be available in buffer * For microseconds fractions extra 7 bytes must be available in buffer * @param buf Buffer to be filled * @param time System time in microseconds to convert * @param frac Add second fractions. 0: none, negative: microseconds, positive: milliseconds * @return The number of chars written in buffer. 0 on failure */ static unsigned int toString(char* buf, uint64_t time, int frac = 0); /** * Convert system time to a string representation * Minimal representation is yyyy-mm-ddThh:mm:ssZ * Destination buffer length must be at least 20 if no fractions are going to be filled * For milliseconds fractions extra 4 bytes must be available in buffer * For microseconds fractions extra 7 bytes must be available in buffer * @param buf Buffer to append to * @param time System time in microseconds to convert * @param frac Add second fractions. 0: none, negative: microseconds, positive: milliseconds * @return The number of chars added to buffer. 0 on failure */ static inline unsigned int appendTo(String& buf, uint64_t time, int frac = 0) { char tmp[30]; unsigned int n = toString(tmp,time,frac); if (n) buf.append(tmp,n); return n; } /** * Decode string to EPOCH time * Decode yyyy-mm-dd{T|t}hh:mm:ss[.SEC-FRAC]{{Z|z}|{+/-hh:mm}} * Date seconds may contain leap seconds (value 60). These are ignored (second will be used as 59) * @param buf Buffer to parse * @param len Buffer length. 0 to detect * @param frac Handle second fractions. 0: none, negative: microseconds, positive: milliseconds * @return EPOCH time in (milli|micro)seconds, -1 on failure */ static uint64_t toEpoch(const char* buf, unsigned int len, int frac = 0); /** * Check if an year is a leap one * @param year The year to check * @return True if the given year is a leap one */ static inline bool isLeap(unsigned int year) { return (year % 400 == 0 || (year % 4 == 0 && year % 100 != 0)); } /** * Retrieve the difference between local time and UTC in seconds east of UTC * @param when UNIX time for which to compute timezone, affects daylight saving * @return Difference between local time and UTC in seconds */ static int timeZone(u_int32_t when = secNow()); private: u_int64_t m_time; }; /** * Implementation of a system independent pseudo random number generator * @short Pseudo random number generator */ class YATE_API Random { public: /** * Constructor * @param seed Number to use as initial sequence seed */ inline Random(u_int32_t seed = Time::now() & 0xffffffff) : m_random(seed) { } /** * Get the latest random number generated * @return Last random number generated */ inline u_int32_t get() const { return m_random; } /** * Set the pseudo random generator to a known state * @param seed Number to set as current state */ inline void set(u_int32_t seed) { m_random = seed; } /** * Advance the pseudo random sequence and return new value * @return Next random number in sequence */ u_int32_t next(); /** * Thread safe (and shared) replacement for library ::random() * @return Next random number in the global sequence */ static long int random(); /** * Thread safe (and shared) replacement for library ::srandom() * @param seed Number to set as seed in the global sequence */ static void srandom(unsigned int seed); private: u_int32_t m_random; }; /** * The DataBlock holds a data buffer with no specific formatting. * @short A class that holds just a block of raw data */ class YATE_API DataBlock : public GenObject { public: /** * Constructs an empty data block * @param overAlloc How many bytes of memory to overallocate */ DataBlock(unsigned int overAlloc = 0); /** * Copy constructor * @param value Data block to copy from */ DataBlock(const DataBlock& value); /** * Copy constructor with overallocation * @param value Data block to copy from * @param overAlloc How many bytes of memory to overallocate */ DataBlock(const DataBlock& value, unsigned int overAlloc); /** * Constructs an initialized data block * @param value Data to assign, may be NULL to fill with zeros * @param len Length of data, may be zero (then value is ignored) * @param copyData True to make a copy of the data, false to just insert the pointer * @param overAlloc How many bytes of memory to overallocate */ DataBlock(void* value, unsigned int len, bool copyData = true, unsigned int overAlloc = 0); /** * Destroys the data, disposes the memory. */ virtual ~DataBlock(); /** * Get a pointer to a derived class given that class name * @param name Name of the class we are asking for * @return Pointer to the requested class or NULL if this object doesn't implement it */ virtual void* getObject(const String& name) const; /** * A static empty data block */ static const DataBlock& empty(); /** * Get a pointer to the stored data. * @return A pointer to the data or NULL. */ inline void* data() const { return m_data; } /** * Get a pointer to a byte range inside the stored data. * @param offs Byte offset inside the stored data * @param len Number of bytes that must be valid starting at offset * @return A pointer to the data or NULL if the range is not available. */ inline unsigned char* data(unsigned int offs, unsigned int len = 1) const { return (offs + len <= m_length) ? (static_cast(m_data) + offs) : 0; } /** * Get the value of a single byte inside the stored data * @param offs Byte offset inside the stored data * @param defvalue Default value to return if offset is outside data * @return Byte value at offset (0-255) or defvalue if offset outside data */ inline int at(unsigned int offs, int defvalue = -1) const { return (offs < m_length) ? static_cast(m_data)[offs] : defvalue; } /** * Checks if the block holds a NULL pointer. * @return True if the block holds NULL, false otherwise. */ inline bool null() const { return !m_data; } /** * Get the length of the stored data. * @return The length of the stored data, zero for NULL. */ inline unsigned int length() const { return m_length; } /** * Get the memory overallocation setting. * @return Amount of memory that will be overallocated. */ inline unsigned int overAlloc() const { return m_overAlloc; } /** * Set the memory overallocation. * @param bytes How many bytes of memory to overallocate */ inline void overAlloc(unsigned int bytes) { m_overAlloc = bytes; } /** * Clear the data and optionally free the memory * @param deleteData True to free the deta block, false to just forget it */ void clear(bool deleteData = true); /** * Assign data to the object * @param value Data to assign, may be NULL to fill with zeros * @param len Length of data, may be zero (then value is ignored) * @param copyData True to make a copy of the data, false to just insert the pointer * @param allocated Real allocated data length in case it should not be copied */ DataBlock& assign(void* value, unsigned int len, bool copyData = true, unsigned int allocated = 0); /** * Append data to the current block * @param value Data to append * @param len Length of data */ inline void append(void* value, unsigned int len) { DataBlock tmp(value,len,false); append(tmp); tmp.clear(false); } /** * Append data to the current block * @param value Data to append */ void append(const DataBlock& value); /** * Append a String to the current block * @param value String to append */ void append(const String& value); /** * Insert data before the current block * @param value Data to insert */ void insert(const DataBlock& value); /** * Resize (re-alloc or free) this block if required size is not the same as the current one * @param len Required block size */ inline void resize(unsigned int len) { if (len != length()) assign(0,len); } /** * Truncate the data block * @param len The maximum length to keep */ void truncate(unsigned int len); /** * Cut off a number of bytes from the data block * @param len Amount to cut, positive to cut from end, negative to cut from start of block */ void cut(int len); /** * Byte indexing operator with signed parameter * @param index Index of the byte to retrieve * @return Byte value at offset (0-255) or -1 if index outside data */ inline int operator[](signed int index) const { return at(index); } /** * Byte indexing operator with unsigned parameter * @param index Index of the byte to retrieve * @return Byte value at offset (0-255) or -1 if index outside data */ inline int operator[](unsigned int index) const { return at(index); } /** * Assignment operator. */ DataBlock& operator=(const DataBlock& value); /** * Appending operator. */ inline DataBlock& operator+=(const DataBlock& value) { append(value); return *this; } /** * Appending operator for Strings. */ inline DataBlock& operator+=(const String& value) { append(value); return *this; } /** * Convert data from a different format * @param src Source data block * @param sFormat Name of the source format * @param dFormat Name of the destination format * @param maxlen Maximum amount to convert, 0 to use source * @return True if converted successfully, false on failure */ bool convert(const DataBlock& src, const String& sFormat, const String& dFormat, unsigned maxlen = 0); /** * Build this data block from a hexadecimal string representation. * Each octet must be represented in the input string with 2 hexadecimal characters. * If a separator is specified, the octets in input string must be separated using * exactly 1 separator. Only 1 leading or 1 trailing separators are allowed. * @param data Input character string * @param len Length of the input string * @param sep Separator character used between octets. 0 if no separator is expected * @return True if the input string was succesfully parsed, false otherwise */ bool unHexify(const char* data, unsigned int len, char sep); /** * Build this data block from a hexadecimal string representation. * Each octet must be represented in the input string with 2 hexadecimal characters. * This method guesses if separators are used. If so the octets in input string must be * separated using exactly 1 separator. Only 1 leading or 1 trailing separators are allowed. * @param data Input character string * @param len Length of the input string * @return True if the input string was succesfully parsed, false otherwise */ bool unHexify(const char* data, unsigned int len); /** * Build this data block from a hexadecimal string representation. * This version parses a String and guesses separators presence. * @param data Input character string * @return True if the input string was succesfully parsed, false otherwise */ inline bool unHexify(const String& data) { return unHexify(data.c_str(),data.length()); } /** * Create an escaped string suitable for use in SQL queries * @param extraEsc Character to escape other than the default ones * @return A string with binary zeros and other special characters escaped */ String sqlEscape(char extraEsc) const; private: unsigned int allocLen(unsigned int len) const; void* m_data; unsigned int m_length; unsigned int m_allocated; unsigned int m_overAlloc; }; /** * Abstract base class representing a hash calculator * @short An abstract hashing class */ class YATE_API Hasher { public: /** * Destroy the instance, free allocated memory */ virtual ~Hasher(); /** * Clear the digest and prepare for reuse */ virtual void clear() = 0; /** * Finalize the digest computation, make result ready. * Subsequent calls to @ref update() will fail */ virtual void finalize() = 0; /** * Returns a pointer to the raw 16-byte binary value of the message digest. * The digest is finalized if if wasn't already * @return Pointer to the raw digest data or NULL if some error occured */ virtual const unsigned char* rawDigest() = 0; /** * Returns the standard hexadecimal representation of the message digest. * The digest is finalized if if wasn't already * @return A String which holds the hex digest or a null one if some error occured */ inline const String& hexDigest() { finalize(); return m_hex; } /** * Update the digest from a buffer of data * @param buf Pointer to the data to be included in digest * @param len Length of data in the buffer * @return True if success, false if @ref finalize() was already called */ inline bool update(const void* buf, unsigned int len) { return updateInternal(buf,len); } /** * Update the digest from the content of a DataBlock * @param data Data to be included in digest * @return True if success, false if @ref finalize() was already called */ inline bool update(const DataBlock& data) { return updateInternal(data.data(), data.length()); } /** * Update the digest from the content of a String * @param str String to be included in digest * @return True if success, false if @ref finalize() was already called */ inline bool update(const String& str) { return updateInternal(str.c_str(), str.length()); } /** * Digest updating operator for Strings * @param value String to be included in digest */ inline Hasher& operator<<(const String& value) { update(value); return *this; } /** * Digest updating operator for DataBlocks * @param data Data to be included in digest */ inline Hasher& operator<<(const DataBlock& data) { update(data); return *this; } /** * Digest updating operator for C strings * @param value String to be included in digest */ Hasher& operator<<(const char* value); /** * Start a HMAC calculation, initialize the hash and the outer pad * @param opad Outer pad to be filled from key * @param key Secret key * @param keyLen Secret key length * @return True if hash and outer pad were successfully initialized */ bool hmacStart(DataBlock& opad, const void* key, unsigned int keyLen); /** * Start a HMAC calculation, initialize the hash and the outer pad * @param opad Outer pad to be filled from key * @param key Secret key * @return True if hash and outer pad were successfully initialized */ inline bool hmacStart(DataBlock& opad, const DataBlock& key) { return hmacStart(opad,key.data(),key.length()); } /** * Start a HMAC calculation, initialize the hash and the outer pad * @param opad Outer pad to be filled from key * @param key Secret key string * @return True if hash and outer pad were successfully initialized */ inline bool hmacStart(DataBlock& opad, const String& key) { return hmacStart(opad,key.c_str(),key.length()); } /** * Finalize a HMAC calculation with this hash * @param opad Outer pad as filled by hmacStart * @return True on success, HMAC result is left in hasher */ bool hmacFinal(const DataBlock& opad); /** * Compute a Message Authentication Code with this hash * @param key Secret key * @param keyLen Secret key length * @param msg Message to authenticate * @param msgLen Message length * @return True if HMAC was computed correctly, result is left in hasher */ bool hmac(const void* key, unsigned int keyLen, const void* msg, unsigned int msgLen); /** * Compute a Message Authentication Code with this hash * @param key Secret key * @param msg Message to authenticate * @return True if HMAC was computed correctly, result is left in hasher */ inline bool hmac(const DataBlock& key, const DataBlock& msg) { return hmac(key.data(),key.length(),msg.data(),msg.length()); } /** * Compute a Message Authentication Code with this hash * @param key Secret key string * @param msg Message string to authenticate * @return True if HMAC was computed correctly, result is left in hasher */ inline bool hmac(const String& key, const String& msg) { return hmac(key.c_str(),key.length(),msg.c_str(),msg.length()); } /** * Return the length of the raw binary digest * @return Length of the digest in octets */ virtual unsigned int hashLength() const = 0; /** * Return the size of the block used in HMAC calculations * @return HMAC block size in octets, usually 64 */ virtual unsigned int hmacBlockSize() const; protected: /** * Default constructor */ inline Hasher() : m_private(0) { } /** * Update the digest from a buffer of data * @param buf Pointer to the data to be included in digest * @param len Length of data in the buffer * @return True if success, false if @ref finalize() was already called */ virtual bool updateInternal(const void* buf, unsigned int len) = 0; void* m_private; String m_hex; }; /** * A class to compute and check MD5 digests * @short A standard MD5 digest calculator */ class YATE_API MD5 : public Hasher { public: /** * Construct a fresh initialized instance */ MD5(); /** * Copy constructor * @param original MD5 instance to copy */ MD5(const MD5& original); /** * Construct a digest from a buffer of data * @param buf Pointer to the data to be included in digest * @param len Length of data in the buffer */ MD5(const void* buf, unsigned int len); /** * Construct a digest from a binary DataBlock * @param data Binary data to be included in digest */ MD5(const DataBlock& data); /** * Construct a digest from a String * @param str String to be included in digest */ MD5(const String& str); /** * Assignment operator. */ MD5& operator=(const MD5& original); /** * Destroy the instance, free allocated memory */ virtual ~MD5(); /** * Clear the digest and prepare for reuse */ virtual void clear(); /** * Finalize the digest computation, make result ready. * Subsequent calls to @ref update() will fail */ virtual void finalize(); /** * Returns a pointer to the raw 16-byte binary value of the message digest. * The digest is finalized if if wasn't already * @return Pointer to the raw digest data or NULL if some error occured */ virtual const unsigned char* rawDigest(); /** * Return the length of the raw binary digest * @return Constant value of 16 */ inline static unsigned int rawLength() { return 16; } /** * Return the length of the raw binary digest * @return Length of the digest in octets */ virtual unsigned int hashLength() const { return 16; } protected: bool updateInternal(const void* buf, unsigned int len); private: void init(); unsigned char m_bin[16]; }; /** * A class to compute and check SHA1 digests * @short A standard SHA1 digest calculator */ class YATE_API SHA1 : public Hasher { public: /** * Construct a fresh initialized instance */ SHA1(); /** * Copy constructor * @param original SHA1 instance to copy */ SHA1(const SHA1& original); /** * Construct a digest from a buffer of data * @param buf Pointer to the data to be included in digest * @param len Length of data in the buffer */ SHA1(const void* buf, unsigned int len); /** * Construct a digest from a binary DataBlock * @param data Binary data to be included in digest */ SHA1(const DataBlock& data); /** * Construct a digest from a String * @param str String to be included in digest */ SHA1(const String& str); /** * Assignment operator. */ SHA1& operator=(const SHA1& original); /** * Destroy the instance, free allocated memory */ virtual ~SHA1(); /** * Clear the digest and prepare for reuse */ virtual void clear(); /** * Finalize the digest computation, make result ready. * Subsequent calls to @ref update() will fail */ virtual void finalize(); /** * Returns a pointer to the raw 20-byte binary value of the message digest. * The digest is finalized if if wasn't already * @return Pointer to the raw digest data or NULL if some error occured */ virtual const unsigned char* rawDigest(); /** * Return the length of the raw binary digest * @return Constant value of 20 */ inline static unsigned int rawLength() { return 20; } /** * Return the length of the raw binary digest * @return Length of the digest in octets */ virtual unsigned int hashLength() const { return 20; } /** * NIST FIPS 186-2 change notice 1 Pseudo Random Function. * Uses a b=160 bits SHA1 based G(t,c) function with no XSEEDj * @param out Block to fill with pseudo-random data * @param seed Data to use as RNG seed, must be 1 to 64 octets long * @param len Desired output length in octets, must be 1 to 512 * @return True on success, false on invalid lengths */ static bool fips186prf(DataBlock& out, const DataBlock& seed, unsigned int len); protected: bool updateInternal(const void* buf, unsigned int len); private: void init(); unsigned char m_bin[20]; }; /** * A class to compute and check SHA256 digests * @short A standard SHA256 digest calculator */ class YATE_API SHA256 : public Hasher { public: /** * Construct a fresh initialized instance */ SHA256(); /** * Copy constructor * @param original SHA256 instance to copy */ SHA256(const SHA256& original); /** * Construct a digest from a buffer of data * @param buf Pointer to the data to be included in digest * @param len Length of data in the buffer */ SHA256(const void* buf, unsigned int len); /** * Construct a digest from a binary DataBlock * @param data Binary data to be included in digest */ SHA256(const DataBlock& data); /** * Construct a digest from a String * @param str String to be included in digest */ SHA256(const String& str); /** * Assignment operator. */ SHA256& operator=(const SHA256& original); /** * Destroy the instance, free allocated memory */ virtual ~SHA256(); /** * Clear the digest and prepare for reuse */ virtual void clear(); /** * Finalize the digest computation, make result ready. * Subsequent calls to @ref update() will fail */ virtual void finalize(); /** * Returns a pointer to the raw 32-byte binary value of the message digest. * The digest is finalized if if wasn't already * @return Pointer to the raw digest data or NULL if some error occured */ virtual const unsigned char* rawDigest(); /** * Return the length of the raw binary digest * @return Constant value of 32 */ inline static unsigned int rawLength() { return 32; } /** * Return the length of the raw binary digest * @return Length of the digest in octets */ virtual unsigned int hashLength() const { return 32; } protected: bool updateInternal(const void* buf, unsigned int len); private: void init(); unsigned char m_bin[32]; }; /** * Base64 encoder/decoder class * @short Base64 encoder/decoder class */ class YATE_API Base64 : public DataBlock { YNOCOPY(Base64); // no automatic copies please public: /** * Constructor */ inline Base64() { } /** * Constructor. Set the buffer * @param src Initial data buffer * @param len Initial data buffer length * @param copyData True to make a copy of the received data */ inline Base64(void* src, unsigned int len, bool copyData = true) : DataBlock(src,len,copyData) { } /** * Encode this buffer to a destination string * @param dest Destination string * @param lineLen The length of a line. If non 0, a line break (CR/LF) will * be inserted in the encoded data after each lineLine characters. * No line break will be added after the last line. Use the lineAtEnd * parameter to do that * @param lineAtEnd True to add a line break at the end of encoded data */ void encode(String& dest, unsigned int lineLen = 0, bool lineAtEnd = false); /** * Decode this buffer to a destination one * @param dest Destination data buffer * @param liberal True to use 'liberal' rules when decoding. Some non alphabet * characters (such as CR, LF, TAB, SPACE or the Base64 padding char '=') * will be accepted and ignored. The resulting number of Base64 chars to * decode must be a valid one * @return True on succes, false if an invalid (non Base64) character was * found or the number of Base64 characters is invalid (must be a multiple * of 4 plus 0, 2 or 3 characters) or the padding is incorrect */ bool decode(DataBlock& dest, bool liberal = true); /** * Base64 append operator for Strings */ inline Base64& operator<<(const String& value) { append(value); return *this; } /** * Base64 append operator for DataBlocks */ inline Base64& operator<<(const DataBlock& data) { append(data); return *this; } /** * Base64 append operator for C strings */ inline Base64& operator<<(const char* value) { return operator<<(String(value)); } }; class NamedIterator; /** * This class holds a named list of named strings * @short A named string container class */ class YATE_API NamedList : public String { friend class NamedIterator; public: /** * Creates a new named list. * @param name Name of the list - must not be NULL or empty */ explicit NamedList(const char* name); /** * Copy constructor * @param original Named list we are copying */ NamedList(const NamedList& original); /** * Creates a named list with subparameters of another list. * @param name Name of the list - must not be NULL or empty * @param original Named list to copy parameters from * @param prefix Prefix to match and remove from parameter names */ NamedList(const char* name, const NamedList& original, const String& prefix); /** * Assignment operator * @param value New name and parameters to assign * @return Reference to this NamedList */ NamedList& operator=(const NamedList& value); /** * Get a pointer to a derived class given that class name * @param name Name of the class we are asking for * @return Pointer to the requested class or NULL if this object doesn't implement it */ virtual void* getObject(const String& name) const; /** * Get the number of parameters * @return Count of named strings */ inline unsigned int length() const { return m_params.length(); } /** * Get the number of non-null parameters * @return Count of existing named strings */ inline unsigned int count() const { return m_params.count(); } /** * Clear all parameters */ inline void clearParams() { m_params.clear(); } /** * Add a named string to the parameter list. * @param param Parameter to add * @return Reference to this NamedList */ NamedList& addParam(NamedString* param); /** * Add a named string to the parameter list. * @param name Name of the new string * @param value Value of the new string * @param emptyOK True to always add parameter, false to skip empty values * @return Reference to this NamedList */ NamedList& addParam(const char* name, const char* value, bool emptyOK = true); /** * Set a named string in the parameter list. * @param param Parameter to set or add * @return Reference to this NamedList */ inline NamedList& setParam(NamedString* param) { if (param) m_params.setUnique(param); return *this; } /** * Set a named string in the parameter list. * @param name Name of the string * @param value Value of the string * @return Reference to this NamedList */ NamedList& setParam(const String& name, const char* value); /** * Clears all instances of a named string in the parameter list. * @param name Name of the string to remove * @param childSep If set clears all child parameters in format name+childSep+anything * @return Reference to this NamedList */ NamedList& clearParam(const String& name, char childSep = 0); /** * Remove a specific parameter * @param param Pointer to parameter to remove * @param delParam True to destroy the parameter * @return Reference to this NamedList */ NamedList& clearParam(NamedString* param, bool delParam = true); /** * Copy a parameter from another NamedList, clears it if not present there * @param original NamedList to copy the parameter from * @param name Name of the string to copy or clear * @param childSep If set copies all child parameters in format name+childSep+anything * @return Reference to this NamedList */ NamedList& copyParam(const NamedList& original, const String& name, char childSep = 0); /** * Copy all parameters from another NamedList, does not clear list first * @param original NamedList to copy the parameters from * @return Reference to this NamedList */ NamedList& copyParams(const NamedList& original); /** * Copy multiple parameters from another NamedList, clears them if not present there * @param original NamedList to copy the parameters from * @param list List of objects (usually String) whose name (blanks stripped) is used as parameters names * @param childSep If set copies all child parameters in format name+childSep+anything * @return Reference to this NamedList */ NamedList& copyParams(const NamedList& original, ObjList* list, char childSep = 0); /** * Copy multiple parameters from another NamedList, clears it if not present there * @param original NamedList to copy the parameter from * @param list Comma separated list of parameters to copy or clear * @param childSep If set copies all child parameters in format name+childSep+anything * @return Reference to this NamedList */ NamedList& copyParams(const NamedList& original, const String& list, char childSep = 0); /** * Copy subparameters from another list * @param original Named list to copy parameters from * @param prefix Prefix to match in parameter names, must not be NULL * @param skipPrefix Skip over the prefix when building new parameter name * @param replace Set to true to replace list parameter instead of adding a new one * @return Reference to this NamedList */ NamedList& copySubParams(const NamedList& original, const String& prefix, bool skipPrefix = true, bool replace = false); /** * Check if we have a parameter that starts with prefix * @param prefix Prefix to match in parameter name, must not be NULL * @return True if a parameter starts with prefix */ bool hasSubParams(const char* prefix) const; /** * Get the index of a named string in the parameter list. * @param param Pointer to the parameter to locate * @return Index of the named string or -1 if not found */ int getIndex(const NamedString* param) const; /** * Get the index of first matching named string in the parameter list. * @param name Name of parameter to locate * @return Index of the first matching named string or -1 if not found */ int getIndex(const String& name) const; /** * Locate a named string in the parameter list. * @param name Name of parameter to locate * @return A pointer to the named string or NULL. */ NamedString* getParam(const String& name) const; /** * Locate a named string in the parameter list. * @param index Index of the parameter to locate * @return A pointer to the named string or NULL. */ NamedString* getParam(unsigned int index) const; /** * Parameter access operator * @param name Name of the parameter to return * @return String value of the parameter, @ref String::empty() if missing */ const String& operator[](const String& name) const; /** * Retrieve the value of a named parameter. * @param name Name of parameter to locate * @param defvalue Default value to return if not found * @return The string contained in the named parameter or the default */ const char* getValue(const String& name, const char* defvalue = 0) const; /** * Retrieve the numeric value of a parameter. * @param name Name of parameter to locate * @param defvalue Default value to return if not found * @param minvalue Minimum value allowed for the parameter * @param maxvalue Maximum value allowed for the parameter * @param clamp Control the out of bound values: true to adjust to the nearest * bound, false to return the default value * @return The number contained in the named parameter or the default */ int getIntValue(const String& name, int defvalue = 0, int minvalue = INT_MIN, int maxvalue = INT_MAX, bool clamp = true) const; /** * Retrieve the numeric value of a parameter trying first a table lookup. * @param name Name of parameter to locate * @param tokens A pointer to an array of tokens to try to lookup * @param defvalue Default value to return if not found * @return The number contained in the named parameter or the default */ int getIntValue(const String& name, const TokenDict* tokens, int defvalue = 0) const; /** * Retrieve the 64-bit numeric value of a parameter. * @param name Name of parameter to locate * @param defvalue Default value to return if not found * @param minvalue Minimum value allowed for the parameter * @param maxvalue Maximum value allowed for the parameter * @param clamp Control the out of bound values: true to adjust to the nearest * bound, false to return the default value * @return The number contained in the named parameter or the default */ int64_t getInt64Value(const String& name, int64_t defvalue = 0, int64_t minvalue = LLONG_MIN, int64_t maxvalue = LLONG_MAX, bool clamp = true) const; /** * Retrieve the unsigned 64-bit numeric value of a parameter. * @param name Name of parameter to locate * @param defvalue Default value to return if not found * @param minvalue Minimum value allowed for the parameter * @param maxvalue Maximum value allowed for the parameter * @param clamp Control the out of bound values: true to adjust to the nearest * bound, false to return the default value * @return The number contained in the named parameter or the default */ uint64_t getUInt64Value(const String& name, uint64_t defvalue = 0, uint64_t minvalue = 0, uint64_t maxvalue = ULLONG_MAX, bool clamp = true) const; /** * Retrieve the floating point value of a parameter. * @param name Name of parameter to locate * @param defvalue Default value to return if not found * @return The number contained in the named parameter or the default */ double getDoubleValue(const String& name, double defvalue = 0.0) const; /** * Retrieve the boolean value of a parameter. * @param name Name of parameter to locate * @param defvalue Default value to return if not found * @return The boolean value contained in the named parameter or the default */ bool getBoolValue(const String& name, bool defvalue = false) const; /** * Replaces all ${paramname} in a String with the corresponding parameters * @param str String in which the replacements will be made * @param sqlEsc True to apply SQL escaping to parameter values * @param extraEsc Character to escape other than the SQL default ones * @return Number of replacements made, -1 if an error occured */ int replaceParams(String& str, bool sqlEsc = false, char extraEsc = 0) const; /** * Dumps the name and all parameters to a string in a human readable format. * No escaping takes place so this method should be used for debugging only * @param str String to which the name and parameters are appended * @param separator Separator string to use before each parameter * @param quote String quoting character, usually single or double quote * @param force True to insert the separator even in an empty string */ void dump(String& str, const char* separator, char quote = 0, bool force = false) const; /** * A static empty named list * @return Reference to a static empty named list */ static const NamedList& empty(); /** * Get the parameters list * @return Pointer to the parameters list */ inline ObjList* paramList() { return &m_params; } /** * Get the parameters list * @return Pointer to the parameters list */ inline const ObjList* paramList() const { return &m_params; } private: NamedList(); // no default constructor please ObjList m_params; }; /** * An iterator for NamedString parameters of a NamedList. * Fast but unsafe, the list must not be modified during iteration. * @short NamedList parameters iterator */ class YATE_API NamedIterator { public: /** * Constructor * @param list NamedList whose parameters are iterated */ inline NamedIterator(const NamedList& list) : m_list(&list), m_item(list.m_params.skipNull()) { } /** * Copy constructor, points to same list and position as the original * @param original Iterator to copy from */ inline NamedIterator(const NamedIterator& original) : m_list(original.m_list), m_item(original.m_item) { } /** * Assignment from list operator * @param list NamedList whose parameters are iterated */ inline NamedIterator& operator=(const NamedList& list) { m_list = &list; m_item = list.m_params.skipNull(); return *this; } /** * Assignment operator, points to same list and position as the original * @param original Iterator to copy from */ inline NamedIterator& operator=(const NamedIterator& original) { m_list = original.m_list; m_item = original.m_item; return *this; } /** * Get the current parameter and advance in the list * @return Pointer to list parameter or NULL if advanced past end (eof) */ const NamedString* get(); /** * Check if the iteration reached end of the parameters list */ inline bool eof() const { return !m_item; } /** * Reset the iterator to the first position in the parameters list */ inline void reset() { m_item = m_list->m_params.skipNull(); } private: NamedIterator(); // no default constructor please const NamedList* m_list; const ObjList* m_item; }; /** * Uniform Resource Identifier encapsulation and parser. * For efficiency reason the parsing is delayed as long as possible * @short Encapsulation for an URI */ class YATE_API URI : public String { public: /** * Empty URI constructor */ URI(); /** * Copy constructor * @param uri Original URI to copy */ URI(const URI& uri); /** * Constructor from a String that gets parsed later * @param uri String form of the URI */ explicit URI(const String& uri); /** * Constructor from a C string that gets parsed later * @param uri String form of the URI */ explicit URI(const char* uri); /** * Constructor from URI components * @param proto Protocol - something like "http", "sip", etc. * @param user User component of the URI * @param host Hostname component of the URI * @param port Port part of the URI (optional) * @param desc Description part in front of the URI (optional) */ URI(const char* proto, const char* user, const char* host, int port = 0, const char* desc = 0); /** * Calling this method ensures the string URI is parsed into components */ void parse() const; /** * Assignment operator from URI * @param value New URI value to assign */ inline URI& operator=(const URI& value) { String::operator=(value); return *this; } /** * Assignment operator from String * @param value New URI value to assign */ inline URI& operator=(const String& value) { String::operator=(value); return *this; } /** * Assignment operator from C string * @param value New URI value to assign */ inline URI& operator=(const char* value) { String::operator=(value); return *this; } /** * Access method to the description part of the URI * @return Description part of the URI */ inline const String& getDescription() const { parse(); return m_desc; } /** * Access method to the protocol part of the URI * @return Protocol part of the URI */ inline const String& getProtocol() const { parse(); return m_proto; } /** * Access method to the user part of the URI * @return User component of the URI */ inline const String& getUser() const { parse(); return m_user; } /** * Access method to the host part of the URI * @return Hostname part of the URI */ inline const String& getHost() const { parse(); return m_host; } /** * Access method to the port part of the URI * @return Port of the URI, zero if not set */ inline int getPort() const { parse(); return m_port; } /** * Access method to the additional text part of the URI * @return Additional text of the URI including the separator */ inline const String& getExtra() const { parse(); return m_extra; } protected: /** * Notification method called whenever the string URI has changed. * The default behaviour is to invalidate the parsed flag and cal the * method inherited from @ref String. */ virtual void changed(); mutable bool m_parsed; mutable String m_desc; mutable String m_proto; mutable String m_user; mutable String m_host; mutable String m_extra; mutable int m_port; }; class MutexPrivate; class SemaphorePrivate; class ThreadPrivate; /** * An abstract base class for implementing lockable objects * @short Abstract interface for lockable objects */ class YATE_API Lockable { public: /** * Destructor */ virtual ~Lockable(); /** * Attempt to lock the object and eventually wait for it * @param maxwait Time in microseconds to wait, -1 wait forever * @return True if successfully locked, false on failure */ virtual bool lock(long maxwait = -1) = 0; /** * Unlock the object, does never wait * @return True if successfully unlocked the object */ virtual bool unlock() = 0; /** * Check if the object is currently locked - as it's asynchronous it * guarantees nothing if other thread changes the status * @return True if the object was locked when the function was called */ virtual bool locked() const = 0; /** * Check if the object is unlocked (try to lock and unlock it) * @param maxwait Time in microseconds to wait, -1 to wait forever * @return True if successfully locked and unlocked, false on failure */ virtual bool check(long maxwait = -1); /** * Fully unlock the object, even if it was previously multiple locked. * There is no guarantee about the object status after the function returns. * This function should be used only if you understand it very well * @return True if the object was fully unlocked */ virtual bool unlockAll(); /** * Set a maximum wait time for debugging purposes * @param maxwait Maximum time in microseconds to wait for any lockable * object when no time limit was requested, zero to disable limit */ static void wait(unsigned long maxwait); /** * Get the maximum wait time used for debugging purposes * @return Maximum time in microseconds, zero if no maximum is set */ static unsigned long wait(); /** * Start actually using lockables, for platforms where these objects are not * usable in global object constructors. * This method must be called at least once somewhere from main() but * before creating any threads and without holding any object locked. */ static void startUsingNow(); /** * Enable some safety and sanity check features. * This provides a safer code and easier locking debugging at the price of performance penalty. * This method must be called early and not changed after initialization * @param safe True to enable locking safety measures, false to disable */ static void enableSafety(bool safe = true); /** * Retrieve safety and sanity check features flag value * @return Locking safety measures flag value */ static bool safety(); }; /** * A simple mutual exclusion for locking access between threads * @short Mutex support */ class YATE_API Mutex : public Lockable { friend class MutexPrivate; public: /** * Construct a new unlocked mutex * @param recursive True if the mutex has to be recursive (reentrant), * false for a normal fast mutex * @param name Static name of the mutex (for debugging purpose only) */ explicit Mutex(bool recursive = false, const char* name = 0); /** * Copy constructor, creates a shared mutex * @param original Reference of the mutex to share */ Mutex(const Mutex& original); /** * Destroy the mutex */ ~Mutex(); /** * Assignment operator makes the mutex shared with the original * @param original Reference of the mutex to share */ Mutex& operator=(const Mutex& original); /** * Attempt to lock the mutex and eventually wait for it * @param maxwait Time in microseconds to wait for the mutex, -1 wait forever * @return True if successfully locked, false on failure */ virtual bool lock(long maxwait = -1); /** * Unlock the mutex, does never wait * @return True if successfully unlocked the mutex */ virtual bool unlock(); /** * Check if the mutex is currently locked - as it's asynchronous it * guarantees nothing if other thread changes the mutex's status * @return True if the mutex was locked when the function was called */ virtual bool locked() const; /** * Retrieve the name of the Thread (if any) holding the Mutex locked * @return Thread name() or NULL if thread not named */ const char* owner() const; /** * Check if this mutex is recursive or not * @return True if this is a recursive mutex, false for a fast mutex */ bool recursive() const; /** * Get the number of mutexes counting the shared ones only once * @return Count of individual mutexes */ static int count(); /** * Get the number of currently locked mutexes * @return Count of locked mutexes, -1 if unknown (not tracked) */ static int locks(); /** * Check if a timed lock() is efficient on this platform * @return True if a lock with a maxwait parameter is efficiently implemented */ static bool efficientTimedLock(); private: MutexPrivate* privDataCopy() const; MutexPrivate* m_private; }; /** * This class holds a Mutex array. Mutexes can be retrieved based on object pointers. * A mutex pool can be used to associate a smaller set of Mutex objects with a much * larger set of objects needing lock. * @short A Mutex pool */ class YATE_API MutexPool { public: /** * Build the mutex pool * @param len The number of mutex objects to build. The length should be an * odd number to obtain an optimal distribution of pointer based mutexes * (usually pointers are aligned at even addresses): some mutexes might never * get used if the length is an even number * @param recursive True if the mutex has to be recursive (reentrant), * false for a normal fast mutex * @param name Static name of the mutex (for debugging purpose only) */ MutexPool(unsigned int len = 13, bool recursive = false, const char* name = 0); /** * Destructor. Release data */ ~MutexPool(); /** * Build an index from object pointer (pointer value modulo array length). * Always cast the pointer to the same type when calling this method to * make sure the same index is returned for a given object * @param ptr The pointer to object * @return Valid array index */ inline unsigned int index(void* ptr) const { return ((unsigned int)(unsigned long)ptr) % m_length; } /** * Retrieve the mutex associated with a given pointer. * Always cast the pointer to the same type when calling this method to * make sure the same mutex is returned for a given object * @param ptr The pointer to object * @return Valid Mutex pointer */ inline Mutex* mutex(void* ptr) const { return m_data[index(ptr)]; } /** * Retrieve the mutex at a given index modulo array length * @param idx The index * @return Valid Mutex pointer */ inline Mutex* mutex(unsigned int idx) const { return m_data[idx % m_length]; } private: String* m_name; // Mutex names Mutex** m_data; // The array unsigned int m_length; // Array length }; /** * A semaphore object for synchronizing threads, can also be used as a token bucket * @short Semaphore implementation */ class YATE_API Semaphore : public Lockable { friend class SemaphorePrivate; public: /** * Construct a new unlocked semaphore * @param maxcount Maximum unlock count, must be strictly positive * @param name Static name of the semaphore (for debugging purpose only) * @param initialCount Initial semaphore count, must not be greater than maxcount */ explicit Semaphore(unsigned int maxcount = 1, const char* name = 0, unsigned int initialCount = 1); /** * Copy constructor, creates a shared semaphore * @param original Reference of the semaphore to share */ Semaphore(const Semaphore& original); /** * Destroy the semaphore */ ~Semaphore(); /** * Assignment operator makes the semaphore shared with the original * @param original Reference of the semaphore to share */ Semaphore& operator=(const Semaphore& original); /** * Attempt to get a lock on the semaphore and eventually wait for it * @param maxwait Time in microseconds to wait, -1 wait forever * @return True if successfully locked, false on failure */ virtual bool lock(long maxwait = -1); /** * Unlock the semaphore, does never wait nor get over counter maximum * @return True if successfully unlocked */ virtual bool unlock(); /** * Check if the semaphore is currently locked (waiting) - as it's * asynchronous it guarantees nothing if other thread changes status * @return True if the semaphore was locked when the function was called */ virtual bool locked() const; /** * Get the number of semaphores counting the shared ones only once * @return Count of individual semaphores */ static int count(); /** * Get the number of currently locked (waiting) semaphores * @return Count of locked semaphores, -1 if unknown (not tracked) */ static int locks(); /** * Check if a timed lock() is efficient on this platform * @return True if a lock with a maxwait parameter is efficiently implemented */ static bool efficientTimedLock(); private: SemaphorePrivate* privDataCopy() const; SemaphorePrivate* m_private; }; /** * A lock is a stack allocated (automatic) object that locks a lockable object * on creation and unlocks it on destruction - typically when exiting a block * @short Ephemeral mutex or semaphore locking object */ class YATE_API Lock { YNOCOPY(Lock); // no automatic copies please public: /** * Create the lock, try to lock the object * @param lck Reference to the object to lock * @param maxwait Time in microseconds to wait, -1 wait forever */ inline Lock(Lockable& lck, long maxwait = -1) { m_lock = lck.lock(maxwait) ? &lck : 0; } /** * Create the lock, try to lock the object * @param lck Pointer to the object to lock * @param maxwait Time in microseconds to wait, -1 wait forever */ inline Lock(Lockable* lck, long maxwait = -1) { m_lock = (lck && lck->lock(maxwait)) ? lck : 0; } /** * Destroy the lock, unlock the mutex if it was locked */ inline ~Lock() { if (m_lock) m_lock->unlock(); } /** * Return a pointer to the lockable object this lock holds * @return A pointer to a Lockable or NULL if locking failed */ inline Lockable* locked() const { return m_lock; } /** * Unlock the object if it was locked and drop the reference to it */ inline void drop() { if (m_lock) m_lock->unlock(); m_lock = 0; } /** * Attempt to acquire a new lock on another object * @param lck Pointer to the object to lock * @param maxwait Time in microseconds to wait, -1 wait forever * @return True if locking succeeded or same object was locked */ inline bool acquire(Lockable* lck, long maxwait = -1) { return (lck && (lck == m_lock)) || (drop(),(lck && (m_lock = lck->lock(maxwait) ? lck : 0))); } /** * Attempt to acquire a new lock on another object * @param lck Reference to the object to lock * @param maxwait Time in microseconds to wait, -1 wait forever * @return True if locking succeeded or same object was locked */ inline bool acquire(Lockable& lck, long maxwait = -1) { return acquire(&lck,maxwait); } private: Lockable* m_lock; /** Make sure no Lock is ever created on heap */ inline void* operator new(size_t); /** Never allocate an array of this class */ inline void* operator new[](size_t); }; /** * A dual lock is a stack allocated (automatic) object that locks a pair * of mutexes on creation and unlocks them on destruction. The mutexes are * always locked in the same order to prevent trivial deadlocks * @short Ephemeral double mutex locking object */ class YATE_API Lock2 { YNOCOPY(Lock2); // no automatic copies please public: /** * Create the dual lock, try to lock each mutex * @param mx1 Pointer to the first mutex to lock * @param mx2 Pointer to the second mutex to lock * @param maxwait Time in microseconds to wait for each mutex, -1 wait forever */ inline Lock2(Mutex* mx1, Mutex* mx2, long maxwait = -1) : m_mx1(0), m_mx2(0) { lock(mx1,mx2,maxwait); } /** * Create the dual lock, try to lock each mutex * @param mx1 Reference to the first mutex to lock * @param mx2 Reference to the second mutex to lock * @param maxwait Time in microseconds to wait for each mutex, -1 wait forever */ inline Lock2(Mutex& mx1, Mutex& mx2, long maxwait = -1) : m_mx1(0), m_mx2(0) { lock(&mx1,&mx2,maxwait); } /** * Destroy the lock, unlock the mutex if it was locked */ inline ~Lock2() { drop(); } /** * Check if the locking succeeded * @return True if all mutexes were locked */ inline bool locked() const { return m_mx1 != 0; } /** * Lock in a new pair of mutexes. Any existing locks are dropped * @param mx1 Pointer to the first mutex to lock * @param mx2 Pointer to the second mutex to lock * @param maxwait Time in microseconds to wait for each mutex, -1 wait forever * @return True on success - non-NULL mutexes locked */ bool lock(Mutex* mx1, Mutex* mx2, long maxwait = -1); /** * Lock in a new pair of mutexes * @param mx1 Reference to the first mutex to lock * @param mx2 Reference to the second mutex to lock * @param maxwait Time in microseconds to wait for each mutex, -1 wait forever * @return True on success - both locked */ inline bool lock(Mutex& mx1, Mutex& mx2, long maxwait = -1) { return lock(&mx1,&mx2,maxwait); } /** * Unlock both mutexes if they were locked and drop the references */ void drop(); private: Mutex* m_mx1; Mutex* m_mx2; /** Make sure no Lock2 is ever created on heap */ inline void* operator new(size_t); /** Never allocate an array of this class */ inline void* operator new[](size_t); }; /** * This class holds the action to execute a certain task, usually in a * different execution thread. * @short Encapsulates a runnable task */ class YATE_API Runnable { public: /** * This method is called in another thread to do the actual job. * When it returns the job or thread terminates. */ virtual void run() = 0; /** * Do-nothing destructor, placed here just to shut up GCC 4+ */ virtual ~Runnable(); }; /** * A thread is a separate execution context that exists in the same address * space. Threads make better use of multiple processor machines and allow * blocking one execution thread while allowing other to run. * @short Thread support class */ class YATE_API Thread : public Runnable { friend class ThreadPrivate; friend class MutexPrivate; friend class SemaphorePrivate; YNOCOPY(Thread); // no automatic copies please public: /** * Running priorities, their mapping is operating system dependent */ enum Priority { Lowest, Low, Normal, High, Highest }; /** * This method is called when the current thread terminates. */ virtual void cleanup(); /** * Actually starts running the new thread which lingers after creation * @return False if an error occured, true if started ok */ bool startup(); /** * Check if the thread creation failed * @return True if an error occured, false if created ok */ bool error() const; /** * Check if the thread is running or not * @return True if running, false if it has terminated or no startup called */ bool running() const; /** * Get the affinity mask of this thread * @param outCpuMask Bit mask specifying CPUs on which the thread is running on. Bit 0 of octet 0 in DataBlock is CPU 0, * bit 1 in octet 0 is CPU 1,..., bit 0 in octet 2 is CPU 8, etc. * @return 0 on success, error otherwise */ int getAffinity(DataBlock& outCpuMask); /** * Set the affinity of this thread by using a string that specifies the * allowed CPUs by listing them separated with commas or as ranges. * Mixing ranges with list is allowed (e.g. 0,2,5-6,10) * @param cpus String specifying CPUs on which this thread should run. * @return 0 on success, error otherwise */ int setAffinity(const String& cpus); /** * Set the affinity of this thread * @param mask Bit mask specifying allowed CPUs kept in a DataBlock. Bit 0 of octet 0 in DataBlock is CPU 0, * bit 1 in octet 0 is CPU 1,..., bit 0 in octet 1 is CPU 8, etc. * @return 0 on success, error otherwise */ int setAffinity(const DataBlock& mask); /** * Count how many Yate mutexes are kept locked by this thread * @return Number of Mutex locks held by this thread */ inline int locks() const { return m_locks; } /** * Check if the thread is currently helding or attempting to lock a mutex * @return True if the current thread is in an unsafe to cancel state */ inline bool locked() const { return m_locking || m_locks; } /** * Get the name of this thread * @return The pointer that was passed in the constructor */ const char* name() const; /** * Get the name of the currently running thread * @return The pointer that was passed in the thread's constructor */ static const char* currentName(); /** * Get the affinity mask of current thread * @param outCpuMask Bit mask specifying CPUs on which the current thread is running on. Bit 0 of octet 0 in DataBlock is CPU 0, * bit 1 in octet 0 is CPU 1,..., bit 0 in octet 1 is CPU 8, etc. * @return 0 on success, error otherwise */ static int getCurrentAffinity(DataBlock& outCpuMask); /** * Get the affinity mask of current thread * @param outCpus String into which to put the affinity * @param hex True to put it as octet string, false as comma-separated list of CPUs * @return 0 on success, error otherwise */ static int getCurrentAffinity(String& outCpus, bool hex = false); /** * Set the affinity of the current thread by using a string that specifies the * allowed CPUs by listing them separated with commas or as ranges. * Mixing ranges with list is allowed (e.g. 0,2,5-6,10) * @param cpus String specifying CPUs on which this thread should run. * @return 0 on success, error otherwise */ static int setCurrentAffinity(const String& cpus); /** * Set the affinity of the current thread * @param mask Bit mask specifying allowed CPUs kept in a DataBlock. Bit 0 of octet 0 in DataBlock is CPU 0, * bit 1 in octet 0 is CPU 1,..., bit 0 in octet 1 is CPU 8, etc. * @return 0 on success, error otherwise */ static int setCurrentAffinity(const DataBlock& mask); /** * Parse a CPU list into a bitmask held in a DataBlock. * String is formated as a list of integers or integer ranges separated by commas.. * Mixing ranges with list is allowed (e.g. 0,2,5-6,10) * @param cpus String specifying CPUs * @param mask Output bitmask resulted from parsing. * @return True if parsing succeeded, false otherwise */ static bool parseCPUMask(const String& cpus, DataBlock& mask); /** * Stringify the CPU mask * @param mask Mask to stringify * @param str Output string * @param hexa Output as hexadecimal string if set, otherwise build a list of comma separated CPUs */ static void printCPUMask(const DataBlock& mask, String& str, bool hexa = true); /** * Give up the currently running timeslice. Note that on some platforms * it also sleeps for the operating system's scheduler resolution * @param exitCheck Terminate the thread if asked so */ static void yield(bool exitCheck = false); /** * Sleep for a system dependent period adequate for an idle thread. * On most operating systems this is a 5 msec sleep. * @param exitCheck Terminate the thread if asked so */ static void idle(bool exitCheck = false); /** * Sleep for a number of seconds * @param sec Number of seconds to sleep * @param exitCheck Terminate the thread if asked so */ static void sleep(unsigned int sec, bool exitCheck = false); /** * Sleep for a number of milliseconds * @param msec Number of milliseconds to sleep * @param exitCheck Terminate the thread if asked so */ static void msleep(unsigned long msec, bool exitCheck = false); /** * Sleep for a number of microseconds * @param usec Number of microseconds to sleep, may be rounded to * milliseconds on some platforms * @param exitCheck Terminate the thread if asked so */ static void usleep(unsigned long usec, bool exitCheck = false); /** * Get the platform dependent idle sleep interval in microseconds * @return Number of microseconds each call to idle() will sleep */ static unsigned long idleUsec(); /** * Get the platform dependent idle sleep interval in milliseconds * @return Number of milliseconds each call to idle() will sleep */ static unsigned long idleMsec(); /** * Set the idle sleep interval or reset to platform default * @param msec Sleep interval in milliseconds, platform default if zero */ static void idleMsec(unsigned long msec); /** * Get a pointer to the currently running thread * @return A pointer to the current thread or NULL for the main thread * or threads created by other libraries */ static Thread* current(); /** * Get the number of Yate created threads * @return Count of current Thread objects */ static int count(); /** * Check if the current thread was asked to terminate. * @param exitNow If thread is marked as cancelled then terminate immediately * @return False if thread should continue running, true if it should stop */ static bool check(bool exitNow = true); /** * Terminates the current thread. */ static void exit(); /** * Terminates the specified thread. * @param hard Kill the thread the hard way rather than just setting an exit check marker */ void cancel(bool hard = false); /** * Check if this thread is the currently running thread * @return True if this is the current thread */ inline bool isCurrent() const { return current() == this; } /** * Get the object counter of this thread * @return Pointer to thread's counter for new objects */ NamedCounter* getObjCounter() const; /** * Set the object counter of this thread * @param counter New counter object or NULL * @return Pointer to old counter object */ NamedCounter* setObjCounter(NamedCounter* counter); /** * Get the object counter of the current thread * @param always Return the object even if counting is disabled * @return Pointer to current counter for new objects */ static NamedCounter* getCurrentObjCounter(bool always = false); /** * Set the object counter of the current thread * @param counter New counter object or NULL * @return Pointer to old counter object */ static NamedCounter* setCurrentObjCounter(NamedCounter* counter); /** * Convert a priority name to a thread priority level * @param name Name of the requested level * @param defvalue Priority to return in case of an invalid name * @return A thread priority level */ static Priority priority(const char* name, Priority defvalue = Normal); /** * Convert a priority level to a textual name * @param prio Priority level to convert * @return Name of the level or NULL if an invalid argument was provided */ static const char* priority(Priority prio); /** * Kills all other running threads. Ouch! * Must be called from the main thread or it does nothing. */ static void killall(); /** * On some platforms this method kills all other running threads. * Must be called after fork() but before any exec*() call. */ static void preExec(); /** * Get the last thread error * @return The value returned by GetLastError() (on Windows) or * the value of C library 'errno' variable otherwise */ static int lastError(); /** * Get the last thread error's string from system. * @param buffer The destination string * @return True if an error string was retrieved. If false is returned, the buffer * is filled with a generic string indicating an unknown error and its code */ static inline bool errorString(String& buffer) { return errorString(buffer,lastError()); } /** * Get an error string from system. * On Windows the code parameter must be a code returned by GetLastError(). * Otherwise, the error code should be a valid value for the C library 'errno' * variable * @param buffer The destination string * @param code The error code * @return True if an error string was retrieved. If false is returned, the buffer * is filled with a generic string indicating an unknown error and its code */ static bool errorString(String& buffer, int code); protected: /** * Creates and starts a new thread * @param name Static name of the thread (for debugging purpose only) * @param prio Thread priority */ Thread(const char *name = 0, Priority prio = Normal); /** * Creates and starts a new thread * @param name Static name of the thread (for debugging purpose only) * @param prio Thread priority level name */ Thread(const char *name, const char* prio); /** * The destructor is called when the thread terminates */ virtual ~Thread(); private: ThreadPrivate* m_private; int m_locks; bool m_locking; }; /** * This class changes the current thread's object counter for its lifetime * @short Ephemeral object counter changer */ class YATE_API TempObjectCounter { YNOCOPY(TempObjectCounter); // no automatic copies please public: /** * Constructor, changes object counter if counting is enabled * @param counter Object counter to apply on the current thread * @param enable True to enable change, false to take no action */ inline TempObjectCounter(NamedCounter* counter, bool enable = GenObject::getObjCounting()) : m_saved(0), m_enabled(enable) { if (m_enabled) m_saved = Thread::setCurrentObjCounter(counter); } /** * Constructor, changes object counter if counting is enabled * @param obj Object to copy the counter from * @param enable True to enable change, false to take no action */ inline TempObjectCounter(const GenObject* obj, bool enable = GenObject::getObjCounting()) : m_saved(0), m_enabled(enable && obj) { if (m_enabled) m_saved = Thread::setCurrentObjCounter(obj->getObjCounter()); } /** * Constructor, changes object counter if counting is enabled * @param obj Object to copy the counter from * @param enable True to enable change, false to take no action */ inline TempObjectCounter(const GenObject& obj, bool enable = GenObject::getObjCounting()) : m_saved(0), m_enabled(enable) { if (m_enabled) m_saved = Thread::setCurrentObjCounter(obj.getObjCounter()); } /** * Destructor, restores saved object counter */ inline ~TempObjectCounter() { if (m_enabled) Thread::setCurrentObjCounter(m_saved); } private: NamedCounter* m_saved; bool m_enabled; }; class Socket; /** * Wrapper class to keep a socket address * @short A socket address holder */ class YATE_API SocketAddr : public GenObject { YCLASS(SocketAddr,GenObject) public: /** * Known address families */ enum Family { Unknown = AF_UNSPEC, IPv4 = AF_INET, AfMax = AF_MAX, AfUnsupported = AfMax, #ifdef AF_INET6 IPv6 = AF_INET6, #else IPv6 = AfUnsupported + 1, #endif #ifdef HAS_AF_UNIX Unix = AF_UNIX, #else Unix = AfUnsupported + 2, #endif }; /** * Default constructor of an empty address */ inline SocketAddr() : m_address(0), m_length(0) { } /** * Copy constructor * @param value Address to copy */ inline SocketAddr(const SocketAddr& value) : GenObject(), m_address(0), m_length(0) { assign(value.address(),value.length()); } /** * Constructor of a null address * @param family Family of the address to create * @param raw Raw address data */ explicit SocketAddr(int family, const void* raw = 0); /** * Constructor that stores a copy of an address * @param addr Pointer to the address to store * @param len Length of the stored address, zero to use default */ SocketAddr(const struct sockaddr* addr, socklen_t len = 0); /** * Destructor that frees and zeroes out everything */ virtual ~SocketAddr(); /** * Assignment operator * @param value Address to copy */ inline SocketAddr& operator=(const SocketAddr& value) { assign(value.address(),value.length()); return *this; } /** * Equality comparation operator * @param other Address to compare to * @return True if the addresses are equal */ bool operator==(const SocketAddr& other) const; /** * Inequality comparation operator * @param other Address to compare to * @return True if the addresses are different */ inline bool operator!=(const SocketAddr& other) const { return !operator==(other); } /** * Clears up the address, frees the memory */ void clear(); /** * Assigns an empty address of a specific type * @param family Family of the address to create * @return True if the address family is supported */ bool assign(int family); /** * Assigns a new address * @param addr Pointer to the address to store * @param len Length of the stored address, zero to use default */ void assign(const struct sockaddr* addr, socklen_t len = 0); /** * Assigns a new address * @param addr Packed binary address to store * @return True if the address family is supported */ bool assign(const DataBlock& addr); /** * Attempt to guess a local address that will be used to reach a remote one * @param remote Remote address to reach * @return True if guessed an address, false if failed */ bool local(const SocketAddr& remote); /** * Check if a non-null address is held * @return True if a valid address is held, false if null */ inline bool valid() const { return m_length && m_address; } /** * Check if a null address is held * @return True if a null address is held */ inline bool null() const { return !(m_length && m_address); } /** * Get the family of the stored address * @return Address family of the stored address or zero (AF_UNSPEC) */ inline int family() const { return m_address ? m_address->sa_family : 0; } /** * Retrieve address family name * @return Address family name */ inline const char* familyName() const { return lookupFamily(family()); } /** * Retrieve the sin6_scope_id value of an IPv6 address * @return The requested value (it may be 0), 0 if not available */ inline unsigned int scopeId() const { return scopeId(address()); } /** * Set the sin6_scope_id value of an IPv6 address * @param val Value to set * @return True on success, false if not available */ inline bool scopeId(unsigned int val) { return scopeId(address(),val); } /** * Get the host of this address * @return Host name as String */ inline const String& host() const { return m_host; } /** * Get the host and port of this address * @return Address String (host:port) */ inline const String& addr() const { if (!m_addr) updateAddr(); return m_addr; } /** * Set the hostname of this address. * Guess address family if not initialized * @param name Host to set * @return True if new host set, false if name could not be parsed */ virtual bool host(const String& name); /** * Get the port of the stored address (if supported) * @return Port number of the socket address or zero */ int port() const; /** * Set the port of the stored address (if supported) * @param newport Port number to set in the socket address * @return True if new port set, false if not supported */ bool port(int newport); /** * Get the contained socket address * @return A pointer to the socket address */ inline struct sockaddr* address() const { return m_address; } /** * Get the length of the address * @return Length of the stored address */ inline socklen_t length() const { return m_length; } /** * Check if this address is empty or null * @return True if the address is empty or '0.0.0.0' (IPv4) or '::' IPv6 */ inline bool isNullAddr() const { return isNullAddr(m_host,family()); } /** * Copy the host address to a buffer * @param addr Buffer to put the packed address into * @return Address family, Unknown on failure */ int copyAddr(DataBlock& addr) const; /** * Check if an address family is supported by the library * @param family Family of the address to check * @return True if the address family is supported */ static bool supports(int family); /** * Retrieve the family of an address * @param addr The address to check * @return Address family */ static int family(const String& addr); /** * Convert the host address to a String * @param buf Destination buffer * @param addr Socket address * @return True on success, false if address family is not supported */ static bool stringify(String& buf, struct sockaddr* addr); /** * Put a host address to a buffer * @param buf Destination buffer. It must be large enough to keep the address * (4 bytes for IPv4, 16 bytes for IPv6) * @param host The host address * @param family Address family, set it to Unknown to detect * @return Address family, Unknown on failure */ static inline int unStringify(uint8_t* buf, const String& host, int family = Unknown) { SocketAddr sa(family); return sa.host(host) ? copyAddr(buf,sa.address()) : Unknown; } /** * Copy a host address to a buffer * @param buf Destination buffer. It must be large enough to keep the address * (4 bytes for IPv4, 16 bytes for IPv6) * @param addr The host address * @return Address family, Unknown on failure */ static int copyAddr(uint8_t* buf, struct sockaddr* addr); /** * Retrieve the scope id value of an IPv6 address * @param addr The address * @return The requested value (it may be 0), 0 if not available */ static inline unsigned int scopeId(struct sockaddr* addr) { #ifdef AF_INET6 if (addr && addr->sa_family == AF_INET6) return ((struct sockaddr_in6*)addr)->sin6_scope_id; #endif return 0; } /** * Set the scope id value of an IPv6 address * @param addr Address to set * @param val Value to set * @return True on success, false if not available */ static inline bool scopeId(struct sockaddr* addr, unsigned int val) { #ifdef AF_INET6 if (addr && addr->sa_family == AF_INET6) { ((struct sockaddr_in6*)addr)->sin6_scope_id = val; return true; } #endif return false; } /** * Append an address to a buffer * @param buf Destination buffer * @param addr Address to append * @param family Address family, set it to Unknown to detect * @return Buffer address */ static String& appendAddr(String& buf, const String& addr, int family = Unknown); /** * Append an address to a buffer in the form addr:port * @param buf Destination buffer * @param addr Address to append * @param port Port to append * @param family Address family, set it to Unknown to detect * @return Buffer address */ static inline String& appendTo(String& buf, const String& addr, int port, int family = Unknown) { appendAddr(buf,addr,family) << ":" << port; return buf; } /** * Append an address to a buffer in the form addr:port * @param addr Address to append * @param port Port to append * @param family Address family, set it to Unknown to detect * @return A String with concatenated address and port */ static inline String appendTo(const String& addr, int port, int family = Unknown) { String buf; appendTo(buf,addr,port,family); return buf; } /** * Check if an address is empty or null * @param addr Address to check * @param family Address family, set it to Unknown to detect * @return True if the address is empty or '0.0.0.0' (IPv4) or '::' IPv6 */ static bool isNullAddr(const String& addr, int family = Unknown); /** * Split an interface from address * An interface may be present in addr after a percent char (e.g. fe80::23%eth0) * It is safe call this method with the same destination and source string * @param buf Source buffer * @param addr Destination buffer for address * @param iface Optional pointer to be filled with interface name */ static void splitIface(const String& buf, String& addr, String* iface = 0); /** * Split an address into ip/port. * Handled formats: addr, addr:port, [addr], [addr]:port * It is safe call this method with the same destination and source string * @param buf Source buffer * @param addr Destination buffer for address * @param port Destination port * @param portPresent Set it to true if the port is always present after the last ':'. * This will handle IPv6 addresses without square brackets and port present * (e.g. fe80::23:5060 will split into addr=fe80::23 and port=5060) */ static void split(const String& buf, String& addr, int& port, bool portPresent = false); /** * Retrieve address family name * @param family Address family to retrieve * @return Address family name */ static inline const char* lookupFamily(int family) { return lookup(family,s_familyName); } /** * Retrieve IPv4 null address * @return IPv4 null address (0.0.0.0) */ static const String& ipv4NullAddr(); /** * Retrieve IPv6 null address * @return IPv6 null address (::) */ static const String& ipv6NullAddr(); /** * Retrieve the family name dictionary * @return Pointer to family name dictionary */ static const TokenDict* dictFamilyName(); protected: /** * Convert the host address to a String stored in m_host */ virtual void stringify(); /** * Store host:port in m_addr */ virtual void updateAddr() const; struct sockaddr* m_address; socklen_t m_length; String m_host; mutable String m_addr; private: static const TokenDict s_familyName[]; }; /** * Abstract interface for an object that filters socket received data packets * @short A filter for received socket data */ class YATE_API SocketFilter : public GenObject { friend class Socket; YNOCOPY(SocketFilter); // no automatic copies please public: /** * Constructor */ SocketFilter(); /** * Destructor, unregisters from socket */ virtual ~SocketFilter(); /** * Get a pointer to a derived class given that class name * @param name Name of the class we are asking for * @return Pointer to the requested class or NULL if this object doesn't implement it */ virtual void* getObject(const String& name) const; /** * Run whatever actions required on idle thread runs * @param when Time when the idle run started */ virtual void timerTick(const Time& when); /** * Notify this filter about a received block of data * @param buffer Buffer for received data * @param length Length of the data in buffer * @param flags Operating system specific bit flags of the operation * @param addr Address of the incoming data, may be NULL * @param adrlen Length of the valid data in address structure * @return True if this filter claimed the data */ virtual bool received(void* buffer, int length, int flags, const struct sockaddr* addr, socklen_t adrlen) = 0; /** * Get the socket to which the filter is currently attached * @return Pointer to the socket of this filter */ inline Socket* socket() const { return m_socket; } /** * Check if the socket of this filter is valid * @return True if the filter has a valid socket */ bool valid() const; private: Socket* m_socket; }; /** * Base class for encapsulating system dependent stream capable objects * @short An abstract stream class capable of reading and writing */ class YATE_API Stream { public: /** * Enumerate seek start position */ enum SeekPos { SeekBegin, // Seek from start of stream SeekEnd, // Seek from stream end SeekCurrent // Seek from current position }; /** * Destructor, terminates the stream */ virtual ~Stream(); /** * Get the error code of the last operation on this stream * @return Error code generated by the last operation on this stream */ inline int error() const { return m_error; } /** * Closes the stream * @return True if the stream was (already) closed, false if an error occured */ virtual bool terminate() = 0; /** * Check if the last error code indicates a retryable condition * @return True if error was temporary and operation should be retried */ virtual bool canRetry() const; /** * Check if the last error code indicates a non blocking operation in progress * @return True if a non blocking operation is in progress */ virtual bool inProgress() const; /** * Check if this stream is valid * @return True if the stream is valid, false if it's invalid or closed */ virtual bool valid() const = 0; /** * Set the blocking or non-blocking operation mode of the stream * @param block True if I/O operations should block, false for non-blocking * @return True if operation was successfull, false if an error occured */ virtual bool setBlocking(bool block = true); /** * Write data to a connected stream * @param buffer Buffer for data transfer * @param length Length of the buffer * @return Number of bytes transferred, negative if an error occurred */ virtual int writeData(const void* buffer, int length) = 0; /** * Write a C string to a connected stream * @param str String to send over the stream * @return Number of bytes transferred, negative if an error occurred */ int writeData(const char* str); /** * Write a String to a connected stream * @param str String to send over the stream * @return Number of bytes transferred, negative if an error occurred */ inline int writeData(const String& str) { return writeData(str.c_str(), str.length()); } /** * Write a Data block to a connected stream * @param buf DataBlock to send over the stream * @return Number of bytes transferred, negative if an error occurred */ inline int writeData(const DataBlock& buf) { return writeData(buf.data(), buf.length()); } /** * Receive data from a connected stream * @param buffer Buffer for data transfer * @param length Length of the buffer * @return Number of bytes transferred, negative if an error occurred */ virtual int readData(void* buffer, int length) = 0; /** * Find the length of the stream if it has one * @return Length of the stream or zero if length is not defined */ virtual int64_t length(); /** * Set the stream read/write pointer * @param pos The seek start as enumeration * @param offset The number of bytes to move the pointer from starting position * @return The new position of the stream read/write pointer. Negative on failure */ virtual int64_t seek(SeekPos pos, int64_t offset = 0); /** * Set the read/write pointer from begin of stream * @param offset The position in stream to move the pointer * @return The new position of the stream read/write pointer. Negative on failure */ inline int64_t seek(int64_t offset) { return seek(SeekBegin,offset); } /** * Allocate a new pair of unidirectionally pipe connected streams * @param reader Reference of a pointer receiving the newly allocated reading side of the pipe * @param writer Reference of a pointer receiving the newly allocated writing side of the pipe * @return True is the stream pipe was created successfully */ static bool allocPipe(Stream*& reader, Stream*& writer); /** * Allocate a new pair of bidirectionally connected streams * @param str1 Reference of a pointer receiving the newly allocated 1st end of the pair * @param str2 Reference of a pointer receiving the newly allocated 2nd end of the pair * @return True is the stream pair was created successfully */ static bool allocPair(Stream*& str1, Stream*& str2); /** * Check if operating system supports unidirectional stream pairs * @return True if unidirectional pipes can be created */ static bool supportsPipes(); /** * Check if operating system supports bidirectional stream pairs * @return True if bidirectional pairs can be created */ static bool supportsPairs(); protected: /** * Default constructor */ inline Stream() : m_error(0) { } /** * Clear the last error code */ inline void clearError() { m_error = 0; } int m_error; }; /** * An implementation of a Stream that reads and writes data in a DataBlock * @short A Stream that operates on DataBlocks in memory */ class YATE_API MemoryStream : public Stream { YNOCOPY(MemoryStream); // no automatic copies please public: /** * Constructor of an empty stream */ inline MemoryStream() : m_offset(0) { } /** * Constructor of aan initialized stream * @param data Initial data to be copied in the memory stream */ inline MemoryStream(const DataBlock& data) : m_data(data), m_offset(0) { } /** * Get read-only access to the DataBlock held * @return Const reference to the DataBlock */ inline const DataBlock& data() const { return m_data; } /** * Do-nothing termination handler * @return True to signal the stream was closed */ virtual bool terminate() { return true; } /** * Do-nothing validity check * @return True to indicate the stream is valid */ virtual bool valid() const { return true; } /** * Write new data to the DataBlock at current position, advance pointer * @param buffer Buffer of source data * @param len Length of data to be written * @return Number of bytes written, negative on error */ virtual int writeData(const void* buffer, int len); /** * Get data from internal DataBlock, advance pointer * @param buffer Buffer for getting the data * @param len Length of the buffer * @return Number of bytes read, negative on error, zero on end of data */ virtual int readData(void* buffer, int len); /** * Get the length of the stream * @return Length of the DataBlock in memory */ virtual int64_t length() { return m_data.length(); } /** * Set the read/write pointer * @param pos The seek start as enumeration * @param offset The number of bytes to move the pointer from starting position * @return The new position of the stream read/write pointer. Negative on failure */ virtual int64_t seek(SeekPos pos, int64_t offset = 0); protected: /** * The DataBlock holding the data in memory */ DataBlock m_data; /** * The current position for read/write operation */ int64_t m_offset; }; /** * Class to encapsulate a system dependent file in a system independent abstraction * @short A stream file class */ class YATE_API File : public Stream { YNOCOPY(File); // no automatic copies please public: /** * Default constructor, creates a closed file */ File(); /** * Constructor from an existing handle * @param handle Operating system handle to an open file */ explicit File(HANDLE handle); /** * Destructor, closes the file */ virtual ~File(); /** * Opens a file from the filesystem pathname * @param name Name of the file according to the operating system's conventions * @param canWrite Open the file for writing * @param canRead Open the file for reading * @param create Create the file if it doesn't exist * @param append Set the write pointer at the end of an existing file * @param binary Open the file in binary mode if applicable * @param pubReadable If the file is created make it public readable * @param pubWritable If the file is created make it public writable * @return True if the file was successfully opened */ virtual bool openPath(const char* name, bool canWrite = false, bool canRead = true, bool create = false, bool append = false, bool binary = false, bool pubReadable = false, bool pubWritable = false); /** * Closes the file handle * @return True if the file was (already) closed, false if an error occured */ virtual bool terminate(); /** * Attach an existing handle to the file, closes any existing first * @param handle Operating system handle to an open file */ void attach(HANDLE handle); /** * Detaches the object from the file handle * @return The handle previously owned by this object */ HANDLE detach(); /** * Get the operating system handle to the file * @return File handle */ inline HANDLE handle() const { return m_handle; } /** * Check if the last error code indicates a retryable condition * @return True if error was temporary and operation should be retried */ virtual bool canRetry() const; /** * Check if this file is valid * @return True if the file is valid, false if it's invalid or closed */ virtual bool valid() const; /** * Get the operating system specific handle value for an invalid file * @return Handle value for an invalid file */ static HANDLE invalidHandle(); /** * Set the blocking or non-blocking operation mode of the file * @param block True if I/O operations should block, false for non-blocking * @return True if operation was successfull, false if an error occured */ virtual bool setBlocking(bool block = true); /** * Find the length of the file if it has one * @return Length of the file or zero if length is not defined */ virtual int64_t length(); /** * Set the file read/write pointer * @param pos The seek start as enumeration * @param offset The number of bytes to move the pointer from starting position * @return The new position of the file read/write pointer. Negative on failure */ virtual int64_t seek(SeekPos pos, int64_t offset = 0); /** * Write data to an open file * @param buffer Buffer for data transfer * @param length Length of the buffer * @return Number of bytes transferred, negative if an error occurred */ virtual int writeData(const void* buffer, int length); /** * Read data from an open file * @param buffer Buffer for data transfer * @param length Length of the buffer * @return Number of bytes transferred, negative if an error occurred */ virtual int readData(void* buffer, int length); /** * Retrieve the file's modification time (the file must be already opened) * @param secEpoch File creation time (seconds since Epoch) * @return True on success */ bool getFileTime(unsigned int& secEpoch); /** * Build the MD5 hex digest of a file. The file must be opened for read access. * This method will move the file pointer * @param buffer Destination buffer * @return True on success */ virtual bool md5(String& buffer); /** * Set a file's modification time. * @param name Path and name of the file * @param secEpoch File modification time (seconds since Epoch) * @param error Optional pointer to error code to be filled on failure * @return True on success */ static bool setFileTime(const char* name, unsigned int secEpoch, int* error = 0); /** * Retrieve a file's modification time * @param name Path and name of the file * @param secEpoch File modification time (seconds since Epoch) * @param error Optional pointer to error code to be filled on failure * @return True on success */ static bool getFileTime(const char* name, unsigned int& secEpoch, int* error = 0); /** * Check if a file exists * @param name The file to check * @param error Optional pointer to error code to be filled on failure * @return True if the file exists */ static bool exists(const char* name, int* error = 0); /** * Rename (move) a file (or directory) entry from the filesystem * @param oldFile Path and name of the file to rename * @param newFile The new path and name of the file * @param error Optional pointer to error code to be filled on failure * @return True if the file was successfully renamed (moved) */ static bool rename(const char* oldFile, const char* newFile, int* error = 0); /** * Deletes a file entry from the filesystem * @param name Absolute path and name of the file to delete * @param error Optional pointer to error code to be filled on failure * @return True if the file was successfully deleted */ static bool remove(const char* name, int* error = 0); /** * Build the MD5 hex digest of a file. * @param name The file to build MD5 from * @param buffer Destination buffer * @param error Optional pointer to error code to be filled on failure * @return True on success */ static bool md5(const char* name, String& buffer, int* error = 0); /** * Create a folder (directory). It only creates the last directory in the path * @param path The folder path * @param error Optional pointer to error code to be filled on failure * @param mode Optional file mode, ignored on some platforms * @return True on success */ static bool mkDir(const char* path, int* error = 0, int mode = -1); /** * Remove an empty folder (directory) * @param path The folder path * @param error Optional pointer to error code to be filled on failure * @return True on success */ static bool rmDir(const char* path, int* error = 0); /** * Enumerate a folder (directory) content. * Fill the given lists with children item names * @param path The folder path * @param dirs List to be filled with child directories. * It can be NULL if not requested * @param files List to be filled with child files. * It can be NULL if not requested * @param error Optional pointer to error code to be filled on failure * @return True on success */ static bool listDirectory(const char* path, ObjList* dirs, ObjList* files, int* error = 0); /** * Create a pair of unidirectionally pipe connected streams * @param reader Reference to a File that becomes the reading side of the pipe * @param writer Reference to a File that becomes the writing side of the pipe * @return True is the pipe was created successfully */ static bool createPipe(File& reader, File& writer); protected: /** * Copy the last error code from the operating system */ void copyError(); HANDLE m_handle; }; /** * This class encapsulates a system dependent socket in a system independent abstraction * @short A generic socket class */ class YATE_API Socket : public Stream { YNOCOPY(Socket); // no automatic copies please public: /** * Types of service */ enum TOS { Normal = 0, LowDelay = IPTOS_LOWDELAY, MaxThroughput = IPTOS_THROUGHPUT, MaxReliability = IPTOS_RELIABILITY, MinCost = IPTOS_MINCOST, }; /** * DiffServ bits */ enum DSCP { DefaultPHB = 0x00, // Class selectors CS0 = 0x00, CS1 = 0x20, CS2 = 0x40, CS3 = 0x60, CS4 = 0x80, CS5 = 0xa0, CS6 = 0xc0, CS7 = 0xe0, // Assured forwarding AF11 = 0x28, AF12 = 0x30, AF13 = 0x38, AF21 = 0x48, AF22 = 0x50, AF23 = 0x58, AF31 = 0x68, AF32 = 0x70, AF33 = 0x78, AF41 = 0x88, AF42 = 0x90, AF43 = 0x98, // Expedited forwarding ExpeditedFwd = 0xb8, VoiceAdmit = 0xb0, }; /** * Default constructor, creates an invalid socket */ Socket(); /** * Constructor from an existing handle * @param handle Operating system handle to an existing socket */ explicit Socket(SOCKET handle); /** * Constructor that also creates the socket handle * @param domain Communication domain for the socket (protocol family) * @param type Type specification of the socket * @param protocol Specific protocol for the domain, 0 to use default */ Socket(int domain, int type, int protocol = 0); /** * Destructor - closes the handle if still open */ virtual ~Socket(); /** * Creates a new socket handle, * @param domain Communication domain for the socket (protocol family) * @param type Type specification of the socket * @param protocol Specific protocol for the domain, 0 to use default * @return True if socket was created, false if an error occured */ virtual bool create(int domain, int type, int protocol = 0); /** * Closes the socket handle, terminates the connection * @return True if socket was (already) closed, false if an error occured */ virtual bool terminate(); /** * Attach an existing handle to the socket, closes any existing first * @param handle Operating system handle to an existing socket */ void attach(SOCKET handle); /** * Detaches the object from the socket handle * @return The handle previously owned by this object */ SOCKET detach(); /** * Get the operating system handle to the socket * @return Socket handle */ inline SOCKET handle() const { return m_handle; } /** * Check if the last error code indicates a retryable condition * @return True if error was temporary and operation should be retried */ virtual bool canRetry() const; /** * Check if the last error code indicates a non blocking operation in progress * @return True if a non blocking operation is in progress */ virtual bool inProgress() const; /** * Check if this socket is valid * @return True if the handle is valid, false if it's invalid */ virtual bool valid() const; /** * Get the operating system specific handle value for an invalid socket * @return Handle value for an invalid socket */ static SOCKET invalidHandle(); /** * Get the operating system specific return value of a failed operation * @return Return value of a failed socket operation */ static int socketError(); /** * Retrieve the keyword lookup table for TOS / DSCP values * @return Pointer to keyword dictionary for TOS and DSCP */ static const TokenDict* tosValues(); /** * Set socket options * @param level Level of the option to set * @param name Socket option for which the value is to be set * @param value Pointer to a buffer holding the value for the requested option * @param length Size of the supplied buffer * @return True if operation was successfull, false if an error occured */ virtual bool setOption(int level, int name, const void* value = 0, socklen_t length = 0); /** * Set or reset socket IPv6 only option. * This option will tell to an IPv6 socket to accept only IPv6 packets. * IPv4 packets will be accepted if disabled. * This method will fail for non PF_INET6 sockets * @param on True to set, false to reset it * @return True if operation was successfull, false if an error occured */ inline bool setIpv6OnlyOption(bool on) { #if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY) int value = on ? 1 : 0; return setOption(IPPROTO_IPV6,IPV6_V6ONLY,&value,sizeof(value)); #else return false; #endif } /** * Get socket options * @param level Level of the option to set * @param name Socket option for which the value is to be set * @param buffer Pointer to a buffer to return the value for the requested option * @param length Pointer to size of the supplied buffer, will be filled on return * @return True if operation was successfull, false if an error occured */ virtual bool getOption(int level, int name, void* buffer, socklen_t* length); /** * Set specific socket parameters. * @param params List of parameters */ virtual bool setParams(const NamedList& params) { return false; } /** * Get specific socket parameters. * @param params Coma separated list of parameters to obtain * @param result List of parameters to fill * @return True if operation was successful, false if an error occurred */ virtual bool getParams(const String& params, NamedList& result) { return false; } /** * Set the Type of Service or Differentiated Services Code Point on the IP level of this socket * @param tos New TOS or DiffServ bits * @return True if operation was successfull, false if an error occured */ virtual bool setTOS(int tos); /** * Set the Type of Service or Differentiated Services Code Point on the IP level of this socket * @param tos Keyword describing new TOS or DSCP value * @param defTos Default TOS or DiffServ value to set if the keyword is not recognized * @return True if operation was successfull, false if an error occured */ inline bool setTOS(const char* tos, int defTos = Normal) { return setTOS(lookup(tos,tosValues(),defTos)); } /** * Retrieve the TOS / DSCP on the IP level of this socket * @return TOS or DiffServ value, Normal if not supported or an error occured */ virtual int getTOS(); /** * Set the blocking or non-blocking operation mode of the socket * @param block True if I/O operations should block, false for non-blocking * @return True if operation was successfull, false if an error occured */ virtual bool setBlocking(bool block = true); /** * Set the local address+port reuse flag of the socket. * This method should be called before bind() or it will have no effect. * @param reuse True if other sockets may listen on same address+port * @param exclusive Grant exclusive access to the address * @return True if operation was successfull, false if an error occured */ virtual bool setReuse(bool reuse = true, bool exclusive = false); /** * Set the way closing a socket is handled * @param seconds How much to block waiting for socket to close, * negative to no wait (close in background), zero to reset connection * @return True if operation was successfull, false if an error occured */ virtual bool setLinger(int seconds = -1); /** * Associates the socket with a local address * @param addr Address to assign to this socket * @param addrlen Length of the address structure * @return True if operation was successfull, false if an error occured */ virtual bool bind(struct sockaddr* addr, socklen_t addrlen); /** * Associates the socket with a local address * @param addr Address to assign to this socket * @return True if operation was successfull, false if an error occured */ inline bool bind(const SocketAddr& addr) { return bind(addr.address(), addr.length()); } /** * Start listening for incoming connections on the socket * @param backlog Maximum length of the queue of pending connections, 0 for system maximum * @return True if operation was successfull, false if an error occured */ virtual bool listen(unsigned int backlog = 0); /** * Create a new socket for an incoming connection attempt on a listening socket * @param addr Address to fill in with the address of the incoming connection * @param addrlen Length of the address structure on input, length of address data on return * @return Open socket to the new connection or NULL on failure */ virtual Socket* accept(struct sockaddr* addr = 0, socklen_t* addrlen = 0); /** * Create a new socket for an incoming connection attempt on a listening socket * @param addr Address to fill in with the address of the incoming connection * @return Open socket to the new connection or NULL on failure */ Socket* accept(SocketAddr& addr); /** * Create a new socket for an incoming connection attempt on a listening socket * @param addr Address to fill in with the address of the incoming connection * @param addrlen Length of the address structure on input, length of address data on return * @return Operating system handle to the new connection or @ref invalidHandle() on failure */ SOCKET acceptHandle(struct sockaddr* addr = 0, socklen_t* addrlen = 0); /** * Update socket error from socket options. * This method should be called when select() indicates a non blocking operation * completed. * Note: if false is returned, the socket error is the reason of getOption() failure * @return Return true on success */ bool updateError(); /** * Check if select() is efficient on this platform and worth using frequently * @return True if select() is efficiently implemented */ static bool efficientSelect(); /** * Check if a socket handle can be used in select * @param handle The socket handle to check * @return True if the socket handle can be safely used in select */ static bool canSelect(SOCKET handle); /** * Check if this socket object can be used in a select * @return True if this socket can be safely used in select */ virtual bool canSelect() const; /** * Connects the socket to a remote address * @param addr Address to connect to * @param addrlen Length of the address structure * @return True if operation was successfull, false if an error occured */ virtual bool connect(struct sockaddr* addr, socklen_t addrlen); /** * Connects the socket to a remote address * @param addr Socket address to connect to * @return True if operation was successfull, false if an error occured */ inline bool connect(const SocketAddr& addr) { return connect(addr.address(), addr.length()); } /** * Asynchronously connects the socket to a remote address. * The socket must be selectable and in non-blocking operation mode * @param addr Address to connect to * @param addrlen Length of the address structure * @param toutUs Timeout interval in microseconds * @param timeout Optional boolean flag to signal timeout * @return True on success */ virtual bool connectAsync(struct sockaddr* addr, socklen_t addrlen, unsigned int toutUs, bool* timeout = 0); /** * Asynchronously connects the socket to a remote address. * The socket must be selectable and in non-blocking operation mode * @param addr Socket address to connect to * @param toutUs Timeout interval in microseconds * @param timeout Optional boolean flag to signal timeout * @return True on success */ inline bool connectAsync(const SocketAddr& addr, unsigned int toutUs, bool* timeout = 0) { return connectAsync(addr.address(),addr.length(),toutUs,timeout); } /** * Shut down one or both directions of a full-duplex socket. * @param stopReads Request to shut down the read side of the socket * @param stopWrites Request to shut down the write side of the socket * @return True if operation was successfull, false if an error occured */ virtual bool shutdown(bool stopReads, bool stopWrites); /** * Retrieve the address of the local socket of a connection * @param addr Address to fill in with the address of the local socket * @param addrlen Length of the address structure on input, length of address data on return * @return True if operation was successfull, false if an error occured */ virtual bool getSockName(struct sockaddr* addr, socklen_t* addrlen); /** * Retrieve the address of the local socket of a connection * @param addr Address to fill in with the address of the local socket * @return True if operation was successfull, false if an error occured */ bool getSockName(SocketAddr& addr); /** * Retrieve the address of the remote socket of a connection * @param addr Address to fill in with the address of the remote socket * @param addrlen Length of the address structure on input, length of address data on return * @return True if operation was successfull, false if an error occured */ virtual bool getPeerName(struct sockaddr* addr, socklen_t* addrlen); /** * Retrieve the address of the remote socket of a connection * @param addr Address to fill in with the address of the remote socket * @return True if operation was successfull, false if an error occured */ bool getPeerName(SocketAddr& addr); /** * Send a message over a connected or unconnected socket * @param buffer Buffer for data transfer * @param length Length of the buffer * @param addr Address to send the message to, if NULL will behave like @ref send() * @param adrlen Length of the address structure * @param flags Operating system specific bit flags that change the behaviour * @return Number of bytes transferred, @ref socketError() if an error occurred */ virtual int sendTo(const void* buffer, int length, const struct sockaddr* addr, socklen_t adrlen, int flags = 0); /** * Send a message over a connected or unconnected socket * @param buffer Buffer for data transfer * @param length Length of the buffer * @param addr Address to send the message to * @param flags Operating system specific bit flags that change the behaviour * @return Number of bytes transferred, @ref socketError() if an error occurred */ inline int sendTo(const void* buffer, int length, const SocketAddr& addr, int flags = 0) { return sendTo(buffer, length, addr.address(), addr.length(), flags); } /** * Send a message over a connected socket * @param buffer Buffer for data transfer * @param length Length of the buffer * @param flags Operating system specific bit flags that change the behaviour * @return Number of bytes transferred, @ref socketError() if an error occurred */ virtual int send(const void* buffer, int length, int flags = 0); /** * Write data to a connected stream socket * @param buffer Buffer for data transfer * @param length Length of the buffer * @return Number of bytes transferred, @ref socketError() if an error occurred */ virtual int writeData(const void* buffer, int length); /** * Receive a message from a connected or unconnected socket * @param buffer Buffer for data transfer * @param length Length of the buffer * @param addr Address to fill in with the address of the incoming data * @param adrlen Length of the address structure on input, length of address data on return * @param flags Operating system specific bit flags that change the behaviour * @return Number of bytes transferred, @ref socketError() if an error occurred */ virtual int recvFrom(void* buffer, int length, struct sockaddr* addr = 0, socklen_t* adrlen = 0, int flags = 0); /** * Receive a message from a connected or unconnected socket * @param buffer Buffer for data transfer * @param length Length of the buffer * @param addr Address to fill in with the address of the incoming data * @param flags Operating system specific bit flags that change the behaviour * @return Number of bytes transferred, @ref socketError() if an error occurred */ int recvFrom(void* buffer, int length, SocketAddr& addr, int flags = 0); /** * Receive a message from a connected socket * @param buffer Buffer for data transfer * @param length Length of the buffer * @param flags Operating system specific bit flags that change the behaviour * @return Number of bytes transferred, @ref socketError() if an error occurred */ virtual int recv(void* buffer, int length, int flags = 0); /** * Receive data from a connected stream socket * @param buffer Buffer for data transfer * @param length Length of the buffer * @return Number of bytes transferred, @ref socketError() if an error occurred */ virtual int readData(void* buffer, int length); /** * Determines the availability to perform synchronous I/O of the socket * @param readok Address of a boolean variable to fill with readability status * @param writeok Address of a boolean variable to fill with writeability status * @param except Address of a boolean variable to fill with exceptions status * @param timeout Maximum time until the method returns, NULL for blocking * @return True if operation was successfull, false if an error occured */ virtual bool select(bool* readok, bool* writeok, bool* except, struct timeval* timeout = 0); /** * Determines the availability to perform synchronous I/O of the socket * @param readok Address of a boolean variable to fill with readability status * @param writeok Address of a boolean variable to fill with writeability status * @param except Address of a boolean variable to fill with exceptions status * @param timeout Maximum time until the method returns, -1 for blocking * @return True if operation was successfull, false if an error occured */ bool select(bool* readok, bool* writeok, bool* except, int64_t timeout); /** * Install a new packet filter in the socket * @param filter Pointer to the packet filter to install * @return True if the filter was installed */ bool installFilter(SocketFilter* filter); /** * Removes a packet filter and optionally destroys it * @param filter Pointer to the packet filter to remove from socket * @param delobj Set to true to also delete the filter */ void removeFilter(SocketFilter* filter, bool delobj = false); /** * Removes and destroys all packet filters */ void clearFilters(); /** * Run whatever actions required on idle thread runs. * The default implementation calls @ref SocketFilter::timerTick() * for all installed filters. * @param when Time when the idle run started */ virtual void timerTick(const Time& when); /** * Create a pair of bidirectionally connected sockets * @param sock1 Reference to first Socket to be paired * @param sock2 Reference to second Socket to be paired * @param domain Communication domain for the sockets (protocol family) * @return True is the stream pair was created successfully */ static bool createPair(Socket& sock1, Socket& sock2, int domain = AF_UNIX); protected: /** * Copy the last error code from the operating system */ void copyError(); /** * Copy the last error code from the operating system if an error occured, clear if not * @param retcode Operation return code to check, 0 for success * @param strict True to consider errors only return codes of @ref socketError() * @return True if operation succeeded (retcode == 0), false otherwise */ bool checkError(int retcode, bool strict = false); /** * Apply installed filters to a received block of data * @param buffer Buffer for received data * @param length Length of the data in buffer * @param flags Operating system specific bit flags of the operation * @param addr Address of the incoming data, may be NULL * @param adrlen Length of the valid data in address structure * @return True if one of the filters claimed the data */ bool applyFilters(void* buffer, int length, int flags, const struct sockaddr* addr = 0, socklen_t adrlen = 0); SOCKET m_handle; ObjList m_filters; }; /** * The SctpSocket interface provides access to SCTP specific functions * @short Abstract SCTP Socket */ class YATE_API SctpSocket : public Socket { YNOCOPY(SctpSocket); // no automatic copies please public: /** * Constructor */ inline SctpSocket() { } /** * Constructor * @param fd File descriptor of an existing handle */ inline explicit SctpSocket(SOCKET fd) : Socket(fd) { } /** * Destructor */ virtual ~SctpSocket(); /** * Bind this socket to multiple addresses * @param addresses The list of addresses (SocketAddr) * @return True if the socket bind succeded */ virtual bool bindx(ObjList& addresses) = 0; /** * Connect this socket to multiple addresses * @param addresses the list of addresses (SocketAddr) * @return True if the socket connect succeded */ virtual bool connectx(ObjList& addresses) = 0; /** * Send a message over a connected or unconnected socket * @param buffer Buffer for data transfer * @param length Length of the buffer * @param stream The stream number * @param addr Address to send the message to, if NULL will behave like @ref send() * @param flags Operating system specific bit flags that change the behaviour * @return Number of bytes transferred, @ref socketError() if an error occurred */ virtual int sendTo(void* buffer, int length, int stream, SocketAddr& addr, int flags) = 0; /** * Accept an incoming connection * @param addr The socket address of the incoming connection * @return A new SctpSocket if an incoming connection was detected */ virtual Socket* accept(SocketAddr& addr) { return 0; } /** * Send a buffer of data over a connected socket * @param buf The data to send * @param length Data length * @param stream The stream number to send over * @param flags Flags, gets altered on return * @return The number of bytes sent */ virtual int sendMsg(const void* buf, int length, int stream, int& flags) = 0; /** * Receive data from a connected socket * @param buf The buffer where the data will be stored * @param length The buffer length * @param addr Gets the remote address from which the data was received * @param stream Gets the stream number on which the data was read * @param flags Flags, gets altered on return * @return The number of bytes read */ virtual int recvMsg(void* buf, int length, SocketAddr& addr, int& stream, int& flags) = 0; /** * Set the number of streams * @param inbound The number of inbound streams * @param outbound The number of outbound streams * @return True if the number of streams was set */ virtual bool setStreams(int inbound, int outbound) = 0; /** * Subscribe to SCTP events * This method should be called if we need to find from which stream the data came * @return True if subscription has succeeded */ virtual bool subscribeEvents() = 0; /** * Get the number of negotiated streams * @param inbound Number of inbound streams * @param outbound Number of outbound streams * @return True if operation has succeded */ virtual bool getStreams(int& inbound, int& outbound) = 0; /** * Set the SCTP payload protocol identifier (RFC 4960) * @param payload Payload identifier code * @return True if set successfully */ virtual bool setPayload(u_int32_t payload) = 0; }; /** * Helper class for insering a Socket pointer as a RefObject in a Message * @short RefObject holding a Socket pointer */ class YATE_API SocketRef : public RefObject { public: /** * Constructor from pointer * @param socket Pointer to the Socket* to hold */ inline SocketRef(Socket** socket) : m_socket(socket) { } /** * Constructor from reference * @param socket Reference to the Socket* to hold */ inline SocketRef(Socket*& socket) : m_socket(&socket) { } /** * Get a pointer to a derived class given that class name * @param name Name of the class we are asking for * @return Pointer to the requested class or NULL if this object doesn't implement it */ virtual void* getObject(const String& name) const { return (name == YATOM("Socket*")) ? m_socket : RefObject::getObject(name); } private: SocketRef(); void* m_socket; }; /** * This class holds a DNS (resolver) record * @short A DNS record */ class YATE_API DnsRecord : public GenObject { YCLASS(DnsRecord,GenObject) YNOCOPY(DnsRecord); public: /** * Build a DNS record * @param ttl Record Time To Live * @param order Record order (priority) * @param pref Record preference */ inline DnsRecord(int ttl, int order, int pref) : m_ttl(ttl), m_order(order), m_pref(pref) {} /** * Default constructor */ inline DnsRecord() : m_order(0), m_pref(0) {} /** * Retrieve the Time To Live * @return Record TTL */ inline int ttl() const { return m_ttl; } /** * Retrieve the record order * @return Record order */ inline int order() const { return m_order; } /** * Retrieve the record preference * @return Record preference */ inline int pref() const { return m_pref; } /** * Dump a record for debug purposes * @param buf Destination buffer * @param sep Fields separator */ virtual void dump(String& buf, const char* sep = " "); /** * Insert a DnsRecord into a list in the proper location given by order and preference * @param list Destination list * @param rec The item to insert * @param ascPref Order preference ascending * @return True on success, false on failure (already in the list) */ static bool insert(ObjList& list, DnsRecord* rec, bool ascPref); protected: int m_ttl; int m_order; int m_pref; }; /** * This class holds a A, AAAA or TXT record from DNS * @short A text based DNS record */ class YATE_API TxtRecord : public DnsRecord { YCLASS(TxtRecord,DnsRecord) YNOCOPY(TxtRecord); public: /** * Build a TXT record * @param ttl Record Time To Live * @param text Text content of the record */ inline TxtRecord(int ttl, const char* text) : DnsRecord(ttl,-1,-1), m_text(text) {} /** * Retrieve the record text * @return Record text */ inline const String& text() const { return m_text; } /** * Dump this record for debug purposes * @param buf Destination buffer * @param sep Fields separator */ virtual void dump(String& buf, const char* sep = " "); /** * Copy a TxtRecord list into another one * @param dest Destination list * @param src Source list */ static void copy(ObjList& dest, const ObjList& src); protected: String m_text; private: TxtRecord() {} // No default contructor }; /** * This class holds a SRV (Service Location) record * @short A SRV record */ class YATE_API SrvRecord : public DnsRecord { YCLASS(SrvRecord,DnsRecord) YNOCOPY(SrvRecord); public: /** * Build a SRV record * @param ttl Record Time To Live * @param prio Record priority (order) * @param weight Record weight (preference) * @param addr Record address * @param port Record port */ inline SrvRecord(int ttl, int prio, int weight, const char* addr, int port) : DnsRecord(ttl,prio,weight), m_address(addr), m_port(port) {} /** * Retrieve the record address * @return Record address */ inline const String& address() const { return m_address; } /** * Retrieve the record port * @return Record port */ inline int port() const { return m_port; } /** * Dump this record for debug purposes * @param buf Destination buffer * @param sep Fields separator */ virtual void dump(String& buf, const char* sep = " "); /** * Copy a SrvRecord list into another one * @param dest Destination list * @param src Source list */ static void copy(ObjList& dest, const ObjList& src); protected: String m_address; int m_port; private: SrvRecord() {} // No default contructor }; /** * This class holds a NAPTR (Naming Authority Pointer) record * @short A NAPTR record */ class YATE_API NaptrRecord : public DnsRecord { YCLASS(NaptrRecord,DnsRecord) YNOCOPY(NaptrRecord); public: /** * Build a NAPTR record * @param ttl Record Time To Live * @param ord Record order * @param pref Record preference * @param flags Interpretation flags * @param serv Available services * @param regexp Substitution expression * @param next Next name to query */ NaptrRecord(int ttl, int ord, int pref, const char* flags, const char* serv, const char* regexp, const char* next); /** * Replace the enclosed template in a given string if matching * the substitution expression * @param str String to replace * @return True on success */ bool replace(String& str) const; /** * Dump this record for debug purposes * @param buf Destination buffer * @param sep Fields separator */ virtual void dump(String& buf, const char* sep = " "); /** * Retrieve record interpretation flags * @return Record interpretation flags */ inline const String& flags() const { return m_flags; } /** * Retrieve available services * @return Available services */ inline const String& serv() const { return m_service; } /** * Retrieve the regular expression match * @return Regular expression used in match */ inline const Regexp& regexp() const { return m_regmatch; } /** * Retrieve the template for replacing * @return Template used to replace the match */ inline const String& repTemplate() const { return m_template; } /** * Retrieve the next domain name to query * @return The next domain to query */ inline const String& nextName() const { return m_next; } protected: String m_flags; String m_service; Regexp m_regmatch; String m_template; String m_next; private: NaptrRecord() {} // No default contructor }; /** * This class offers DNS query services * @short DNS services */ class YATE_API Resolver { public: /** * Resolver handled types */ enum Type { Unknown, Srv, // SRV (Service Location) Naptr, // NAPTR (Naming Authority Pointer) A4, // A (Address) A6, // AAAA (IPv6 Address) Txt, // TXT (Text) }; /** * Runtime check for resolver availability * @param type Optional type to check. Set it to Unknown (default) to check * general resolver availability * @return True if the resolver is available on current platform */ static bool available(Type type = Unknown); /** * Initialize the resolver in the current thread * @param timeout Query timeout. Negative to use default * @param retries The number of query retries. Negative to use default * @return True on success */ static bool init(int timeout = -1, int retries = -1); /** * Make a query * @param type Query type as enumeration * @param dname Domain to query * @param result List of resulting record items * @param error Optional string to be filled with error string * @return 0 on success, error code otherwise (h_errno value on Linux) */ static int query(Type type, const char* dname, ObjList& result, String* error = 0); /** * Make a SRV (Service Location) query * @param dname Domain to query * @param result List of resulting SrvRecord items * @param error Optional string to be filled with error string * @return 0 on success, error code otherwise (h_errno value on Linux) */ static int srvQuery(const char* dname, ObjList& result, String* error = 0); /** * Make a NAPTR (Naming Authority Pointer) query * @param dname Domain to query * @param result List of resulting NaptrRecord items * @param error Optional string to be filled with error string * @return 0 on success, error code otherwise (h_errno value on Linux) */ static int naptrQuery(const char* dname, ObjList& result, String* error = 0); /** * Make an A (IPv4 Address) query * @param dname Domain to query * @param result List of resulting TxtRecord items * @param error Optional string to be filled with error string * @return 0 on success, error code otherwise (h_errno value on Linux) */ static int a4Query(const char* dname, ObjList& result, String* error = 0); /** * Make an AAAA (IPv6 Address) query * @param dname Domain to query * @param result List of resulting TxtRecord items * @param error Optional string to be filled with error string * @return 0 on success, error code otherwise (h_errno value on Linux) */ static int a6Query(const char* dname, ObjList& result, String* error = 0); /** * Make a TXT (Text) query * @param dname Domain to query * @param result List of resulting TxtRecord items * @param error Optional string to be filled with error string * @return 0 on success, error code otherwise (h_errno value on Linux) */ static int txtQuery(const char* dname, ObjList& result, String* error = 0); /** * Resolver type names */ static const TokenDict s_types[]; }; /** * The Cipher class provides an abstraction for data encryption classes * @short An abstract cipher */ class YATE_API Cipher : public GenObject { public: /** * Cipher direction */ enum Direction { Bidir, Encrypt, Decrypt, }; /** * Get the dictionary of cipher directions * @return Pointer to the dictionary of cipher directions */ inline static const TokenDict* directions() { return s_directions; } /** * Get a direction from the dictionary given the name * @param name Name of the direction * @param defdir Default direction to return if name is empty or unknown * @return Direction associated with the given name */ inline static Direction direction(const char* name, Direction defdir = Bidir) { return (Direction)TelEngine::lookup(name,s_directions,defdir); } /** * Destructor */ virtual ~Cipher(); /** * Get a pointer to a derived class given that class name * @param name Name of the class we are asking for * @return Pointer to the requested class or NULL if this object doesn't implement it */ virtual void* getObject(const String& name) const; /** * Check if the cipher instance is valid for a specific direction * @param dir Direction to check * @return True if the cipher is able to perform operation on given direction */ virtual bool valid(Direction dir = Bidir) const; /** * Get the cipher block size * @return Cipher block size in bytes */ virtual unsigned int blockSize() const = 0; /** * Get the initialization vector size * @return Initialization vector size in bytes, 0 if not applicable */ virtual unsigned int initVectorSize() const; /** * Round up a buffer length to a multiple of block size * @param len Length of data to encrypt or decrypt in bytes * @return Length of required buffer in bytes */ unsigned int bufferSize(unsigned int len) const; /** * Check if a buffer length is multiple of block size * @param len Length of data to encrypt or decrypt in bytes * @return True if buffer length is multiple of block size */ bool bufferFull(unsigned int len) const; /** * Set the key required to encrypt or decrypt data * @param key Pointer to binary key data * @param len Length of key in bytes * @param dir Direction to set key for * @return True if the key was set successfully */ virtual bool setKey(const void* key, unsigned int len, Direction dir = Bidir) = 0; /** * Set the key required to encrypt or decrypt data * @param key Binary key data block * @param dir Direction to set key for * @return True if the key was set successfully */ inline bool setKey(const DataBlock& key, Direction dir = Bidir) { return setKey(key.data(),key.length(),dir); } /** * Set the Initialization Vector if applicable * @param vect Pointer to binary Initialization Vector data * @param len Length of Initialization Vector in bytes * @param dir Direction to set the Initialization Vector for * @return True if the Initialization Vector was set successfully */ virtual bool initVector(const void* vect, unsigned int len, Direction dir = Bidir); /** * Set the Initialization Vector is applicable * @param vect Binary Initialization Vector * @param dir Direction to set the Initialization Vector for * @return True if the Initialization Vector was set successfully */ inline bool initVector(const DataBlock& vect, Direction dir = Bidir) { return initVector(vect.data(),vect.length(),dir); } /** * Encrypt data * @param outData Pointer to buffer for output (encrypted) and possibly input data * @param len Length of output data, may not be multiple of block size * @param inpData Pointer to buffer containing input (unencrypted) data, NULL to encrypt in place * @return True if data was successfully encrypted */ virtual bool encrypt(void* outData, unsigned int len, const void* inpData = 0) = 0; /** * Encrypt a DataBlock in place * @param data Data block to encrypt * @return True if data was successfully encrypted */ inline bool encrypt(DataBlock& data) { return encrypt(data.data(),data.length()); } /** * Decrypt data * @param outData Pointer to buffer for output (decrypted) and possibly input data * @param len Length of output data, may not be multiple of block size * @param inpData Pointer to buffer containing input (encrypted) data, NULL to decrypt in place * @return True if data was successfully decrypted */ virtual bool decrypt(void* outData, unsigned int len, const void* inpData = 0) = 0; /** * Decrypt a DataBlock in place * @param data Data block to decrypt * @return True if data was successfully decrypted */ inline bool decrypt(DataBlock& data) { return decrypt(data.data(),data.length()); } private: static const TokenDict s_directions[]; }; /** * The Compressor class provides an abstraction for data (de)compressor classes. * The String component keeps an optional object name to be used for debug purposes * @short An abstract data (de)compressor */ class YATE_API Compressor : public String { YCLASS(Compressor,String) YNOCOPY(Compressor); // no automatic copies please public: /** * Constructor * @param format Compression format * @param name Optional object name */ inline Compressor(const char* format, const char* name = 0) : String(name), m_format(format) {} /** * Destructor */ virtual ~Compressor() {} /** * Retrieve (de)compressor format * @return The format of this (de)compressor */ inline const String& format() const { return m_format; } /** * Initialize * @param comp True to initialize compressor * @param decomp True to initialize decompressor * @param params Optional parameters * @return True on success */ virtual bool init(bool comp = true, bool decomp = true, const NamedList& params = NamedList::empty()) { return true; } /** * Finalize the (de)compression * @param comp True to finalize compression, false to finalize decompression */ virtual void finalize(bool comp) {} /** * Compress the input buffer, flush all pending data, * append compressed data to the received data block * @param buf Pointer to input data * @param len Length of input in bytes * @param dest Destination buffer * @return The number of bytes wrote to compressor, negative on error */ virtual int compress(const void* buf, unsigned int len, DataBlock& dest); /** * Decompress the input buffer, flush all pending data, * append decompressed data to the received data block * @param buf Pointer to input data * @param len Length of input in bytes * @param dest Destination buffer * @return The number of bytes wrote to decompressor, negative on error */ virtual int decompress(const void* buf, unsigned int len, DataBlock& dest); /** * Push data to compressor. Flush compressor input if input buffer is NULL * or the length is 0 and flush is true * @param buf Pointer to input data * @param len Length of input in bytes * @param flush True to compress all now, false to let the compressor accumulate * more data for better compression * @return The number of bytes written, negative on error. An incomplete write may occur * if the output buffer is full */ virtual int writeComp(const void* buf, unsigned int len, bool flush) = 0; /** * Push data to compressor * @param data Input data block * @param flush True to compress all now, false to let the compressor accumulate * more data for better compression * @return The number of bytes written, negative on error. An incomplete write may occur * if the output buffer is full */ inline int writeComp(const DataBlock& data, bool flush) { return writeComp(data.data(),data.length(),flush); } /** * Push data to compressor * @param data Input string * @param flush True to compress all now, false to let the compressor accumulate * more data for better compression * @return The number of bytes written, negative on error. An incomplete write may occur * if the output buffer is full */ inline int writeComp(const String& data, bool flush) { return writeComp(data.c_str(),data.length(),flush); } /** * Read data from compressor. Append it to 'buf' * @param buf Destination data block * @param flush True to flush all compressor input data * @return The number of bytes read, negative on error */ virtual int readComp(DataBlock& buf, bool flush) = 0; /** * Push data to decompressor * @param buf Pointer to input data * @param len Length of input in bytes * @param flush True to try to decompress all data * @return The number of bytes written, negative on error. An incomplete write may occur * if the output buffer is full */ virtual int writeDecomp(const void* buf, unsigned int len, bool flush) = 0; /** * Push data to decompressor * @param data Input data block * @param flush True to try to decompress all data * @return The number of bytes written, negative on error. An incomplete write may occur * if the output buffer is full */ inline int writeDecomp(const DataBlock& data, bool flush) { return writeDecomp(data.data(),data.length(),flush); } /** * Push data to decompressor * @param data Input string * @param flush True to try to decompress all data * @return The number of bytes written, negative on error. An incomplete write may occur * if the output buffer is full */ inline int writeDecomp(const String& data, bool flush) { return writeDecomp(data.c_str(),data.length(),flush); } /** * Read data from decompressor. Append it to 'buf' * @param buf Destination data block * @param flush True to flush all decompressor input data * @return The number of bytes read, negative on error */ virtual int readDecomp(DataBlock& buf, bool flush) = 0; protected: String m_format; }; /** * The SysUsage class allows collecting some statistics about engine's usage * of system resources * @short A class exposing system resources usage */ class YATE_API SysUsage { public: /** * Type of time usage requested */ enum Type { WallTime, UserTime, KernelTime }; /** * Initialize the system start variable */ static void init(); /** * Get the wall time used as start for the usage time * @return Time of the first direct or implicit call of @ref init() */ static u_int64_t startTime(); /** * Get the program's running time in microseconds * @param type Type of running time requested * @return Time in microseconds since the start of the program */ static u_int64_t usecRunTime(Type type = WallTime); /** * Get the program's running time in milliseconds * @param type Type of running time requested * @return Time in milliseconds since the start of the program */ static u_int64_t msecRunTime(Type type = WallTime); /** * Get the program's running time in seconds * @param type Type of running time requested * @return Time in seconds since the start of the program */ static u_int32_t secRunTime(Type type = WallTime); /** * Get the program's running time in seconds * @param type Type of running time requested * @return Time in seconds since the start of the program */ static double runTime(Type type = WallTime); }; }; // namespace TelEngine #endif /* __YATECLASS_H */ /* vi: set ts=8 sw=4 sts=4 noet: */