/** * yateiax.h * Yet Another IAX2 Stack * This file is part of the YATE Project http://YATE.null.ro * * Yet Another Telephony Engine - a fully featured software PBX and IVR * Copyright (C) 2004-2023 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 __YATEIAX_H #define __YATEIAX_H #include #ifdef _WINDOWS #ifdef LIBYIAX_EXPORTS #define YIAX_API __declspec(dllexport) #else #ifndef LIBYIAX_STATIC #define YIAX_API __declspec(dllimport) #endif #endif #endif /* _WINDOWS */ #ifndef YIAX_API #define YIAX_API #endif /** * Holds all Telephony Engine related classes. */ namespace TelEngine { class IAXInfoElement; // A single IAX2 Information Element class IAXInfoElementString; // A single IAX2 text Information Element class IAXInfoElementNumeric; // A single IAX2 numeric Information Element class IAXInfoElementBinary; // A single IAX2 numeric Information Element class IAXIEList; // Information Element container class IAXAuthMethod; // Wrapper class for authentication methods values class IAXFormatDesc; // IAX format description class IAXFormat; // Wrapper class for formats class IAXControl; // Wrapper class for subclasses of frames of type IAX class IAXFrame; // This class holds an IAX frame class IAXFullFrame; // This class holds an IAX full frame class IAXFrameOut; // This class holds an outgoing IAX full frame class IAXTrunkInfo; // Trunk info class IAXMetaTrunkFrame; // Meta trunk frame class IAXMediaData; // IAX2 transaction media data class IAXTransaction; // An IAX2 transaction class IAXEvent; // Event class class IAXEngine; // IAX engine #define IAX_PROTOCOL_VERSION 0x0002 // Protocol version #define IAX2_MAX_CALLNO 32767 // Max call number value #define IAX2_MAX_TRANSINFRAMELIST 127 // Max transaction incoming frame list // Trunk frame header length #define IAX2_TRUNKFRAME_HEADERLENGTH 8 // Trunk frame length #define IAX2_TRUNKFRAME_LEN_MIN 20 // 16 bytes: meta header + miniframe with timestamps header #define IAX2_TRUNKFRAME_LEN_DEF 1400 // Trunk frame send interval in milliseconds #define IAX2_TRUNKFRAME_SEND_MIN 5 #define IAX2_TRUNKFRAME_SEND_DEF 20 // Frame retransmission #define IAX2_RETRANS_COUNT_MIN 1 #define IAX2_RETRANS_COUNT_MAX 10 #define IAX2_RETRANS_COUNT_DEF 4 #define IAX2_RETRANS_INTERVAL_MIN 200 #define IAX2_RETRANS_INTERVAL_MAX 5000 #define IAX2_RETRANS_INTERVAL_DEF 500 // Ping #define IAX2_PING_INTERVAL_MIN 10000 #define IAX2_PING_INTERVAL_DEF 20000 // Sent challenge timeout #define IAX2_CHALLENGETOUT_MIN 5000 #define IAX2_CHALLENGETOUT_DEF 30000 /** * This class holds a single Information Element with no data * @short A single IAX2 Information Element */ class YIAX_API IAXInfoElement : public RefObject { public: /** * Information Element enumeration types */ enum Type { textframe = 0x00, // Text Used internally only to generate an event of type Text CALLED_NUMBER = 0x01, // Text CALLING_NUMBER = 0x02, // Text CALLING_ANI = 0x03, // Text CALLING_NAME = 0x04, // Text CALLED_CONTEXT = 0x05, // Text USERNAME = 0x06, // Text PASSWORD = 0x07, // Text CAPABILITY = 0x08, // DW FORMAT = 0x09, // DW LANGUAGE = 0x0a, // Text VERSION = 0x0b, // W Value: IAX_PROTOCOL_VERSION ADSICPE = 0x0c, // W DNID = 0x0d, // Text AUTHMETHODS = 0x0e, // W CHALLENGE = 0x0f, // Text MD5_RESULT = 0x10, // Text RSA_RESULT = 0x11, // Text APPARENT_ADDR = 0x12, // BIN REFRESH = 0x13, // W DPSTATUS = 0x14, // W CALLNO = 0x15, // W Max value: IAX2_MAX_CALLNO CAUSE = 0x16, // Text IAX_UNKNOWN = 0x17, // B MSGCOUNT = 0x18, // W AUTOANSWER = 0x19, // Null MUSICONHOLD = 0x1a, // Text TRANSFERID = 0x1b, // DW RDNIS = 0x1c, // Text PROVISIONING = 0x1d, // BIN AESPROVISIONING = 0x1e, // BIN DATETIME = 0x1f, // DW DEVICETYPE = 0x20, // Text SERVICEIDENT = 0x21, // BIN FIRMWAREVER = 0x22, // W FWBLOCKDESC = 0x23, // DW FWBLOCKDATA = 0x24, // BIN PROVVER = 0x25, // DW CALLINGPRES = 0x26, // B CALLINGTON = 0x27, // B CALLINGTNS = 0x28, // W SAMPLINGRATE = 0x29, // DW CAUSECODE = 0x2a, // B ENCRYPTION = 0x2b, // B ENKEY = 0x2c, // BIN CODEC_PREFS = 0x2d, // Text RR_JITTER = 0x2e, // DW RR_LOSS = 0x2f, // DW RR_PKTS = 0x30, // DW RR_DELAY = 0x31, // W RR_DROPPED = 0x32, // DW RR_OOO = 0x33, // DW CALLTOKEN = 0x36, // BIN CAPABILITY2 = 0x37, // BIN 1 byte version + array FORMAT2 = 0x38, // BIN 1 byte version + array CALLINGANI2 = 0x39, // DW }; /** * Constructor * @param type Type of this IE */ inline IAXInfoElement(Type type) : m_type(type) {} /** * Destructor */ virtual ~IAXInfoElement() {} /** * Get the type of this IE * @return Type of this IE */ inline Type type() const { return m_type; } /** * Constructs a buffer containing this Information Element * @param buf Destination buffer */ virtual void toBuffer(DataBlock& buf); /** * Add this element to a string * @param buf Destination string */ virtual void toString(String& buf); /** * Get the text associated with an IE type value * @param ieCode Numeric code of the IE * @return Pointer to the IE text or 0 if it doesn't exist */ static inline const char* ieText(u_int8_t ieCode) { return lookup(ieCode,s_ieData); } /** * Retrieve the cause name associated with a given code * @param code Cause code * @return Cause name, 0 if not found */ static inline const char* causeName(int code) { return lookup(code,s_causeName); } /** * Retrieve the cause code associated with a given name * @param name Cause name * @param defVal Default value to return if not found * @return Cause code */ static inline int causeCode(const char* name, int defVal = 0) { return lookup(name,s_causeName,defVal); } /** * Cause code dictionary */ static const TokenDict s_causeName[]; /** * Number type dictionary */ static const TokenDict s_typeOfNumber[]; /** * Number presentation dictionary */ static const TokenDict s_presentation[]; /** * Number screening dictionary */ static const TokenDict s_screening[]; private: static const TokenDict s_ieData[];// Association between IE type and text Type m_type; // Type of this IE }; /** * This class holds a single Information Element with text data * @short A single IAX2 text Information Element */ class YIAX_API IAXInfoElementString : public IAXInfoElement { public: /** * Constructor * @param type Type of this IE * @param buf Source buffer to construct this IE * @param len Buffer length */ inline IAXInfoElementString(Type type, const char* buf, unsigned len) : IAXInfoElement(type), m_strData(buf,(int)len) {} /** * Destructor */ virtual ~IAXInfoElementString() {} /** * Get the data length * @return The data length */ inline int length() const { return m_strData.length(); } /** * Get the data * @return The data */ inline String& data() { return m_strData; } /** * Constructs a buffer containing this Information Element * @param buf Destination buffer */ virtual void toBuffer(DataBlock& buf); /** * Add this element to a string * @param buf Destination string */ virtual void toString(String& buf) { buf << m_strData; } private: String m_strData; // IE text data }; /** * This class holds a single Information Element with 1, 2 or 4 byte(s) length data * @short A single IAX2 numeric Information Element */ class YIAX_API IAXInfoElementNumeric : public IAXInfoElement { public: /** * Constructor * @param type Type of this IE * @param val Source value to construct this IE * @param len Value length */ IAXInfoElementNumeric(Type type, u_int32_t val, u_int8_t len); /** * Destructor */ virtual ~IAXInfoElementNumeric() {} /** * Get the data length * @return The data length */ inline int length() const { return m_length; } /** * Get the data * @return The data */ inline u_int32_t data() const { return m_numericData; } /** * Constructs a buffer containing this Information Element * @param buf Destination buffer */ virtual void toBuffer(DataBlock& buf); /** * Add this element to a string * @param buf Destination string */ virtual void toString(String& buf); private: u_int8_t m_length; // IE data length u_int32_t m_numericData; // IE numeric data }; /** * This class holds a single Information Element with binary data * @short A single IAX2 numeric Information Element */ class YIAX_API IAXInfoElementBinary : public IAXInfoElement { public: /** * Constructor * @param type Type of this IE * @param buf Source buffer to construct this IE * @param len Buffer length */ IAXInfoElementBinary(Type type, unsigned char* buf, unsigned len) : IAXInfoElement(type), m_data(buf,len) {} /** * Destructor */ virtual ~IAXInfoElementBinary() {} /** * Get the data length * @return The data length */ inline int length() const { return m_data.length(); } /** * Get the data * @return The data */ inline DataBlock& data() { return m_data; } /** * Set the data * @param buf Source buffer to construct this IE * @param len Buffer length */ inline void setData(void* buf, unsigned len) { m_data.assign(buf,len); } /** * Constructs a buffer containing this Information Element * @param buf Destination buffer */ virtual void toBuffer(DataBlock& buf); /** * Constructs an APPARENT_ADDR information element from a SocketAddr object * @param addr Source object * @return A valid IAXInfoElementBinary pointer */ static IAXInfoElementBinary* packIP(const SocketAddr& addr); /** * Decode an APPARENT_ADDR information element and copy it to a SocketAddr object * @param addr Destination object * @param ie Source IE * @return False if ie is 0 */ static bool unpackIP(SocketAddr& addr, IAXInfoElementBinary* ie); /** * Add this element to a string * @param buf Destination string */ virtual void toString(String& buf); private: DataBlock m_data; // IE binary data }; /** * Management class for a list of Information Elements * @short Information Element container */ class YIAX_API IAXIEList { public: /** * Constructor */ IAXIEList(); /** * Constructor. Construct the list from an IAXFullFrame object * @param frame Source object * @param incoming True if it is an incoming frame */ IAXIEList(const IAXFullFrame* frame, bool incoming = true); /** * Destructor */ ~IAXIEList(); /** * Get the invalid IE list flag * @return False if the last frame parse was unsuccessful */ inline bool invalidIEList() const { return m_invalidIEList; } /** * Clear the list */ inline void clear() { m_list.clear(); } /** * Check if the list is empty * @return True if the list is empty */ inline bool empty() { return 0 == m_list.skipNull(); } /** * Insert a VERSION Information Element in the list if not already done */ void insertVersion(); /** * Get the validity of the VERSION Information Element of the list if any * @return False if version is not IAX_PROTOCOL_VERSION or the list doesn't contain a VERSION Information Element */ inline bool validVersion() { u_int32_t ver = 0xFFFF; getNumeric(IAXInfoElement::VERSION,ver); return ver == IAX_PROTOCOL_VERSION; } /** * Append an Information Element to the list * @param ie IAXInfoElement pointer to append */ inline void appendIE(IAXInfoElement* ie) { m_list.append(ie); } /** * Append an Information Element taken from another list * @param src Source IE list * @param type IE to move * @return True if found and added */ inline bool appendIE(IAXIEList& src, IAXInfoElement::Type type) { IAXInfoElement* ie = src.getIE(type,true); if (ie) appendIE(ie); return ie != 0; } /** * Append an Information Element to the list * @param type The type of the IAXInfoElement to append */ inline void appendNull(IAXInfoElement::Type type) { m_list.append(new IAXInfoElement(type)); } /** * Append a text Information Element to the list from a String * @param type The type of the IAXInfoElementString to append * @param src The source */ inline void appendString(IAXInfoElement::Type type, const String& src) { m_list.append(new IAXInfoElementString(type,src.c_str(),src.length())); } /** * Append a text Information Element to the list from a buffer * @param type The type of the IAXInfoElementString to append * @param src The source * @param len Source length */ inline void appendString(IAXInfoElement::Type type, unsigned char* src, unsigned len) { m_list.append(new IAXInfoElementString(type,(char*)src,len)); } /** * Append a numeric Information Element to the list * @param type The type of the IAXInfoElementNumeric to append * @param value The source * @param len Source length */ inline void appendNumeric(IAXInfoElement::Type type, u_int32_t value, u_int8_t len) { m_list.append(new IAXInfoElementNumeric(type,value,len)); } /** * Append a binary Information Element to the list * @param type The type of the IAXInfoElementBinary to append * @param data The source data to append * @param len Source length */ inline void appendBinary(IAXInfoElement::Type type, unsigned char* data, unsigned len) { m_list.append(new IAXInfoElementBinary(type,data,len)); } /** * Construct the list from an IAXFullFrame object. * On exit m_invalidIEList will contain the opposite of the returned value * @param frame Source object * @param incoming True if it is an incoming frame * @return False if the frame contains invalid IEs */ bool createFromFrame(const IAXFullFrame* frame, bool incoming = true); /** * Construct a buffer from this list * @param buf Destination buffer */ void toBuffer(DataBlock& buf); /** * Add this list to a string * @param dest Destination string * @param indent Optional indent for each element */ void toString(String& dest, const char* indent = 0); /** * Retrieve an IAXInfoElement from the list * @param type The desired type * @param remove True to remove from list. The caller will own the object * @return An IAXInfoElement pointer or 0 if the list doesn't contain an IE of this type */ IAXInfoElement* getIE(IAXInfoElement::Type type, bool remove = false); /** * Get the data of a list item into a String. Before any operation dest is cleared * @param type The desired type * @param dest The destination String * @return False if the list doesn't contain an IE of this type */ bool getString(IAXInfoElement::Type type, String& dest); /** * Get the data of a list item into a numeric destination * @param type The desired type * @param dest The destination * @return False if the list doesn't contain an IE of this type */ bool getNumeric(IAXInfoElement::Type type, u_int32_t& dest); /** * Get the data of a list item into a DataBlock. Before any operation dest is cleared * @param type The desired type * @param dest The destination buffer * @return False if the list doesn't contain an IE of this type */ bool getBinary(IAXInfoElement::Type type, DataBlock& dest); private: bool m_invalidIEList; // Invalid IE flag ObjList m_list; // The IE list }; /** * This class holds the enumeration values for authentication methods * @short Wrapper class for authentication methods values */ class YIAX_API IAXAuthMethod { public: /** * Authentication method enumeration types */ enum Type { Text = 1, MD5 = 2, RSA = 4, }; /** * Create a string list from authentication methods * @param dest The destination * @param auth The authentication methods as ORed bits * @param sep The separator to use */ static void authList(String& dest, u_int16_t auth, char sep); static TokenDict s_texts[]; }; /** * This class holds IAX format description * @short IAX format description */ class YIAX_API IAXFormatDesc { public: /** * Constructor */ inline IAXFormatDesc() : m_format(0), m_multiplier(1) {} /** * Get the format * @return The format */ inline u_int32_t format() const { return m_format; } /** * Get the format multiplier used to translate timestamps * @return The format multiplier (always greater then 0) */ inline unsigned int multiplier() const { return m_multiplier; } /** * Set the format * @param fmt The format * @param type Format type as IAXFormat::Media enumeration */ void setFormat(u_int32_t fmt, int type); protected: u_int32_t m_format; // The format unsigned int m_multiplier; // Format multiplier derived from sampling rate }; /** * This class holds the enumeration values for audio and video formats * @short Wrapper class for audio and video formats */ class YIAX_API IAXFormat { public: /** * Format enumeration types */ enum Formats { G723_1 = (1 << 0), GSM = (1 << 1), ULAW = (1 << 2), ALAW = (1 << 3), G726 = (1 << 4), ADPCM = (1 << 5), SLIN = (1 << 6), LPC10 = (1 << 7), G729 = (1 << 8), SPEEX = (1 << 9), ILBC = (1 << 10), G726AAL2 = (1 << 11), G722 = (1 << 12), AMR = (1 << 13), // NOTE: GSM Half Rate is not defined in RFC5456 GSM_HR = (1 << 31), AudioMask = G723_1 | GSM | ULAW | ALAW | G726 | ADPCM | SLIN | LPC10 | G729 | SPEEX | ILBC | G726AAL2 | G722 | AMR | GSM_HR, JPEG = (1 << 16), PNG = (1 << 17), ImageMask = JPEG | PNG, H261 = (1 << 18), H263 = (1 << 19), H263p = (1 << 20), H264 = (1 << 21), VideoMask = H261 | H263 | H263p | H264, }; /** * Media type enumeration */ enum Media { Audio = 0, Video, Image, TypeCount }; /** * Constructor. Build an audio format * @param type Media type */ inline IAXFormat(int type = Audio) : m_type(type) {} /** * Get the media type * @return Media type */ inline int type() const { return m_type; } /** * Get the format * @return The format */ inline u_int32_t format() const { return m_format.format(); } /** * Get the incoming format * @return The incoming format */ inline u_int32_t in() const { return m_formatIn.format(); } /** * Get the outgoing format * @return The outgoing format */ inline u_int32_t out() const { return m_formatOut.format(); } /** * Get the incoming or outgoing format description * @param in True to retrieve the incoming format, false to retrieve the outgoing one * @return Requested format desc */ inline const IAXFormatDesc& formatDesc(bool in) const { return in ? m_formatIn : m_formatOut; } /** * Get the text associated with the format * @return Format name */ inline const char* formatName() const { return formatName(format()); } /** * Get the text associated with the media type * @return Media name */ inline const char* typeName() const { return typeName(m_type); } /** * Set format * @param fmt Optional pointer to format to set * @param fmtIn Optional pointer to incoming format to set * @param fmtOut Optional pointer to outgoing format to set */ void set(u_int32_t* fmt, u_int32_t* fmtIn, u_int32_t* fmtOut); /** * Create a string list from formats * @param dest The destination * @param formats The formats * @param dict Optional dictionary to use, 0 to use s_formats * @param sep The separator to use */ static void formatList(String& dest, u_int32_t formats, const TokenDict* dict = 0, const char* sep = ","); /** * Pick a format from a list of capabilities * @param formats Capabilities list * @param format Optional format to pick * @return IAX format, 0 if not found */ static u_int32_t pickFormat(u_int32_t formats, u_int32_t format = 0); /** * Encode a formats list * @param formats Formats list * @param dict Dictionary to use * @param sep Formats list separator * @return Encoded formats */ static u_int32_t encode(const String& formats, const TokenDict* dict, char sep = ','); /** * Mask formats by type * @param value Input format(s) * @param type Media type to retrieve * @return Media format(s) from input */ static inline u_int32_t mask(u_int32_t value, int type) { if (type == Audio) return value & AudioMask; if (type == Video) return value & VideoMask; if (type == Image) return value & ImageMask; return 0; } /** * Clear formats by type * @param value Input format(s) * @param type Media type to clear * @return Cleared format(s) from input */ static inline u_int32_t clear(u_int32_t value, int type) { if (type == Audio) return value & ~AudioMask; if (type == Video) return value & ~VideoMask; if (type == Image) return value & ~ImageMask; return value; } /** * Get the text associated with a format * @param fmt The desired format * @return A pointer to the text associated with the format or 0 if the format doesn't exist */ static inline const char* formatName(u_int32_t fmt) { return lookup(fmt,s_formats); } /** * Get the text associated with a media type * @param type The media type * @return A pointer to the text associated with the media type */ static inline const char* typeName(int type) { return lookup(type,s_types); } /** * Get the text associated with a media type * @param type The media type * @return A string associated with the media type */ static inline const String& typeNameStr(int type) { return s_typesList[type]; } /** * Keep the texts associated with the formats */ static const TokenDict s_formats[]; /** * Keep the texts associated with type */ static const TokenDict s_types[]; /** * Keep the texts associated with a type also as String */ static const String s_typesList[TypeCount]; protected: int m_type; IAXFormatDesc m_format; IAXFormatDesc m_formatIn; IAXFormatDesc m_formatOut; }; /** * This class holds the enumeration values for IAX control (subclass) * @short Wrapper class for subclasses of frames of type IAX */ class YIAX_API IAXControl { public: /** * IAX control (subclass) enumeration types */ enum Type { New = 0x01, Ping = 0x02, Pong = 0x03, Ack = 0x04, Hangup = 0x05, Reject = 0x06, Accept = 0x07, AuthReq = 0x08, AuthRep = 0x09, Inval = 0x0a, LagRq = 0x0b, LagRp = 0x0c, RegReq = 0x0d, RegAuth = 0x0e, RegAck = 0x0f, RegRej = 0x10, RegRel = 0x11, VNAK = 0x12, DpReq = 0x13, DpRep = 0x14, Dial = 0x15, TxReq = 0x16, TxCnt = 0x17, TxAcc = 0x18, TxReady = 0x19, TxRel = 0x1a, TxRej = 0x1b, Quelch = 0x1c, Unquelch = 0x1d, Poke = 0x1e, //Reserved = 0x1f, MWI = 0x20, Unsupport = 0x21, Transfer = 0x22, Provision = 0x23, FwDownl = 0x24, FwData = 0x25, CallToken = 0x28, }; /** * Get the string associated with the given IAX control type * @param type The requested type * @return The text if type is valid or 0 */ static inline const char* typeText(int type) { return lookup(type,s_types,0); } private: static TokenDict s_types[]; // Keep the association between IAX control codes and their name }; /** * This class holds all data needded to manage an IAX frame * @short This class holds an IAX frame */ class YIAX_API IAXFrame : public RefObject { public: /** * IAX frame type enumeration */ enum Type { DTMF = 0x01, Voice = 0x02, Video = 0x03, Control = 0x04, Null = 0x05, IAX = 0x06, Text = 0x07, Image = 0x08, HTML = 0x09, Noise = 0x0a, }; /** * Constructor. Constructs an incoming frame * @param type Frame type * @param sCallNo Source call number * @param tStamp Frame timestamp * @param retrans Retransmission flag * @param buf IE buffer * @param len IE buffer length * @param mark Mark flag */ IAXFrame(Type type, u_int16_t sCallNo, u_int32_t tStamp, bool retrans, const unsigned char* buf, unsigned int len, bool mark = false); /** * Destructor */ virtual ~IAXFrame(); /** * Get the type of this frame as enumeration * @return The type of this frame as enumeration */ inline Type type() const { return m_type; } /** * Get the data buffer of the frame * @return The data buffer of the frame */ inline DataBlock& data() { return m_data; } /** * Get the retransmission flag of this frame * @return The retransmission flag of this frame */ inline bool retrans() const { return m_retrans; } /** * Get the source call number of this frame * @return The source call number of this frame */ inline u_int16_t sourceCallNo() const { return m_sCallNo; } /** * Get the timestamp of this frame * @return The timestamp of this frame */ inline u_int32_t timeStamp() const { return m_tStamp; } /** * Get the mark flag * @return The mark flag */ inline bool mark() const { return m_mark; } /** * Get a pointer to this frame if it is a full frame * @return A pointer to this frame if it is a full frame or 0 */ virtual IAXFullFrame* fullFrame(); /** * Parse a received buffer and returns a IAXFrame pointer if valid * @param buf Received buffer * @param len Buffer length * @param engine The IAXEngine who requested the operation * @param addr The source address * @return A frame pointer on success or 0 */ static IAXFrame* parse(const unsigned char* buf, unsigned int len, IAXEngine* engine = 0, const SocketAddr* addr = 0); /** * Build a miniframe buffer * @param dest Destination buffer * @param sCallNo Source call number * @param ts Frame timestamp * @param data Data * @param len Data length */ static inline void buildMiniFrame(DataBlock& dest, u_int16_t sCallNo, u_int32_t ts, void* data, unsigned int len) { unsigned char header[4] = {(unsigned char)(sCallNo >> 8), (unsigned char)sCallNo,(unsigned char)(ts >> 8),(unsigned char)ts}; dest.assign(header,4); dest.append(data,len); } /** * Build a video meta frame buffer * @param dest Destination buffer * @param sCallNo Source call number * @param tStamp Frame timestamp * @param mark Frame mark * @param data Data * @param len Data length */ static void buildVideoMetaFrame(DataBlock& dest, u_int16_t sCallNo, u_int32_t tStamp, bool mark, void* data, unsigned int len); /** * Pack a subclass value according to IAX protocol * @param value Value to pack * @return The packed subclass value or 0 if invalid (>255 and not a power of 2) */ static u_int8_t packSubclass(u_int32_t value); /** * Unpack a subclass value according to IAX protocol * @param value Value to unpack * @return The unpacked subclass value */ static u_int32_t unpackSubclass(u_int8_t value); /** * Get the string associated with the given IAX frame type * @param type The requested type * @return The text if type is valid or 0 */ static inline const char* typeText(int type) { return lookup(type,s_types,0); } protected: /** * Contains the frame's IE list for an incoming frame or the whole frame for an outgoing one */ DataBlock m_data; /** * Retransmission flag */ bool m_retrans; private: static TokenDict s_types[]; // Keep the association between IAX frame types and their names Type m_type; // Frame type u_int16_t m_sCallNo; // Source call number u_int32_t m_tStamp; // Frame timestamp bool m_mark; // Mark flag }; /** * This class holds all data needded to manage an IAX full frame * @short This class holds an IAX full frame */ class YIAX_API IAXFullFrame : public IAXFrame { public: /** * IAX frame subclass enumeration types for frames of type Control */ enum ControlType { Hangup = 0x01, //Ring = 0x02, Ringing = 0x03, Answer = 0x04, Busy = 0x05, Congestion = 0x08, FlashHook = 0x09, Option = 0x0b, KeyRadio = 0x0c, UnkeyRadio = 0x0d, Progressing = 0x0e, Proceeding = 0x0f, Hold = 0x10, Unhold = 0x11, VidUpdate = 0x12, SrcUpdate = 0x14, StopSounds = 0xff, }; /** * Constructor. Constructs an incoming full frame * @param type Frame type * @param subclass Frame subclass * @param sCallNo Source (remote) call number * @param dCallNo Destination (local) call number * @param oSeqNo Outgoing sequence number * @param iSeqNo Incoming (expected) sequence number * @param tStamp Frame timestamp * @param retrans Retransmission flag * @param buf IE buffer * @param len IE buffer length * @param mark Mark flag */ IAXFullFrame(Type type, u_int32_t subclass, u_int16_t sCallNo, u_int16_t dCallNo, unsigned char oSeqNo, unsigned char iSeqNo, u_int32_t tStamp, bool retrans, const unsigned char* buf, unsigned int len, bool mark = false); /** * Constructor. Constructs an outgoing full frame * @param type Frame type * @param subclass Frame subclass * @param sCallNo Source (remote) call number * @param dCallNo Destination (local) call number * @param oSeqNo Outgoing sequence number * @param iSeqNo Incoming (expected) sequence number * @param tStamp Frame timestamp * @param buf IE buffer * @param len IE buffer length * @param mark Mark flag */ IAXFullFrame(Type type, u_int32_t subclass, u_int16_t sCallNo, u_int16_t dCallNo, unsigned char oSeqNo, unsigned char iSeqNo, u_int32_t tStamp, const unsigned char* buf = 0, unsigned int len = 0, bool mark = false); /** * Constructor. Constructs an outgoing full frame * @param type Frame type * @param subclass Frame subclass * @param sCallNo Source (remote) call number * @param dCallNo Destination (local) call number * @param oSeqNo Outgoing sequence number * @param iSeqNo Incoming (expected) sequence number * @param tStamp Frame timestamp * @param ieList List of frame IEs * @param maxlen Max frame data length * @param mark Mark flag */ IAXFullFrame(Type type, u_int32_t subclass, u_int16_t sCallNo, u_int16_t dCallNo, unsigned char oSeqNo, unsigned char iSeqNo, u_int32_t tStamp, IAXIEList* ieList, u_int16_t maxlen, bool mark = false); /** * Destructor */ virtual ~IAXFullFrame(); /** * Get the destination call number * @return The destination call number */ inline u_int16_t destCallNo() const { return m_dCallNo; } /** * Get the outgoing sequence number * @return The outgoing sequence number */ inline unsigned char oSeqNo() const { return m_oSeqNo; } /** * Get the incoming sequence number * @return The incoming sequence number */ inline unsigned char iSeqNo() const { return m_iSeqNo; } /** * Get the subclass of this frame * @return The subclass of this frame */ inline u_int32_t subclass() const { return m_subclass; } /** * Check if this frame is used to request authentication * @return True if this frame is used to request authentication (like RegReq or RegAuth) */ inline bool isAuthReq() const { return type() == IAXFrame::IAX && (subclass() == IAXControl::AuthReq || subclass() == IAXControl::RegAuth); } /** * Check if this frame is an INVAL one * @return True if this frame is INVAL */ inline bool isInval() const { return type() == IAXFrame::IAX && subclass() == IAXControl::Inval; } /** * Get a pointer to this frame if it is a full frame * @return A pointer to this frame */ virtual IAXFullFrame* fullFrame(); /** * Rebuild frame buffer from the list of IEs * @param maxlen Max frame data length */ void updateBuffer(u_int16_t maxlen); /** * Retrieve the IE list * @return IAXIEList pointer or NULL */ inline IAXIEList* ieList() { return m_ieList; } /** * Update IE list from buffer if not already done * @param incoming True if this is an incoming frame * @return True if the list is valid */ bool updateIEList(bool incoming); /** * Remove the IE list * @param delObj True to delete it * @return IAXIEList pointer or NULL if requested to delete it or already NULL */ IAXIEList* removeIEList(bool delObj = true); /** * Fill a string with this frame * @param dest The string to fill * @param local The local address * @param remote The remote address * @param incoming True if it is an incoming frame */ void toString(String& dest, const SocketAddr& local, const SocketAddr& remote, bool incoming); /** * Get the string associated with the given IAX control type * @param type The requested control type * @return The text if type is valid or 0 */ static inline const char* controlTypeText(int type) { return lookup(type,s_controlTypes,0); } protected: /** * Destroyed notification. Clear data */ virtual void destroyed(); private: // Build frame buffer header void setDataHeader(); static TokenDict s_controlTypes[]; // Keep the association between control types and their names u_int16_t m_dCallNo; // Destination call number unsigned char m_oSeqNo; // Out sequence number unsigned char m_iSeqNo; // In sequence number u_int32_t m_subclass; // Subclass IAXIEList* m_ieList; // List of IEs }; /** * This class holds all data needded to manage an outgoing IAX full frame * @short This class holds an outgoing IAX full frame */ class YIAX_API IAXFrameOut : public IAXFullFrame { public: /** * Constructor. Constructs an outgoing full frame * @param type Frame type * @param subclass Frame subclass * @param sCallNo Source (remote) call number * @param dCallNo Destination (local) call number * @param oSeqNo Outgoing sequence number * @param iSeqNo Incoming (expected) sequence number * @param tStamp Frame timestamp * @param buf IE buffer * @param len IE buffer length * @param retransCount Retransmission counter * @param retransIntervalMs Time interval to the next retransmission * @param ackOnly Acknoledge only flag. If true, the frame only expects an ACK * @param mark Mark flag */ inline IAXFrameOut(Type type, u_int32_t subclass, u_int16_t sCallNo, u_int16_t dCallNo, unsigned char oSeqNo, unsigned char iSeqNo, u_int32_t tStamp, const unsigned char* buf, unsigned int len, u_int16_t retransCount, u_int32_t retransIntervalMs, bool ackOnly, bool mark = false) : IAXFullFrame(type,subclass,sCallNo,dCallNo,oSeqNo,iSeqNo,tStamp,buf,len,mark), m_ack(false), m_ackOnly(ackOnly), m_retransCount(retransCount), m_retransTimeInterval(retransIntervalMs * 1000), m_nextTransTime(Time::now() + m_retransTimeInterval) {} /** * Constructor. Constructs an outgoing full frame * @param type Frame type * @param subclass Frame subclass * @param sCallNo Source (remote) call number * @param dCallNo Destination (local) call number * @param oSeqNo Outgoing sequence number * @param iSeqNo Incoming (expected) sequence number * @param tStamp Frame timestamp * @param ieList List of frame IEs * @param maxlen Max frame data length * @param retransCount Retransmission counter * @param retransIntervalMs Time interval to the next retransmission * @param ackOnly Acknoledge only flag. If true, the frame only expects an ACK * @param mark Mark flag */ inline IAXFrameOut(Type type, u_int32_t subclass, u_int16_t sCallNo, u_int16_t dCallNo, unsigned char oSeqNo, unsigned char iSeqNo, u_int32_t tStamp, IAXIEList* ieList, u_int16_t maxlen, u_int16_t retransCount, u_int32_t retransIntervalMs, bool ackOnly, bool mark = false) : IAXFullFrame(type,subclass,sCallNo,dCallNo,oSeqNo,iSeqNo,tStamp,ieList,maxlen,mark), m_ack(false), m_ackOnly(ackOnly), m_retransCount(retransCount), m_retransTimeInterval(retransIntervalMs * 1000), m_nextTransTime(Time::now() + m_retransTimeInterval) {} /** * Destructor */ virtual ~IAXFrameOut() {} /** * Get the retransmission counter of this frame * @return The retransmission counter is 0 */ inline unsigned int retransCount() const { return m_retransCount; } /** * Ask the frame if it's time for retransmit * @param time Current time * @return True if it's time to retransmit */ inline bool timeForRetrans(u_int64_t time) const { return time >= m_nextTransTime; } /** * Set the retransmission flag of this frame */ inline void setRetrans() { if (m_retrans) return; m_retrans = true; ((unsigned char*)m_data.data())[2] |= 0x80; } /** * Update the retransmission counter and the time to next retransmission */ inline void transmitted() { if (!m_retransCount) return; m_retransCount--; m_retransTimeInterval *= 2; m_nextTransTime += m_retransTimeInterval; } /** * Get the acknoledged flag of this frame * @return The acknoledged flag of this frame */ inline bool ack() const { return m_ack; } /** * Set the acknoledged flag of this frame */ inline void setAck() { m_ack = true; } /** * Get the acknoledge only flag of this frame * @return The acknoledge only flag of this frame */ inline bool ackOnly() const { return m_ackOnly; } /** * Check if absolute timeout can be set * @return True if absolute timeout can be set */ inline bool canSetTimeout() { return m_retransTimeInterval != 0; } /** * Set absolute timeout. Reset retransmission counter * @param tout Timeout time */ inline void setTimeout(u_int64_t tout) { if (!m_retransTimeInterval) return; m_retransTimeInterval = 0; m_retransCount = 0; m_nextTransTime = tout; } private: bool m_ack; // Acknoledge flag bool m_ackOnly; // Frame need only ACK as a response u_int16_t m_retransCount; // Retransmission counter u_int32_t m_retransTimeInterval; // Retransmission interval u_int64_t m_nextTransTime; // Next transmission time }; /** * This class holds trunk description * @short Trunk info */ class YIAX_API IAXTrunkInfo : public RefObject { public: /** * Constructor */ inline IAXTrunkInfo() : m_timestamps(true), m_sendInterval(IAX2_TRUNKFRAME_SEND_DEF), m_maxLen(IAX2_TRUNKFRAME_LEN_DEF), m_efficientUse(false), m_trunkInSyncUsingTs(true), m_trunkInTsDiffRestart(5000), m_retransCount(IAX2_RETRANS_COUNT_DEF), m_retransInterval(IAX2_RETRANS_INTERVAL_DEF), m_pingInterval(IAX2_PING_INTERVAL_DEF) {} /** * Init non trunking related data * @param params Parameter list * @param prefix Parameter prefix * @param def Optional defaults */ void init(const NamedList& params, const String& prefix = String::empty(), const IAXTrunkInfo* def = 0); /** * Init trunking from parameters * @param params Parameter list * @param prefix Parameter prefix * @param def Optional defaults * @param out True to init outgoing trunk data * @param in True to init incoming trunk data */ void initTrunking(const NamedList& params, const String& prefix = String::empty(), const IAXTrunkInfo* def = 0, bool out = true, bool in = true); /** * Update trunking from parameters. Don't change values not present in list * @param params Parameter list * @param prefix Parameter prefix * @param out True to update outgoing trunk data * @param in True to update incoming trunk data */ void updateTrunking(const NamedList& params, const String& prefix = String::empty(), bool out = true, bool in = true); /** * Dump info * @param buf Destination buffer * @param sep Parameters separator * @param out True to dump outgoing trunking info * @param in True to dump incoming trunking info * @param other True to dump non trunking info */ void dump(String& buf, const char* sep = " ", bool out = true, bool in = true, bool other = true); bool m_timestamps; // Trunk type: with(out) timestamps unsigned int m_sendInterval; // Send interval unsigned int m_maxLen; // Max frame length bool m_efficientUse; // Outgoing trunking: use or not the trunk based on calls using it bool m_trunkInSyncUsingTs; // Incoming trunk without timestamps: use trunk // time or trunk timestamp to re-build frame ts u_int32_t m_trunkInTsDiffRestart; // Incoming trunk without timestamp: diff between // timestamps at which we restart unsigned int m_retransCount; // Frame retransmission counter unsigned int m_retransInterval; // Frame retransmission interval in milliseconds unsigned int m_pingInterval; // Ping interval in milliseconds }; /** * Handle meta trunk frame with timestamps * @short Meta trunk frame */ class YIAX_API IAXMetaTrunkFrame : public RefObject, public Mutex { public: /** * Constructor. Constructs an outgoing meta trunk frame * @param engine The engine that owns this frame * @param addr Remote peer address * @param timestamps True if miniframes have timestamps, false if not * @param maxLen Maximum frame length * @param sendInterval Trunk send interval in milliseconds */ IAXMetaTrunkFrame(IAXEngine* engine, const SocketAddr& addr, bool timestamps, unsigned int maxLen, unsigned int sendInterval); /** * Destructor */ virtual ~IAXMetaTrunkFrame(); /** * Get the remote peer address * @return The remote peer address */ inline const SocketAddr& addr() const { return m_addr; } /** * Retrieve the number of calls using this trunk * @return The number of calls using this trunk */ inline unsigned int calls() const { return m_calls; } /** * Change the number of calls using this trunk * @param add True to add a call, false to remove it */ inline void changeCalls(bool add) { Lock lck(this); if (add) m_calls++; else if (m_calls) m_calls--; } /** * Check if the frame is adding mini frames timestamps * @return True if the frame is adding mini frames timestamps */ inline bool trunkTimestamps() const { return m_trunkTimestamps; } /** * Retrieve the send interval * @return Send interval in milliseconds */ inline unsigned int sendInterval() const { return m_sendInterval; } /** * Retrieve the frame maximum length * @return Frame maximum length */ inline unsigned int maxLen() const { return m_maxLen; } /** * Add a mini frame. If no room, send before adding * @param sCallNo Sorce call number * @param data Mini frame data * @param tStamp Mini frame timestamp * @return The number of data bytes added to trunk, 0 on failure */ unsigned int add(u_int16_t sCallNo, const DataBlock& data, u_int32_t tStamp); /** * Send this frame to remote peer if the time arrived * @param now Current time * @return The result of the write operation */ inline bool timerTick(const Time& now = Time()) { if (m_dataAddIdx == IAX2_TRUNKFRAME_HEADERLENGTH || !m_send) return false; Lock lck(this); return (now > m_send) && doSend(now,true); } /** * Send this frame to remote peer if there is any data in buffer * @return The result of the write operation */ inline bool send() { if (m_dataAddIdx == IAX2_TRUNKFRAME_HEADERLENGTH) return false; Lock lck(this); return m_dataAddIdx != IAX2_TRUNKFRAME_HEADERLENGTH && doSend(); } private: IAXMetaTrunkFrame() {} // No default constructor // Send this frame to remote peer bool doSend(const Time& now = Time(), bool onTime = false); // Set timestamp and next time to send inline void setTimestamp(u_int64_t now) { m_timeStamp = now; m_send = now + (u_int64_t)m_sendInterval * 1000; } // Set next time to send inline void setSendTime(u_int64_t now) { m_send = now + (u_int64_t)m_sendInterval * 1000; } // Set the timestamp of this frame inline void setTimestamp(u_int32_t tStamp) { m_data[4] = (u_int8_t)(tStamp >> 24); m_data[5] = (u_int8_t)(tStamp >> 16); m_data[6] = (u_int8_t)(tStamp >> 8); m_data[7] = (u_int8_t)tStamp; } unsigned int m_calls; // The number of calls using it u_int8_t* m_data; // Data buffer u_int16_t m_dataAddIdx; // Current add index u_int64_t m_timeStamp; // First time data was added u_int64_t m_send; // Time to send u_int32_t m_lastSentTs; // Last sent timestamp unsigned int m_sendInterval;// Send interval in milliseconds IAXEngine* m_engine; // The engine that owns this frame SocketAddr m_addr; // Remote peer address bool m_trunkTimestamps; // Trunk type: with(out) timestamps unsigned int m_maxLen; // Max frame length unsigned int m_maxDataLen; // Max frame data length unsigned char m_miniHdrLen; // Miniframe header length }; /** * This class holds data used by transaction to sync media. * The mutexes are not reentrant * @short IAX2 transaction media data */ class YIAX_API IAXMediaData { friend class IAXTransaction; public: /** * Constructor */ inline IAXMediaData() : m_inMutex(false,"IAXTransaction::InMedia"), m_outMutex(false,"IAXTransaction::OutMedia"), m_startedIn(false), m_startedOut(false), m_outStartTransTs(0), m_outFirstSrcTs(0), m_lastOut(0), m_lastIn(0), m_sent(0), m_sentBytes(0), m_recv(0), m_recvBytes(0), m_ooPackets(0), m_ooBytes(0), m_showInNoFmt(true), m_showOutOldTs(true), m_dropOut(0), m_dropOutBytes(0) {} /** * Increase drop out data * @param len The number of dropped bytes */ inline void dropOut(unsigned int len) { if (len) { m_dropOut++; m_dropOutBytes += len; } } /** * Print statistics * @param buf Destination buffer */ void print(String& buf); protected: Mutex m_inMutex; Mutex m_outMutex; bool m_startedIn; // Incoming media started bool m_startedOut; // Outgoing media started int m_outStartTransTs; // Transaction timestamp where media send started unsigned int m_outFirstSrcTs; // First outgoing source packet timestamp as received from source u_int32_t m_lastOut; // Last transmitted mini timestamp u_int32_t m_lastIn; // Last received timestamp unsigned int m_sent; // Packets sent unsigned int m_sentBytes; // Bytes sent unsigned int m_recv; // Packets received unsigned int m_recvBytes; // Bytes received unsigned int m_ooPackets; // Dropped received out of order packets unsigned int m_ooBytes; // Dropped received out of order bytes bool m_showInNoFmt; // Show incoming media arrival without format debug bool m_showOutOldTs; // Show dropped media out debug message unsigned int m_dropOut; // The number of dropped outgoing packets unsigned int m_dropOutBytes; // The number of dropped outgoing bytes }; /** * This class holds all the data needded for the management of an IAX2 transaction * which might be a call leg, a register/unregister or a poke one * @short An IAX2 transaction */ class YIAX_API IAXTransaction : public RefObject, public Mutex { friend class IAXEvent; friend class IAXEngine; public: /** * The transaction type as enumeration */ enum Type { Incorrect, // Unsupported/unknown type New, // Media exchange call RegReq, // Registration RegRel, // Registration release Poke, // Ping //FwDownl, }; /** * The transaction state as enumeration */ enum State { Connected, // Call leg established (Accepted) for transactions of type New NewLocalInvite, // New outgoing transaction: Poke/New/RegReq/RegRel NewLocalInvite_AuthRecv, // Auth request received for an outgoing transaction NewLocalInvite_RepSent, // Auth reply sent for an outgoing transaction NewRemoteInvite, // New incoming transaction: Poke/New/RegReq/RegRel NewRemoteInvite_AuthSent, // Auth sent for an incoming transaction NewRemoteInvite_RepRecv, // Auth reply received for an incoming transaction Unknown, // Initial state Terminated, // Terminated. No more frames accepted Terminating, // Terminating. Wait for ACK or timeout to terminate }; /** * Constructs an incoming transaction from a received full frame with an IAX * control message that needs a new transaction * @param engine The engine that owns this transaction * @param frame A valid full frame * @param lcallno Local call number * @param addr Address from where the frame was received * @param data Pointer to arbitrary user data */ static IAXTransaction* factoryIn(IAXEngine* engine, IAXFullFrame* frame, u_int16_t lcallno, const SocketAddr& addr, void* data = 0); /** * Constructs an outgoing transaction with an IAX control message that needs a new transaction * @param engine The engine that owns this transaction * @param type Transaction type * @param lcallno Local call number * @param addr Address to use * @param ieList Starting IE list * @param data Pointer to arbitrary user data */ static IAXTransaction* factoryOut(IAXEngine* engine, Type type, u_int16_t lcallno, const SocketAddr& addr, IAXIEList& ieList, void* data = 0); /** * Destructor */ virtual ~IAXTransaction(); /** * The IAX engine this transaction belongs to * @return Pointer to the IAXEngine of this transaction */ inline IAXEngine* getEngine() const { return m_engine; } /** * Get the type of this transaction * @return The type of the transaction as enumeration */ inline Type type() const { return m_type; } /** * Retrieve transaction type name * @return Transaction type name */ inline const char* typeName() { return typeName(type()); } /** * Get the state of this transaction * @return The state of the transaction as enumeration */ inline State state() const { return m_state; } /** * Retrieve the transaction state name * @return Transaction state name */ inline const char* stateName() { return stateName(state()); } /** * Get the timestamp of this transaction * @return The timestamp of this transaction */ inline u_int64_t timeStamp() const { return Time::msecNow() - m_timeStamp; } /** * Get the direction of this transaction * @return True if it is an outgoing transaction */ inline bool outgoing() const { return m_localInitTrans; } /** * Store a pointer to arbitrary user data * @param data User provided pointer */ inline void setUserData(void* data) { m_userdata = data; } /** * Return the opaque user data stored in the transaction * @return Pointer set by user */ inline void* getUserData() const { return m_userdata; } /** * Retrieve the local call number * @return 15-bit local call number */ inline u_int16_t localCallNo() const { return m_lCallNo; } /** * Retrieve the remote call number * @return 15-bit remote call number */ inline u_int16_t remoteCallNo() const { return m_rCallNo; } /** * Retrieve the remote host+port address * @return A reference to the remote address */ inline const SocketAddr& remoteAddr() const { return m_addr; } /** * Retrieve the username * @return A reference to the username */ inline const String& username() { return m_username; } /** * Retrieve the calling number * @return A reference to the calling number */ inline const String& callingNo() { return m_callingNo; } /** * Retrieve the calling name * @return A reference to the calling name */ inline const String& callingName() { return m_callingName; } /** * Retrieve the called number * @return A reference to the called number */ inline const String& calledNo() { return m_calledNo; } /** * Retrieve the called context * @return A reference to the called context */ inline const String& calledContext() { return m_calledContext; } /** * Retrieve the challenge sent/received during authentication * @return A reference to the challenge */ inline const String& challenge() { return m_challenge; } /** * Retrieve the media of a given type * @param type Media type to retrieve * @return IAXFormat pointer or 0 for invalid type */ inline IAXFormat* getFormat(int type) { if (type == IAXFormat::Audio) return &m_format; if (type == IAXFormat::Video) return &m_formatVideo; return 0; } /** * Retrieve the media data for a given type * @param type Media type to retrieve * @return IAXMediaData pointer or 0 for invalid type */ inline IAXMediaData* getData(int type) { if (type == IAXFormat::Audio) return &m_dataAudio; if (type == IAXFormat::Video) return &m_dataVideo; return 0; } /** * Retrieve the media format used during initialization * @param type Media type to retrieve * @return The initial media format for the given type */ inline u_int32_t format(int type) { IAXFormat* fmt = getFormat(type); return fmt ? fmt->format() : 0; } /** * Retrieve the incoming media format * @param type Media type to retrieve * @return The incoming media format for the given type */ inline u_int32_t formatIn(int type) { IAXFormat* fmt = getFormat(type); return fmt ? fmt->in() : 0; } /** * Retrieve the outgoing media format * @param type Media type to retrieve * @return The outgoing media format for the given type */ inline u_int32_t formatOut(int type) { IAXFormat* fmt = getFormat(type); return fmt ? fmt->out() : 0; } /** * Retrieve the media capability of this transaction * @return The media capability of this transaction */ inline u_int32_t capability() const { return m_capability; } /** * Retrieve the expiring time for a register/unregister transaction * @return The expiring time for a register/unregister transaction */ inline u_int32_t expire() const { return m_expire; } /** * Retrieve the authentication data sent/received during authentication * @return A reference to the authentication data */ inline const String& authdata() { return m_authdata; } /** * Set the destroy flag */ inline void setDestroy() { m_destroy = true; } /** * Start an outgoing transaction. * This method is thread safe */ void start(); /** * Process a frame from remote peer. * This method is thread safe * @param frame IAX frame belonging to this transaction to process * @return 'this' if successful or NULL if the frame is invalid */ IAXTransaction* processFrame(IAXFrame* frame); /** * Process received media data * @param data Received data * @param tStamp Mini frame timestamp multiplied by format multiplier * @param type Media type * @param full True if received in a full frame * @param mark Mark flag * @return 0 */ IAXTransaction* processMedia(DataBlock& data, u_int32_t tStamp, int type = IAXFormat::Audio, bool full = false, bool mark = false); /** * Send media data to remote peer. Update the outgoing media format if changed * @param data Data to send * @param tStamp Data timestamp * @param format Data format * @param type Media type * @param mark Mark flag * @return The number of bytes sent */ unsigned int sendMedia(const DataBlock& data, unsigned int tStamp, u_int32_t format, int type = IAXFormat::Audio, bool mark = false); /** * Get an IAX event from the queue * This method is thread safe. * @param now Current time * @return Pointer to an IAXEvent or 0 if none available */ IAXEvent* getEvent(const Time& now = Time()); /** * Get the maximum allowed number of full frames in the incoming frame list * @return The maximum allowed number of full frames in the incoming frame list */ static unsigned char getMaxFrameList(); /** * Set the maximum allowed number of full frames in the incoming frame list * @param value The new value of m_maxInFrames * @return False if value is greater then IAX2_MAX_TRANSINFRAMELIST */ static bool setMaxFrameList(unsigned char value); /** * Send an ANSWER frame to remote peer * This method is thread safe * @return False if the current transaction state is not Connected */ inline bool sendAnswer() { return sendConnected(IAXFullFrame::Answer); } /** * Send a RINGING frame to remote peer * This method is thread safe * @return False if the current transaction state is not Connected */ inline bool sendRinging() { return sendConnected(IAXFullFrame::Ringing); } /** * Send a PROCEEDING frame to remote peer * This method is thread safe * @return False if the current transaction state is not Connected */ inline bool sendProgress() { return sendConnected(IAXFullFrame::Proceeding); } /** * Send an ACCEPT/REGACK frame to remote peer * This method is thread safe * @param expires Optional pointer to expiring time for register transactions * @return False if the transaction type is not New and state is NewRemoteInvite or NewRemoteInvite_AuthRep or * if the transaction type is not RegReq and state is NewRemoteInvite or * type is not RegReq/RegRel and state is NewRemoteInvite_AuthRep */ bool sendAccept(unsigned int* expires = 0); /** * Send a HANGUP frame to remote peer * This method is thread safe * @param cause Optional reason for hangup * @param code Optional code of reason * @return False if the transaction type is not New or state is Terminated/Terminating */ bool sendHangup(const char* cause = 0, u_int8_t code = 0); /** * Send a REJECT/REGREJ frame to remote peer * This method is thread safe * @param cause Optional reason for reject * @param code Optional code of reason * @return False if the transaction type is not New/RegReq/RegRel or state is Terminated/Terminating */ bool sendReject(const char* cause = 0, u_int8_t code = 0); /** * Send an AUTHREQ/REGAUTH frame to remote peer * This method is thread safe * @return False if the current transaction state is not NewRemoteInvite */ bool sendAuth(); /** * Send an AUTHREP/REGREQ/REGREL frame to remote peer as a response to AUTHREQ/REGREQ/REGREL * This method is thread safe * @param response Response to send * @return False if the current transaction state is not NewLocalInvite_AuthRecv */ bool sendAuthReply(const String& response); /** * Send a DTMF frame to remote peer * This method is thread safe * @param dtmf DTMF char to send * @return False if the current transaction state is not Connected or dtmf is grater then 127 */ inline bool sendDtmf(u_int8_t dtmf) { return dtmf <= 127 ? sendConnected((IAXFullFrame::ControlType)dtmf,IAXFrame::DTMF) : false; } /** * Send a TEXT frame to remote peer * This method is thread safe * @param text Text to send * @return False if the current transaction state is not Connected */ bool sendText(const char* text); /** * Send a NOISE frame to remote peer * This method is thread safe * @param noise Noise value to send * @return False if the current transaction state is not Connected or noise is grater then 127 */ inline bool sendNoise(u_int8_t noise) { return noise <= 127 ? sendConnected((IAXFullFrame::ControlType)noise,IAXFrame::Noise) : false; } /** * Abort a registration transaction * This method is thread safe * @return False transaction is not a registration one or is already terminating */ bool abortReg(); /** * Enable trunking for this transaction * @param trunkFrame Pointer to IAXMetaTrunkFrame used to send trunked media * @param efficientUse Use or not the trunk based on calls using it * @return False trunking is already enabled for this transactio or trunkFrame is 0 */ bool enableTrunking(IAXMetaTrunkFrame* trunkFrame, bool efficientUse); /** * Process a received call token * This method is thread safe * @param callToken Received call token */ void processCallToken(const DataBlock& callToken); /** * Process incoming audio miniframes from trunk without timestamps * @param ts Trunk frame timestamp * @param blocks Received blocks * @param now Current time */ void processMiniNoTs(u_int32_t ts, ObjList& blocks, const Time& now = Time()); /** * Print transaction data on stdin * @param printStats True to print media statistics * @param printFrames True to print in/out pending frames * @param location Additional location info to be shown in debug */ void print(bool printStats = false, bool printFrames = false, const char* location = "status"); /** * Retrieve transaction type name from transaction type * @param type Transaction type * @return Requested type name */ static inline const char* typeName(int type) { return lookup(type,s_typeName); } /** * Retrieve transaction state name * @param state Transaction state * @return Requested state name */ static inline const char* stateName(int state) { return lookup(state,s_stateName); } /** * Transaction type name */ static const TokenDict s_typeName[]; /** * Transaction state name */ static const TokenDict s_stateName[]; /** * Standard message sent if unsupported/unknown/none authentication methosd was received */ static String s_iax_modNoAuthMethod; /** * Standard message sent if unsupported/unknown/none media format was received */ static String s_iax_modNoMediaFormat; /** * Standard message sent if the received authentication data is incorrect */ static String s_iax_modInvalidAuth; /** * Standard message sent if a received frame doesn't have an username information element */ static String s_iax_modNoUsername; protected: /** * Constructor: constructs an incoming transaction from a received full frame with an IAX * control message that needs a new transaction * @param engine The engine that owns this transaction * @param frame A valid full frame * @param lcallno Local call number * @param addr Address from where the frame was received * @param data Pointer to arbitrary user data */ IAXTransaction(IAXEngine* engine, IAXFullFrame* frame, u_int16_t lcallno, const SocketAddr& addr, void* data = 0); /** * Constructor: constructs an outgoing transaction with an IAX control message that needs a new transaction * @param engine The engine that owns this transaction * @param type Transaction type: see Type enumeration * @param lcallno Local call number * @param addr Address to use * @param ieList Starting IE list * @param data Pointer to arbitrary user data */ IAXTransaction(IAXEngine* engine, Type type, u_int16_t lcallno, const SocketAddr& addr, IAXIEList& ieList, void* data = 0); /** * Cleanup */ virtual void destroyed(); /** * Init data members from an IE list * @param ieList IE list to init from */ void init(IAXIEList& ieList); /** * Increment sequence numbers (inbound or outbound) for the frames that need it * @param frame Received frame if inbound is true, otherwise a transmitted one * @param inbound True for inbound frames * @return True if incremented. */ bool incrementSeqNo(const IAXFullFrame* frame, bool inbound); /** * Test if frame is acceptable (not an out of order or a late one) * @param frame Frame to test * @return True if frame can be added to incoming frame list */ bool isFrameAcceptable(const IAXFullFrame* frame); /** * Change the transaction state * @param newState the new transaction state * @return False if trying to change a termination state into a non termination one */ bool changeState(State newState); /** * Terminate the transaction. * @param evType IAXEvent type to generate * @param local If true it is a locally generated event * @param frame Frame to build event from * @param createIEList If true create IE list in the generated event * @return Pointer to a valid IAXEvent */ IAXEvent* terminate(u_int8_t evType, bool local, IAXFullFrame* frame = 0, bool createIEList = true); /** * Wait for ACK to terminate the transaction. No more events will be generated * @param evType IAXEvent type to generate * @param local If true it is a locally generated event * @param frame Frame to build event from * @return Pointer to a valid IAXEvent if evType if non 0, 0 otherwise */ IAXEvent* waitForTerminate(u_int8_t evType = 0, bool local = true, IAXFullFrame* frame = 0); /** * Constructs an IAXFrameOut frame, send it to remote peer and put it in the transmission list * This method is thread safe * @param type Frame type * @param subclass Frame subclass * @param data Frame IE list * @param len Frame IE list length * @param tStamp Frame timestamp. If 0 the transaction timestamp will be used * @param ackOnly Frame's acknoledge only flag * @param mark Frame mark flag */ void postFrame(IAXFrame::Type type, u_int32_t subclass, void* data = 0, u_int16_t len = 0, u_int32_t tStamp = 0, bool ackOnly = false, bool mark = false); /** * Constructs an IAXFrameOut frame, send it to remote peer and put it in the transmission list * This method is thread safe * @param type Frame type * @param subclass Frame subclass * @param ies Frame IE list * @param tStamp Frame timestamp. If 0 the transaction timestamp will be used * @param ackOnly Frame's acknoledge only flag */ void postFrameIes(IAXFrame::Type type, u_int32_t subclass, IAXIEList* ies, u_int32_t tStamp = 0, bool ackOnly = false); /** * Send a full frame to remote peer * @param frame Frame to send * @param vnak If true the transmission is a response to a VNAK frame * @return True on success */ bool sendFrame(IAXFrameOut* frame, bool vnak = false); /** * Create an event * @param evType Event type * @param local If true it is a locally generated event. * @param frame Frame to create from * @param newState The transaction new state * @return Pointer to an IAXEvent or 0 (invalid IE list) */ IAXEvent* createEvent(u_int8_t evType, bool local, IAXFullFrame* frame, State newState); /** * Create an event from a received frame that is a response to a sent frame and * change the transaction state to newState. Remove the response from incoming list. * @param frame Frame to create response for * @param findType Frame type to find * @param findSubclass Frame subclass to find * @param evType Event type to generate * @param local Local flag for the generated event. * @param newState New transaction state if an event was generated * @return Pointer to an IAXEvent or 0 (invalid IE list) */ IAXEvent* createResponse(IAXFrameOut* frame, u_int8_t findType, u_int8_t findSubclass, u_int8_t evType, bool local, State newState); /** * Find a response for a previously sent frame * @param frame Frame to find response for * @param delFrame Delete frame flag. If true on exit, a response was found * @return Pointer to an IAXEvent or 0 */ IAXEvent* getEventResponse(IAXFrameOut* frame, bool& delFrame); /** * Find a response for a previously sent frame if the transaction type is New * @param frame Frame to find response for * @param delFrame Delete frame flag. If true on exit, a response was found * @return Pointer to an IAXEvent or 0 */ IAXEvent* getEventResponse_New(IAXFrameOut* frame, bool& delFrame); /** * Process an authentication request. If valid, send an authentication reply * @param event Already generated event * @return Pointer to a valid IAXEvent */ IAXEvent* processAuthReq(IAXEvent* event); /** * Process an accept. If not valid (call m_engine->acceptFormatAndCapability) send a reject. * Otherwise return the event * @param event Already generated event * @return Pointer to a valid IAXEvent */ IAXEvent* processAccept(IAXEvent* event); /** * Process an authentication reply * @param event Already generated event * @return Pointer to a valid IAXEvent */ IAXEvent* processAuthRep(IAXEvent* event); /** * Find a response for a previously sent frame if the transaction type is RegReq/RegRel * @param frame Frame to find response for * @param delFrame Delete frame flag. If true on exit, a response was found * @return Pointer to an IAXEvent or 0 */ IAXEvent* getEventResponse_Reg(IAXFrameOut* frame, bool& delFrame); /** * Update transaction data from the event * @param event Already generated event * @return The received event */ IAXEvent* processRegAck(IAXEvent* event); /** * Find out if an incoming frame would start a transaction * @param frame Frame to process * @param delFrame Delete frame flag. If true on exit, frame is valid * @return Pointer to an IAXEvent or 0 */ IAXEvent* getEventStartTrans(IAXFullFrame* frame, bool& delFrame); /** * Find out if a frame is a remote request * @param frame Frame to process * @param delFrame Delete rame flag. If true on exit, a request was found * @return Pointer to an IAXEvent or 0 */ IAXEvent* getEventRequest(IAXFullFrame* frame, bool& delFrame); /** * Find out if a frame is a remote request if transaction type is New * @param frame Frame to process * @param delFrame Delete rame flag. If true on exit, a request was found * @return Pointer to an IAXEvent or 0 */ IAXEvent* getEventRequest_New(IAXFullFrame* frame, bool& delFrame); /** * Search for a frame in m_inFrames having the given type and subclass * @param type Frame type to find. * @param subclass Frame subclass to find. * @return Pointer to frame if found or 0. */ IAXFullFrame* findInFrame(IAXFrame::Type type, u_int32_t subclass); /** * Search in m_inFrames for a frame with the same timestamp as frameOut and deletes it. * @param frameOut Frame to find response for * @param type Frame type to find * @param subclass Frame subclass to find * @return True if found. */ bool findInFrameTimestamp(const IAXFullFrame* frameOut, IAXFrame::Type type, u_int32_t subclass); /** * Search in m_inFrames for an ACK frame which confirm the received frame and deletes it * @param frameOut Frame to find response for * @return True if found. */ bool findInFrameAck(const IAXFullFrame* frameOut); /** * Acknoledge the last received full frame */ void ackInFrames(); /** * Send a frame to remote peer in state Connected * This method is thread safe * @param subclass Frame subclass to send * @param frametype Frame type to send * @return False if the current transaction state is not Connected */ bool sendConnected(IAXFullFrame::ControlType subclass, IAXFrame::Type frametype = IAXFrame::Control); /** * Send an ACK frame * @param frame Aknoledged frame */ void sendAck(const IAXFullFrame* frame); /** * Send an VNAK frame */ void sendVNAK(); /** * Send an Unsupport frame * @param subclass Unsupported frame's subclass */ void sendUnsupport(u_int32_t subclass); /** * Internal protocol outgoing frames processing (PING/LAGRQ) * @param frame Frame to process * @param delFrame Delete frame flag. If true on exit, a response was found * @return 0. */ IAXEvent* processInternalOutgoingRequest(IAXFrameOut* frame, bool& delFrame); /** * Internal protocol incoming frames processing (PING/LAGRQ) * @param frame Frame to process * @param delFrame Delete frame flag. If true on exit, a request was found * @return 0. */ IAXEvent* processInternalIncomingRequest(const IAXFullFrame* frame, bool& delFrame); /** * Process mid call control frames * @param frame Frame to process * @param delFrame Delete frame flag. If true on exit, a request was found * @return A valid IAXEvent or 0 */ IAXEvent* processMidCallControl(IAXFullFrame* frame, bool& delFrame); /** * Process mid call IAX control frames * @param frame Frame to process * @param delFrame Delete frame flag. If true on exit, a request was found * @return A valid IAXEvent or 0 */ IAXEvent* processMidCallIAXControl(IAXFullFrame* frame, bool& delFrame); /** * Test if frame is a Reject/RegRej frame * @param frame Frame to process. * @param delFrame Delete frame flag. If true on exit, a request was found * @return A valid IAXEvent or 0. */ IAXEvent* remoteRejectCall(IAXFullFrame* frame, bool& delFrame); /** * Process received media full frames * @param frame Received frame * @param type Media type * @return 0 */ IAXTransaction* processMediaFrame(const IAXFullFrame* frame, int type); /** * Send all frames from outgoing queue with outbound sequence number starting with seqNo. * @param seqNo Requested sequence number * @return 0 */ IAXTransaction* retransmitOnVNAK(u_int16_t seqNo); /** * Generate a Reject event after internally rejecting a transaction * @param reason The reason of rejecting * @param code Error code * @return A valid IAXEvent */ IAXEvent* internalReject(const char* reason, u_int8_t code); /** * Event terminated feedback * This method is thread safe * @param event The event notifying termination */ void eventTerminated(IAXEvent* event); /** * Set the current event * @param event The event notifying termination * @return event */ inline IAXEvent* keepEvent(IAXEvent* event) { m_currentEvent = event; return event; } private: void adjustTStamp(u_int32_t& tStamp); void postFrame(IAXFrameOut* frame); void receivedVoiceMiniBeforeFull(); void resetTrunk(); void init(); void setPendingEvent(IAXEvent* ev = 0); inline void restartTrunkIn(u_int64_t now, u_int32_t ts) { m_trunkInStartTime = now; u_int64_t dt = (now - m_lastVoiceFrameIn) / 1000; m_trunkInTsDelta = m_lastVoiceFrameInTs + (u_int32_t)dt; m_trunkInFirstTs = ts; } // Process accept format and caps bool processAcceptFmt(IAXIEList* list); // Process queued ACCEPT. Reject with given reason/code if not found // Reject with 'nomedia' if found and format is not acceptable IAXEvent* checkAcceptRecv(const char* reason, u_int8_t code); // Params bool m_localInitTrans; // True: local initiated transaction bool m_localReqEnd; // Local client requested terminate Type m_type; // Transaction type State m_state; // Transaction state bool m_destroy; // Destroy flag bool m_accepted; // ACCEPT received and processed u_int64_t m_timeStamp; // Transaction creation timestamp u_int64_t m_timeout; // Transaction timeout in Terminating state SocketAddr m_addr; // Socket u_int16_t m_lCallNo; // Local peer call id u_int16_t m_rCallNo; // Remote peer call id unsigned char m_oSeqNo; // Outgoing frame sequence number unsigned char m_iSeqNo; // Incoming frame sequence number IAXEngine* m_engine; // Engine that owns this transaction void* m_userdata; // Arbitrary user data u_int32_t m_lastFullFrameOut; // Last transmitted full frame timestamp IAXMediaData m_dataAudio; IAXMediaData m_dataVideo; u_int16_t m_lastAck; // Last ack'd received frame's oseqno IAXEvent* m_pendingEvent; // Pointer to a pending event or 0 IAXEvent* m_currentEvent; // Pointer to last generated event or 0 // Outgoing frames management ObjList m_outFrames; // Transaction & protocol control outgoing frames unsigned int m_retransCount; // Retransmission counter. 0 --> Timeout unsigned int m_retransInterval; // Frame retransmission interval // Incoming frames management ObjList m_inFrames; // Transaction & protocol control incoming frames static unsigned char m_maxInFrames; // Max frames number allowed in m_inFrames // Call leg management u_int32_t m_pingInterval; // Ping remote peer interval u_int64_t m_timeToNextPing; // Time of the next Ping // Statistics u_int32_t m_inTotalFramesCount; // Total received frames u_int32_t m_inOutOfOrderFrames; // Total out of order frames u_int32_t m_inDroppedFrames; // Total dropped frames // Data IAXAuthMethod::Type m_authmethod; // Authentication method to use String m_username; // Username String m_callingNo; // Calling number String m_callingName; // Calling name String m_calledNo; // Called number String m_calledContext; // Called context String m_challenge; // Challenge String m_authdata; // Auth data received with auth reply u_int32_t m_expire; // Registration expiring time IAXFormat m_format; // Audio format IAXFormat m_formatVideo; // Video format u_int32_t m_capability; // Media capability of this transaction bool m_callToken; // Call token supported/expected unsigned int m_adjustTsOutThreshold; // Adjust outgoing data timestamp threshold unsigned int m_adjustTsOutOverrun; // Value used to adjust outgoing data timestamp on data // overrun (incoming data with rate greater then expected) unsigned int m_adjustTsOutUnderrun; // Value used to adjust outgoing data timestamp on data // underrun (incoming data with rate less then expected) u_int64_t m_lastVoiceFrameIn; // Time we received the last voice frame u_int32_t m_lastVoiceFrameInTs; // Timestamp in the last received voice frame int m_reqVoiceVNAK; // Send VNAK if not received full voice frame // Meta trunking IAXMetaTrunkFrame* m_trunkFrame; // Reference to a trunk frame if trunking is enabled for this transaction bool m_trunkFrameCallsSet; // Trunk frame calls increased bool m_trunkOutEfficientUse; // Use or not the trunk frame based on calls using it bool m_trunkOutSend; // Currently using the trunk frame bool m_trunkInSyncUsingTs; // Incoming trunk without timestamps: generate timestamp // using time or using trunk timestamp u_int64_t m_trunkInStartTime; // First time we received trunk in data u_int32_t m_trunkInTsDelta; // Value used to re-build ts: last voice timestamp u_int32_t m_trunkInTsDiffRestart; // Incoming trunk without timestamp: diff between timestamps at which we restart u_int32_t m_trunkInFirstTs; // Incoming trunk without timestamp: first trunk timestamp // Postponed start IAXIEList* m_startIEs; // Postponed start }; /** * This class holds an event generated by a transaction * @short Event class */ class YIAX_API IAXEvent { friend class IAXTransaction; friend class IAXConnectionlessTransaction; public: /** * Event type as enumeration */ enum Type { DontSet = 0, // Used internal Invalid, // Invalid frame received Terminated, // Transaction terminated Timeout, // Transaction timeout NotImplemented, // Feature not implemented New, // New remote transaction AuthReq, // Auth request AuthRep, // Auth reply Accept, // Request accepted Hangup, // Remote hangup Reject, // Remote reject Busy, // Call busy Text, // Text frame received Dtmf, // DTMF frame received Noise, // Noise frame received Answer, // Call answered Quelch, // Quelch the call Unquelch, // Unquelch the call Progressing, // Call progressing Ringing, // Ringing }; /** * Destructor * Dereferences the transaction possibly causing its destruction */ ~IAXEvent(); /** * Get the type of this event * @return The type of the event as enumeratio */ inline Type type() const { return m_type; } /** * Check if this is a locally generated event * @return True if it is a locally generated event */ inline bool local() const { return m_local; } /** * Check if this is a transaction finalization event * @return True if the transaction has finalized and will be destroyed */ inline bool final() const { return m_final; } /** * Set the final flag. */ inline void setFinal() { m_final = true; } /** * Get the type of the frame that generated the event * If 0 (internal event), the event consumer must delete the event * @return Frame type */ inline u_int8_t frameType() { return m_frameType; } /** * Get the subclass of the frame that generated the event * @return Frame subclass */ inline u_int32_t subclass() { return m_subClass; } /** * Get the IAX engine this event belongs to, if any * @return The IAX engine this event belongs to, if any */ inline IAXEngine* getEngine() const { return m_transaction ? m_transaction->getEngine() : 0; } /** * Get the IAX transaction that generated the event, if any * @return The IAX transaction that generated the event, if any */ inline IAXTransaction* getTransaction() const { return m_transaction; } /** * Get the opaque user data stored in the transaction * @return The opaque user data stored in the transaction */ inline void* getUserData() const { return m_transaction ? m_transaction->getUserData() : 0; } /** * Get the IE list * @return IE list reference */ inline IAXIEList& getList() { return *m_ieList; } protected: /** * Constructor * @param type Event type * @param local Local flag * @param final Final flag * @param transaction IAX transaction that generated the event * @param frameType The type of the frame that generated the event * @param subclass The subclass of the frame that generated the event */ IAXEvent(Type type, bool local, bool final, IAXTransaction* transaction, u_int8_t frameType = 0, u_int32_t subclass = 0); /** * Constructor * @param type Event type * @param local Local flag * @param final Final flag * @param transaction IAX transaction that generated the event * @param frame The frame that generated the event */ IAXEvent(Type type, bool local, bool final, IAXTransaction* transaction, IAXFullFrame* frame = 0); private: inline IAXEvent() {} // Default constructor Type m_type; // Event type u_int8_t m_frameType; // Frame type u_int32_t m_subClass; // Frame subclass bool m_local; // If true the event is generated locally, the receiver MUST not respond bool m_final; // Final event flag IAXTransaction* m_transaction; // Transaction that generated this event IAXIEList* m_ieList; // IAXInfoElement list }; /** * This class holds all information needded to manipulate all IAX transactions and events * @short IAX engine class */ class YIAX_API IAXEngine : public DebugEnabler, public Mutex { public: /** * Constructor * @param iface Address of the interface to use, default all (0.0.0.0) * @param port UDP port to run the protocol on * @param format Default media format * @param capab Media capabilities of this engine * @param params Optional extra parameter list * @param name Engine name */ IAXEngine(const char* iface, int port, u_int32_t format, u_int32_t capab, const NamedList* params = 0, const char* name = "iaxengine"); /** * Destructor * Closes all transactions belonging to this engine and flush all queues */ virtual ~IAXEngine(); /** * Retrieve the engine name * @return Engine name */ inline const String& name() const { return m_name; } /** * Retrieve the default caller number type * @return Default caller number type */ inline u_int8_t callerNumType() const { return m_callerNumType; } /** * Retrieve the default caller number presentation and screening concatenated value * @return Default caller number presentation and screening */ inline u_int8_t callingPres() const { return m_callingPres; } /** * Add a parsed frame to the transaction list * @param addr Address from which the frame was received * @param frame A parsed IAX frame * @return Pointer to the transaction or 0 to deref the frame */ IAXTransaction* addFrame(const SocketAddr& addr, IAXFrame* frame); /** * Add a raw frame to the transaction list * @param addr Address from which the message was received * @param buf Pointer to the start of the buffer holding the IAX frame * @param len Length of the message buffer * @return Pointer to the transaction or 0 */ IAXTransaction* addFrame(const SocketAddr& addr, const unsigned char* buf, unsigned int len); /** * Find a complete transaction. * This method is thread safe * @param addr Remote address * @param rCallNo Remote transaction call number * @return Referrenced pointer to the transaction or 0 */ IAXTransaction* findTransaction(const SocketAddr& addr, u_int16_t rCallNo); /** * Process media from remote peer. Descendents must override this method * @param transaction IAXTransaction that owns the call leg * @param data Media data * @param tStamp Media timestamp * @param type Media type * @param mark Mark flag */ virtual void processMedia(IAXTransaction* transaction, DataBlock& data, u_int32_t tStamp, int type, bool mark) {} /** * Event processor method. Keeps calling getEvent() and passing * any events to processEvent() until there are no more events * @return True if at least one event was processed */ bool process(); /** * Get the timeout interval sent challenge * @return Sent challenge timeout interval */ inline unsigned int challengeTout() const { return m_challengeTout; } /** * Get the maximum allowed frame length * @return The maximum allowed frame length */ inline u_int16_t maxFullFrameDataLen() const { return m_maxFullFrameDataLen; } /** * Get the default media format * @param audio True to retrieve default audio format, false for video format * @return The default media format */ inline u_int32_t format(bool audio = true) const { return audio ? m_format : m_formatVideo; } /** * Get the media capability of this engine * @return The media capability of this engine */ inline u_int32_t capability() const { return m_capability; } /** * Retrieve outgoing data timestamp adjust values * @param thres Adjust outgoing data timestamp threshold * @param over Value used to adjust outgoing data timestamp on data overrun * @param under Value used to adjust outgoing data timestamp on data underrun */ inline void getOutDataAdjust(unsigned int& thres, unsigned int& over, unsigned int& under) const { thres = m_adjustTsOutThreshold; over = m_adjustTsOutOverrun; under = m_adjustTsOutUnderrun; } /** * Initialize outgoing data timestamp adjust values. * This method is thread safe * @param params Parameters list * @param tr Optional transaction to init, initialize the engine's data if 0 */ void initOutDataAdjust(const NamedList& params, IAXTransaction* tr = 0); /** * (Re)Initialize the engine * @param params Parameter list */ void initialize(const NamedList& params); /** * Read data from socket * @param addr Socket to read from */ void readSocket(SocketAddr& addr); /** * Write data to socket. * @param buf Data to write * @param len Data length * @param addr Socket to write to * @param frame Optional frame to be printed * @param sent Pointer to variable to be filled with the number of bytes sent * @return True on success */ bool writeSocket(const void* buf, int len, const SocketAddr& addr, IAXFullFrame* frame = 0, unsigned int* sent = 0); /** * Write a full frame to socket * @param addr Socket to write to * @param frame Frame to write * @return True on success */ inline bool writeSocket(const SocketAddr& addr, IAXFullFrame* frame) { return !frame || writeSocket(frame->data().data(),frame->data().length(),addr,frame); } /** * Read events */ void runGetEvents(); /** * Removes a transaction from queue. Free the allocated local call number * Does not delete it * @param transaction Transaction to remove */ void removeTransaction(IAXTransaction* transaction); /** * Check if there are any transactions in the engine * This method is thread safe * @return True if the engine holds at least 1 transaction */ bool haveTransactions(); /** * Return the transactions count * This method is thread safe * @return Transactions count */ u_int32_t transactionCount(); /** * Send an INVAL with call numbers set to 0 to a remote peer to keep it alive * @param addr Address to send to */ void keepAlive(const SocketAddr& addr); /** * Process a new format received with a full frame * @param trans Transaction that received the new format * @param type Media type * @param format The received format * @return True if accepted */ virtual bool mediaFormatChanged(IAXTransaction* trans, int type, u_int32_t format) { return false; } /** * Check call token on incoming call requests. * This method is called by the engine when processing an incoming call request * @param addr The address from where the call request was received * @param frame Received frame * @return True if accepted, false to ignore the call */ virtual bool checkCallToken(const SocketAddr& addr, IAXFullFrame& frame); /** * Process the initial received format and capability. * If accepted on exit will set the transaction format and capability * @param trans Transaction that received the new format * @param caps Optional codecs to set in transaction before processing * @param type Media type * @return True if accepted */ bool acceptFormatAndCapability(IAXTransaction* trans, unsigned int* caps = 0, int type = IAXFormat::Audio); /** * Default event handler. event MUST NOT be deleted * @param event The event to handle */ virtual void defaultEventHandler(IAXEvent* event); /** * Check if the engine is exiting * @return True if the engine is exiting */ inline bool exiting() const { return m_exiting; } /** * Set the exiting flag */ virtual void setExiting(); /** * Enable trunking for the given transaction. Allocate a trunk meta frame if needed. * Trunk data is ignored if a trunk object for transaction remote address already exists * @param trans Transaction to enable trunking for * @param params Trunk parameters list, may be 0 * @param prefix Trunk parameters name prefix */ void enableTrunking(IAXTransaction* trans, const NamedList* params, const String& prefix = String::empty()); /** * Enable trunking for the given transaction. Allocate a trunk meta frame if needed. * Trunk data is ignored if a trunk object for transaction remote address already exists * @param trans Transaction to enable trunking for * @param data Trunk info to use */ void enableTrunking(IAXTransaction* trans, IAXTrunkInfo& data); /** * Init incoming trunking data for a given transaction * @param trans Transaction to init * @param params Trunk parameters list, may be 0 * @param prefix Trunk parameters name prefix */ void initTrunkIn(IAXTransaction* trans, const NamedList* params, const String& prefix = String::empty()); /** * Init incoming trunking data for a given transaction * @param trans Transaction to init * @param data Trunk info to use */ void initTrunkIn(IAXTransaction* trans, IAXTrunkInfo& data); /** * Retrieve the default trunk info data * @param info Destination to be set with trunk info pointer * @return True if destination pointr is valid */ inline bool trunkInfo(RefPointer& info) { Lock lck(m_trunkInfoMutex); info = m_trunkInfoDef; return info != 0; } /** * Send an INVAL frame * @param frame Frame for which to send an INVAL frame * @param addr The address from where the call request was received */ void sendInval(IAXFullFrame* frame, const SocketAddr& addr); /** * Keep calling processTrunkFrames to send trunked media data */ void runProcessTrunkFrames(); /** * Get the socket used for engine operation * @return Reference to the UDP socket */ inline Socket& socket() { return m_socket; } /** * Retrieve the socket address on wgich we are bound * @return Local address we are bound on */ inline const SocketAddr& addr() const { return m_addr; } /** * Send engine formats * @param caps Capabilities * @param fmtAudio Default audio format * @param fmtVideo Default video format */ inline void setFormats(u_int32_t caps, u_int32_t fmtAudio, u_int32_t fmtVideo) { m_format = fmtAudio; m_formatVideo = fmtVideo; m_capability = caps; } /** * Retrieve a port parameter * @param params Parameters list * @param param Parameter to retrieve * @return The port (default, 4569, if the parameter is missing or invalid) */ static inline int getPort(const NamedList& params, const String& param = "port") { return params.getIntValue(param,4569); } /** * Get the MD5 data from a challenge and a password * @param md5data Destination String * @param challenge Challenge source * @param password Password source */ static void getMD5FromChallenge(String& md5data, const String& challenge, const String& password); /** * Test if a received response to an authentication request is correct * @param md5data Data to compare with * @param challenge Received challenge * @param password Password source */ static bool isMD5ChallengeCorrect(const String& md5data, const String& challenge, const String& password); /** * Build a time signed secret used to authenticate an IP address * @param buf Destination buffer * @param secret Extra secret to add to MD5 sum * @param addr Socket address */ static void buildAddrSecret(String& buf, const String& secret, const SocketAddr& addr); /** * Decode a secret built using buildAddrSecret() * @param buf Input buffer * @param secret Extra secret to check * @param addr Socket address * @return Secret age, negative if invalid */ static int addrSecretAge(const String& buf, const String& secret, const SocketAddr& addr); /** * Add string (keyword) if found in a dictionary or integer parameter to a named list * @param list Destination list * @param param Parameter to add to the list * @param tokens The dictionary used to find the given value * @param val The value to find/add to the list */ static inline void addKeyword(NamedList& list, const char* param, const TokenDict* tokens, unsigned int val) { const char* value = lookup(val,tokens); if (value) list.addParam(param,value); else list.addParam(param,String(val)); } /** * Decode a DATETIME value * @param dt Value to decode * @param year The year component of the date * @param month The month component of the date * @param day The day component of the date * @param hour The hour component of the time * @param minute The minute component of the time * @param sec The seconds component of the time */ static void decodeDateTime(u_int32_t dt, unsigned int& year, unsigned int& month, unsigned int& day, unsigned int& hour, unsigned int& minute, unsigned int& sec); /** * Calculate overall timeout from interval and retransmission counter * @param interval The first retransmisssion interval * @param nRetrans The number of retransmissions * @return The overall timeout */ static unsigned int overallTout(unsigned int interval = IAX2_RETRANS_INTERVAL_DEF, unsigned int nRetrans = IAX2_RETRANS_COUNT_DEF); protected: /** * Process all trunk meta frames in the queue * @param time Time of the call * @return True if at least one frame was sent */ bool processTrunkFrames(const Time& time = Time()); /** * Default event for connection transactions handler. This method may be overriden to perform custom * processing * This method is thread safe * @param event Event to process */ virtual void processEvent(IAXEvent* event); /** * Get an IAX event from the queue. * This method is thread safe. * @param now Current time * @return Pointer to an IAXEvent or 0 if none is available */ IAXEvent* getEvent(const Time& now = Time()); /** * Generate call number. Update used call numbers list * @return Call number or 0 if none available */ u_int16_t generateCallNo(); /** * Release a call number * @param lcallno Call number to release */ void releaseCallNo(u_int16_t lcallno); /** * Start a transaction based on a local request * @param type Transaction type * @param addr Remote address to send the request * @param ieList First frame IE list * @param refTrans Return a refferenced transaction pointer * @param startTrans Start transaction * @return IAXTransaction pointer on success */ IAXTransaction* startLocalTransaction(IAXTransaction::Type type, const SocketAddr& addr, IAXIEList& ieList, bool refTrans = false, bool startTrans = true); /** * Bind the socket. Terminate it before trying * @param iface Address of the interface to use, default all (0.0.0.0) * @param port UDP port to run the protocol on * @param force Force binding if failed on required port * @return True on success */ bool bind(const char* iface, int port, bool force); int m_trunking; // Trunking capability: negative: ok, otherwise: not enabled private: String m_name; // Engine name Socket m_socket; // Socket SocketAddr m_addr; // Address we are bound on ObjList** m_transList; // Full transactions ObjList m_incompleteTransList; // Incomplete transactions (no remote call number) bool m_lUsedCallNo[IAX2_MAX_CALLNO + 1]; // Used local call numnmbers flags int m_lastGetEvIndex; // getEvent: keep last array entry bool m_exiting; // Exiting flag // Parameters int m_maxFullFrameDataLen; // Max full frame data (IE list) length u_int16_t m_startLocalCallNo; // Start index of local call number allocation u_int16_t m_transListCount; // m_transList count unsigned int m_challengeTout; // Sent challenge timeout interval bool m_callToken; // Call token required on incoming calls String m_callTokenSecret; // Secret used to generate call tokens int m_callTokenAge; // Max allowed call token age bool m_showCallTokenFailures; // Print incoming call token failures to output bool m_rejectMissingCallToken; // Reject/ignore incoming calls without call token if mandatory bool m_printMsg; // Print frame to output u_int8_t m_callerNumType; // Caller number type u_int8_t m_callingPres; // Caller presentation + screening // Media u_int32_t m_format; // The default media format u_int32_t m_formatVideo; // Default video format u_int32_t m_capability; // The media capability unsigned int m_adjustTsOutThreshold; // Adjust outgoing data timestamp threshold unsigned int m_adjustTsOutOverrun; // Value used to adjust outgoing data timestamp on data // overrun (incoming data with rate greater then expected) unsigned int m_adjustTsOutUnderrun; // Value used to adjust outgoing data timestamp on data // underrun (incoming data with rate less then expected) // Trunking Mutex m_mutexTrunk; // Mutex for trunk operations ObjList m_trunkList; // Trunk frames list Mutex m_trunkInfoMutex; // Trunk info mutex RefPointer m_trunkInfoDef; // Defaults for trunk data }; } #endif /* __YATEIAX_H */ /* vi: set ts=8 sw=4 sts=4 noet: */