Source: libs/yiax/yateiax.h


Annotated List
Files
Globals
Hierarchy
Index
/**
 * 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 

#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 data The source data to append
     * @param len Source length
     */
    inline void appendBinary(IAXInfoElement::Type type, unsigned char* data, unsigned len)
	{ m_list.append(new IAXInfoElementBinary(type,data,len)); }

    /**
     * Construct the list from an IAXFullFrame object.
     *  On exit m_invalidIEList will contain the opposite of the returned value
     * @param frame Source object
     * @param incoming True if it is an incoming frame
     * @return False if the frame contains invalid IEs
     */
    bool createFromFrame(const IAXFullFrame* frame, bool incoming = true);

    /**
     * Construct a buffer from this list
     * @param buf Destination buffer
     */
    void toBuffer(DataBlock& buf);

    /**
     * Add this list to a string
     * @param dest Destination string
     * @param indent Optional indent for each element
     */
    void toString(String& dest, const char* indent = 0);

    /**
     * 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 auth The authentication methods as ORed bits
     * @param sep The separator to use
    */
    static void authList(String& dest, u_int16_t auth, char sep);

    static TokenDict s_texts[];
};

/**
 * This class holds 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 frame Frame to create from
     * @param newState The transaction new state
     * @return Pointer to an IAXEvent or 0 (invalid IE list)
     */
    IAXEvent* createEvent(u_int8_t evType, bool local, 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 frametype Frame type to send
     * @return False if the current transaction state is not Connected
     */
    bool sendConnected(IAXFullFrame::ControlType subclass, IAXFrame::Type frametype = IAXFrame::Control);

    /**
     * Send an ACK frame
     * @param frame Aknoledged frame
     */
    void sendAck(const IAXFullFrame* frame);

    /**
     * Send an 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 metaFrame 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: */

Generated by: paulc on bussard on Mon Mar 8 12:18:15 2010, using kdoc 2.0a54.