mirror of https://github.com/asterisk/asterisk
				
				
				
			
			You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							302 lines
						
					
					
						
							10 KiB
						
					
					
				
			
		
		
	
	
							302 lines
						
					
					
						
							10 KiB
						
					
					
				| /* $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_REPLACES_H__
 | |
| #define __PJSIP_REPLACES_H__
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * @file sip_replaces.h
 | |
|  * @brief SIP Replaces support (RFC 3891 - SIP "Replaces" Header)
 | |
|  */
 | |
| #include <pjsip/sip_msg.h>
 | |
| 
 | |
| /**
 | |
|  * @defgroup PJSIP_REPLACES SIP Replaces support (RFC 3891 - "Replaces" Header)
 | |
|  * @ingroup PJSIP_HIGH_UA
 | |
|  * @brief SIP Replaces support (RFC 3891 - "Replaces" Header)
 | |
|  * @{
 | |
|  *
 | |
|  * This module implements support for Replaces header in PJSIP. The Replaces
 | |
|  * specification is written in RFC 3891 - The Session Initiation Protocol (SIP) 
 | |
|  * "Replaces" Header, and can be used to enable a variety of features, 
 | |
|  * for example: "Attended Transfer" and "Call Pickup".
 | |
|  *
 | |
|  * 
 | |
|  *
 | |
|  * \section PJSIP_REPLACES_USING_SEC Using PJSIP Replaces Support
 | |
|  *
 | |
|  * \subsection PJSIP_REPLACES_INIT_SUBSEC Initialization
 | |
|  *
 | |
|  * Application needs to call #pjsip_replaces_init_module() during application
 | |
|  * initialization stage to register "replaces" support in PJSIP. 
 | |
|  *
 | |
|  *
 | |
|  * 
 | |
|  * \subsection PJSIP_REPLACES_UAC_SUBSEC UAC Behavior: Sending a Replaces Header
 | |
|  *
 | |
|  * A User Agent that wishes to replace a single existing early or
 | |
|  * confirmed dialog with a new dialog of its own, MAY send the target
 | |
|  * User Agent an INVITE request containing a Replaces header field.  The
 | |
|  * User Agent Client (UAC) places the Call-ID, to-tag, and from-tag
 | |
|  * information for the target dialog in a single Replaces header field
 | |
|  * and sends the new INVITE to the target.
 | |
|  *
 | |
|  * To initiate outgoing INVITE request with Replaces header, application
 | |
|  * would create the INVITE request with #pjsip_inv_invite(), then adds
 | |
|  * #pjsip_replaces_hdr instance into the request, filling up the Call-ID,
 | |
|  * To-tag, and From-tag properties of the header with the identification
 | |
|  * of the dialog to be replaced. Application may also optionally
 | |
|  * set the \a early_only property of the header to indicate that it only
 | |
|  * wants to replace early dialog.
 | |
|  *
 | |
|  * Note that when the outgoing INVITE request (with Replaces) is initiated
 | |
|  * from an incoming REFER request (as in Attended Call Transfer case),
 | |
|  * this process should be done rather more automatically by PJSIP. Upon 
 | |
|  * receiving incoming incoming REFER request, normally these processes
 | |
|  * will be performed:
 | |
|  *  - Application finds \a Refer-To header,
 | |
|  *  - Application creates outgoing dialog/invite session, specifying
 | |
|  *    the URI in the \a Refer-To header as the initial remote target,
 | |
|  *  - The URI in the \a Refer-To header may contain header parameters such
 | |
|  *    as \a Replaces and \a Require headers.
 | |
|  *  - The dialog keeps the header fields in the header parameters
 | |
|  *    of the URI, and the invite session would add these headers into
 | |
|  *    the outgoing INVITE request. Because of this, the outgoing 
 | |
|  *    INVITE request will contain the \a Replaces and \a Require headers.
 | |
|  *
 | |
|  *
 | |
|  * For more information, please see the implementation of 
 | |
|  * #pjsua_call_xfer_replaces() in \ref PJSUA_LIB source code.
 | |
|  *
 | |
|  *
 | |
|  * \subsection PJSIP_REPLACES_UAS_SUBSEC UAS Behavior: Receiving a Replaces Header
 | |
|  *
 | |
|  * The Replaces header contains information used to match an existing
 | |
|  * SIP dialog (call-id, to-tag, and from-tag).  Upon receiving an INVITE
 | |
|  * with a Replaces header, the User Agent (UA) attempts to match this
 | |
|  * information with a confirmed or early dialog.  
 | |
|  *
 | |
|  * In PJSIP, if application wants to process the Replaces header in the
 | |
|  * incoming INVITE request, it should call #pjsip_replaces_verify_request()
 | |
|  * before creating the INVITE session. The #pjsip_replaces_verify_request()
 | |
|  * function checks and verifies the request to see if Replaces request
 | |
|  * can be processed. To be more specific, it performs the following
 | |
|  * verification:
 | |
|  *  - checks that Replaces header is present. If not, the function will
 | |
|  *    return PJ_SUCCESS without doing anything.
 | |
|  *  - checks that no duplicate Replaces headers are present, or otherwise
 | |
|  *    it will return 400 "Bad Request" response.
 | |
|  *  - checks for matching dialog and verifies that the invite session has
 | |
|  *    the correct state, and may return 481 "Call/Transaction Does Not Exist",
 | |
|  *    603 "Declined", or 486 "Busy Here" according to the processing rules
 | |
|  *    specified in RFC 3891.
 | |
|  *  - if matching dialog with correct state is found, it will give PJ_SUCCESS
 | |
|  *    status and return the matching dialog back to the application.
 | |
|  *
 | |
|  * The following pseudocode illustrates how application can process the
 | |
|  * incoming INVITE if it wants to support Replaces extension:
 | |
|  *
 | |
|  \code
 | |
|   // Incoming INVITE request handler
 | |
|   pj_bool_t on_rx_invite(pjsip_rx_data *rdata)
 | |
|   {
 | |
|     pjsip_dialog *dlg, *replaced_dlg;
 | |
|     pjsip_inv_session *inv;
 | |
|     pjsip_tx_data *response;
 | |
|     pj_status_t status;
 | |
| 
 | |
|     // Check whether Replaces header is present in the request and process accordingly.
 | |
|     //
 | |
|     status = pjsip_replaces_verify_request(rdata, &replaced_dlg, PJ_FALSE, &response);
 | |
|     if (status != PJ_SUCCESS) {
 | |
| 	// Something wrong with Replaces request.
 | |
| 	//
 | |
| 	if (response) {
 | |
| 	    pjsip_endpt_send_response(endpt, rdata, response, NULL, NULL);
 | |
| 	} else {
 | |
| 	    // Respond with 500 (Internal Server Error)
 | |
| 	    pjsip_endpt_respond_stateless(endpt, rdata, 500, NULL, NULL, NULL);
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|     // Create UAS Invite session as usual.
 | |
|     //
 | |
|     status = pjsip_dlg_create_uas(.., rdata, .., &dlg);
 | |
|     ..
 | |
|     status = pjsip_inv_create_uas(dlg, .., &inv);
 | |
| 
 | |
|     // Send initial 100 "Trying" to the INVITE request
 | |
|     //
 | |
|     status = pjsip_inv_initial_answer(inv, rdata, 100, ..., &response);
 | |
|     if (status == PJ_SUCCESS)
 | |
| 	pjsip_inv_send_msg(inv, response);
 | |
| 
 | |
| 
 | |
|     // This is where processing is different between normal call
 | |
|     // (without Replaces) and call with Replaces.
 | |
|     //
 | |
|     if (replaced_dlg) {
 | |
| 	pjsip_inv_session *replaced_inv;
 | |
| 
 | |
| 	// Always answer the new INVITE with 200, regardless whether
 | |
| 	// the replaced call is in early or confirmed state.
 | |
| 	//
 | |
| 	status = pjsip_inv_answer(inv, 200, NULL, NULL, &response);
 | |
| 	if (status == PJ_SUCCESS)
 | |
| 	    pjsip_inv_send_msg(inv, response);
 | |
| 
 | |
| 
 | |
| 	// Get the INVITE session associated with the replaced dialog.
 | |
| 	//
 | |
| 	replaced_inv = pjsip_dlg_get_inv_session(replaced_dlg);
 | |
| 
 | |
| 
 | |
| 	// Disconnect the "replaced" INVITE session.
 | |
| 	//
 | |
| 	status = pjsip_inv_end_session(replaced_inv, PJSIP_SC_GONE, NULL, &tdata);
 | |
| 	if (status == PJ_SUCCESS && tdata)
 | |
| 	    status = pjsip_inv_send_msg(replaced_inv, tdata);
 | |
| 
 | |
| 
 | |
| 	// It's up to application to associate the new INVITE session
 | |
| 	// with the old (now terminated) session. For example, application
 | |
| 	// may assign the same User Interface object for the new INVITE
 | |
| 	// session.
 | |
| 
 | |
|     } else {
 | |
| 	// Process normal INVITE without Replaces.
 | |
| 	...
 | |
|     }
 | |
|   }
 | |
| 
 | |
|  \endcode
 | |
|  *
 | |
|  *
 | |
|  * For a complete sample implementation, please see \a pjsua_call_on_incoming()
 | |
|  * function of \ref PJSUA_LIB in \a pjsua_call.c file.
 | |
|  *
 | |
|  *
 | |
|  * \section PJSIP_REPLACES_REFERENCE References
 | |
|  *
 | |
|  * References:
 | |
|  *  - <A HREF="http://www.ietf.org/rfc/rfc3891.txt">RFC 3891: The Session 
 | |
|  *    Initiation Protocol (SIP) "Replaces" Header</A>
 | |
|  *  - \ref PJSUA_XFER
 | |
|  */
 | |
