summaryrefslogtreecommitdiff
path: root/pjsip/include
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2006-11-11 16:16:04 +0000
committerBenny Prijono <bennylp@teluu.com>2006-11-11 16:16:04 +0000
commite6a5b770072500cf89a9cc10e4b99a972a6787b8 (patch)
treeec336215fc83344cec58d01dd30a74d7f6054e67 /pjsip/include
parente4fa39f3acb0b969dd1f952e81b33b2dff671002 (diff)
Attended call transfer implementation. The changes involves:
- Added support for SIP Replaces extension (RFC 3891) - Added pjsua_call_xfer_replaces() to perform attended call transfer. - PJSUA checks and process Replaces header in incoming calls - Added pjsip_ua_find_dialog() API. - Added pjsip_endpt_has_capability() API. - Added pjsip_endpt_send_response2() API. - etc. git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@797 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjsip/include')
-rw-r--r--pjsip/include/pjsip-ua/sip_replaces.h300
-rw-r--r--pjsip/include/pjsip-ua/sip_xfer.h31
-rw-r--r--pjsip/include/pjsip/sip_endpoint.h25
-rw-r--r--pjsip/include/pjsip/sip_ua_layer.h22
-rw-r--r--pjsip/include/pjsip/sip_util.h25
-rw-r--r--pjsip/include/pjsip_ua.h1
-rw-r--r--pjsip/include/pjsua-lib/pjsua.h67
7 files changed, 461 insertions, 10 deletions
diff --git a/pjsip/include/pjsip-ua/sip_replaces.h b/pjsip/include/pjsip-ua/sip_replaces.h
new file mode 100644
index 00000000..38c8aa99
--- /dev/null
+++ b/pjsip/include/pjsip-ua/sip_replaces.h
@@ -0,0 +1,300 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2003-2006 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__ */
+
diff --git a/pjsip/include/pjsip-ua/sip_xfer.h b/pjsip/include/pjsip-ua/sip_xfer.h
index 56809141..53d98e90 100644
--- a/pjsip/include/pjsip-ua/sip_xfer.h
+++ b/pjsip/include/pjsip-ua/sip_xfer.h
@@ -29,17 +29,32 @@
#include <pjsip/sip_msg.h>
/**
- * @defgroup PJSUA_XFER Call Transfer
+ * @defgroup PJSUA_XFER SIP REFER (RFC 3515) for Call Transfer etc.
* @ingroup PJSIP_HIGH_UA
- * @brief Provides call transfer functionality.
+ * @brief SIP REFER dialog usage (call transfer, etc.)
* @{
*
- * This implements call transfer functionality to INVITE sessions. The call
- * transfer functionality uses SIP Event Subscription framework for
- * managing call transfer status.
- *
- * Application must link with <b>pjsip-ua</b> AND <b>pjsip-simple</b> static
- * libraries to use call transfer functionality.
+ * This describes a generic handling of SIP REFER request. The SIP REFER
+ * request is described in RFC 3515, and commonly used to perform call
+ * transfer functionality. Other types of SIP REFER usages are described
+ * in draft-worley-sip-many-refers-00 draft, for example:
+ * - Remote Dial: where UAC sends REFER to instruct REFER recipient to
+ * initiate an INVITE session to some target.
+ *
+ * A REFER request can be sent inside or outside existing dialog context,
+ * although for call transfer case, it is more common to send REFER inside
+ * existing INVITE session context. PJSIP supports both sending REFER request
+ * inside or outside dialog context.
+ *
+ * The REFER framework uses @ref PJSIP_EVENT_NOT to manage the event
+ * subscription created by the REFER request. Because of this, application
+ * must link with <b>pjsip-ua</b> AND <b>pjsip-simple</b> static libraries
+ * to use REFER functionality.
+ *
+ * Reference:
+ * - <A HREF="http://www.ietf.org/rfc/rfc3515.txt">RFC 3515: The Session
+ * Initiation Protocol (SIP) Refer Method</A>
+ * - @ref PJSIP_EVENT_NOT
*/
diff --git a/pjsip/include/pjsip/sip_endpoint.h b/pjsip/include/pjsip/sip_endpoint.h
index 6e166090..34413d7c 100644
--- a/pjsip/include/pjsip/sip_endpoint.h
+++ b/pjsip/include/pjsip/sip_endpoint.h
@@ -403,6 +403,31 @@ PJ_DECL(const pjsip_hdr*) pjsip_endpt_get_capability( pjsip_endpoint *endpt,
/**
+ * Check if we have the specified capability.
+ *
+ * @param endpt The endpoint.
+ * @param htype The header type to be retrieved, which value may be:
+ * - PJSIP_H_ACCEPT
+ * - PJSIP_H_ALLOW
+ * - PJSIP_H_SUPPORTED
+ * @param hname If htype specifies PJSIP_H_OTHER, then the header name
+ * must be supplied in this argument. Otherwise the value
+ * must be set to NULL.
+ * @param token The capability token to check. For example, if \a htype
+ * is PJSIP_H_ALLOW, then \a token specifies the method
+ * names; if \a htype is PJSIP_H_SUPPORTED, then \a token
+ * specifies the extension names such as "100rel".
+ *
+ * @return PJ_TRUE if the specified capability is supported,
+ * otherwise PJ_FALSE..
+ */
+PJ_DECL(pj_bool_t) pjsip_endpt_has_capability( pjsip_endpoint *endpt,
+ int htype,
+ const pj_str_t *hname,
+ const pj_str_t *token);
+
+
+/**
* Add or register new capabilities as indicated by the tags to the
* appropriate header fields in the endpoint.
*
diff --git a/pjsip/include/pjsip/sip_ua_layer.h b/pjsip/include/pjsip/sip_ua_layer.h
index c4e2d7c7..26dea965 100644
--- a/pjsip/include/pjsip/sip_ua_layer.h
+++ b/pjsip/include/pjsip/sip_ua_layer.h
@@ -81,6 +81,28 @@ PJ_DECL(pjsip_user_agent*) pjsip_ua_instance(void);
/**
+ * Find a dialog with the specified Call-ID and tags properties. This
+ * function may optionally lock the matching dialog instance before
+ * returning it back to the caller.
+ *
+ * @param call_id The call ID to be matched.
+ * @param local_tag The local tag to be matched.
+ * @param remote_tag The remote tag to be matched.
+ * @param lock_dialog If non-zero, instruct the function to lock the
+ * matching dialog with #pjsip_dlg_inc_lock().
+ * Application is responsible to release the dialog's
+ * lock after it has finished manipulating the dialog,
+ * by calling #pjsip_dlg_dec_lock().
+ *
+ * @return The matching dialog instance, or NULL if no matching
+ * dialog is found.
+ */
+PJ_DECL(pjsip_dialog*) pjsip_ua_find_dialog(const pj_str_t *call_id,
+ const pj_str_t *local_tag,
+ const pj_str_t *remote_tag,
+ pj_bool_t lock_dialog);
+
+/**
* Destroy the user agent layer.
*
* @return PJ_SUCCESS on success.
diff --git a/pjsip/include/pjsip/sip_util.h b/pjsip/include/pjsip/sip_util.h
index 2b77e469..8a030fd6 100644
--- a/pjsip/include/pjsip/sip_util.h
+++ b/pjsip/include/pjsip/sip_util.h
@@ -333,6 +333,31 @@ PJ_DECL(pj_status_t) pjsip_endpt_send_response( pjsip_endpoint *endpt,
pj_bool_t *cont));
/**
+ * This is a convenient function which wraps #pjsip_get_response_addr() and
+ * #pjsip_endpt_send_response() in a single function.
+ *
+ * @param endpt The endpoint instance.
+ * @param rdata The original request to be responded.
+ * @param tdata The response message to be sent.
+ * @param token Token to be passed back when the callback is called.
+ * @param cb Optional callback to notify the transmission status
+ * to application, and to inform whether next address or
+ * transport will be tried.
+ *
+ * @return PJ_SUCCESS if response has been successfully created and
+ * sent to transport layer, or a non-zero error code.
+ * However, even when it returns PJ_SUCCESS, there is no
+ * guarantee that the response has been successfully sent.
+ */
+PJ_DECL(pj_status_t) pjsip_endpt_send_response2(pjsip_endpoint *endpt,
+ pjsip_rx_data *rdata,
+ pjsip_tx_data *tdata,
+ void *token,
+ void (*cb)(pjsip_send_state*,
+ pj_ssize_t sent,
+ pj_bool_t *cont));
+
+/**
* This composite function sends response message statelessly to an incoming
* request message. Internally it calls #pjsip_endpt_create_response() and
* #pjsip_endpt_send_response().
diff --git a/pjsip/include/pjsip_ua.h b/pjsip/include/pjsip_ua.h
index 205ef757..d3dda395 100644
--- a/pjsip/include/pjsip_ua.h
+++ b/pjsip/include/pjsip_ua.h
@@ -21,6 +21,7 @@
#include <pjsip-ua/sip_inv.h>
#include <pjsip-ua/sip_regc.h>
+#include <pjsip-ua/sip_replaces.h>
#include <pjsip-ua/sip_xfer.h>
diff --git a/pjsip/include/pjsua-lib/pjsua.h b/pjsip/include/pjsua-lib/pjsua.h
index efdf9f4c..12503780 100644
--- a/pjsip/include/pjsua-lib/pjsua.h
+++ b/pjsip/include/pjsua-lib/pjsua.h
@@ -337,6 +337,38 @@ typedef struct pjsua_callback
pj_bool_t *p_cont);
/**
+ * Notify application about incoming INVITE with Replaces header.
+ * Application may reject the request by setting non-2xx code.
+ *
+ * @param call_id The call ID to be replaced.
+ * @param rdata The incoming INVITE request to replace the call.
+ * @param st_code Status code to be set by application. Application
+ * should only return a final status (200-699).
+ * @param st_text Optional status text to be set by application.
+ */
+ void (*on_call_replace_request)(pjsua_call_id call_id,
+ pjsip_rx_data *rdata,
+ int *st_code,
+ pj_str_t *st_text);
+
+ /**
+ * Notify application that an existing call has been replaced with
+ * a new call. This happens when PJSUA-API receives incoming INVITE
+ * request with Replaces header.
+ *
+ * After this callback is called, normally PJSUA-API will disconnect
+ * \a old_call_id and establish \a new_call_id.
+ *
+ * @param old_call_id Existing call which to be replaced with the
+ * new call.
+ * @param new_call_id The new call.
+ * @param rdata The incoming INVITE with Replaces request.
+ */
+ void (*on_call_replaced)(pjsua_call_id old_call_id,
+ pjsua_call_id new_call_id);
+
+
+ /**
* Notify application when registration status has changed.
* Application may then query the account info to get the
* registration details.
@@ -1752,9 +1784,11 @@ PJ_DECL(pj_status_t) pjsua_call_reinvite(pjsua_call_id call_id,
/**
- * Initiate call transfer to the specified address.
+ * Initiate call transfer to the specified address. This function will send
+ * REFER request to instruct remote call party to initiate a new INVITE
+ * session to the specified destination/target.
*
- * @param call_id Call identification.
+ * @param call_id The call id to be transfered.
* @param dest Address of new target to be contacted.
* @param msg_data Optional message components to be sent with
* the request.
@@ -1766,6 +1800,35 @@ PJ_DECL(pj_status_t) pjsua_call_xfer(pjsua_call_id call_id,
const pjsua_msg_data *msg_data);
/**
+ * Flag to indicate that "Require: replaces" should not be put in the
+ * outgoing INVITE request caused by REFER request created by
+ * #pjsua_call_xfer_replaces().
+ */
+#define PJSUA_XFER_NO_REQUIRE_REPLACES 1
+
+/**
+ * Initiate attended call transfer. This function will send REFER request
+ * to instruct remote call party to initiate new INVITE session to the URL
+ * of \a dest_call_id. The party at \a dest_call_id then should "replace"
+ * the call with us with the new call from the REFER recipient.
+ *
+ * @param call_id The call id to be transfered.
+ * @param dest_call_id The call id to be replaced.
+ * @param options Application may specify PJSUA_XFER_NO_REQUIRE_REPLACES
+ * to suppress the inclusion of "Require: replaces" in
+ * the outgoing INVITE request created by the REFER
+ * request.
+ * @param msg_data Optional message components to be sent with
+ * the request.
+ *
+ * @return PJ_SUCCESS on success, or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pjsua_call_xfer_replaces(pjsua_call_id call_id,
+ pjsua_call_id dest_call_id,
+ unsigned options,
+ const pjsua_msg_data *msg_data);
+
+/**
* Send DTMF digits to remote using RFC 2833 payload formats.
*
* @param call_id Call identification.