blob: a9a16f195dc3efdf12bb67b1297b7c85955a77e9 [file] [log] [blame]
Benny Prijono053f5222006-11-11 16:16:04 +00001/* $Id$ */
2/*
Benny Prijonoa771a512007-02-19 01:13:53 +00003 * Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org>
Benny Prijono053f5222006-11-11 16:16:04 +00004 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19#ifndef __PJSIP_REPLACES_H__
20#define __PJSIP_REPLACES_H__
21
22
23/**
24 * @file sip_replaces.h
25 * @brief SIP Replaces support (RFC 3891 - SIP "Replaces" Header)
26 */
27#include <pjsip/sip_msg.h>
28
29/**
30 * @defgroup PJSIP_REPLACES SIP Replaces support (RFC 3891 - "Replaces" Header)
31 * @ingroup PJSIP_HIGH_UA
32 * @brief SIP Replaces support (RFC 3891 - "Replaces" Header)
33 * @{
34 *
35 * This module implements support for Replaces header in PJSIP. The Replaces
36 * specification is written in RFC 3891 - The Session Initiation Protocol (SIP)
37 * "Replaces" Header, and can be used to enable a variety of features,
38 * for example: "Attended Transfer" and "Call Pickup".
39 *
40 *
41 *
42 * \section PJSIP_REPLACES_USING_SEC Using PJSIP Replaces Support
43 *
44 * \subsection PJSIP_REPLACES_INIT_SUBSEC Initialization
45 *
46 * Application needs to call #pjsip_replaces_init_module() during application
47 * initialization stage to register "replaces" support in PJSIP.
48 *
49 *
50 *
51 * \subsection PJSIP_REPLACES_UAC_SUBSEC UAC Behavior: Sending a Replaces Header
52 *
53 * A User Agent that wishes to replace a single existing early or
54 * confirmed dialog with a new dialog of its own, MAY send the target
55 * User Agent an INVITE request containing a Replaces header field. The
56 * User Agent Client (UAC) places the Call-ID, to-tag, and from-tag
57 * information for the target dialog in a single Replaces header field
58 * and sends the new INVITE to the target.
59 *
60 * To initiate outgoing INVITE request with Replaces header, application
61 * would create the INVITE request with #pjsip_inv_invite(), then adds
62 * #pjsip_replaces_hdr instance into the request, filling up the Call-ID,
63 * To-tag, and From-tag properties of the header with the identification
64 * of the dialog to be replaced. Application may also optionally
65 * set the \a early_only property of the header to indicate that it only
66 * wants to replace early dialog.
67 *
68 * Note that when the outgoing INVITE request (with Replaces) is initiated
69 * from an incoming REFER request (as in Attended Call Transfer case),
70 * this process should be done rather more automatically by PJSIP. Upon
71 * receiving incoming incoming REFER request, normally these processes
72 * will be performed:
73 * - Application finds \a Refer-To header,
74 * - Application creates outgoing dialog/invite session, specifying
75 * the URI in the \a Refer-To header as the initial remote target,
76 * - The URI in the \a Refer-To header may contain header parameters such
77 * as \a Replaces and \a Require headers.
78 * - The dialog keeps the header fields in the header parameters
79 * of the URI, and the invite session would add these headers into
80 * the outgoing INVITE request. Because of this, the outgoing
81 * INVITE request will contain the \a Replaces and \a Require headers.
82 *
83 *
84 * For more information, please see the implementation of
85 * #pjsua_call_xfer_replaces() in \ref PJSUA_LIB source code.
86 *
87 *
88 * \subsection PJSIP_REPLACES_UAS_SUBSEC UAS Behavior: Receiving a Replaces Header
89 *
90 * The Replaces header contains information used to match an existing
91 * SIP dialog (call-id, to-tag, and from-tag). Upon receiving an INVITE
92 * with a Replaces header, the User Agent (UA) attempts to match this
93 * information with a confirmed or early dialog.
94 *
95 * In PJSIP, if application wants to process the Replaces header in the
96 * incoming INVITE request, it should call #pjsip_replaces_verify_request()
97 * before creating the INVITE session. The #pjsip_replaces_verify_request()
98 * function checks and verifies the request to see if Replaces request
99 * can be processed. To be more specific, it performs the following
100 * verification:
101 * - checks that Replaces header is present. If not, the function will
102 * return PJ_SUCCESS without doing anything.
103 * - checks that no duplicate Replaces headers are present, or otherwise
104 * it will return 400 "Bad Request" response.
105 * - checks for matching dialog and verifies that the invite session has
106 * the correct state, and may return 481 "Call/Transaction Does Not Exist",
107 * 603 "Declined", or 486 "Busy Here" according to the processing rules
108 * specified in RFC 3891.
109 * - if matching dialog with correct state is found, it will give PJ_SUCCESS
110 * status and return the matching dialog back to the application.
111 *
112 * The following pseudocode illustrates how application can process the
113 * incoming INVITE if it wants to support Replaces extension:
114 *
115 \code
116 // Incoming INVITE request handler
117 pj_bool_t on_rx_invite(pjsip_rx_data *rdata)
118 {
119 pjsip_dialog *dlg, *replaced_dlg;
120 pjsip_inv_session *inv;
121 pjsip_tx_data *response;
122 pj_status_t status;
123
124 // Check whether Replaces header is present in the request and process accordingly.
125 //
126 status = pjsip_replaces_verify_request(rdata, &replaced_dlg, PJ_FALSE, &response);
127 if (status != PJ_SUCCESS) {
128 // Something wrong with Replaces request.
129 //
130 if (response) {
131 pjsip_endpt_send_response(endpt, rdata, response, NULL, NULL);
132 } else {
133 // Respond with 500 (Internal Server Error)
134 pjsip_endpt_respond_stateless(endpt, rdata, 500, NULL, NULL, NULL);
135 }
136 }
137
138 // Create UAS Invite session as usual.
139 //
140 status = pjsip_dlg_create_uas(.., rdata, .., &dlg);
141 ..
142 status = pjsip_inv_create_uas(dlg, .., &inv);
143
144 // Send initial 100 "Trying" to the INVITE request
145 //
146 status = pjsip_inv_initial_answer(inv, rdata, 100, ..., &response);
147 if (status == PJ_SUCCESS)
148 pjsip_inv_send_msg(inv, response);
149
150
151 // This is where processing is different between normal call
152 // (without Replaces) and call with Replaces.
153 //
154 if (replaced_dlg) {
155 pjsip_inv_session *replaced_inv;
156
157 // Always answer the new INVITE with 200, regardless whether
158 // the replaced call is in early or confirmed state.
159 //
160 status = pjsip_inv_answer(inv, 200, NULL, NULL, &response);
161 if (status == PJ_SUCCESS)
162 pjsip_inv_send_msg(inv, response);
163
164
165 // Get the INVITE session associated with the replaced dialog.
166 //
167 replaced_inv = pjsip_dlg_get_inv_session(replaced_dlg);
168
169
170 // Disconnect the "replaced" INVITE session.
171 //
172 status = pjsip_inv_end_session(replaced_inv, PJSIP_SC_GONE, NULL, &tdata);
173 if (status == PJ_SUCCESS && tdata)
174 status = pjsip_inv_send_msg(replaced_inv, tdata);
175
176
177 // It's up to application to associate the new INVITE session
178 // with the old (now terminated) session. For example, application
179 // may assign the same User Interface object for the new INVITE
180 // session.
181
182 } else {
183 // Process normal INVITE without Replaces.
184 ...
185 }
186 }
187
188 \endcode
189 *
190 *
191 * For a complete sample implementation, please see \a pjsua_call_on_incoming()
192 * function of \ref PJSUA_LIB in \a pjsua_call.c file.
193 *
194 *
195 * \section PJSIP_REPLACES_REFERENCE References
196 *
197 * References:
198 * - <A HREF="http://www.ietf.org/rfc/rfc3891.txt">RFC 3891: The Session
199 * Initiation Protocol (SIP) "Replaces" Header</A>
200 * - \ref PJSUA_XFER
201 */
202
203PJ_BEGIN_DECL
204
205
206/**
207 * Declaration of SIP Replaces header (RFC 3891).
208 */
209typedef struct pjsip_replaces_hdr
210{
211 /** Standard header field. */
212 PJSIP_DECL_HDR_MEMBER(struct pjsip_replaces_hdr);
213
214 /** Call-Id */
215 pj_str_t call_id;
216
217 /** to-tag */
218 pj_str_t to_tag;
219
220 /** from-tag */
221 pj_str_t from_tag;
222
223 /** early-only? */
224 pj_bool_t early_only;
225
226 /** Other parameters */
227 pjsip_param other_param;
228
229} pjsip_replaces_hdr;
230
231
232
233/**
234 * Initialize Replaces support in PJSIP. This would, among other things,
235 * register the header parser for Replaces header.
236 *
237 * @param endpt The endpoint instance.
238 *
239 * @return PJ_SUCCESS on success.
240 */
241PJ_DECL(pj_status_t) pjsip_replaces_init_module(pjsip_endpoint *endpt);
242
243
244/**
245 * Create Replaces header.
246 *
247 * @param pool Pool to allocate the header instance from.
248 *
249 * @return An empty Replaces header instance.
250 */
251PJ_DECL(pjsip_replaces_hdr*) pjsip_replaces_hdr_create(pj_pool_t *pool);
252
253
254/**
255 * Verify that incoming request with Replaces header can be processed.
256 * This function will perform all necessary checks according to RFC 3891
257 * Section 3 "User Agent Server Behavior: Receiving a Replaces Header".
258 *
259 * @param rdata The incoming request to be verified.
260 * @param p_dlg On return, it will be filled with the matching
261 * dialog.
262 * @param lock_dlg Specifies whether this function should acquire lock
263 * to the matching dialog. If yes (and should be yes!),
264 * then application will need to release the dialog's
265 * lock with #pjsip_dlg_dec_lock() when the function
266 * returns PJ_SUCCESS and the \a p_dlg parameter is filled
267 * with the dialog instance.
268 * @param p_tdata Upon error, it will be filled with the final response
269 * to be sent to the request sender.
270 *
271 * @return The function returns the following:
272 * - If the request doesn't contain Replaces header, the
273 * function returns PJ_SUCCESS and \a p_dlg parameter
274 * will be set to NULL.
275 * - If the request contains Replaces header and a valid,
276 * matching dialog is found, the function returns
277 * PJ_SUCCESS and \a p_dlg parameter will be set to the
278 * matching dialog instance.
279 * - Upon error condition (as described by RFC 3891), the
280 * function returns non-PJ_SUCCESS, and \a p_tdata
281 * parameter SHOULD be set with a final response message
282 * to be sent to the sender of the request.
283 */
284PJ_DECL(pj_status_t) pjsip_replaces_verify_request(pjsip_rx_data *rdata,
285 pjsip_dialog **p_dlg,
286 pj_bool_t lock_dlg,
287 pjsip_tx_data **p_tdata);
288
289
290
291PJ_END_DECL
292
293
294/**
295 * @}
296 */
297
298
299#endif /* __PJSIP_REPLACES_H__ */
300