Logo Search packages:      
Sourcecode: yate version File versions  Download package

ysip.h

/**
 * ysip.h
 * Yet Another SIP 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <telengine.h>
#include <telephony.h>

/** 
 * We use Telephony Engine namespace, which in fact holds just the 
 * generic classes 
*/
namespace TelEngine {

class URI : public String
{
public:
    URI();
    URI(const String& uri);
    URI(const URI& uri);
    URI(const char* proto, const char* user, const char* host, int port = 0);
    void parse() const;
    inline URI& operator=(const URI& value)
      { String::operator=(value); return *this; }
    inline URI& operator=(const String& value)
      { String::operator=(value); return *this; }
    inline URI& operator=(const char value)
      { String::operator=(value); return *this; }
    inline const String& getProtocol() const
      { parse(); return m_proto; }
    inline const String& getUser() const
      { parse(); return m_user; }
    inline const String& getHost() const
      { parse(); return m_host; }
    inline int getPort() const
      { parse(); return m_port; }
protected:
    virtual void changed();
    mutable bool m_parsed;
    mutable String m_proto;
    mutable String m_user;
    mutable String m_host;
    mutable int m_port;
};

class SIPEngine;
class SIPEvent;

class SIPParty : public RefObject
{
public:
    SIPParty();
    SIPParty(bool reliable);
    virtual ~SIPParty();
    virtual void transmit(SIPEvent* event) = 0;
    virtual const char* getProtoName() const = 0;
    virtual bool setParty(const URI& uri) = 0;
    inline const String& getLocalAddr() const
      { return m_local; }
    inline const String& getPartyAddr() const
      { return m_party; }
    inline int getLocalPort() const
      { return m_localPort; }
    inline int getPartyPort() const
      { return m_partyPort; }
    inline bool isReliable() const
      { return m_reliable; }
protected:
    bool m_reliable;
    bool m_init;
    String m_local;
    String m_party;
    int m_localPort;
    int m_partyPort;
};

class SIPBody
{
public:
    SIPBody(const String& type);
    virtual ~SIPBody();
    inline const String& getType() const
      { return m_type; }
    static SIPBody* build(const char *buf, int len, const String& type);
    const DataBlock& getBody() const;
    virtual bool isSDP() const
      { return false; }
    virtual SIPBody* clone() const = 0;
protected:
    virtual void buildBody() const = 0;
    String m_type;
    mutable DataBlock m_body;
};

class SDPBody : public SIPBody
{
public:
    SDPBody();
    SDPBody(const String& type, const char *buf, int len);
    virtual ~SDPBody();
    virtual bool isSDP() const
      { return true; }
    virtual SIPBody* clone() const;
    inline const ObjList& lines() const
      { return m_lines; }
    inline void addLine(const char *name, const char *value = 0)
      { m_lines.append(new NamedString(name,value)); }
    const NamedString* getLine(const char *name) const;
protected:
    SDPBody(const SDPBody& original);
    virtual void buildBody() const;
    ObjList m_lines;
};

class BinaryBody : public SIPBody
{
public:
    BinaryBody(const String& type, const char *buf, int len);
    virtual ~BinaryBody();
    virtual SIPBody* clone() const;
protected:
    BinaryBody(const BinaryBody& original);
    virtual void buildBody() const;
};

class StringBody : public SIPBody
{
public:
    StringBody(const String& type, const char *buf, int len);
    virtual ~StringBody();
    virtual SIPBody* clone() const;
protected:
    StringBody(const StringBody& original);
    virtual void buildBody() const;
    String m_text;
};

class HeaderLine : public NamedString
{
public:
    HeaderLine(const char *name, const String& value);
    HeaderLine(const HeaderLine& original);
    virtual ~HeaderLine();
    inline const ObjList& params() const
      { return m_params; }
    void setParam(const char *name, const char *value = 0);
    void delParam(const char *name);
    const NamedString* getParam(const char *name) const;
protected:
    ObjList m_params;
};

/**
 * An object that holds the sip message parsed into this library model.
 * This class can be used to parse a sip message from a text buffer, or it
 * can be used to create a text buffer from a sip message.
 */
00176 class SIPMessage : public RefObject
{
public:
    /**
     * Creates a new, empty, outgoing SIPMessage.
     */
    SIPMessage(const char* _method, const char* _uri, const char* _version = "SIP/2.0");

    /**
     * Creates a new SIPMessage from parsing a text buffer.
     */
    SIPMessage(SIPParty* ep, const char *buf, int len = -1);

    /**
     * Creates a new SIPMessage as answer to another message.
     */
    SIPMessage(const SIPMessage* message, int _code, const char* _reason);

    /**
     * Creates an ACK message from a response message.
     */
    SIPMessage(const SIPMessage* message, bool newtran);

    /**
     * Destroy the message and all
     */
    virtual ~SIPMessage();

    /**
     * Construct a new SIP message by parsing a text buffer
     * @return A pointer to a valid new message or NULL
     */
    static SIPMessage* fromParsing(SIPParty* ep, const char *buf, int len = -1);

    /**
     * Complete missing fields with defaults taken from a SIP engine
     */
    void complete(SIPEngine* engine, const char* user = 0, const char* domain = 0, const char* dlgTag = 0);

    /**
     * Copy an entire header line (including all parameters) from another message
     * @param message Pointer to the message to copy the header from
     * @param name Name of the header to copy
     * @return True if the header was found and copied
     */
    bool copyHeader(const SIPMessage* message, const char* name);

    /**
     * Copy multiple header lines (including all parameters) from another message
     * @param message Pointer to the message to copy the header from
     * @param name Name of the headers to copy
     * @return Number of headers found and copied
     */
    int copyAllHeaders(const SIPMessage* message, const char* name);

    /**
     * Get the endpoint this message uses
     * @return Pointer to the endpoint of this message
     */
00235     inline SIPParty* getParty() const
      { return m_ep; }

    /**
     * Set the endpoint this message uses
     * @param ep Pointer to the endpoint of this message
     */
    void setParty(SIPParty* ep = 0);

    /**
     * Check if this message is valid as result of the parsing
     */
00247     inline bool isValid() const
      { return m_valid; }

    /**
     * Check if this message is an answer or a request
     */
00253     inline bool isAnswer() const
      { return m_answer; }

    /**
     * Check if this message is an outgoing message
     * @return True if this message should be sent to remote
     */
00260     inline bool isOutgoing() const
      { return m_outgoing; }

    /**
     * Check if this message is an ACK message
     * @return True if this message has an ACK method
     */
00267     inline bool isACK() const
      { return m_ack; }

    /**
     * Check if this message is handled by a reliable protocol
     * @return True if a reliable protocol (TCP, SCTP) is used
     */
00274     inline bool isReliable() const
      { return m_ep ? m_ep->isReliable() : false; }

    /**
     * Get the Command Sequence number from this message
     */
00280     inline int getCSeq() const
      { return m_cseq; }

    /**
     * Find a header line by name
     * @param name Name of the header to locate
     * @return A pointer to the first matching header line or 0 if not found
     */
    const HeaderLine* getHeader(const char* name) const;

    /**
     * Find the last header line that matches a given name name
     * @param name Name of the header to locate
     * @return A pointer to the last matching header line or 0 if not found
     */
    const HeaderLine* getLastHeader(const char* name) const;

    /**
     * Count the header lines matching a specific name
     * @param name Name of the header to locate
     * @return Number of matching header lines
     */
    int countHeaders(const char* name) const;

    /**
     * Find a header parameter by name
     * @param name Name of the header to locate
     * @param param Name of the parameter to locate in the tag
     * @return A pointer to the first matching header line or 0 if not found
     */
    const NamedString* getParam(const char* name, const char* param) const;

    /**
     * Get a string value (without parameters) from a header line
     * @param name Name of the header to locate
     * @return The value hold in the header or an empty String
     */
    const String& getHeaderValue(const char* name) const;

    /**
     * Get a string value from a parameter in a header line
     * @param name Name of the header to locate
     * @param param Name of the parameter to locate in the tag
     * @return The value hold in the parameter or an empty String
     */
    const String& getParamValue(const char* name, const char* param) const;

    /**
     * Append a new header line constructed from name and content
     */
00330     inline void addHeader(const char* name, const char* value = 0)
      { header.append(new HeaderLine(name,value)); }

    /**
     * Append an already constructed header line
     */
00336     inline void addHeader(HeaderLine* line)
      { header.append(line); }

    /**
     * Creates a binary buffer from a SIPMessage.
     */
    const DataBlock& getBuffer() const;

    /**
     * Creates a text buffer from the headers.
     */
    const String& getHeaders() const;

    /**
     * Set a new body for this message
     */
    void setBody(SIPBody* newbody = 0);

    /**
     * Sip Version
     */
00357     String version;

    /**
     * This holds the method name of the message.
     */
00362     String method;

    /**
     * URI of the request
     */
00367     String uri;

    /**
     * Status code
     */
00372     int code;

    /**
     * Reason Phrase
     */
00377     String reason;

    /**
     * All the headers should be in this list.
     */
00382     ObjList header;

    /**
     * All the body realted things should be here, including the entire body and
     * the parsed body.
     */
00388     SIPBody* body;

protected:
    bool parse(const char* buf, int len);
    bool parseFirst(String& line);
    SIPParty* m_ep;
    bool m_valid;
    bool m_answer;
    bool m_outgoing;
    bool m_ack;
    int m_cseq;
    mutable String m_string;
    mutable DataBlock m_data;
};

/**
 * A class to store information required to identify a dialog
 */
00406 class SIPDialog : public String
{
public:
    SIPDialog();
    SIPDialog(const SIPDialog& original);
    SIPDialog(const SIPMessage& message);
    SIPDialog& operator=(const SIPDialog& original);
    SIPDialog& operator=(const SIPMessage& message);
    SIPDialog& operator=(const String& callid);
    bool operator==(const SIPDialog& other) const;
    bool operator!=(const SIPDialog& other) const;
    String localURI;
    String localTag;
    String remoteURI;
    String remoteTag;
};

/**
 * All informaton related to a SIP transaction, starting with 1st message
 */
00426 class SIPTransaction : public RefObject
{
public:
00429     enum State {
      /**
       * Invalid state - before constructor or after destructor
       */
00433       Invalid,

      /**
       * Initial state - after the initial message was inserted
       */
00438       Initial,

      /**
       * Trying state - got the message but no decision made yet
       */
00443       Trying,

      /**
       * Process state - while locally processing the event
       */
00448       Process,

      /**
       * Retrans state - waiting for cleanup, retransmits latest message
       */
00453       Retrans,

      /**
       * Finish state - transmits the last message and goes to Retrans
       */
00458       Finish,

      /**
       * Cleared state - removed from engine, awaiting destruction
       */
00463       Cleared,
    };
    /**
     * Constructor from first message
     * @param message A pointer to the initial message, should not be used
     *  afterwards as the transaction takes ownership
     * @param engine A pointer to the SIP engine this transaction belongs
     * @param outgoing True if this transaction is for an outgoing request
     */
    SIPTransaction(SIPMessage* message, SIPEngine* engine, bool outgoing = true);

    /**
     * Destructor - clears all held objects
     */
    virtual ~SIPTransaction();

    /**
     * Get the name of a transaction state
     */
    static const char* stateName(int state);

    /**
     * The current state of the transaction
     */
00487     inline int getState() const
      { return m_state; }

    /**
     * The first message that created this transaction
     */
00493     inline const SIPMessage* initialMessage() const
      { return m_firstMessage; }

    /**
     * The last message (re)sent by this transaction
     */
00499     inline const SIPMessage* latestMessage() const
      { return m_lastMessage; }

    /**
     * The most recent message handled by this transaction
     */
00505     inline const SIPMessage* recentMessage() const
      { return m_lastMessage ? m_lastMessage : m_firstMessage; }

    /**
     * The SIPEngine this transaction belongs to
     */
00511     inline SIPEngine* getEngine() const
      { return m_engine; }

    /**
     * Get the mutex that protects the engine's objects
     * @return Pointer to the engine's mutex object or NULL if none exists
     */
    Mutex* mutex();

    /**
     * Check if this transaction was initiated by the remote peer or locally
     * @return True if the transaction was created by an outgoing message
     */
00524     inline bool isOutgoing() const
      { return m_outgoing; }

    /**
     * Check if this transaction was initiated locally or by the remote peer
     * @return True if the transaction was created by an incoming message
     */
00531     inline bool isIncoming() const
      { return !m_outgoing; }

    /**
     * Check if this transaction is an INVITE transaction or not
     * @return True if the transaction is an INVITE
     */
00538     inline bool isInvite() const
      { return m_invite; }

    /**
     * Check if this transaction is handled by a reliable protocol
     * @return True if a reliable protocol (TCP, SCTP) is used
     */
00545     inline bool isReliable() const
      { return m_firstMessage ? m_firstMessage->isReliable() : false; }

    /**
     * The SIP method this transaction handles
     */
00551     inline const String& getMethod() const
      { return m_firstMessage ? m_firstMessage->method : String::empty(); }

    /**
     * The SIP URI this transaction handles
     */
00557     inline const String& getURI() const
      { return m_firstMessage ? m_firstMessage->uri : String::empty(); }

    /**
     * The Via branch that may uniquely identify this transaction
     * @return The branch parameter taken from the Via header
     */
00564     inline const String& getBranch() const
      { return m_branch; }

    /**
     * The call ID may identify this transaction
     * @return The Call-ID parameter taken from the message
     */
00571     inline const String& getCallID() const
      { return m_callid; }

    /**
     * The dialog tag that may identify this transaction
     * @return The dialog tag parameter
     */
00578     inline const String& getDialogTag() const
      { return m_tag; }

    /**
     * Set the (re)transmission flag that allows the latest outgoing message
     *  to be send over the wire
     */
00585     inline void setTransmit()
      { m_transmit = true; }

    /**
     * Check if a message belongs to this transaction and process it if so
     * @param message A pointer to the message to check, should not be used
     *  afterwards if this method returned True
     * @param branch The branch parameter extracted from first Via header
     * @return True if the message was handled by this transaction, in
     *  which case it takes ownership over the message
     */
    virtual bool processMessage(SIPMessage* message, const String& branch);

    /**
     * Get an event for this transaction if any is available.
     * It provides default handling for invalid states, otherwise calls
     *  the more specific protected version.
     * You may override this method if you need processing of invalid states.
     * @return A newly allocated event or NULL if none is needed
     */
    virtual SIPEvent* getEvent();

    /**
     * Creates and transmits a final response message
     */
    void setResponse(int code, const char* reason);

    /**
     * Transmits a final response message
     */
    void setResponse(SIPMessage* message);

    /**
     * Set an arbitrary pointer as user specific data
     */
00620     inline void setUserData(void* data)
      { m_private = data; }

    /**
     * Return the opaque user data
     */
00626     inline void* getUserData() const
      { return m_private; }

protected:
    /**
     * Get an event only for client transactions
     * @param state The current state of the transaction
     * @param timeout If timeout occured, number of remaining timeouts,
     *  otherwise -1
     * @return A newly allocated event or NULL if none is needed
     */
    virtual SIPEvent* getClientEvent(int state, int timeout);

    /**
     * Get an event only for server transactions.
     * @param state The current state of the transaction
     * @param timeout If timeout occured, number of remaining timeouts,
     *  otherwise -1
     * @return A newly allocated event or NULL if none is needed
     */
    virtual SIPEvent* getServerEvent(int state, int timeout);

    /**
     * Process only the messages for client transactions
     * @param message A pointer to the message to process, should not be used
     *  afterwards if this method returned True
     * @param state The current state of the transaction
     */
    virtual void processClientMessage(SIPMessage* message, int state);

    /**
     * Process only the messages for server transactions
     * @param message A pointer to the message to process, should not be used
     *  afterwards if this method returned True
     * @param state The current state of the transaction
     */
    virtual void processServerMessage(SIPMessage* message, int state);

    /**
     * Change the transaction state
     * @param newstate The desired new state
     * @return True if state change occured
     */
    bool changeState(int newstate);

    /**
     * Set the latest message sent by this transaction
     * @param message Pointer to the latest message
     */
    void setLatestMessage(SIPMessage* message = 0);

    /**
     * Store a pending event to be picked up at the next @ref getEvent() call
     * @param event Event to store
     * @param replace True to replace any existing pending event
     */
    void setPendingEvent(SIPEvent* event = 0, bool replace = false);

    /**
     * Check if there is a pending event waiting
     * @return True is there is a pending event
     */
00688     inline bool isPendingEvent() const
      { return m_pending; }

    /**
     * Set a repetitive timeout
     * @param delay How often (in microseconds) to fire the timeout
     * @param count How many times to keep firing the timeout
     */
    void setTimeout(unsigned long long delay = 0, unsigned int count = 1);

    bool m_outgoing;
    bool m_invite;
    bool m_transmit;
    int m_state;
    unsigned int m_timeouts;
    unsigned long long m_delay;
    unsigned long long m_timeout;
    SIPMessage* m_firstMessage;
    SIPMessage* m_lastMessage;
    SIPEvent* m_pending;
    SIPEngine* m_engine;
    String m_branch;
    String m_callid;
    String m_tag;
    void *m_private;
};

/**
 * This object is an event that will be taken from SIPEngine
 */ 
00718 class SIPEvent
{
    friend class SIPTransaction;
public:

    SIPEvent()
      : m_message(0), m_transaction(0)
      { }

    SIPEvent(SIPMessage* message, SIPTransaction* transaction = 0);

    ~SIPEvent();

    /**
     * The SIPEngine this event belongs to
     */
00734     inline SIPEngine* getEngine() const
      { return m_transaction ? m_transaction->getEngine() : 0; }

    inline const SIPMessage* getMessage() const
      { return m_message; }

    inline SIPTransaction* getTransaction() const
      { return m_transaction; }

    /**
     * Check if the message is an outgoing message
     * @return True if the message should be sent to remote
     */
00747     inline bool isOutgoing() const
      { return m_message && m_message->isOutgoing(); }

    /**
     * Check if the message is an incoming message
     * @return True if the message is coming from remote
     */
00754     inline bool isIncoming() const
      { return m_message && !m_message->isOutgoing(); }

    /**
     * Get the pointer to the endpoint this event uses
     */
00760     inline SIPParty* getParty() const
      { return m_message ? m_message->getParty() : 0; }

    /**
     * Return the opaque user data stored in the transaction
     */
00766     inline void* getUserData() const
      { return m_transaction ? m_transaction->getUserData() : 0; }

    /**
     * The state of the transaction when the event was generated
     */
00772     inline int getState() const
      { return m_state; }

protected:
    SIPMessage* m_message;
    SIPTransaction* m_transaction;
    int m_state;
};

/**
 * This object can be one for each SIPListener.
 */
00784 class SIPEngine
{
public:
    /**
     * Create the SIP Engine
     */
    SIPEngine(const char* userAgent = 0);

    /**
     * Destroy the SIP Engine
     */
    virtual ~SIPEngine();

    /**
     * Build a new SIPParty for a message
     */
    virtual bool buildParty(SIPMessage* message) = 0;

    /**
     * Add a message into the transaction list
     * @param buf A buffer containing the SIP message text
     * @param len The length of the message or -1 to interpret as C string
     * @return Pointer to the transaction or NULL if message was invalid
     */
    SIPTransaction* addMessage(SIPParty* ep, const char *buf, int len = -1);

    /**
     * Add a message into the transaction list
     * This method is thread safe
     * @param message A parsed SIP message to add to the transactions
     * @return Pointer to the transaction or NULL if message was invalid
     */
    SIPTransaction* addMessage(SIPMessage* message);

    /**
     * Get a SIPEvent from the queue. 
     * This method mainly looks into the transaction list and get all kind of 
     * events, like an incoming request (INVITE, REGISTRATION), a timer, an
     * outgoing message.
     * This method is thread safe
     */
    SIPEvent *getEvent();

    /**
     * This method should be called very often to get the events from the list and 
     * to send them to processEvent method.
     * @return True if some events were processed this turn
     */
    bool process();

    /**
     * Default handling for events.
     * This method should be overriden for what you need and at the end you
     * should call this default one
     * This method is thread safe
     */
    virtual void processEvent(SIPEvent *event);

    /**
     * Get the length of a timer
     * @param which A one-character constant that selects which timer to return
     * @param reliable Whether we request the timer value for a reliable protocol
     * @return Duration of the selected timer or 0 if invalid
     */
    unsigned long long getTimer(char which, bool reliable = false) const;

    /**
     * Get the default value of the Max-Forwards header for this engine
     * @return The maximum number of hops the request is allowed to pass
     */
00854     inline unsigned int getMaxForwards() const
      { return m_maxForwards; }

    /**
     * Get the User agent for this SIP engine
     */
00860     inline const String& getUserAgent() const
      { return m_userAgent; }

    /**
     * Get a CSeq value suitable for use in a new request
     */
00866     inline int getNextCSeq()
      { return ++m_cseq; }

    /**
     * Check if a method is in the allowed methods list
     * @param method Uppercase name of the method to check
     * @return True if the method should be allowed processing
     */
    bool isAllowed(const char* method) const;

    /**
     * Add a method to the allowed methods list
     * @param method Uppercase name of the method to add
     */
    void addAllowed(const char* method);

    /**
     * Get all the allowed methods
     * @return Comma separated list of allowed methods
     */
00886     inline const String& getAllowed() const
      { return m_allowed; }

    /**
     * Get the mutex that protects objects in this engine
     * @return Pointer to the engine's mutex object
     */
00893     inline Mutex* mutex()
      { return &m_mutex; }

    /**
     * TransList is the key. 
     * Is the list that holds all the transactions.
     */
00900     ObjList TransList;

protected:
    Mutex m_mutex;
    unsigned long long m_t1;
    unsigned long long m_t4;
    unsigned int m_maxForwards;
    int m_cseq;
    String m_userAgent;
    String m_allowed;
};

}

/* vi: set ts=8 sw=4 sts=4 noet: */

Generated by  Doxygen 1.6.0   Back to index