text: /* $Id$ */
  /* 
   * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
   * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
   *
   * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
   */
  #ifndef __PJSIP_SIP_TRANSPORT_H__
  #define __PJSIP_SIP_TRANSPORT_H__
  
  /**
   * @file sip_transport.h
   * @brief SIP Transport
   */
  
  #include <pjsip/sip_msg.h>
  #include <pjsip/sip_parser.h>
  #include <pjsip/sip_resolve.h>
  #include <pj/sock.h>
  #include <pj/list.h>
  #include <pj/ioqueue.h>
  #include <pj/timer.h>
  
  PJ_BEGIN_DECL
  
  /**
   * @defgroup PJSIP_TRANSPORT Transport
   * @ingroup PJSIP_CORE
   * @brief This is the transport framework.
   *
   * The transport framework is fully extensible. Please see
   * <A HREF="/docs.htm">PJSIP Developer's Guide</A> PDF
   * document for more information.
   *
   * Application MUST register at least one transport to PJSIP before any
   * messages can be sent or received. Please see @ref PJSIP_TRANSPORT_UDP
   * on how to create/register UDP transport to the transport framework.
   *
   * @{
   */
  
  /*****************************************************************************
   *
   * GENERAL TRANSPORT (NAMES, TYPES, ETC.)
   *
   *****************************************************************************/
  
  /*
   * Forward declaration for transport factory (since it is referenced by
   * the transport factory itself).
   */
  typedef struct pjsip_tpfactory pjsip_tpfactory;
  
  
  /**
   * Flags for SIP transports.
   */
  enum pjsip_transport_flags_e
  {
      PJSIP_TRANSPORT_RELIABLE	    = 1,    /**< Transport is reliable.	    */
      PJSIP_TRANSPORT_SECURE	    = 2,    /**< Transport is secure.	    */
      PJSIP_TRANSPORT_DATAGRAM	    = 4     /**< Datagram based transport.  
  					         (it's also assumed to be 
  						 connectionless)	    */
  };
  
  /**
   * Check if transport tp is reliable.
   */
  #define PJSIP_TRANSPORT_IS_RELIABLE(tp)	    \
  	    ((tp)->flag & PJSIP_TRANSPORT_RELIABLE)
  
  /**
   * Check if transport tp is secure.
   */
  #define PJSIP_TRANSPORT_IS_SECURE(tp)	    \
  	    ((tp)->flag & PJSIP_TRANSPORT_SECURE)
  
  /**
   * Register new transport type to PJSIP. The PJSIP transport framework
   * contains the info for some standard transports, as declared by
   * #pjsip_transport_type_e. Application may use non-standard transport
   * with PJSIP, but before it does so, it must register the information
   * about the new transport type to PJSIP by calling this function.
   *
   * @param tp_flag   The flags describing characteristics of this
   *		    transport type.
   * @param tp_name   Transport type name.
   * @param def_port  Default port to be used for the transport.
   * @param p_tp_type On successful registration, it will be filled with
   *		    the registered type. This argument is optional.
   *
   * @return	    PJ_SUCCESS if registration is successful, or
   *		    PJSIP_ETYPEEXISTS if the same transport type has
   *		    already been registered.
   */
  PJ_DECL(pj_status_t) pjsip_transport_register_type(unsigned tp_flag,
  						   const char *tp_name,
  						   int def_port,
  						   int *p_tp_type);
  
  
  /**
   * Get the transport type from the transport name.
   *
   * @param name	    Transport name, such as "TCP", or "UDP".
   *
   * @return	    The transport type, or PJSIP_TRANSPORT_UNSPECIFIED if 
   *		    the name is not recognized as the name of supported 
   *		    transport.
   */
  PJ_DECL(pjsip_transport_type_e) 
  pjsip_transport_get_type_from_name(const pj_str_t *name);
  
  /**
   * Get the transport type for the specified flags.
   *
   * @param flag	    The transport flag.
   *
   * @return	    Transport type.
   */
  PJ_DECL(pjsip_transport_type_e) 
  pjsip_transport_get_type_from_flag(unsigned flag);
  
  /**
   * Get the socket address family of a given transport type.
   *
   * @param type	    Transport type.
   *
   * @return	    Transport type.
   */
  PJ_DECL(int) pjsip_transport_type_get_af(pjsip_transport_type_e type);
  
  /**
   * Get transport flag from type.
   *
   * @param type	    Transport type.
   *
   * @return	    Transport flags.
   */
  PJ_DECL(unsigned)
  pjsip_transport_get_flag_from_type( pjsip_transport_type_e type );
  
  /**
   * Get the default SIP port number for the specified type.
   *
   * @param type	    Transport type.
   *
   * @return	    The port number, which is the default SIP port number for
   *		    the specified type.
   */
  PJ_DECL(int) 
  pjsip_transport_get_default_port_for_type(pjsip_transport_type_e type);
  
  /**
   * Get transport type name.
   *
   * @param t	    Transport type.
   *
   * @return	    Transport name.
   */
  PJ_DECL(const char*) pjsip_transport_get_type_name(pjsip_transport_type_e t);
  
  /**
   * Get longer description for the specified transport type.
   *
   * @param t	    Transport type.
   *
   * @return	    Transport description.
   */
  PJ_DECL(const char*) pjsip_transport_get_type_desc(pjsip_transport_type_e t);
  
  
  
  /*****************************************************************************
   *
   * TRANSPORT SELECTOR.
   *
   *****************************************************************************/
  
  /**
   * This structure describes the type of data in pjsip_tpselector.
   */
  typedef enum pjsip_tpselector_type
  {
      /** Transport is not specified. */
      PJSIP_TPSELECTOR_NONE,
  
      /** Use the specific transport to send request. */
      PJSIP_TPSELECTOR_TRANSPORT,
  
      /** Use the specific listener to send request. */
      PJSIP_TPSELECTOR_LISTENER,
  
  } pjsip_tpselector_type;
  
  
  /**
   * This structure describes the transport/listener preference to be used
   * when sending outgoing requests.
   *
   * Normally transport will be selected automatically according to rules about
   * sending requests. But some applications (such as proxies or B2BUAs) may 
   * want to explicitly use specific transport to send requests, for example
   * when they want to make sure that outgoing request should go from a specific
   * network interface.
   *
   * The pjsip_tpselector structure is used for that purpose, i.e. to allow
   * application specificly request that a particular transport/listener
   * should be used to send request. This structure is used when calling
   * pjsip_tsx_set_transport() and pjsip_dlg_set_transport().
   *
   * If application disables connection reuse and wants to force creating
   * a new transport, it needs to consider the following couple of things:
   * - If it still wants to reuse an existing transport (if any), it
   *   needs to keep a reference to that transport and specifically set
   *   the transport to be used for sending requests.
   * - Delete those existing transports manually when no longer needed.
   */
  typedef struct pjsip_tpselector
  {
      /** The type of data in the union */
      pjsip_tpselector_type   type;
  
      /**
       * Whether to disable reuse of an existing connection.
       * This setting will be ignored if (type == PJSIP_TPSELECTOR_TRANSPORT)
       * and transport in the union below is set.
       */
      pj_bool_t disable_connection_reuse;
  
      /** Union representing the transport/listener criteria to be used. */
      union {
  	pjsip_transport	*transport;
  	pjsip_tpfactory	*listener;
  	void		*ptr;
      } u;
  
  } pjsip_tpselector;
  
  
  /**
   * Add transport/listener reference in the selector to prevent the specified
   * transport/listener from being destroyed while application still has
   * reference to it.
   *
   * @param sel	The transport selector.
   */
  PJ_DECL(void) pjsip_tpselector_add_ref(pjsip_tpselector *sel);
  
  
  /**
   * Decrement transport/listener reference in the selector.
   * @param sel	The transport selector
   */
  PJ_DECL(void) pjsip_tpselector_dec_ref(pjsip_tpselector *sel);
  
  
  /*****************************************************************************
   *
   * RECEIVE DATA BUFFER.
   *
   *****************************************************************************/
  
  /** 
   * A customized ioqueue async operation key which is used by transport
   * to locate rdata when a pending read operation completes.
   */
  typedef struct pjsip_rx_data_op_key
  {
      pj_ioqueue_op_key_t		op_key;	/**< ioqueue op_key.		*/
      pjsip_rx_data	       *rdata;	/**< rdata associated with this */
  } pjsip_rx_data_op_key;
  
  
  /**
   * Incoming message buffer.
   * This structure keep all the information regarding the received message. This
   * buffer lifetime is only very short, normally after the transaction has been
   * called, this buffer will be deleted/recycled. So care must be taken when
   * allocating storage from the pool of this buffer.
   */
  struct pjsip_rx_data
  {
  
      /**
       * tp_info is part of rdata that remains static for the duration of the
       * buffer. It is initialized when the buffer was created by transport.
       */
      struct 
      {
  	/** Memory pool for this buffer. */
  	pj_pool_t		*pool;
  
  	/** The transport object which received this packet. */
  	pjsip_transport		*transport;
  
  	/** Other transport specific data to be attached to this buffer. */
  	void			*tp_data;
  
  	/** Ioqueue key. */
  	pjsip_rx_data_op_key	 op_key;
  
      } tp_info;
  
  
      /**
       * pkt_info is initialized by transport when it receives an incoming
       * packet.
       */
      struct
      {
  	/** Time when the message was received. */
  	pj_time_val		 timestamp;
  
  	/** Pointer to the original packet. */
  	char			 packet[PJSIP_MAX_PKT_LEN];
  
  	/** Zero termination for the packet. */
  	pj_uint32_t		 zero;
  
  	/** The length of the packet received. */
  	pj_ssize_t		 len;
  
  	/** The source address from which the packet was received. */
  	pj_sockaddr		 src_addr;
  
  	/** The length of the source address. */
  	int			 src_addr_len;
  
  	/** The IP source address string (NULL terminated). */
  	char			 src_name[PJ_INET6_ADDRSTRLEN];
  
  	/** The IP source port number. */
  	int			 src_port;
  
      } pkt_info;
  
  
      /**
       * msg_info is initialized by transport mgr (tpmgr) before this buffer
       * is passed to endpoint.
       */
      struct
      {
  	/** Start of msg buffer. */
  	char			*msg_buf;
  
  	/** Length fo message. */
  	int			 len;
  
  	/** The parsed message, if any. */
  	pjsip_msg		*msg;
  
  	/** Short description about the message. 
  	 *  Application should use #pjsip_rx_data_get_info() instead.
  	 */
  	char			*info;
  
  	/** The Call-ID header as found in the message. */
  	pjsip_cid_hdr		*cid;
  
  	/** The From header as found in the message. */
  	pjsip_from_hdr		*from;
  
  	/** The To header as found in the message. */
  	pjsip_to_hdr		*to;
  
  	/** The topmost Via header as found in the message. */
  	pjsip_via_hdr		*via;
  
  	/** The CSeq header as found in the message. */
  	pjsip_cseq_hdr		*cseq;
  
  	/** Max forwards header. */
  	pjsip_max_fwd_hdr	*max_fwd;
  
  	/** The first route header. */
  	pjsip_route_hdr		*route;
  
  	/** The first record-route header. */
  	pjsip_rr_hdr		*record_route;
  
  	/** Content-type header. */
  	pjsip_ctype_hdr		*ctype;
  
  	/** Content-length header. */
  	pjsip_clen_hdr		*clen;
  
  	/** "Require" header containing aggregates of all Require
  	 *  headers found in the message, or NULL. 
  	 */
  	pjsip_require_hdr	*require;
  
  	/** "Supported" header containing aggregates of all Supported
  	 *  headers found in the message, or NULL. 
  	 */
  	pjsip_supported_hdr	*supported;
  
  	/** The list of error generated by the parser when parsing 
  	    this message. 
  	 */
  	pjsip_parser_err_report parse_err;
  
      } msg_info;
  
  
      /**
       * endpt_info is initialized by endpoint after this buffer reaches
       * endpoint.
       */
      struct
      {
  	/** 
  	 * Data attached by modules to this message. 
  	 */
  	void	*mod_data[PJSIP_MAX_MODULE];
  
      } endpt_info;
  
  };
  
  /**
   * Get printable information about the message in the rdata.
   *
   * @param rdata	    The receive data buffer.
   *
   * @return	    Printable information.
   */
  PJ_DECL(char*) pjsip_rx_data_get_info(pjsip_rx_data *rdata);
  
  /**
   * Clone pjsip_rx_data. This will duplicate the contents of
   * pjsip_rx_data and add reference count to the transport.
   * Once application has finished using the cloned pjsip_rx_data,
   * it must release it by calling  #pjsip_rx_data_free_cloned().
   *
   * By default (if flags is set to zero), this function copies the
   * transport pointer in \a tp_info, duplicates the \a pkt_info,
   * perform deep clone of the \a msg_info parts of the rdata, and
   * fills the \a endpt_info (i.e. the \a mod_data) with zeros.
   *
   * @param src	    The source to be cloned.
   * @param flags	    Optional flags. Must be zero for now.
   * @param p_rdata   Pointer to receive the cloned rdata.
   *
   * @return	    PJ_SUCCESS on success or the appropriate error.
   */
  PJ_DECL(pj_status_t) pjsip_rx_data_clone(const pjsip_rx_data *src,
                                           unsigned flags,
                                           pjsip_rx_data **p_rdata);
  
  /**
   * Free cloned pjsip_rx_data. This function must be and must only
   * be called for a cloned pjsip_rx_data. Specifically, it must NOT
   * be called for the original pjsip_rx_data that is returned by
   * transports.
   *
   * This function will free the memory used by the pjsip_rx_data and
   * decrement the transport reference counter.
   *
   * @param rdata	    The receive data buffer.
   *
   * @return	    PJ_SUCCESS on success or the appropriate error.
   */
  PJ_DECL(pj_status_t) pjsip_rx_data_free_cloned(pjsip_rx_data *rdata);
  
  
  /*****************************************************************************
   *
   * TRANSMIT DATA BUFFER MANIPULATION.
   *
   *****************************************************************************/
  
  /** Customized ioqueue async operation key, used by transport to keep
   *  callback parameters.
   */
  typedef struct pjsip_tx_data_op_key
  {
      /** ioqueue pending operation key. */
      pj_ioqueue_op_key_t	    key;
  
      /** Transmit data associated with this key. */
      pjsip_tx_data	   *tdata;
  
      /** Arbitrary token (attached by transport) */
      void		   *token;
  
      /** Callback to be called when pending transmit operation has
          completed.
       */
      void		  (*callback)(pjsip_transport*,void*,pj_ssize_t);
  } pjsip_tx_data_op_key;
  
  
  /**
   * Data structure for sending outgoing message. Application normally creates
   * this buffer by calling #pjsip_endpt_create_tdata.
   *
   * The lifetime of this buffer is controlled by the reference counter in this
   * structure, which is manipulated by calling #pjsip_tx_data_add_ref and
   * #pjsip_tx_data_dec_ref. When the reference counter has reached zero, then
   * this buffer will be destroyed.
   *
   * A transaction object normally will add reference counter to this buffer
   * when application calls #pjsip_tsx_send_msg, because it needs to keep the
   * message for retransmission. The transaction will release the reference
   * counter once its state has reached final state.
   */
  struct pjsip_tx_data
  {
      /** This is for transmission queue; it's managed by transports. */
      PJ_DECL_LIST_MEMBER(struct pjsip_tx_data);
  
      /** Memory pool for this buffer. */
      pj_pool_t		*pool;
  
      /** A name to identify this buffer. */
      char		 obj_name[PJ_MAX_OBJ_NAME];
  
      /** Short information describing this buffer and the message in it. 
       *  Application should use #pjsip_tx_data_get_info() instead of
       *  directly accessing this member.
       */
      char		*info;
  
      /** For response message, this contains the reference to timestamp when 
       *  the original request message was received. The value of this field
       *  is set when application creates response message to a request by
       *  calling #pjsip_endpt_create_response.
       */
      pj_time_val		 rx_timestamp;
  
      /** The transport manager for this buffer. */
      pjsip_tpmgr		*mgr;
  
      /** Ioqueue asynchronous operation key. */
      pjsip_tx_data_op_key op_key;
  
      /** Lock object. */
      pj_lock_t		*lock;
  
      /** The message in this buffer. */
      pjsip_msg 		*msg;
  
      /** Strict route header saved by #pjsip_process_route_set(), to be
       *  restored by #pjsip_restore_strict_route_set().
       */
      pjsip_route_hdr	*saved_strict_route;
  
      /** Buffer to the printed text representation of the message. When the
       *  content of this buffer is set, then the transport will send the content
       *  of this buffer instead of re-printing the message structure. If the
       *  message structure has changed, then application must invalidate this
       *  buffer by calling #pjsip_tx_data_invalidate_msg.
       */
      pjsip_buffer	 buf;
  
      /** Reference counter. */
      pj_atomic_t		*ref_cnt;
  
      /** Being processed by transport? */
      int			 is_pending;
  
      /** Transport manager internal. */
      void		*token;
  
      /** Callback to be called when this tx_data has been transmitted.	*/
      void	       (*cb)(void*, pjsip_tx_data*, pj_ssize_t);
  
      /** Destination information, to be used to determine the network address
       *  of the message. For a request, this information is  initialized when
       *  the request is sent with #pjsip_endpt_send_request_stateless() and
       *  network address is resolved. For CANCEL request, this information
       *  will be copied from the original INVITE to make sure that the CANCEL
       *  request goes to the same physical network address as the INVITE
       *  request.
       */
      struct
      {
  	/** Server name. 
  	 */
  	pj_str_t		 name;
  
  	/** Server addresses resolved. 
  	 */
  	pjsip_server_addresses   addr;
  
  	/** Current server address being tried. 
  	 */
  	unsigned cur_addr;
  
      } dest_info;
  
      /** Transport information, only valid during on_tx_request() and 
       *  on_tx_response() callback.
       */
      struct
      {
  	pjsip_transport	    *transport;	    /**< Transport being used.	*/
  	pj_sockaddr	     dst_addr;	    /**< Destination address.	*/
  	int		     dst_addr_len;  /**< Length of address.	*/
  	char		     dst_name[PJ_INET6_ADDRSTRLEN]; /**< Destination address.	*/
  	int		     dst_port;	    /**< Destination port.	*/
      } tp_info;
  
      /** 
       * Transport selector, to specify which transport to be used. 
       * The value here must be set with pjsip_tx_data_set_transport(),
       * to allow reference counter to be set properly.
       */
      pjsip_tpselector	    tp_sel;
  
      /**
       * Special flag to indicate that this transmit data is a request that has
       * been updated with proper authentication response and is ready to be
       * sent for retry.
       */
      pj_bool_t		    auth_retry;
  
      /**
       * Arbitrary data attached by PJSIP modules.
       */
      void		    *mod_data[PJSIP_MAX_MODULE];
  
      /**
       * If via_addr is set, it will be used as the "sent-by" field of the
       * Via header for outgoing requests as long as the request uses via_tp
       * transport. Normally application should not use or access these fields.
       */
      pjsip_host_port          via_addr;      /**< Via address.	        */
      const void              *via_tp;        /**< Via transport.	        */
  };
  
  
  /**
   * Create a new, blank transmit buffer. The reference count is initialized
   * to zero.
   *
   * @param mgr		The transport manager.
   * @param tdata		Pointer to receive transmit data.
   *
   * @return		PJ_SUCCESS, or the appropriate error code.
   *
   * @see pjsip_endpt_create_tdata
   */
  PJ_DECL(pj_status_t) pjsip_tx_data_create( pjsip_tpmgr *mgr,
  					   pjsip_tx_data **tdata );
  
  /**
   * Add reference counter to the transmit buffer. The reference counter controls
   * the life time of the buffer, ie. when the counter reaches zero, then it 
   * will be destroyed.
   *
   * @param tdata	    The transmit buffer.
   */
  PJ_DECL(void) pjsip_tx_data_add_ref( pjsip_tx_data *tdata );
  
  /**
   * Decrement reference counter of the transmit buffer.
   * When the transmit buffer is no longer used, it will be destroyed and
   * caller is informed with PJSIP_EBUFDESTROYED return status.
   *
   * @param tdata	    The transmit buffer data.
   * @return	    This function will always succeeded eventhough the return
   *		    status is non-zero. A status PJSIP_EBUFDESTROYED will be
   *		    returned to inform that buffer is destroyed.
   */
  PJ_DECL(pj_status_t) pjsip_tx_data_dec_ref( pjsip_tx_data *tdata );
  
  /**
   * Print the SIP message to transmit data buffer's internal buffer. This
   * may allocate memory for the buffer, if the buffer has not been allocated
   * yet, and encode the SIP message to that buffer.
   *
   * @param tdata	    The transmit buffer.
   *
   * @return	    PJ_SUCCESS on success of the appropriate error code.
   */
  PJ_DECL(pj_status_t) pjsip_tx_data_encode(pjsip_tx_data *tdata);
  
  /**
   * Check if transmit data buffer contains a valid message.
   *
   * @param tdata	    The transmit buffer.
   * @return	    Non-zero (PJ_TRUE) if buffer contains a valid message.
   */
  PJ_DECL(pj_bool_t) pjsip_tx_data_is_valid( pjsip_tx_data *tdata );
  
  /**
   * Invalidate the print buffer to force message to be re-printed. Call
   * when the message has changed after it has been printed to buffer. The
   * message is printed to buffer normally by transport when it is about to be 
   * sent to the wire. Subsequent sending of the message will not cause
   * the message to be re-printed, unless application invalidates the buffer
   * by calling this function.
   *
   * @param tdata	    The transmit buffer.
   */
  PJ_DECL(void) pjsip_tx_data_invalidate_msg( pjsip_tx_data *tdata );
  
  /**
   * Get short printable info about the transmit data. This will normally return
   * short information about the message.
   *
   * @param tdata	    The transmit buffer.
   *
   * @return	    Null terminated info string.
   */
  PJ_DECL(char*) pjsip_tx_data_get_info( pjsip_tx_data *tdata );
  
  /**
   * Set the explicit transport to be used when sending this transmit data.
   * Application should not need to call this function, but rather use
   * pjsip_tsx_set_transport() and pjsip_dlg_set_transport() instead (which
   * will call this function).
   *
   * @param tdata	    The transmit buffer.
   * @param sel	    Transport selector.
   *
   * @return	    PJ_SUCCESS on success.
   */
  PJ_DECL(pj_status_t) pjsip_tx_data_set_transport(pjsip_tx_data *tdata,
  						 const pjsip_tpselector *sel);
  
  /**
   * Clone pjsip_tx_data. This will duplicate the message contents of
   * pjsip_tx_data (pjsip_tx_data.msg) and add reference count to the tdata.
   * Once application has finished using the cloned pjsip_tx_data,
   * it must release it by calling  #pjsip_tx_data_dec_ref().
   * Currently, this will only clone response message.
   *
   * @param src	    The source to be cloned.
   * @param flags	    Optional flags. Must be zero for now.
   * @param p_rdata   Pointer to receive the cloned tdata.
   *
   * @return	    PJ_SUCCESS on success or the appropriate error.
   */
  PJ_DECL(pj_status_t) pjsip_tx_data_clone(const pjsip_tx_data *src,
                                           unsigned flags,
                                           pjsip_tx_data **p_rdata);
  
  /*****************************************************************************
   *
   * TRANSPORT
   *
   *****************************************************************************/
  /**
   * Type of callback to receive transport operation status.
   */
  typedef void (*pjsip_transport_callback)(pjsip_transport *tp, void *token,
                                           pj_ssize_t sent_bytes);
  
  /**
   * This structure describes transport key to be registered to hash table.
   */
  typedef struct pjsip_transport_key
  {
      /**
       * Transport type.
       */
      long		    type;
  
      /**
       * Destination address.
       */
      pj_sockaddr		    rem_addr;
  
  } pjsip_transport_key;
  
  
  /**
   * Enumeration of transport direction types.
   */
  typedef enum pjsip_transport_dir
  {
      PJSIP_TP_DIR_NONE,		    /**< Direction not set, normally used by
  				         connectionless transports such as 
  					 UDP transport.			    */
      PJSIP_TP_DIR_OUTGOING,	    /**< Outgoing connection or client mode,
  				         this is only for connection-oriented 
  					 transports.			    */
      PJSIP_TP_DIR_INCOMING,	    /**< Incoming connection or server mode,
  					 this is only for connection-oriented
  					 transports.			    */
  } pjsip_transport_dir;
  
  
  /**
   * This structure represent the "public" interface of a SIP transport.
   * Applications normally extend this structure to include transport
   * specific members.
   */
  struct pjsip_transport
  {
      char		    obj_name[PJ_MAX_OBJ_NAME];	/**< Name. */
  
      pj_pool_t		   *pool;	    /**< Pool used by transport.    */
      pj_atomic_t		   *ref_cnt;	    /**< Reference counter.	    */
      pj_lock_t		   *lock;	    /**< Lock object.		    */
      pj_grp_lock_t	   *grp_lock;	    /**< Group lock for sync with
  					         ioqueue and timer.	    */
      pj_bool_t		    tracing;	    /**< Tracing enabled?	    */
      pj_bool_t		    is_shutdown;    /**< Being shutdown?	    */
      pj_bool_t		    is_destroying;  /**< Destroy in progress?	    */
  
      /** Key for indexing this transport in hash table. */
      pjsip_transport_key	    key;
  
      char		   *type_name;	    /**< Type name.		    */
      unsigned		    flag;	    /**< #pjsip_transport_flags_e   */
      char		   *info;	    /**< Transport info/description.*/
  
      int			    addr_len;	    /**< Length of addresses.	    */
      pj_sockaddr		    local_addr;	    /**< Bound address.		    */
      pjsip_host_port	    local_name;	    /**< Published name (eg. STUN). */
      pjsip_host_port	    remote_name;    /**< Remote address name.	    */
      pjsip_transport_dir	    dir;	    /**< Connection direction.	    */
      
      pjsip_endpoint	   *endpt;	    /**< Endpoint instance.	    */
      pjsip_tpmgr		   *tpmgr;	    /**< Transport manager.	    */
      pjsip_tpfactory	   *factory;	    /**< Factory instance. Note: it
  					         may be invalid/shutdown.   */
      pj_timer_entry	    idle_timer;	    /**< Timer when ref cnt is zero.*/
  
      pj_timestamp	    last_recv_ts;   /**< Last time receiving data.  */
      pj_size_t		    last_recv_len;  /**< Last received data length. */
  
      void		   *data;	    /**< Internal transport data.   */
  
      /**
       * Function to be called by transport manager to send SIP message.
       *
       * @param transport	    The transport to send the message.
       * @param packet	    The buffer to send.
       * @param length	    The length of the buffer to send.
       * @param op_key	    Completion token, which will be supplied to
       *			    caller when pending send operation completes.
       * @param rem_addr	    The remote destination address.
       * @param addr_len	    Size of remote address.
       * @param callback	    If supplied, the callback will be called
       *			    once a pending transmission has completed. If
       *			    the function completes immediately (i.e. return
       *			    code is not PJ_EPENDING), the callback will not
       *			    be called.
       *
       * @return		    Should return PJ_SUCCESS only if data has been
       *			    succesfully queued to operating system for 
       *			    transmission. Otherwise it may return PJ_EPENDING
       *			    if the underlying transport can not send the
       *			    data immediately and will send it later, which in
       *			    this case caller doesn't have to do anything 
       *			    except wait the calback to be called, if it 
       *			    supplies one.
       *			    Other return values indicate the error code.
       */
      pj_status_t (*send_msg)(pjsip_transport *transport, 
  			    pjsip_tx_data *tdata,
  			    const pj_sockaddr_t *rem_addr,
  			    int addr_len,
  			    void *token,
  			    pjsip_transport_callback callback);
  
      /**
       * Instruct the transport to initiate graceful shutdown procedure.
       * After all objects release their reference to this transport,
       * the transport will be deleted.
       *
       * Note that application MUST use #pjsip_transport_shutdown() instead.
       *
       * @param transport	    The transport.
       *
       * @return		    PJ_SUCCESS on success.
       */
      pj_status_t (*do_shutdown)(pjsip_transport *transport);
  
      /**
       * Forcefully destroy this transport regardless whether there are
       * objects that currently use this transport. This function should only
       * be called by transport manager or other internal objects (such as the
       * transport itself) who know what they're doing. Application should use
       * #pjsip_transport_shutdown() instead.
       *
       * @param transport	    The transport.
       *
       * @return		    PJ_SUCCESS on success.
       */
      pj_status_t (*destroy)(pjsip_transport *transport);
  
      /*
       * Application may extend this structure..
       */
  };
  
  
  /**
   * Register a transport instance to the transport manager. This function
   * is normally called by the transport instance when it is created
   * by application.
   *
   * @param mgr		The transport manager.
   * @param tp		The new transport to be registered.
   *
   * @return		PJ_SUCCESS on success.
   */
  PJ_DECL(pj_status_t) pjsip_transport_register( pjsip_tpmgr *mgr,
  					       pjsip_transport *tp );
  
  
  /**
   * Start graceful shutdown procedure for this transport. After graceful
   * shutdown has been initiated, no new reference can be obtained for
   * the transport. However, existing objects that currently uses the
   * transport may still use this transport to send and receive packets.
   *
   * After all objects release their reference to this transport,
   * the transport will be destroyed immediately.
   *
   * @param tp		    The transport.
   *
   * @return		    PJ_SUCCESS on success.
   */
  PJ_DECL(pj_status_t) pjsip_transport_shutdown(pjsip_transport *tp);
  
  /**
   * Start shutdown procedure for this transport. If \a force is false,
   * the API is the same as #pjsip_transport_shutdown(), while
   * if \a force is true, existing transport users will immediately
   * receive PJSIP_TP_STATE_DISCONNECTED notification and should not
   * use the transport anymore. In either case, transport will
   * only be destroyed after all objects release their references.
   *
   * @param tp		    The transport.
   * @param force		    Force transport to immediately send
   *			    disconnection state notification.
   *
   * @return		    PJ_SUCCESS on success.
   */
  PJ_DECL(pj_status_t) pjsip_transport_shutdown2(pjsip_transport *tp,
  					       pj_bool_t force);
  
  /**
   * Destroy a transport when there is no object currently uses the transport.
   * This function is normally called internally by transport manager or the
   * transport itself. Application should use #pjsip_transport_shutdown()
   * instead.
   *
   * @param tp		The transport instance.
   *
   * @return		PJ_SUCCESS on success or the appropriate error code.
   *			Some of possible errors are PJSIP_EBUSY if the 
   *			transport's reference counter is not zero.
   */
  PJ_DECL(pj_status_t) pjsip_transport_destroy( pjsip_transport *tp);
  
  /**
   * Add reference counter to the specified transport. Any objects that wishes
   * to keep the reference of the transport MUST increment the transport's
   * reference counter to prevent it from being destroyed.
   *
   * @param tp		The transport instance.
   *
   * @return		PJ_SUCCESS on success or the appropriate error code.
   */
  PJ_DECL(pj_status_t) pjsip_transport_add_ref( pjsip_transport *tp );
  
  /**
   * Decrement reference counter of the specified transport. When an object no
   * longer want to keep the reference to the transport, it must decrement the
   * reference counter. When the reference counter of the transport reaches 
   * zero, the transport manager will start the idle timer to destroy the
   * transport if no objects acquire the reference counter during the idle
   * interval.
   *
   * @param tp		The transport instance.
   *
   * @return		PJ_SUCCESS on success.
   */
  PJ_DECL(pj_status_t) pjsip_transport_dec_ref( pjsip_transport *tp );
  
  
  /**
   * This function is called by transport instances to report an incoming 
   * packet to the transport manager. The transport manager then would try to
   * parse all SIP messages in the packet, and for each parsed SIP message, it
   * would report the message to the SIP endpoint (#pjsip_endpoint).
   *
   * @param mgr		The transport manager instance.
   * @param rdata		The receive data buffer containing the packet. The
   *			transport MUST fully initialize tp_info and pkt_info
   *			member of the rdata.
   *
   * @return		The number of bytes successfully processed from the
   *			packet. If the transport is datagram oriented, the
   *			value will be equal to the size of the packet. For
   *			stream oriented transport (e.g. TCP, TLS), the value
   *			returned may be less than the packet size, if 
   *			partial message is received. The transport then MUST
   *			keep the remainder part and report it again to
   *			this function once more data/packet is received.
   */
  PJ_DECL(pj_ssize_t) pjsip_tpmgr_receive_packet(pjsip_tpmgr *mgr,
  					       pjsip_rx_data *rdata);
  
  
  /*****************************************************************************
   *
   * TRANSPORT FACTORY
   *
   *****************************************************************************/
  
  
  /**
   * A transport factory is normally used for connection oriented transports
   * (such as TCP or TLS) to create instances of transports. It registers
   * a new transport type to the transport manager, and the transport manager
   * would ask the factory to create a transport instance when it received
   * command from application to send a SIP message using the specified
   * transport type.
   */
  struct pjsip_tpfactory
  {
      /** This list is managed by transport manager. */
      PJ_DECL_LIST_MEMBER(struct pjsip_tpfactory);
  
      char		    obj_name[PJ_MAX_OBJ_NAME];	/**< Name.	*/
  
      pj_pool_t		   *pool;	    /**< Owned memory pool.	*/
      pj_lock_t		   *lock;	    /**< Lock object.		*/
  
      pjsip_transport_type_e  type;	    /**< Transport type.	*/
      char		   *type_name;      /**< Type string name.	*/
      unsigned		    flag;	    /**< Transport flag.	*/
      char		   *info;	    /**< Transport info/description.*/
  
      pj_sockaddr		    local_addr;	    /**< Bound address.		*/
      pjsip_host_port	    addr_name;	    /**< Published name.	*/
  
      /**
       * Create new outbound connection suitable for sending SIP message
       * to specified remote address.
       * Note that the factory is responsible for both creating the
       * transport and registering it to the transport manager.
       */
      pj_status_t (*create_transport)(pjsip_tpfactory *factory,
  				    pjsip_tpmgr *mgr,
  				    pjsip_endpoint *endpt,
  				    const pj_sockaddr *rem_addr,
  				    int addr_len,
  				    pjsip_transport **transport);
  
      /**
       * Create new outbound connection suitable for sending SIP message
       * to specified remote address by also considering outgoing SIP 
       * message data.
       * Note that the factory is responsible for both creating the
       * transport and registering it to the transport manager.
       */
      pj_status_t (*create_transport2)(pjsip_tpfactory *factory,
  				     pjsip_tpmgr *mgr,
  				     pjsip_endpoint *endpt,
  				     const pj_sockaddr *rem_addr,
  				     int addr_len,
  				     pjsip_tx_data *tdata,
  				     pjsip_transport **transport);
  
      /**
       * Destroy the listener.
       */
      pj_status_t (*destroy)(pjsip_tpfactory *factory);
  
      /*
       * Application may extend this structure..
       */
  };
  
  
  
  /**
   * Register a transport factory.
   *
   * @param mgr		The transport manager.
   * @param tpf		Transport factory.
   *
   * @return		PJ_SUCCESS if listener was successfully created.
   */
  PJ_DECL(pj_status_t) pjsip_tpmgr_register_tpfactory(pjsip_tpmgr *mgr,
  						    pjsip_tpfactory *tpf);
  
  /**
   * Unregister factory.
   *
   * @param mgr		The transport manager.
   * @param tpf		Transport factory.
   *
   * @return		PJ_SUCCESS is sucessfully unregistered.
   */
  PJ_DECL(pj_status_t) pjsip_tpmgr_unregister_tpfactory(pjsip_tpmgr *mgr,
  						      pjsip_tpfactory *tpf);
  
  
  /*****************************************************************************
   *
   * TRANSPORT MANAGER
   *
   *****************************************************************************/
  
  /**
   * Type of callback to be called when transport manager receives incoming
   * SIP message.
   *
   * @param ep	    Endpoint.
   * @param status    Receiption status.
   * @param rd	    Received packet.
   */
  typedef void (*pjsip_rx_callback)(pjsip_endpoint *ep, pj_status_t status, 
  				  pjsip_rx_data *rd);
  
  /**
   * Type of callback to be called before transport manager is about
   * to transmit SIP message.
   *
   * @param ep	    Endpoint.
   * @param td	    Transmit data.
   */
  typedef pj_status_t (*pjsip_tx_callback)(pjsip_endpoint *ep, pjsip_tx_data*td);
  
  /**
   * Create a transport manager. Normally application doesn't need to call
   * this function directly, since a transport manager will be created and
   * destroyed automatically by the SIP endpoint.
   *
   * @param pool	    Pool.
   * @param endpt	    Endpoint instance.
   * @param rx_cb	    Callback to receive incoming message.
   * @param tx_cb	    Callback to be called before transport manager is sending
   *		    outgoing message.
   * @param p_mgr	    Pointer to receive the new transport manager.
   *
   * @return	    PJ_SUCCESS or the appropriate error code on error.
   */
  PJ_DECL(pj_status_t) pjsip_tpmgr_create( pj_pool_t *pool,
  					 pjsip_endpoint * endpt,
  					 pjsip_rx_callback rx_cb,
  					 pjsip_tx_callback tx_cb,
  					 pjsip_tpmgr **p_mgr);
  
  
  /**
   * Find out the appropriate local address info (IP address and port) to
   * advertise in Contact header based on the remote address to be 
   * contacted. The local address info would be the address name of the
   * transport or listener which will be used to send the request.
   *
   * In this implementation, it will only select the transport based on
   * the transport type in the request.
   *
   * @see pjsip_tpmgr_find_local_addr2()
   *
   * @param tpmgr	    The transport manager.
   * @param pool	    Pool to allocate memory for the IP address.
   * @param type	    Destination address to contact.
   * @param sel	    Optional pointer to prefered transport, if any.
   * @param ip_addr   Pointer to receive the IP address.
   * @param port	    Pointer to receive the port number.
   *
   * @return	    PJ_SUCCESS, or the appropriate error code.
   */
  PJ_DECL(pj_status_t) pjsip_tpmgr_find_local_addr( pjsip_tpmgr *tpmgr,
  						  pj_pool_t *pool,
  						  pjsip_transport_type_e type,
  						  const pjsip_tpselector *sel,
  						  pj_str_t *ip_addr,
  						  int *port);
  
  /**
   * Parameter for pjsip_tpmgr_find_local_addr2() function.
   */
  typedef struct pjsip_tpmgr_fla2_param
  {
      /**
       * Specify transport type to use. This must be set.
       */
      pjsip_transport_type_e	 tp_type;
  
      /**
       * Optional pointer to preferred transport, if any.
       */
      const pjsip_tpselector	*tp_sel;
  
      /**
       * Destination host, if known. The destination host is needed
       * if \a local_if field below is set.
       */
      pj_str_t			 dst_host;
  
      /**
       * Specify if the function should return which local interface
       * to use for the specified destination in \a dst_host. By definition,
       * the returned address will always be local interface address.
       */
      pj_bool_t			 local_if;
  
      /**
       * The returned address.
       */
      pj_str_t			 ret_addr;
  
      /**
       * The returned port.
       */
      pj_uint16_t			 ret_port;
  
      /**
       * Returned pointer to the transport. Only set if local_if is set.
       */
      const void			*ret_tp;
  
  } pjsip_tpmgr_fla2_param;
  
  /**
   * Initialize with default values.
   *
   * @param prm	    The parameter to be initialized.
   */
  PJ_DECL(void) pjsip_tpmgr_fla2_param_default(pjsip_tpmgr_fla2_param *prm);
  
  /**
   * Find out the appropriate local address info (IP address and port) to
   * advertise in Contact or Via header header based on the remote address
   * to be contacted. The local address info would be the address name of the
   * transport or listener which will be used to send the request.
   *
   * @see pjsip_tpmgr_find_local_addr()
   *
   * @param tpmgr	    The transport manager.
   * @param pool	    Pool to allocate memory for the IP address.
   * @param param	    Function input and output parameters.
   *
   * @return	    PJ_SUCCESS, or the appropriate error code.
   */
  PJ_DECL(pj_status_t) pjsip_tpmgr_find_local_addr2(pjsip_tpmgr *tpmgr,
                                                    pj_pool_t *pool,
                                                    pjsip_tpmgr_fla2_param *prm);
  
  /**
   * Return number of transports currently registered to the transport
   * manager.
   *
   * @param mgr	    The transport manager.
   *
   * @return	    Number of transports.
   */
  PJ_DECL(unsigned) pjsip_tpmgr_get_transport_count(pjsip_tpmgr *mgr);
  
  
  /**
   * Destroy a transport manager. Normally application doesn't need to call
   * this function directly, since a transport manager will be created and
   * destroyed automatically by the SIP endpoint.
   *
   * @param mgr	    The transport manager.
   *
   * @return	    PJ_SUCCESS on success.
   */
  PJ_DECL(pj_status_t) pjsip_tpmgr_destroy(pjsip_tpmgr *mgr);
  
  
  /**
   * Dump transport info and status to log.
   *
   * @param mgr	    The transport manager.
   */
  PJ_DECL(void) pjsip_tpmgr_dump_transports(pjsip_tpmgr *mgr);
  
  
  /*****************************************************************************
   *
   * PUBLIC API
   *
   *****************************************************************************/
  
  
  /**
   * Find transport to be used to send message to remote destination. If no
   * suitable transport is found, a new one will be created.
   *
   * This is an internal function since normally application doesn't have access
   * to transport manager. Application should use pjsip_endpt_acquire_transport()
   * instead.
   *
   * @param mgr	    The transport manager instance.
   * @param type	    The type of transport to be acquired.
   * @param remote    The remote address to send message to.
   * @param addr_len  Length of the remote address.
   * @param sel	    Optional pointer to transport selector instance which is
   *		    used to find explicit transport, if required.
   * @param tp	    Pointer to receive the transport instance, if one is found.
   *
   * @return	    PJ_SUCCESS on success, or the appropriate error code.
   */
  PJ_DECL(pj_status_t) pjsip_tpmgr_acquire_transport(pjsip_tpmgr *mgr,
  						   pjsip_transport_type_e type,
  						   const pj_sockaddr_t *remote,
  						   int addr_len,
  						   const pjsip_tpselector *sel,
  						   pjsip_transport **tp);
  
  /**
   * Find suitable transport for sending SIP message to specified remote 
   * destination by also considering the outgoing SIP message. If no suitable 
   * transport is found, a new one will be created.
   *
   * This is an internal function since normally application doesn't have access
   * to transport manager. Application should use pjsip_endpt_acquire_transport2()
   * instead.
   *
   * @param mgr	    The transport manager instance.
   * @param type	    The type of transport to be acquired.
   * @param remote    The remote address to send message to.
   * @param addr_len  Length of the remote address.
   * @param sel	    Optional pointer to transport selector instance which is
   *		    used to find explicit transport, if required.
   * @param tdata	    Optional pointer to data to be sent.
   * @param tp	    Pointer to receive the transport instance, if one is found.
   *
   * @return	    PJ_SUCCESS on success, or the appropriate error code.
   */
  PJ_DECL(pj_status_t) pjsip_tpmgr_acquire_transport2(pjsip_tpmgr *mgr,
  						    pjsip_transport_type_e type,
  						    const pj_sockaddr_t *remote,
  						    int addr_len,
  						    const pjsip_tpselector *sel,
  						    pjsip_tx_data *tdata,
  						    pjsip_transport **tp);
  
  /**
   * Type of callback to receive notification when message or raw data
   * has been sent.
   *
   * @param token		The token that was given when calling the function
   *			to send message or raw data.
   * @param tdata		The transmit buffer used to send the message.
   * @param bytes_sent	Number of bytes sent. On success, the value will be
   *			positive number indicating the number of bytes sent.
   *			On failure, the value will be a negative number of
   *			the error code (i.e. bytes_sent = -status).
   */
  typedef void (*pjsip_tp_send_callback)(void *token, pjsip_tx_data *tdata,
  				       pj_ssize_t bytes_sent);
  
  
  /**
   * This is a low-level function to send a SIP message using the specified
   * transport to the specified destination.
   * 
   * @param tr	    The SIP transport to be used.
   * @param tdata	    Transmit data buffer containing SIP message.
   * @param addr	    Destination address.
   * @param addr_len  Length of destination address.
   * @param token	    Arbitrary token to be returned back to callback.
   * @param cb	    Optional callback to be called to notify caller about
   *		    the completion status of the pending send operation.
   *
   * @return	    If the message has been sent successfully, this function
   *		    will return PJ_SUCCESS and the callback will not be 
   *		    called. If message cannot be sent immediately, this
   *		    function will return PJ_EPENDING, and application will
   *		    be notified later about the completion via the callback.
   *		    Any statuses other than PJ_SUCCESS or PJ_EPENDING
   *		    indicates immediate failure, and in this case the 
   *		    callback will not be called.
   */
  PJ_DECL(pj_status_t) pjsip_transport_send( pjsip_transport *tr, 
  					   pjsip_tx_data *tdata,
  					   const pj_sockaddr_t *addr,
  					   int addr_len,
  					   void *token,
  					   pjsip_tp_send_callback cb);
  
  
  /**
   * This is a low-level function to send raw data to a destination.
   *
   * See also #pjsip_endpt_send_raw() and #pjsip_endpt_send_raw_to_uri().
   *
   * @param mgr	    Transport manager.
   * @param tp_type   Transport type.
   * @param sel	    Optional pointer to transport selector instance if
   *		    application wants to use a specific transport instance
   *		    rather then letting transport manager finds the suitable
   *		    transport.
   * @param tdata	    Optional transmit data buffer to be used. If this value
   *		    is NULL, this function will create one internally. If
   *		    tdata is specified, this function will decrement the
   *		    reference counter upon completion.
   * @param raw_data  The data to be sent.
   * @param data_len  The length of the data.
   * @param addr	    Destination address.
   * @param addr_len  Length of destination address.
   * @param token	    Arbitrary token to be returned back to callback.
   * @param cb	    Optional callback to be called to notify caller about
   *		    the completion status of the pending send operation.
   *
   * @return	    If the message has been sent successfully, this function
   *		    will return PJ_SUCCESS and the callback will not be 
   *		    called. If message cannot be sent immediately, this
   *		    function will return PJ_EPENDING, and application will
   *		    be notified later about the completion via the callback.
   *		    Any statuses other than PJ_SUCCESS or PJ_EPENDING
   *		    indicates immediate failure, and in this case the 
   *		    callback will not be called.
   */
  PJ_DECL(pj_status_t) pjsip_tpmgr_send_raw(pjsip_tpmgr *mgr,
  					  pjsip_transport_type_e tp_type,
  					  const pjsip_tpselector *sel,
  					  pjsip_tx_data *tdata,
  					  const void *raw_data,
  					  pj_size_t data_len,
  					  const pj_sockaddr_t *addr,
  					  int addr_len,
  					  void *token,
  					  pjsip_tp_send_callback cb);
  
  
  /**
   * Enumeration of transport state types.
   */
  typedef enum pjsip_transport_state
  {
      PJSIP_TP_STATE_CONNECTED,	    /**< Transport connected, applicable only
  					 to connection-oriented transports
  					 such as TCP and TLS.		    */
      PJSIP_TP_STATE_DISCONNECTED,    /**< Transport disconnected, applicable
  					 only to connection-oriented 
  					 transports such as TCP and TLS.    */
      PJSIP_TP_STATE_SHUTDOWN,        /**< Transport shutdown, either
                                           due to TCP/TLS disconnect error
                                           from the network, or when shutdown
                                           is initiated by PJSIP itself.      */
      PJSIP_TP_STATE_DESTROY,         /**< Transport destroy, when transport
                                           is about to be destroyed.          */
  } pjsip_transport_state;
  
  
  /**
   * Definition of transport state listener key.
   */
  typedef void pjsip_tp_state_listener_key;
  
  /**
   * Structure of transport state info passed by #pjsip_tp_state_callback.
   */
  typedef struct pjsip_transport_state_info {
      /**
       * The last error code related to the transport state.
       */
      pj_status_t		 status;
  
      /**
       * Optional extended info, the content is specific for each transport type.
       */
      void		*ext_info;
  
      /**
       * Optional user data. In global transport state notification, this will
       * always be NULL.
       */
      void		*user_data;
  
  } pjsip_transport_state_info;
  
  
  /**
   * Type of callback to receive transport state notifications, such as
   * transport connected/disconnected. Application may shutdown the transport
   * in this callback.
   *
   * @param tp		The transport instance.
   * @param state		The transport state.
   * @param info		The transport state info.
   */
  typedef void (*pjsip_tp_state_callback)(
  				    pjsip_transport *tp,
  				    pjsip_transport_state state,
  				    const pjsip_transport_state_info *info);
  
  
  /**
   * Set callback of global transport state notification. The caller will be
   * notified whenever the state of any transport is changed. The type of events
   * are defined in #pjsip_transport_state.
   *
   * Note that this function will override the existing callback, if any, so
   * application is recommended to keep the old callback and manually forward
   * the notification to the old callback, otherwise other component that 
   * concerns about the transport state will no longer receive transport state 
   * events.
   * 
   * @param mgr	    Transport manager.
   * @param cb	    Callback to be called to notify caller about transport 
   *		    state changing.
   *
   * @return	    PJ_SUCCESS on success, or the appropriate error code.
   */
  PJ_DECL(pj_status_t) pjsip_tpmgr_set_state_cb(pjsip_tpmgr *mgr,
  					      pjsip_tp_state_callback cb);
  
  
  /**
   * Get the callback of global transport state notification.
   * 
   * @param mgr	    Transport manager.
   *
   * @return	    The transport state callback or NULL if it is not set.
   */
  PJ_DECL(pjsip_tp_state_callback) pjsip_tpmgr_get_state_cb(
  					      const pjsip_tpmgr *mgr);
  
  
  /**
   * Add a listener to the specified transport for transport state notification.
   * 
   * @param tp	    The transport.
   * @param cb	    Callback to be called to notify listener about transport 
   *		    state changing.
   * @param user_data The user data.
   * @param key	    Output key, used to remove this listener.
   *
   * @return	    PJ_SUCCESS on success, or the appropriate error code.
   */
  PJ_DECL(pj_status_t) pjsip_transport_add_state_listener (
  					    pjsip_transport *tp,
  					    pjsip_tp_state_callback cb,
  					    void *user_data,
  					    pjsip_tp_state_listener_key **key);
  
  
  /**
   * Remove a listener from the specified transport for transport state 
   * notification.
   * 
   * @param tp	    The transport.
   * @param key	    The listener key.
   * @param user_data The user data, for validation purpose.
   *
   * @return	    PJ_SUCCESS on success, or the appropriate error code.
   */
  PJ_DECL(pj_status_t) pjsip_transport_remove_state_listener (
  				    pjsip_transport *tp,
  				    pjsip_tp_state_listener_key *key,
  				    const void *user_data);
  
  
  /**
   * Structure of dropped received data.
   */
  typedef struct pjsip_tp_dropped_data
  {
      /**
       * The transport receiving the data.
       */
      pjsip_transport *tp;
  
      /**
       * The data.
       */
      void	    *data;
  
      /**
       * The data length.
       * If the status field below indicates an invalid SIP message
       * (PJSIP_EINVALIDMSG) and application detects a SIP message
       * at position p, it can pass the data back to PJSIP to be processed
       * by setting the len to p. This can be useful for apps which
       * wishes to use the same transport for SIP signalling and non-SIP
       * purposes (such as SIP outbound using STUN message).
       */
      pj_size_t	     len;
  
      /**
       * The status or reason of drop. For example, a leading newlines (common
       * keep-alive packet) will be dropped with status PJ_EIGNORED, an invalid
       * SIP message will have status PJSIP_EINVALIDMSG, a SIP message overflow
       * will have status PJSIP_ERXOVERFLOW.
       */
      pj_status_t	     status;
  
  } pjsip_tp_dropped_data;
  
  
  /**
   * Type of callback to data dropping notifications.
   *
   * @param data		The dropped data.
   */
  typedef void (*pjsip_tp_on_rx_dropped_cb)(pjsip_tp_dropped_data *data);
  
  
  /**
   * Set callback of data dropping. The caller will be notified whenever any
   * received data is dropped (due to leading newlines or keep-alive packet or
   * invalid SIP message). This callback can be useful for application,
   * for example, to implement custom keep-alive mechanism or connection
   * availability detection.
   *
   * @param mgr	    Transport manager.
   * @param cb	    The callback function, set to NULL to reset the callback.
   *
   * @return	    PJ_SUCCESS on success, or the appropriate error code.
   */
  PJ_DECL(pj_status_t) pjsip_tpmgr_set_drop_data_cb(pjsip_tpmgr *mgr,
  						  pjsip_tp_on_rx_dropped_cb cb);
  
  
  /**
   * @}
   */
  
  
  PJ_END_DECL
  
  #endif	/* __PJSIP_SIP_TRANSPORT_H__ */
  
  