| 
 | |
| PJ_BEGIN_DECL
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * Declaration of SIP Replaces header (RFC 3891).
 | |
|  */
 | |
| typedef struct pjsip_replaces_hdr
 | |
| {
 | |
|     /** Standard header field. */
 | |
|     PJSIP_DECL_HDR_MEMBER(struct pjsip_replaces_hdr);
 | |
| 
 | |
|     /** Call-Id */
 | |
|     pj_str_t	call_id;
 | |
| 
 | |
|     /** to-tag */
 | |
|     pj_str_t	to_tag;
 | |
| 
 | |
|     /** from-tag */
 | |
|     pj_str_t	from_tag;
 | |
| 
 | |
|     /** early-only? */
 | |
|     pj_bool_t	early_only;
 | |
| 
 | |
|     /** Other parameters */
 | |
|     pjsip_param	other_param;
 | |
| 
 | |
| } pjsip_replaces_hdr;
 | |
| 
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * Initialize Replaces support in PJSIP. This would, among other things, 
 | |
|  * register the header parser for Replaces header.
 | |
|  *
 | |
|  * @param endpt	    The endpoint instance.
 | |
|  *
 | |
|  * @return	    PJ_SUCCESS on success.
 | |
|  */
 | |
| PJ_DECL(pj_status_t) pjsip_replaces_init_module(pjsip_endpoint *endpt);
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * Create Replaces header.
 | |
