yate/libs/yiax/yateiax.h

2318 lines
71 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-2006 Null Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#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;
class IAXInfoElementString;
class IAXInfoElementNumeric;
class IAXInfoElementBinary;
class IAXFullFrame;
class IAXFrameOut;
class IAXEvent;
class IAXEngine;
#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
/**
* 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
};
/**
* 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); }
private:
static 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 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; }
/**
* 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
*/
inline IAXIEList() : m_invalidIEList(false)
{}
/**
* Constructor. Construct the list from an IAXFullFrame object
* @param frame Source object
* @param incoming True if it is an incoming frame
*/
inline IAXIEList(const IAXFullFrame* frame, bool incoming = true) : m_invalidIEList(false)
{ createFromFrame(frame,incoming); }
/**
* Destructor
*/
inline ~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(); }
/**
* 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 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 value The source
* @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);
/**
* Get an IAXInfoElement from the list
* @param type The desired type
* @return An IAXInfoElement pointer or 0 if the list doesn't contain an IE of this type
*/
IAXInfoElement* getIE(IAXInfoElement::Type type);
/**
* 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 formats The authentication methods
* @param sep The separator to use
*/
static void authList(String& dest, u_int16_t auth, char sep);
static TokenDict s_texts[];
};
/**
* This class holds the enumeration values for audio and video formats
* @short Wrapper class for audio and video formats
*/
class YIAX_API IAXFormat
{
public:
/**
* Audio format enumeration types
*/
enum Audio {
G723_1 = (1 << 0),
GSM = (1 << 1),
ULAW = (1 << 2),
ALAW = (1 << 3),
MP3 = (1 << 4),
ADPCM = (1 << 5),
SLIN = (1 << 6),
LPC10 = (1 << 7),
G729A = (1 << 8),
SPEEX = (1 << 9),
ILBC = (1 << 10),
};
/**
* Video format enumeration types
*/
enum Video {
JPEG = (1 << 16),
PNG = (1 << 17),
H261 = (1 << 18),
H263 = (1 << 19),
};
/**
* Create a string list from formats
* @param dest The destination
* @param formats The formats
* @param sep The separator to use
*/
static void formatList(String& dest, u_int32_t formats, char sep = ',');
/**
* Get the text associated with an audio format
* @param audio 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* audioText(u_int32_t audio)
{ return lookup(audio,audioData); }
/**
* Get the text associated with a video format
* @param video 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* videoText(u_int32_t video)
{ return lookup(video,videoData); }
/**
* Keep the texts associated with the audio formats
*/
static TokenDict audioData[];
/**
* Keep the texts associated with the video formats
*/
static TokenDict videoData[];
};
/**
* 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,
};
/**
* 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
*/
IAXFrame(Type type, u_int16_t sCallNo, u_int32_t tStamp, bool retrans,
const unsigned char* buf, unsigned int len);
/**
* 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 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 const IAXFullFrame* fullFrame() const;
/**
* 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);
/**
* 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
};
/**
* 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,
};
/**
* 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
*/
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);
/**
* 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
*/
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);
/**
* 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; }
/**
* Get a pointer to this frame if it is a full frame
* @return A pointer to this frame
*/
virtual const IAXFullFrame* fullFrame() const;
/**
* 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) const;
/**
* 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); }
private:
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
};
/**
* 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 retransInterval Time interval to the next retransmission
* @param ackOnly Acknoledge only flag. If true, the frame only expects an ACK
*/
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 retransInterval, bool ackOnly)
: IAXFullFrame(type,subclass,sCallNo,dCallNo,oSeqNo,iSeqNo,tStamp,buf,len),
m_ack(false), m_ackOnly(ackOnly), m_retransCount(retransCount), m_retransTimeInterval(retransInterval),
m_nextTransTime(Time::msecNow() + m_retransTimeInterval)
{}
/**
* Destructor
*/
virtual ~IAXFrameOut()
{}
/**
* Get the timeout (retransmission counter) of this frame
* @return True if the retransmission counter is 0
*/
inline bool timeout() const
{ return m_retransCount == 0; }
/**
* 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
*/
void setRetrans();
/**
* Update the retransmission counter and the time to next retransmission
*/
void transmitted();
/**
* 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; }
/**
* Increase the timeout for acknoledged authentication frames sent and set the counter to 1
* @param nextTransTime Next transmission time
*/
void adjustAuthTimeout(u_int64_t nextTransTime);
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
};
/**
* 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
*/
IAXMetaTrunkFrame(IAXEngine* engine, const SocketAddr& addr);
/**
* Destructor
*/
virtual ~IAXMetaTrunkFrame();
/**
* Get the remote peer address
* @return The remote peer address
*/
inline const SocketAddr& addr() const
{ return m_addr; }
/**
* Get the timestamp of this frame
* @return The timestamp of this frame
*/
inline u_int32_t timestamp()
{ return m_timestamp; }
/**
* Set the timestamp of this frame
* @param tStamp Timestamp value to set
*/
void setTimestamp(u_int32_t tStamp);
/**
* 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 False if the frame was sent and the write operation failed
*/
bool add(u_int16_t sCallNo, const DataBlock& data, u_int32_t tStamp);
/**
* Send this frame to remote peer
* @param tStamp Frame timestamp
* @return The result of the write operation
*/
bool send(u_int32_t tStamp);
private:
u_int8_t* m_data; // Data buffer
u_int16_t m_dataAddIdx; // Current add index
u_int32_t m_timestamp; // Frame timestamp
IAXEngine* m_engine; // The engine that owns this frame
SocketAddr m_addr; // Remote peer address
};
/**
* 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; }
/**
* Get the state of this transaction
* @return The state of the transaction as enumeration
*/
inline State state() const
{ return m_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; }
/**
* Retrive the local call number
* @return 15-bit local call number
*/
inline u_int16_t localCallNo() const
{ return m_lCallNo; }
/**
* Retrive the remote call number
* @return 15-bit remote call number
*/
inline u_int16_t remoteCallNo() const
{ return m_rCallNo; }
/**
* Retrive the remote host+port address
* @return A reference to the remote address
*/
inline const SocketAddr& remoteAddr() const
{ return m_addr; }
/**
* Retrive the username
* @return A reference to the username
*/
inline const String& username()
{ return m_username; }
/**
* Retrive the calling number
* @return A reference to the calling number
*/
inline const String& callingNo()
{ return m_callingNo; }
/**
* Retrive the calling name
* @return A reference to the calling name
*/
inline const String& callingName()
{ return m_callingName; }
/**
* Retrive the called number
* @return A reference to the called number
*/
inline const String& calledNo()
{ return m_calledNo; }
/**
* Retrive the called context
* @return A reference to the called context
*/
inline const String& calledContext()
{ return m_calledContext; }
/**
* Retrive the challenge sent/received during authentication
* @return A reference to the challenge
*/
inline const String& challenge()
{ return m_challenge; }
/**
* Retrive the media format used during initialization
* @return The initial media format
*/
inline u_int32_t format()
{ return m_format; }
/**
* Retrive the incoming media format
* @return The incoming media format
*/
inline u_int32_t formatIn()
{ return m_formatIn; }
/**
* Retrive the outgoing media format
* @return The outgoing media format
*/
inline u_int32_t formatOut() const
{ return m_formatOut; }
/**
* Retrive the media capability of this transaction
* @return The media capability of this transaction
*/
inline u_int32_t capability() const
{ return m_capability; }
/**
* Retrive 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; }
/**
* Retrive the authentication data sent/received during authentication
* @return A reference to the authentication data
*/
inline const String& authdata()
{ return m_authdata; }
/**
* 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 mini frame data
* @param data Received data
* @param tStamp Mini frame timestamp
* @param voice True if received mini frame inside a Voice full frame
* @return 0
*/
IAXTransaction* processMedia(DataBlock& data, u_int32_t tStamp, bool voice = false);
/**
* Send media data to remote peer. Update the outgoing media format if changed
* @param data Data to send
* @param format Data format
* @return 'this' if successful or 0
*/
IAXTransaction* sendMedia(const DataBlock& data, u_int32_t format);
/**
* Get an IAX event from the queue
* This method is thread safe.
* @param time The time this method was called
* @return Pointer to an IAXEvent or 0 if none available
*/
IAXEvent* getEvent(u_int64_t 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
* @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();
/**
* 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
* @return False trunking is already enabled for this transactio or trunkFrame is 0
*/
bool enableTrunking(IAXMetaTrunkFrame* trunkFrame);
/**
* Print transaction data on stdin
*/
void print();
/**
* 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);
/**
* 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, const 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
*/
IAXEvent* waitForTerminate(u_int8_t evType, bool local, const IAXFullFrame* frame);
/**
* 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
*/
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);
/**
* 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 frameOut 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, const 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 subclass 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 INVAL frame
*/
void sendInval();
/**
* 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(const 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(const 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(const IAXFullFrame* frame, bool& delFrame);
/**
* Terminate the transaction if state is Terminating on a remote request
* @param time Current time
* @return A valid IAXEvent or 0
*/
IAXEvent* getEventTerminating(u_int64_t time);
/**
* Process received Voice frames
* @param frame Received voice frame
* @return 0
*/
IAXTransaction* processVoiceFrame(const IAXFullFrame* frame);
/**
* 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 an Accept event after internally accepting a transaction
* @return A valid IAXEvent
*/
IAXEvent* internalAccept();
/**
* Generate a Reject event after internally rejecting a transaction
* @param reason The reason of rejecting
* @return A valid IAXEvent
*/
IAXEvent* internalReject(String& reason);
/**
* 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:
// 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
u_int64_t m_timeStamp; // Transaction creation timestamp
u_int32_t m_timeout; // Transaction timeout (in seconds) on remote termination request
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
u_int16_t m_lastMiniFrameOut; // Last transmitted mini frame timestamp
u_int32_t m_lastMiniFrameIn; // Last received mini frame timestamp
u_int16_t m_lastAck; // Last ack'd received frame's oseqno
Mutex m_mutexInMedia; // Keep received media thread safe
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
u_int16_t m_retransCount; // Retransmission counter. 0 --> Timeout
u_int32_t 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
u_int32_t m_format; // Media format used for initial negotiation
u_int32_t m_formatIn; // Incoming media format
u_int32_t m_formatOut; // Outgoing media format
u_int32_t m_capability; // Media capability of this transaction
// Meta trunking
IAXMetaTrunkFrame* m_trunkFrame; // Reference to a trunk frame if trunking is enabled for this transaction
};
/**
* 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 {
Invalid = 0, // 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, const 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 transListCount Number of entries in the transaction hash table
* @param retransCount Retransmission counter for each transaction belonging to this engine
* @param retransInterval Retransmission interval default value in miliseconds
* @param authTimeout Timeout (in seconds) of acknoledged auth frames sent
* @param transTimeout Timeout (in seconds) on remote request of transactions belonging to this engine
* @param maxFullFrameDataLen Max full frame IE list (buffer) length
* @param format Default media format
* @param capab Media capabilities of this engine
* @param trunkSendInterval Send trunk meta frame interval
* @param authRequired Automatically challenge all clients for authentication
*/
IAXEngine(const char* iface, int port, u_int16_t transListCount, u_int16_t retransCount, u_int16_t retransInterval,
u_int16_t authTimeout, u_int16_t transTimeout, u_int16_t maxFullFrameDataLen,
u_int32_t format, u_int32_t capab, u_int32_t trunkSendInterval, bool authRequired);
/**
* Destructor
* Closes all transactions belonging to this engine and flush all queues
*/
virtual ~IAXEngine();
/**
* 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);
/**
* 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
*/
virtual void processMedia(IAXTransaction* transaction, DataBlock& data, u_int32_t tStamp)
{}
/**
* 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 default frame retransmission counter
* @return Frame retransmission counter
*/
inline u_int16_t retransCount() const
{ return m_retransCount; }
/**
* Get default frame retransmission starting interval
* @return Frame retransmission starting interval
*/
inline u_int16_t retransInterval() const
{ return m_retransInterval; }
/**
* Check if a transaction should automatically request authentication
* @return True to automatically request authentication
*/
inline bool authRequired() const
{ return m_authRequired; }
/**
* Get the timeout (in seconds) of acknoledged auth frames sent
* @return Auth timeout in seconds
*/
inline u_int16_t authTimeout() const
{ return m_authTimeout; }
/**
* Get the timeout (in seconds) of transactions belonging to this engine
* @return Timeout (in seconds) of transactions belonging to this engine
*/
inline u_int32_t transactionTimeout() const
{ return m_transTimeout; }
/**
* 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
* @return The default media format
*/
inline u_int32_t format() const
{ return m_format; }
/**
* Get the media capability of this engine
* @return The media capability of this engine
*/
inline u_int32_t capability() const
{ return m_capability; }
/**
* 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 if debug is DebugAll
* @return True on success
*/
bool writeSocket(const void* buf, int len, const SocketAddr& addr, IAXFullFrame* frame = 0);
/**
* 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);
/**
* 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(SocketAddr& addr);
/**
* Process a new format received with a Voice frame
* @param trans Transaction that received the new format
* @param format The received format
* @return True if accepted
*/
virtual bool voiceFormatChanged(IAXTransaction* trans, u_int32_t format)
{ return false; }
/**
* 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
* @return True if accepted
*/
bool acceptFormatAndCapability(IAXTransaction* trans);
/**
* Default event handler. event MUST NOT be deleted
* @param event The event to handle
*/
virtual void defaultEventHandler(IAXEvent* event);
/**
* Enable trunking for the given transaction. Allocate a trunk meta frame if needded
* @param trans Transaction to enable trunking for
*/
void enableTrunking(IAXTransaction* trans);
/**
* Remove a trunk meta frame from the queue and deref it
* @param trunkFrame The trunk meta frame to remove
*/
void removeTrunkFrame(IAXMetaTrunkFrame* metaFrame);
/**
* 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; }
/**
* 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);
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(u_int32_t time = Time::msecNow());
/**
* 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 time Time of the call
* @return Pointer to an IAXEvent or 0 if none is available
*/
IAXEvent* getEvent(u_int64_t 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 trunking Enable/disable trunking for this transaction
* @return IAXTransaction pointer on success.
*/
IAXTransaction* startLocalTransaction(IAXTransaction::Type type, const SocketAddr& addr, IAXIEList& ieList, bool trunking = false);
private:
Socket m_socket; // Socket
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
// Parameters
bool m_authRequired; // Automatically request authentication
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
u_int16_t m_retransCount; // Retransmission counter for each transaction belonging to this engine
u_int16_t m_retransInterval; // Retransmission interval default value in miliseconds
u_int16_t m_authTimeout; // Timeout (in seconds) of acknoledged auth frames sent
u_int32_t m_transTimeout; // Timeout (in seconds) on remote request of transactions
// belonging to this engine
// Media
u_int32_t m_format; // The default media format
u_int32_t m_capability; // The media capability
// Trunking
Mutex m_mutexTrunk; // Mutex for trunk operations
ObjList m_trunkList; // Trunk frames list
u_int32_t m_trunkSendInterval; // Trunk frame send interval
};
}
#endif /* __YATEIAX_H */
/* vi: set ts=8 sw=4 sts=4 noet: */