yate/libs/yiax/yateiax.h

3361 lines
106 KiB
C++

/**
* 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 <yateclass.h>
#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<IAXTrunkInfo>& 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<IAXTrunkInfo> m_trunkInfoDef; // Defaults for trunk data
};
}
#endif /* __YATEIAX_H */
/* vi: set ts=8 sw=4 sts=4 noet: */