yate/contrib/yiax/yateiax.h

1636 lines
52 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 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 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:
enum Type { // Type Length Note
textframe = 0x00, // Generated for IAXFrame::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 4 Mask
FORMAT = 0x09, // DW 4 -
LANGUAGE = 0x0a, // Text - -
VERSION = 0x0b, // W 2 Value: 0x0002
ADSICPE = 0x0c, // W 2 -
DNID = 0x0d, // Text - -
AUTHMETHODS = 0x0e, // W 2 Mask
CHALLENGE = 0x0f, // Text - -
MD5_RESULT = 0x10, // Text - -
RSA_RESULT = 0x11, // Text - -
APPARENT_ADDR = 0x12, // BIN - -
REFRESH = 0x13, // W 2 -
DPSTATUS = 0x14, // W 2 Mask
CALLNO = 0x15, // W 2 Max value: IAX2_MAX_CALLNO
CAUSE = 0x16, // Text - -
IAX_UNKNOWN = 0x17, // B 1 -
MSGCOUNT = 0x18, // W 2 Format
AUTOANSWER = 0x19, //
MUSICONHOLD = 0x1a, // Text - Optional
TRANSFERID = 0x1b, // DW 4 -
RDNIS = 0x1c, // Text - -
PROVISIONING = 0x1d, // BIN - -
AESPROVISIONING = 0x1e, // BIN - -
DATETIME = 0x1f, // DW 4 Format
DEVICETYPE = 0x20, // Text - -
SERVICEIDENT = 0x21, // BIN 6 -
FIRMWAREVER = 0x22, // W 2 -
FWBLOCKDESC = 0x23, // DW 4 -
FWBLOCKDATA = 0x24, // BIN - Length = 0 : END
PROVVER = 0x25, // DW 4 -
CALLINGPRES = 0x26, // B 1 -
CALLINGTON = 0x27, // B 1 -
CALLINGTNS = 0x28, // W 2 Format
SAMPLINGRATE = 0x29, // DW 4 -
CAUSECODE = 0x2a, // B 1 -
ENCRYPTION = 0x2b, // B 1 Mask
ENKEY = 0x2c, // BIN - -
CODEC_PREFS = 0x2d, // Text - LIST
RR_JITTER = 0x2e, // DW 4 -
RR_LOSS = 0x2f, // DW 4 Format
RR_PKTS = 0x30, // DW 4 -
RR_DELAY = 0x31, // W 2 -
RR_DROPPED = 0x32, // DW 4 -
RR_OOO = 0x33, // DW 4 -
};
/**
* Constructor
* @param type Type of the IE
*/
inline IAXInfoElement(Type type) : m_type(type) {}
/**
* Destructor
*/
virtual ~IAXInfoElement() {}
/**
* Get the type of this IE
* @return Type of the IE
*/
inline Type type() const
{ return m_type; }
/**
* Add binary data to buf for packing.
* @param buf Binary data to add
*/
virtual void toBuffer(DataBlock& buf);
/**
* Get the name of an IE goven the type
* @param ieCode Numeric code of the IE
* @return Name of the IE, NULL if unknown
*/
static const char* ieText(u_int8_t ieCode);
protected:
/**
* Type of this IE
*/
Type m_type;
};
/**
* This class holds a single text Information Element that is attached to a message
*/
class YIAX_API IAXInfoElementString : public IAXInfoElement
{
public:
inline IAXInfoElementString(Type type, const char* buf, unsigned len) : IAXInfoElement(type), m_strData(buf,(int)len)
{}
virtual ~IAXInfoElementString() {}
inline int length() const
{ return m_strData.length(); }
inline String& data()
{ return m_strData; }
virtual void toBuffer(DataBlock& buf);
protected:
String m_strData; /* IE text data */
};
/**
* This class holds a 1, 2 & 4 byte length Information Element that is attached to a message
*/
class IAXInfoElementNumeric : public IAXInfoElement
{
public:
IAXInfoElementNumeric(Type type, u_int32_t val, u_int8_t len);
virtual ~IAXInfoElementNumeric() {}
inline int length() const
{ return m_length; }
inline u_int32_t data() const
{ return m_numericData; }
virtual void toBuffer(DataBlock& buf);
protected:
u_int8_t m_length; /* IE data length */
u_int32_t m_numericData; /* IE numeric data */
};
/**
* This class holds a single binary Information Element that is attached to a message
*/
class YIAX_API IAXInfoElementBinary : public IAXInfoElement
{
public:
IAXInfoElementBinary(Type type, unsigned char* buf, unsigned len) : IAXInfoElement(type), m_data(buf,len)
{}
virtual ~IAXInfoElementBinary() {}
inline int length() const
{ return m_data.length(); }
inline DataBlock& data()
{ return m_data; }
virtual void toBuffer(DataBlock& buf);
static IAXInfoElementBinary* packIP(const SocketAddr& addr);
static bool unpackIP(SocketAddr& addr, IAXInfoElementBinary* ie);
protected:
DataBlock m_data; /* IE binary data */
};
/**
* This class holds an IE list
*/
class YIAX_API IAXIEList
{
public:
inline IAXIEList() : m_invalidIEList(false)
{}
inline IAXIEList(const IAXFullFrame* frame) : m_invalidIEList(false)
{ createFromFrame(frame); }
inline ~IAXIEList()
{}
void insertVersion();
inline void appendIE(IAXInfoElement* ie)
{ m_list.append(ie); }
inline void appendNull(IAXInfoElement::Type type)
{ m_list.append(new IAXInfoElementBinary(type,0,0)); }
inline void appendString(IAXInfoElement::Type type, const String& src)
{ m_list.append(new IAXInfoElementString(type,src.c_str(),src.length())); }
inline void appendString(IAXInfoElement::Type type, unsigned char* src, unsigned len)
{ m_list.append(new IAXInfoElementString(type,(char*)src,len)); }
inline void appendNumeric(IAXInfoElement::Type type, u_int32_t value, u_int8_t len)
{ m_list.append(new IAXInfoElementNumeric(type,value,len)); }
inline void appendBinary(IAXInfoElement::Type type, unsigned char* data, unsigned len)
{ m_list.append(new IAXInfoElementBinary(type,data,len)); }
bool createFromFrame(const IAXFullFrame* frame);
void toBuffer(DataBlock& buf);
IAXInfoElement* getIE(IAXInfoElement::Type type);
bool getString(IAXInfoElement::Type type, String& dest);
bool getNumeric(IAXInfoElement::Type type, u_int32_t& dest);
bool getBinary(IAXInfoElement::Type type, DataBlock& dest);
inline bool invalidIEList()
{ return m_invalidIEList; }
inline bool validVersion() {
u_int32_t ver = 0xFFFF;
getNumeric(IAXInfoElement::VERSION,ver);
return ver == IAX_PROTOCOL_VERSION;
}
inline void clear()
{ m_list.clear(); }
private:
bool m_invalidIEList;
ObjList m_list;
};
/**
* This class holds the enumeration values for authentication methods
*/
class YIAX_API IAXAuthMethod
{
public:
enum Type {
Text = 1,
MD5 = 2,
RSA = 4,
};
};
/**
* This class holds the enumeration values for audio and video formats
* @short Wrapper class for audio and video formats
*/
class YIAX_API IAXFormat
{
public:
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),
};
enum Video {
JPEG = (1 << 16),
PNG = (1 << 17),
H261 = (1 << 18),
H263 = (1 << 19),
};
static const char* audioText(u_int8_t audio);
static const char* videoText(u_int8_t video);
static TokenDict audioData[];
static TokenDict videoData[];
};
/**
* This class holds the enumeration values for IAX control (subclass)
*/
class YIAX_API IAXControl
{
public:
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,
};
};
class YIAX_API IAXFrame : public RefObject
{
public:
enum Type {
DTMF = 0x01,
Voice = 0x02,
Video = 0x03,
Control = 0x04,
Null = 0x05,
IAX = 0x06,
Text = 0x07,
Image = 0x08,
HTML = 0x09,
Noise = 0x0a,
};
/**
* Constructs an incoming frame
*/
IAXFrame(Type type, u_int16_t sCallNo, u_int32_t tStamp, bool retrans,
const unsigned char* buf, unsigned int len);
virtual ~IAXFrame();
inline DataBlock& data()
{ return m_data; }
inline Type type() const
{ return m_type; }
inline bool retrans() const
{ return m_retrans; }
inline u_int16_t sourceCallNo() const
{ return m_sCallNo; }
inline u_int32_t timeStamp() const
{ return m_tStamp; }
inline u_int32_t subclass() const
{ return m_subclass; }
virtual const IAXFullFrame* fullFrame() const;
/**
* Parse a received buffer ans returns a IAXFrame pointer if valid
*/
static IAXFrame* parse(const unsigned char* buf, unsigned int len, IAXEngine* engine = 0, const SocketAddr* addr = 0);
/**
* Pack the the value received according to IAX protocol
* @return The packed subclass or 0 if invalid (>127 && not a power of 2)
*/
static u_int8_t packSubclass(u_int32_t value);
/**
* Unpack the the value received according to IAX protocol
* @return The unpacked subclass
*/
static u_int32_t IAXFrame::unpackSubclass(u_int8_t value);
protected:
Type m_type; /* Frame type */
DataBlock m_data; /* Frame data if incoming, packed frame for outgoing */
bool m_retrans; // Retransmission flag
u_int16_t m_sCallNo; // Source call number
u_int32_t m_tStamp; // Timestamp
u_int32_t m_subclass; // Subclass
};
class YIAX_API IAXFullFrame : public IAXFrame
{
public:
enum ControlType {
//TODO: validate codes with asterisk, libiax, rfc-draft
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,
};
/**
* Constructs a full frame from an incoming frame
*/
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);
/**
* Constructs a full frame for outgoing (m_data will contain the entire frame)
*/
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);
virtual ~IAXFullFrame();
inline u_int16_t destCallNo() const
{ return m_dCallNo; }
inline unsigned char oSeqNo() const
{ return m_oSeqNo; }
inline unsigned char iSeqNo() const
{ return m_iSeqNo; }
virtual const IAXFullFrame* fullFrame() const;
private:
u_int16_t m_dCallNo; // Destination call number
unsigned char m_oSeqNo; // Out sequence number
unsigned char m_iSeqNo; // In sequence number
};
class YIAX_API IAXFrameOut : public IAXFullFrame
{
public:
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)
{}
virtual ~IAXFrameOut()
{}
inline bool timeout() const
{ return !(bool)m_retransCount; }
inline bool timeForRetrans(u_int64_t time)
{ return time > m_nextTransTime; }
void transmitted();
inline void hurryTransmission(u_int64_t time = Time::msecNow())
{ m_nextTransTime = time; }
inline bool ack()
{ return m_ack; }
inline void setAck()
{ m_ack = true; }
inline bool ackOnly()
{ 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);
protected:
bool m_ack; /* Acknoledge flag */
bool m_ackOnly; /* frame need only Ack as response */
u_int16_t m_retransCount; /* Retransmission counter */
u_int32_t m_retransTimeInterval; /* Retransmission interval */
u_int64_t m_nextTransTime; /* Next transmission time */
};
/**
* Handle transactions of type New
*/
class YIAX_API IAXTransaction : public RefObject, public Mutex
{
friend class IAXEvent;
friend class IAXEngine;
public:
enum Type {
Incorrect,
New,
RegReq,
RegRel,
Poke,
FwDownl,
};
enum State {
/* *** New */
Connected, /* Call leg established (Accepted). */
/* Outgoing */
NewLocalInvite, /* Sent: New, RegReq/RegRel */
/* New */
/* *** Send: */
/* Hangup --> Terminating */
/* *** Receive: */
/* AuthReq --> NewLocalInvite_AuthRecv */
/* Accept --> Connected */
/* Reject, Hangup --> Terminating */
/* RegReq/RegRel */
/* *** Send: */
/* RegRej --> Terminating */
/* *** Receive: */
/* RegAuth --> NewLocalInvite_AuthRecv */
/* RegAck (if RegReq) --> Terminating */
/* RegRej --> Terminating */
NewLocalInvite_AuthRecv, /* Received: AuthReq, RegReq/RegRel */
/* New */
/* *** Send: */
/* AuthRep --> NewLocalInvite_RepSent */
/* Hangup, Reject --> Terminating */
/* *** Receive: */
/* Reject, Hangup --> Terminating */
/* RegReq/RegRel */
/* *** Send: */
/* RegReq/RegRel --> NewLocalInvite_RepSent */
/* RegRej --> Terminating */
/* *** Receive: */
/* RegRej --> Terminating */
NewLocalInvite_RepSent, /* Sent: AuthRep, RegReq/RegRel */
/* New */
/* *** Send: */
/* Hangup --> Terminating */
/* *** Receive: */
/* Accept --> Connected */
/* Reject, Hangup --> Terminating */
/* RegReq/RegRel */
/* *** Send: */
/* RegRej --> Terminating */
/* *** Receive: */
/* RegAck --> Terminating */
/* RegRej --> Terminating */
/* Incoming */
NewRemoteInvite, /* Received: New, RegReq/RegRel*/
/* New */
/* *** Send: */
/* AuthReq --> NewRemoteInvite_AuthSent */
/* Accept --> Connected */
/* Hangup --> Terminating */
/* *** Receive: */
/* Reject, Hangup --> Terminating */
/* RegReq/RegRel */
/* *** Send: */
/* RegAuth --> NewRemoteInvite_AuthSent */
/* RegAck (if RegReq) --> Terminated */
/* RegRej --> Terminating */
/* *** Receive: */
/* RegRej --> Terminating */
NewRemoteInvite_AuthSent, /* Sent: AuthReq, RegAuth */
/* New */
/* *** Send: */
/* Hangup --> Terminating */
/* *** Receive: */
/* AuthRep --> NewRemoteInvite_RepRecv */
/* Reject, Hangup --> Terminating */
/* RegReq/RegRel */
/* *** Send: */
/* RegRej --> Terminating */
/* *** Receive: */
/* RegReq/RegRel --> NewRemoteInvite_RepRecv */
/* RegRej --> Terminating */
NewRemoteInvite_RepRecv, /* Received: AuthRep, RegReq/RegRel*/
/* New */
/* *** Send: */
/* Accept --> Connected */
/* Hangup --> Terminating */
/* *** Receive: */
/* Reject, Hangup --> Terminating */
/* RegReq/RegRel */
/* *** Send: */
/* RegAck, RegRej --> Terminating */
/* *** Receive: */
/* RegRej --> Terminating */
/* Not initialized or terminated */
Unknown, /* Initial state. */
Terminated, /* Terminated. No more frames accepted. */
Terminating, /* Terminating. Wait for ACK or timeout to terminate. */
};
/**
* Destructor
*/
virtual ~IAXTransaction();
/**
* 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: 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
*/
static IAXTransaction* factoryOut(IAXEngine* engine, Type type, u_int16_t lcallno, const SocketAddr& addr,
IAXIEList& ieList, void* data = 0);
/**
* 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
*/
inline u_int64_t timeStamp() const
{ return Time::msecNow() - m_timeStamp; }
/**
* Get the direction of this 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; }
inline const String& username()
{ return m_username; }
inline const String& password()
{ return m_password; }
inline const String& callingNo()
{ return m_callingNo; }
inline const String& callingName()
{ return m_callingName; }
inline const String& calledNo()
{ return m_calledNo; }
inline const String& calledContext()
{ return m_calledContext; }
inline const String& challenge()
{ return m_challenge; }
inline u_int32_t format()
{ return m_format; }
inline u_int32_t formatIn()
{ return m_formatIn; }
inline u_int32_t formatOut()
{ return m_formatOut; }
inline u_int32_t capability()
{ return m_capability; }
inline u_int16_t expire()
{ return m_expire; }
inline const String& authdata()
{ return m_authdata; }
/**
* Process a frame from remote peer
* If successful and frame is a full frame increment m_iSeqNo
* 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 'this' if successful or 0
*/
IAXTransaction* processMedia(DataBlock& data, u_int32_t tStamp, bool voice = false);
/**
* Send media data to remote peer
* @param data Data to send
* @return 'this' if successful or 0
*/
IAXTransaction* sendMedia(const DataBlock& data, u_int8_t format);
/**
* Get an IAX event from the queue.
* This method is thread safe.
* @return Pointer to an IAXEvent or 0 if none available
*/
IAXEvent* getEvent(u_int64_t time);
/**
*/
static unsigned char getMaxFrameList();
/**
*/
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 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.
* @param pwd Required password
* @return False if the current transaction state is not NewRemoteInvite.
*/
bool sendAuth(const String& pwd);
/**
* Send an AUTHREP/REGREQ/REGREL frame to remote peer as a response to AUTHREQ/REGREQ/REGREL.
* This method is thread safe.
* @return False if the current transaction state is not NewLocalInvite_AuthRecv.
*/
bool sendAuthReply();
/**
* 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 dtmf 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();
/**
* Print transaction data on stdin.
*/
void print();
static String s_iax_modNoAuthMethod;
static String s_iax_modNoMediaFormat;
static String s_iax_modInvalidAuth;
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 number (inbound or outbound) for the frames that need it.
* @param frame Received frame if @ref inbound is true, otherwise the transmitted frame.
* @param inbound True for inbound frames.
* @return True if incremented.
*/
bool incrementSeqNo(const IAXFullFrame* frame, bool inbound);
/**
* Test if frame is acceptable.
* @param frame Frame to test.
* @return True if @ref 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 state.
*/
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 with the reason.
*/
IAXEvent* terminate(u_int8_t evType, bool local, const IAXFullFrame* frame = 0, bool createIEList = true);
/**
* Terminate the transaction. Wait for ACK to terminate. 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 with the reason.
*/
IAXEvent* waitForTerminate(u_int8_t evType, bool local, const IAXFullFrame* frame);
/**
* Send a full frame to remote peer and put it in transmission list
* This method is thread safe.
* tStamp = 0 : use transaction timestamp
*/
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 from a frame.
* @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 @ref frame flag. If true on exit, @ref frame will be deleted
* @return Pointer to an IAXEvent or 0
*/
IAXEvent* getEventResponse(IAXFrameOut* frame, bool& delFrame);
IAXEvent* IAXTransaction::getEventResponse_New(IAXFrameOut* frame, bool& delFrame);
IAXEvent* IAXTransaction::processAuthReq(IAXEvent* event);
IAXEvent* IAXTransaction::processAuthRep(IAXEvent* event);
IAXEvent* IAXTransaction::getEventResponse_Reg(IAXFrameOut* frame, bool& delFrame);
IAXEvent* IAXTransaction::processRegAck(IAXEvent* event);
/**
* Find an incoming frame that would start a transaction.
* @param frame Frame process
* @param delFrame Delete @ref frame flag. If true on exit, @ref frame will be deleted
* @return Pointer to an IAXEvent or 0
*/
IAXEvent* getEventStartTrans(IAXFullFrame* frame, bool& delFrame);
/**
* Find a request inside a transaction.
* If delFrame is true on exit frame will be deleted.
* @param frame Frame to process
* @param delFrame Delete @ref frame flag. If true on exit, @ref frame will be deleted
* @return Pointer to an IAXEvent or 0
*/
IAXEvent* getEventRequest(IAXFullFrame* frame, bool& delFrame);
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 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 @ref frame.
* @param frameOut Frame to find response for
* @return True if found.
*/
bool findInFrameAck(const IAXFullFrame* frameOut);
/**
* Send a frame to remote peer in state Connected.
* This method is thread safe.
* @param subclass Frame subclass 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();
/**
* Internal protocol outgoing frames processing (e.g. IAX PING, LAGRQ).
* @param frame Frame to process
* @param delFrame Delete @ref frame flag. If true on exit, @ref frame will be deleted
* @return 0.
*/
IAXEvent* processInternalOutgoingRequest(IAXFrameOut* frame, bool& delFrame);
/**
* Internal protocol incoming frames processing
* @param frame Frame to process
* @param delFrame Delete @ref frame flag. If true on exit, @ref frame will be deleted
* @return 0.
*/
IAXEvent* processInternalIncomingRequest(const IAXFullFrame* frame, bool& delFrame);
/**
* Process mid call control frames.
* @param frame Frame to process.
* @param delFrame Delete @ref frame flag. If true on exit, @ref frame will be deleted
* @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 @ref frame flag. If true on exit, @ref frame will be deleted
* @return A valid IAXEvent or 0.
*/
IAXEvent* processMidCallIAXControl(const IAXFullFrame* frame, bool& delFrame);
/**
* Test if @ref frame is e Reject/RegRej frame
* @param frame Frame to process.
* @param delFrame Delete @ref frame flag. If true on exit, @ref frame will be deleted
* @return A valid IAXEvent or 0.
*/
IAXEvent* remoteRejectCall(const IAXFullFrame* frame, bool& delFrame);
/**
* Terminate the transaction if state is Terminating and timeout.
* @param time Current time
* @return A valid IAXEvent or 0.
*/
IAXEvent* getEventTerminating(u_int64_t time);
/**
* Send all frames from outgoing queue with
* outbound sequence number starting with @ref seqNo.
* @param seqNo Requested sequence number
* @return 0.
*/
IAXTransaction* IAXTransaction::retransmittOnVNAK(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.
*/
inline void eventTerminated(IAXEvent* event) {
Lock lock(this);
if (event == m_currentEvent)
m_currentEvent = 0;
}
/**
* Set the current event.
* @param event The event notifying termination.
* @return @ref 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; /* User data */
u_int16_t m_lastMiniFrameOut; /* Last transmitted mini frame timestamp */
u_int32_t m_lastMiniFrameIn; /* Last received mini frame timestamp */
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;
u_int64_t m_timeToNextPing;
/* 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_password; /* Password */
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 */
};
class YIAX_API IAXEvent
{
friend class IAXTransaction;
friend class IAXConnectionlessTransaction;
public:
/**
* Types of events
*/
enum Type {
Invalid = 0,
Terminated,
Timeout,
NotImplemented,
New, /* New remote transaction. */
AuthReq, /* Auth request. Internally processed. */
AuthRep, /* Auth reply. */
Accept,
Hangup,
Reject,
Busy,
Text,
Dtmf,
Noise,
Answer,
Quelch,
Unquelch,
Progressing,
Ringing,
};
/**
* Destructor.
* If final and transaction is terminated, remove the transaction from its engine queue.
* Dereferences the transaction possibly causing its destruction.
*/
~IAXEvent();
/**
* Get the type of this event.
* @return The type of the event as enumeration
*/
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 getEvent 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_int8_t subclass()
{ return m_subClass; }
/**
* The IAX engine this event belongs to, if any
*/
inline IAXEngine* getEngine() const
{ return m_transaction ? m_transaction->getEngine() : 0; }
/**
* The IAX transaction that generated the event, if any
*/
inline IAXTransaction* getTransaction() const
{ return m_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
*/
inline IAXIEList& getList()
{ return m_ieList; }
protected:
/**
* Constructor
* @param transaction IAX transaction that generated the event
*/
IAXEvent(Type type, bool local, bool final, IAXTransaction* transaction, u_int8_t frameType = 0, u_int8_t subclass = 0);
IAXEvent(Type type, bool local, bool final, IAXTransaction* transaction, const IAXFullFrame* frame = 0);
private:
Type m_type; /* Event type */
u_int8_t m_frameType; /* Frame type */
u_int8_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 */
};
class YIAX_API IAXEngine : public DebugEnabler, public Mutex
{
public:
/**
* Constructor
* @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
*/
IAXEngine(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);
/**
* Destructor
*/
virtual ~IAXEngine();
/**
* Add a parsed frame to the transaction list
* @param addr Address from which the message was received
* @param frame A parsed IAX frame
* @return Pointer to the transaction, NULL if invalid
*/
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, NULL if invalid
*/
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 @ref getEvent() and passing
* any events to @ref 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()
{ return m_retransCount; }
/**
* Get default frame retransmission starting interval.
* @return Frame retransmission starting interval
*/
inline u_int16_t retransInterval()
{ return m_retransInterval; }
/**
* Get the timeout (in seconds) of acknoledged auth frames sent.
* @return Auth timeout in seconds
*/
inline u_int16_t authTimeout()
{ 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()
{ return m_transTimeout; }
inline u_int16_t maxFullFrameDataLen()
{ return m_maxFullFrameDataLen; }
inline u_int32_t format()
{ return m_format; }
inline u_int32_t capability()
{ return m_capability; }
/**
* Read data from socket
*/
void readSocket(SocketAddr& addr);
/**
* Write data to socket.
* @return True on success
*/
bool writeSocket(const void* buf, int len, const SocketAddr& addr);
/**
* 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 transaction count.
* This method is thread safe.
* @return True if transaction still exists.
*/
u_int32_t transactionCount();
/**
* Send an INVAL with call numbers set to 0 to a remote peer to keep alive.
* @param addr Address to send.
*/
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. @ref event MUST NOT be deleted.
* @param event The event to handle.
*/
virtual void defaultEventHandler(IAXEvent* event);
/**
* Get the socket used for engine operation
* @return Reference to the UDP socket
*/
inline Socket& socket()
{ return m_socket; }
static void getMD5FromChallenge(String& md5data, const String& challenge, const String& password);
static bool isMD5ChallengeCorrect(const String& md5data, const String& challenge, const String& password);
protected:
/**
* Default event for connection transactions handler. This method may be overriden to perform custom
* processing.
* This method is thread safe.
*/
virtual void processEvent(IAXEvent* event);
/**
* Get an IAX event from the queue.
* This method is thread safe.
* @return Pointer to an IAXEvent or NULL 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();
/**
* Generate call number. Update used call numbers list
*/
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 regdata Pointer to IAXRegData for RegReq/RegRel transactions
* @return IAXTransaction pointer on success.
*/
IAXTransaction* startLocalTransaction(IAXTransaction::Type type, const SocketAddr& addr, IAXIEList& ieList);
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 */
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;
u_int32_t m_capability;
};
}
#endif /* __YATEIAX_H */
/* vi: set ts=8 sw=4 sts=4 noet: */