|  *
 | |
|  * @param pool	    Pool to allocate the header instance from.
 | |
|  *
 | |
|  * @return	    An empty Replaces header instance.
 | |
|  */
 | |
| PJ_DECL(pjsip_replaces_hdr*) pjsip_replaces_hdr_create(pj_pool_t *pool);
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * Verify that incoming request with Replaces header can be processed.
 | |
|  * This function will perform all necessary checks according to RFC 3891
 | |
|  * Section 3 "User Agent Server Behavior: Receiving a Replaces Header".
 | |
|  *
 | |
|  * @param rdata	    The incoming request to be verified.
 | |
|  * @param p_dlg	    On return, it will be filled with the matching 
 | |
|  *		    dialog.
 | |
|  * @param lock_dlg  Specifies whether this function should acquire lock
 | |
|  *		    to the matching dialog. If yes (and should be yes!),
 | |
|  *		    then application will need to release the dialog's
 | |
|  *		    lock with #pjsip_dlg_dec_lock() when the function
 | |
|  *		    returns PJ_SUCCESS and the \a p_dlg parameter is filled
 | |
|  *		    with the dialog instance.
 | |
|  * @param p_tdata   Upon error, it will be filled with the final response
 | |
|  *		    to be sent to the request sender.
 | |
|  *
 | |
|  * @return	    The function returns the following:
 | |
|  *		    - If the request doesn't contain Replaces header, the
 | |
|  *		      function returns PJ_SUCCESS and \a p_dlg parameter
 | |
|  *		      will be set to NULL.
 | |
|  *		    - If the request contains Replaces header and a valid,
 | |
|  *		      matching dialog is found, the function returns 
 | |
|  *		      PJ_SUCCESS and \a p_dlg parameter will be set to the
 | |
|  *		      matching dialog instance.
 | |
|  *		    - Upon error condition (as described by RFC 3891), the
 | |
|  *		      function returns non-PJ_SUCCESS, and \a p_tdata 
 | |
|  *		      parameter SHOULD be set with a final response message
 | |
|  *		      to be sent to the sender of the request.
 | |
|  */
 | |
| PJ_DECL(pj_status_t) pjsip_replaces_verify_request(pjsip_rx_data *rdata,
 | |
| 						   pjsip_dialog **p_dlg,
 | |
| 						   pj_bool_t lock_dlg,
 | |
| 						   pjsip_tx_data **p_tdata);
 | |
| 
 | |
| 
 | |
| 
 | |
| PJ_END_DECL
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * @}
 | |
|  */
 | |
| 
 | |
| 
 | |
| #endif	/* __PJSIP_REPLACES_H__ */
 | |
| 
 |