* nua: passing the culprit to the dialog usage removal functions

If a session was terminated because of a error response returned to a
  request (as specified by RFC 5157), the nua_i_state event was not sent.
  
  Even with this fix, if a dialog has multiple usages, the event usages can be
  terminated without any indication to the application.



git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@7816 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
Michael Jerris 2008-03-07 17:41:29 +00:00
parent f35f29b1c1
commit bbb36378b2
9 changed files with 290 additions and 121 deletions

View File

@ -60,7 +60,9 @@
/* Dialog handling */
static void nua_dialog_usage_remove_at(nua_owner_t*, nua_dialog_state_t*,
nua_dialog_usage_t**);
nua_dialog_usage_t**,
nua_client_request_t *cr,
nua_server_request_t *sr);
static void nua_dialog_log_usage(nua_owner_t *, nua_dialog_state_t *);
/**@internal
@ -331,7 +333,9 @@ nua_dialog_usage_t *nua_dialog_usage_add(nua_owner_t *own,
/** @internal Remove dialog usage. */
void nua_dialog_usage_remove(nua_owner_t *own,
nua_dialog_state_t *ds,
nua_dialog_usage_t *du)
nua_dialog_usage_t *du,
nua_client_request_t *cr,
nua_server_request_t *sr)
{
nua_dialog_usage_t **at;
@ -343,7 +347,7 @@ void nua_dialog_usage_remove(nua_owner_t *own,
assert(*at);
nua_dialog_usage_remove_at(own, ds, at);
nua_dialog_usage_remove_at(own, ds, at, cr, sr);
}
/** @internal Remove dialog usage.
@ -353,7 +357,9 @@ void nua_dialog_usage_remove(nua_owner_t *own,
static
void nua_dialog_usage_remove_at(nua_owner_t *own,
nua_dialog_state_t *ds,
nua_dialog_usage_t **at)
nua_dialog_usage_t **at,
nua_client_request_t *cr0,
nua_server_request_t *sr0)
{
if (*at) {
nua_dialog_usage_t *du = *at;
@ -368,10 +374,10 @@ void nua_dialog_usage_remove_at(nua_owner_t *own,
SU_DEBUG_5(("nua(%p): removing %s usage%s%s\n",
(void *)own, nua_dialog_usage_name(du),
o ? " with event " : "", o ? o->o_type :""));
du->du_class->usage_remove(own, ds, du);
du->du_class->usage_remove(own, ds, du, cr0, sr0);
/* Destroy saved client request */
if (nua_client_is_bound(du->du_cr)) {
if (cr0 != du->du_cr && nua_client_is_bound(du->du_cr)) {
nua_client_bind(cr = du->du_cr, NULL);
if (nua_client_is_queued(cr))
@ -391,8 +397,11 @@ void nua_dialog_usage_remove_at(nua_owner_t *own,
for (sr = ds->ds_sr; sr; sr = sr_next) {
sr_next = sr->sr_next;
if (sr->sr_usage == du)
nua_server_request_destroy(sr);
if (sr->sr_usage == du) {
if (sr != sr0)
nua_server_request_destroy(sr);
sr->sr_usage = NULL;
}
}
su_home_unref(own);
@ -454,7 +463,7 @@ void nua_dialog_deinit(nua_owner_t *own,
ds->ds_terminating = 1;
while (ds->ds_usage) {
nua_dialog_usage_remove_at(own, ds, &ds->ds_usage);
nua_dialog_usage_remove_at(own, ds, &ds->ds_usage, NULL, NULL);
}
nua_dialog_remove(own, ds, NULL);

View File

@ -286,12 +286,12 @@ struct nua_client_request
url_t *cr_target;
uint32_t cr_seq;
char const *cr_phrase; /**< Latest status phrase */
unsigned short cr_status; /**< Latest status */
unsigned short cr_retry_count; /**< Retry count for this request */
uint32_t cr_seq;
/* Flags used with offer-answer */
unsigned short cr_answer_recv; /**< Recv answer in response
* with this status.
@ -382,7 +382,9 @@ typedef struct {
nua_dialog_usage_t *du);
void (*usage_remove)(nua_owner_t *,
nua_dialog_state_t *ds,
nua_dialog_usage_t *du);
nua_dialog_usage_t *du,
nua_client_request_t *cr,
nua_server_request_t *sr);
char const *(*usage_name)(nua_dialog_usage_t const *du);
void (*usage_peer_info)(nua_dialog_usage_t *du,
nua_dialog_state_t const *ds,
@ -446,7 +448,9 @@ nua_dialog_usage_t *nua_dialog_usage_get(nua_dialog_state_t const *ds,
void nua_dialog_usage_remove(nua_owner_t *,
nua_dialog_state_t *ds,
nua_dialog_usage_t *du);
nua_dialog_usage_t *du,
nua_client_request_t *cr,
nua_server_request_t *sr);
void nua_dialog_deinit(nua_owner_t *own,
nua_dialog_state_t *ds);

View File

@ -74,8 +74,10 @@ static int nua_notify_usage_add(nua_handle_t *nh,
nua_dialog_state_t *ds,
nua_dialog_usage_t *du);
static void nua_notify_usage_remove(nua_handle_t *nh,
nua_dialog_state_t *ds,
nua_dialog_usage_t *du);
nua_dialog_state_t *ds,
nua_dialog_usage_t *du,
nua_client_request_t *cr,
nua_server_request_t *sr);
static void nua_notify_usage_refresh(nua_handle_t *nh,
nua_dialog_state_t *ds,
nua_dialog_usage_t *du,
@ -102,8 +104,8 @@ static char const *nua_notify_usage_name(nua_dialog_usage_t const *du)
static
int nua_notify_usage_add(nua_handle_t *nh,
nua_dialog_state_t *ds,
nua_dialog_usage_t *du)
nua_dialog_state_t *ds,
nua_dialog_usage_t *du)
{
ds->ds_has_events++;
ds->ds_has_notifys++;
@ -112,8 +114,10 @@ int nua_notify_usage_add(nua_handle_t *nh,
static
void nua_notify_usage_remove(nua_handle_t *nh,
nua_dialog_state_t *ds,
nua_dialog_usage_t *du)
nua_dialog_state_t *ds,
nua_dialog_usage_t *du,
nua_client_request_t *cr,
nua_server_request_t *sr)
{
ds->ds_has_events--;
ds->ds_has_notifys--;
@ -796,7 +800,7 @@ static void nua_notify_usage_refresh(nua_handle_t *nh,
NUTAG_SUBSTATE(nua_substate_terminated),
TAG_END());
nua_dialog_usage_remove(nh, ds, du);
nua_dialog_usage_remove(nh, ds, du, NULL, NULL);
}
/** @interal Shut down NOTIFY usage.
@ -827,7 +831,7 @@ static int nua_notify_usage_shutdown(nua_handle_t *nh,
return 0;
}
nua_dialog_usage_remove(nh, ds, du);
nua_dialog_usage_remove(nh, ds, du, NULL, NULL);
return 200;
}

View File

@ -60,8 +60,10 @@ static int nua_publish_usage_add(nua_handle_t *nh,
nua_dialog_state_t *ds,
nua_dialog_usage_t *du);
static void nua_publish_usage_remove(nua_handle_t *nh,
nua_dialog_state_t *ds,
nua_dialog_usage_t *du);
nua_dialog_state_t *ds,
nua_dialog_usage_t *du,
nua_client_request_t *cr,
nua_server_request_t *sr);
static void nua_publish_usage_refresh(nua_handle_t *nh,
nua_dialog_state_t *ds,
nua_dialog_usage_t *du,
@ -101,8 +103,11 @@ int nua_publish_usage_add(nua_handle_t *nh,
static
void nua_publish_usage_remove(nua_handle_t *nh,
nua_dialog_state_t *ds,
nua_dialog_usage_t *du)
nua_dialog_state_t *ds,
nua_dialog_usage_t *du,
nua_client_request_t *cr,
nua_server_request_t *sr
)
{
struct publish_usage *pu = nua_dialog_usage_private(du);
@ -433,7 +438,7 @@ static void nua_publish_usage_refresh(nua_handle_t *nh,
nua_r_publish, NUA_ERROR_AT(__FILE__, __LINE__),
NULL);
nua_dialog_usage_remove(nh, ds, du);
nua_dialog_usage_remove(nh, ds, du, NULL, NULL);
}
/** @interal Shut down PUBLISH usage.
@ -454,7 +459,7 @@ static int nua_publish_usage_shutdown(nua_handle_t *nh,
}
/* XXX - report to user */
nua_dialog_usage_remove(nh, ds, du);
nua_dialog_usage_remove(nh, ds, du, NULL, NULL);
return 200;
}

View File

@ -104,7 +104,9 @@ static int nua_register_usage_add(nua_handle_t *nh,
nua_dialog_usage_t *du);
static void nua_register_usage_remove(nua_handle_t *nh,
nua_dialog_state_t *ds,
nua_dialog_usage_t *du);
nua_dialog_usage_t *du,
nua_client_request_t *cr,
nua_server_request_t *sr);
static void nua_register_usage_peer_info(nua_dialog_usage_t *du,
nua_dialog_state_t const *ds,
sip_t const *sip);
@ -196,7 +198,9 @@ static int nua_register_usage_add(nua_handle_t *nh,
static void nua_register_usage_remove(nua_handle_t *nh,
nua_dialog_state_t *ds,
nua_dialog_usage_t *du)
nua_dialog_usage_t *du,
nua_client_request_t *cr,
nua_server_request_t *sr)
{
nua_registration_t *nr = nua_dialog_usage_private(du);
@ -1050,7 +1054,7 @@ static void nua_register_usage_refresh(nua_handle_t *nh,
/* Report that we have de-registered */
nua_stack_event(nua, nh, NULL, nua_r_register, NUA_ERROR_AT(__FILE__, __LINE__), NULL);
nua_dialog_usage_remove(nh, ds, du);
nua_dialog_usage_remove(nh, ds, du, NULL, NULL);
}
/** @interal Shut down REGISTER usage.
@ -1078,7 +1082,7 @@ static int nua_register_usage_shutdown(nua_handle_t *nh,
if (nr->nr_tport)
tport_decref(&nr->nr_tport), nr->nr_tport = NULL;
nua_dialog_usage_remove(nh, ds, du);
nua_dialog_usage_remove(nh, ds, du, NULL, NULL);
return 200;
}

View File

@ -181,7 +181,9 @@ static int nua_session_usage_add(nua_handle_t *nh,
nua_dialog_usage_t *du);
static void nua_session_usage_remove(nua_handle_t *nh,
nua_dialog_state_t *ds,
nua_dialog_usage_t *du);
nua_dialog_usage_t *du,
nua_client_request_t *cr,
nua_server_request_t *sr);
static void nua_session_usage_refresh(nua_owner_t *,
nua_dialog_state_t *,
nua_dialog_usage_t *,
@ -190,6 +192,11 @@ static int nua_session_usage_shutdown(nua_owner_t *,
nua_dialog_state_t *,
nua_dialog_usage_t *);
static void signal_call_state_change(nua_handle_t *nh,
nua_session_usage_t *ss,
int status, char const *phrase,
enum nua_callstate next_state);
static int nua_invite_client_ack(nua_client_request_t *cr, tagi_t const *tags);
static int nua_invite_client_complete(nua_client_request_t *cr);
@ -230,15 +237,17 @@ int nua_session_usage_add(nua_handle_t *nh,
static
void nua_session_usage_remove(nua_handle_t *nh,
nua_dialog_state_t *ds,
nua_dialog_usage_t *du)
nua_dialog_state_t *ds,
nua_dialog_usage_t *du,
nua_client_request_t *cr0,
nua_server_request_t *sr0)
{
nua_session_usage_t *ss = nua_dialog_usage_private(du);
nua_client_request_t *cr, *cr_next;
cr = du->du_cr;
if (cr && cr->cr_orq && cr->cr_status >= 200 &&
if (cr != cr0 && cr && cr->cr_orq && cr->cr_status >= 200 &&
cr->cr_method == sip_method_invite) {
ss->ss_reporting = 1;
nua_invite_client_ack(cr, NULL);
@ -252,7 +261,10 @@ void nua_session_usage_remove(nua_handle_t *nh,
if (cr->cr_method != sip_method_invite)
continue;
if (cr == du->du_cr)
if (cr == cr0)
continue;
if (cr == du->du_cr && cr->cr_orq)
continue;
if (cr->cr_status < 200) {
@ -268,7 +280,19 @@ void nua_session_usage_remove(nua_handle_t *nh,
cr_next = ds->ds_cr;
}
if (ss->ss_state != nua_callstate_terminated &&
ss->ss_state != nua_callstate_init &&
!ss->ss_reporting) {
int status = 0; char const *phrase = "Terminated";
if (cr0)
status = cr0->cr_status, phrase = cr0->cr_phrase ? cr0->cr_phrase : phrase;
else if (sr0)
status = sr0->sr_status, phrase = sr0->sr_phrase;
signal_call_state_change(nh, ss, status, phrase, nua_callstate_terminated);
}
ds->ds_has_session = 0;
nh->nh_has_invite = 0;
nh->nh_active_call = 0;
@ -306,7 +330,7 @@ void nua_session_usage_destroy(nua_handle_t *nh,
nua_session_usage_t *ss)
{
/* Remove usage */
nua_dialog_usage_remove(nh, nh->nh_ds, nua_dialog_usage_public(ss));
nua_dialog_usage_remove(nh, nh->nh_ds, nua_dialog_usage_public(ss), NULL, NULL);
SU_DEBUG_5(("nua: terminated session %p\n", (void *)nh));
}
@ -349,11 +373,6 @@ static int nh_referral_check(nua_handle_t *nh, tagi_t const *tags);
static void nh_referral_respond(nua_handle_t *,
int status, char const *phrase);
static void signal_call_state_change(nua_handle_t *nh,
nua_session_usage_t *ss,
int status, char const *phrase,
enum nua_callstate next_state);
static
int session_get_description(sip_t const *sip,
char const **return_sdp,
@ -380,17 +399,26 @@ int nua_server_retry_after(nua_server_request_t *sr,
/**@fn void nua_invite(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
*
* Place a call using SIP INVITE method.
* Place a call using SIP @b INVITE method.
*
* Incomplete call can be hung-up with nua_cancel(). Complete or incomplete
* calls can be hung-up with nua_bye().
* The INVITE method is used to initiate a call between two parties. The
* call is also known as <i>SIP session</i>.
*
* At SIP level the session is represented as @e Dialog, which is a
* peer-to-peer association between two SIP User-Agents. The dialog is
* established by a successful 2XX response to the INVITE. The dialog is
* terminated by BYE transaction, which application can initiate with
* nua_bye() call.
*
* Optionally
* - uses early media if NUTAG_EARLY_MEDIA() tag is used with non zero-value
* - media parameters can be set by SOA tags
* - nua_invite() can be used to change status of an existing call:
* - #SOATAG_HOLD tag can be used to list the media that will be put on hold,
* the value "*" sets all the media beloginging to the session on hold
* An @e early @e dialog is established by an preliminary response
* (101..199), such as <i>180 Ringing</i>. An early dialog is terminated
* with an error response with response code in range 300...699.
*
* The media session belonging to the SIP session is usually represented by
* SDP, Session Description Protocol. The media session it is usually
* established during the call set-up with procedure known as SDP
* Offer/Answer exchange, defined by @RFC3264. See <b>Media Session
* Handling</b> below for details.
*
* @param nh Pointer to operation handle
* @param tag, value, ... List of tagged parameters
@ -398,22 +426,30 @@ int nua_server_retry_after(nua_server_request_t *sr,
* @return
* nothing
*
* @par Related Tags:
* NUTAG_URL() \n
* Tags of nua_set_hparams() \n
* NUTAG_INCLUDE_EXTRA_SDP() \n
* SOATAG_HOLD(), SOATAG_AF(), SOATAG_ADDRESS(),
* SOATAG_RTP_SELECT(), SOATAG_RTP_SORT(), SOATAG_RTP_MISMATCH(),
* SOATAG_AUDIO_AUX(), \n
* SOATAG_USER_SDP() or SOATAG_USER_SDP_STR() \n
* See use of tags in <sip_tag.h> below
*
* @par Events:
* #nua_r_invite \n
* #nua_i_state (#nua_i_active, #nua_i_terminated) \n
* #nua_i_media_error \n
* #nua_i_fork \n
*
* @par Tags:
* NUTAG_AUTH_CACHE() \n
* NUTAG_AUTOACK() \n
* NUTAG_AUTOANSWER() \n
* NUTAG_EARLY_MEDIA() \n
* NUTAG_ENABLEINVITE() \n
* NUTAG_INITIAL_ROUTE(), NUTAG_INITIAL_ROUTE_STR() \n
* NUTAG_INVITE_TIMER() \n
* NUTAG_MEDIA_ENABLE() \n
* NUTAG_MEDIA_FEATURES() \n
* NUTAG_MIN_SE() \n
* NUTAG_RETRY_COUNT() \n
* NUTAG_SERVICE_ROUTE_ENABLE() \n
* NUTAG_SESSION_REFRESHER() \n
* NUTAG_SESSION_TIMER() \n
* NUTAG_SOA_NAME() \n
* NUTAG_UPDATE_REFRESH() \n
*
* @par Populating SIP Request Message with Tagged Arguments
* The tagged arguments can be used to pass values for any SIP headers to
* the stack. When the INVITE message (or any other SIP message) is created,
@ -449,7 +485,27 @@ int nua_server_retry_after(nua_server_request_t *sr,
* application. At this point, the target URI is stored in the request line,
* together with method name ("INVITE") and protocol version ("SIP/2.0").
* The initial dialog information is also created: @CallID, @CSeq headers
* are generated, if they do not exist, and tag is added to @From header.
* are generated, if they do not exist, and an unique tag is added to @From
* header.
*
* @par
* For the initial INVITE requests, the @Route headers specified by
* SIPTAG_ROUTE()/SIPTAG_ROUTER_STR() tags in nua_handle() and nua_invite()
* calls are inserted to the request. Next the initial route set specified
* by NUTAG_INITIAL_ROUTE()/NUTAG_INITIAL_ROUTE_STR() tags is prepended to
* the route. Finally (unless NUTAG_SERVICE_ROUTE_ENABLE(0) is used) the
* @ServiceRoute set received from the registrar is also appended to the
* route set of the initial request message.
*
* @par
* Next, the stack generates a @Contact header for the request (Unless the
* application already gave a @Contact header or it does not want to use
* @Contact and indicates that by including SIPTAG_CONTACT(NULL) or
* SIPTAG_CONTACT(SIP_NONE) in the tagged parameters.) If the application
* has a registration active, the @Contact header used with registration is
* used. Otherwise, the @Contact header is generated from the local IP
* address and port number, taking also the values from NUTAG_M_DISPLAY(),
* NUTAG_M_FEATURES(), NUTAG_M_PARAMS(), and NUTAG_M_USERNAME().
*
* @par
* For in-dialog INVITE (re-INVITE), the request URI is taken from the
@ -464,19 +520,6 @@ int nua_server_retry_after(nua_server_request_t *sr,
* also added now, if it does not exist.
*
* @par
* Next, the stack generates a @Contact header for the request (Unless the
* application already gave a @Contact header or it does not want to use
* @Contact and indicates that by including SIPTAG_CONTACT(NULL) or
* SIPTAG_CONTACT(SIP_NONE) in the tagged parameters.) If the application
* has registered the URI in @From header, the @Contact header used with
* registration is used. Otherwise, the @Contact header is generated from the
* local IP address and port number.
*
* @par
* For the initial INVITE requests, @ServiceRoute set received from
* the registrar is also added to the request message.
*
* @par
* The INVITE request message created by nua_invite() operation is saved as
* a template for automatic re-INVITE requests sent by the session timer
* ("timer") feature (see NUTAG_SESSION_TIMER() for more details). Please
@ -485,27 +528,105 @@ int nua_server_retry_after(nua_server_request_t *sr,
* dialog-specific headers like @To, @From, and @CallID as well as
* preference headers @Allow, @Supported, @UserAgent, @Organization).
*
* @par Tags Related to SIP Headers and Request-URI
* NUTAG_URL(), SIPTAG_REQUEST(), SIPTAG_REQUEST_STR() \n
* NUTAG_INITIAL_ROUTE(), NUTAG_INITIAL_ROUTE_STR(),
* SIPTAG_ROUTE(), SIPTAG_ROUTE_STR(),
* NUTAG_SERVICE_ROUTE_ENABLE() \n
* SIPTAG_MAX_FORWARDS(), SIPTAG_MAX_FORWARDS_STR() \n
* SIPTAG_PROXY_REQUIRE(), SIPTAG_PROXY_REQUIRE_STR() \n
* SIPTAG_FROM(), SIPTAG_FROM_STR() \n
* SIPTAG_TO(), SIPTAG_TO_STR() \n
* SIPTAG_CALL_ID(), SIPTAG_CALL_ID_STR() \n
* SIPTAG_CSEQ(), SIPTAG_CSEQ_STR()
* (note that @CSeq value is incremented if request gets retried)\n
* SIPTAG_CONTACT(), SIPTAG_CONTACT_STR() \n
* SIPTAG_REQUEST_DISPOSITION(), SIPTAG_REQUEST_DISPOSITION_STR() \n
* SIPTAG_ACCEPT_CONTACT(), SIPTAG_ACCEPT_CONTACT_STR() \n
* SIPTAG_REJECT_CONTACT(), SIPTAG_REJECT_CONTACT_STR() \n
* SIPTAG_EXPIRES(), SIPTAG_EXPIRES_STR() \n
* SIPTAG_DATE(), SIPTAG_DATE_STR() \n
* SIPTAG_TIMESTAMP(), SIPTAG_TIMESTAMP_STR() \n
* SIPTAG_SUBJECT(), SIPTAG_SUBJECT_STR() \n
* SIPTAG_PRIORITY(), SIPTAG_PRIORITY_STR() \n
* SIPTAG_CALL_INFO(), SIPTAG_CALL_INFO_STR() \n
* SIPTAG_ORGANIZATION(), SIPTAG_ORGANIZATION_STR() \n
* NUTAG_USER_AGENT(), SIPTAG_USER_AGENT() and SIPTAG_USER_AGENT_STR() \n
* SIPTAG_IN_REPLY_TO(), SIPTAG_IN_REPLY_TO_STR() \n
* SIPTAG_ACCEPT(), SIPTAG_ACCEPT_STR() \n
* SIPTAG_ACCEPT_ENCODING(), SIPTAG_ACCEPT_ENCODING_STR() \n
* SIPTAG_ACCEPT_LANGUAGE(), SIPTAG_ACCEPT_LANGUAGE_STR() \n
* NUTAG_ALLOW(), SIPTAG_ALLOW(), and SIPTAG_ALLOW_STR() \n
* NUTAG_EARLY_MEDIA(), SIPTAG_REQUIRE(), and SIPTAG_REQUIRE_STR() \n
* NUTAG_SUPPORTED(), SIPTAG_SUPPORTED(), and SIPTAG_SUPPORTED_STR() \n
* SIPTAG_ALLOW_EVENTS(), SIPTAG_ALLOW_EVENTS_STR() \n
* SIPTAG_PROXY_AUTHORIZATION(), SIPTAG_PROXY_AUTHORIZATION_STR() \n
* SIPTAG_AUTHORIZATION(), SIPTAG_AUTHORIZATION_STR() \n
* SIPTAG_REFERRED_BY(), SIPTAG_REFERRED_BY_STR() \n
* SIPTAG_REPLACES(), SIPTAG_REPLACES_STR() \n
* NUTAG_SESSION_TIMER(), NUTAG_SESSION_REFRESHER(),
* SIPTAG_SESSION_EXPIRES(), SIPTAG_SESSION_EXPIRES_STR() \n
* NUTAG_MIN_SE(), SIPTAG_MIN_SE(), SIPTAG_MIN_SE_STR() \n
* SIPTAG_SECURITY_CLIENT(), SIPTAG_SECURITY_CLIENT_STR() \n
* SIPTAG_SECURITY_VERIFY(), SIPTAG_SECURITY_VERIFY_STR() \n
* SIPTAG_PRIVACY(), SIPTAG_PRIVACY_STR() \n
* SIPTAG_MIME_VERSION(), SIPTAG_MIME_VERSION_STR() \n
* SIPTAG_CONTENT_TYPE(), SIPTAG_CONTENT_TYPE_STR() \n
* SIPTAG_CONTENT_ENCODING(), SIPTAG_CONTENT_ENCODING_STR() \n
* SIPTAG_CONTENT_LANGUAGE(), SIPTAG_CONTENT_LANGUAGE_STR() \n
* SIPTAG_CONTENT_DISPOSITION(), SIPTAG_CONTENT_DISPOSITION_STR() \n
* SIPTAG_HEADER(), SIPTAG_HEADER_STR() \n
* SIPTAG_PAYLOAD(), SIPTAG_PAYLOAD_STR() \n
*
* @par SDP Handling
* The initial nua_invite() creates a @ref soa_session_t "soa media session"
* unless NUTAG_MEDIA_ENABLE(0) has been given. The SDP description of the
* @ref soa_session_t "soa media session" is included in the INVITE request
* as message body.
* By default the nua_invite() uses an @ref soa_session_t "SOA media
* session" object to take care of the Offer/Answer exchange. The SOA can
* be disabled with tag NUTAG_MEDIA_ENABLE(0).
*
* @par
* The SDP in a 1XX or 2XX response message is interpreted as an answer,
* given to the @ref soa_session_t "soa media session" object for
* processing.
* The SDP description of the
* @ref soa_session_t "soa media session" is included in the INVITE request
* as a message body.
* The SDP in the message body of the 1XX or 2XX response message is
* interpreted as an answer, given to the @ref soa_session_t "soa media
* session" object for processing.
*
* @bug If the INVITE request already contains a message body, SDP is not
* added. Also, if the response contains a multipart body, it is not parsed.
* added. Also, if the response contains a multipart body, it is not parsed.
*
* @par Tags Related to SDP Management and Offer/Answer Model:
* NUTAG_MEDIA_ENABLE(), \n
* NUTAG_INCLUDE_EXTRA_SDP(), \n
* SOATAG_HOLD(), SOATAG_AF(), SOATAG_ADDRESS(),
* SOATAG_ORDERED_USER(), SOATAG_REUSE_REJECTED(),
* SOATAG_RTP_SELECT(), SOATAG_RTP_SORT(), SOATAG_RTP_MISMATCH(),
* SOATAG_AUDIO_AUX(), \n
* SOATAG_USER_SDP() or SOATAG_USER_SDP_STR() \n
*
* @par Alternative Call Models
* In addition to the basic SIP call model described in @RFC3261 and
* @RFC3264, the early media model described in @RFC3262 is available. The
* use of 100rel and early media can be use can be forced with
* NUTAG_EARLY_MEDIA(1).
*
* Also, the "precondition" call model described in @RFC3312 is supported at
* SIP level, that is, the SIP PRACK and UPDATE requests are sent if
* "precondition" is added to the @Require header in the INVITE request.
*
* Optionally
* - uses early media if NUTAG_EARLY_MEDIA() tag is used with non zero-value
* - media parameters can be set by SOA tags
* - nua_invite() can be used to change status of an existing call:
* - #SOATAG_HOLD tag can be used to list the media that will be put on hold,
* the value "*" sets all the media beloginging to the session on hold
*
* @par Authentication
* The INVITE request may need authentication. Each proxy or server
* requiring authentication can respond with 401 or 407 response. The
* nua_authenticate() operation stores authentication information (username
* and password) to the handle, and stack tries to authenticate all the rest
* of the requests (e.g., PRACK, ACK, UPDATE, re-INVITE, BYE) using same
* username and password.
* of the requests (e.g., PRACK, ACK, UPDATE, re-INVITE, BYE) using the
* stored username and password.
*
* @sa @ref nua_call_model, #nua_r_invite, #nua_i_state, \n
* nua_handle_has_active_call() \n
@ -803,7 +924,7 @@ static int nua_session_client_response(nua_client_request_t *cr,
#define LOG3(m) \
SU_DEBUG_3(("nua(%p): %s: %s %s in %u %s\n", \
(void *)nh, cr->cr_method_name, (m), \
(void *)nh, cr->cr_method_name, (m), \
received ? received : "SDP", status, phrase))
#define LOG5(m) \
SU_DEBUG_5(("nua(%p): %s: %s %s in %u %s\n", \
@ -1445,7 +1566,7 @@ static int nua_session_usage_shutdown(nua_handle_t *nh,
break;
}
nua_dialog_usage_remove(nh, ds, du);
nua_dialog_usage_remove(nh, ds, du, NULL, NULL);
return 200;
}
@ -1652,11 +1773,7 @@ static int nua_prack_client_report(nua_client_request_t *cr,
status, phrase,
tags);
if (!ss || cr->cr_terminated || cr->cr_graceful)
return 1;
if (cr->cr_waiting)
/* Do not report call state change if restarting later */
if (!ss || cr->cr_terminated || cr->cr_graceful || cr->cr_waiting)
return 1;
if (cr->cr_offer_sent || cr->cr_answer_sent) {
@ -2231,9 +2348,12 @@ int nua_invite_server_report(nua_server_request_t *sr, tagi_t const *tags)
if (retval >= 2 || ss == NULL) {
/* Session has been terminated. */
if (!initial && !neutral)
if (!initial && !neutral) {
#if 0
signal_call_state_change(nh, NULL, status, phrase,
nua_callstate_terminated);
#endif
}
return retval;
}
@ -2628,9 +2748,11 @@ int nua_prack_server_report(nua_server_request_t *sr, tagi_t const *tags)
retval = nua_base_server_report(sr, tags), sr = NULL; /* destroys sr */
if (retval >= 2 || ss == NULL) {
#if 0
signal_call_state_change(nh, NULL,
status, phrase,
nua_callstate_terminated);
#endif
return retval;
}
@ -3155,11 +3277,7 @@ static int nua_update_client_report(nua_client_request_t *cr,
status, phrase,
tags);
if (!ss || cr->cr_terminated || cr->cr_graceful)
return 1;
if (cr->cr_waiting)
/* Do not report call state change if restarting later */
if (!ss || cr->cr_terminated || cr->cr_graceful || cr->cr_waiting)
return 1;
if (cr->cr_offer_sent) {
@ -3360,8 +3478,10 @@ int nua_update_server_report(nua_server_request_t *sr, tagi_t const *tags)
retval = nua_base_server_report(sr, tags), sr = NULL; /* destroys sr */
if (retval >= 2 || ss == NULL) {
#if 0
signal_call_state_change(nh, NULL, status, phrase,
nua_callstate_terminated);
#endif
return retval;
}
@ -3633,7 +3753,8 @@ int nua_bye_server_init(nua_server_request_t *sr)
int nua_bye_server_report(nua_server_request_t *sr, tagi_t const *tags)
{
nua_handle_t *nh = sr->sr_owner;
nua_session_usage_t *ss = nua_dialog_usage_private(sr->sr_usage);
nua_dialog_usage_t *du = sr->sr_usage;
nua_session_usage_t *ss = nua_dialog_usage_private(du);
int early = 0, retval;
if (sr->sr_status < 200)
@ -3645,7 +3766,11 @@ int nua_bye_server_report(nua_server_request_t *sr, tagi_t const *tags)
early = ss->ss_state < nua_callstate_ready;
phrase = early ? "Early Session Terminated" : "Session Terminated";
#if 0
sr->sr_usage = NULL;
#endif
for (sr0 = nh->nh_ds->ds_sr; sr0; sr0 = sr_next) {
sr_next = sr0->sr_next;
@ -3658,16 +3783,22 @@ int nua_bye_server_report(nua_server_request_t *sr, tagi_t const *tags)
}
nua_server_request_destroy(sr0);
}
sr->sr_phrase = phrase;
}
retval = nua_base_server_report(sr, tags);
assert(2 <= retval && retval < 4);
if (ss)
signal_call_state_change(nh, NULL, 200,
#if 0
if (ss) {
signal_call_state_change(nh, ss, 200,
early ? "Received early BYE" : "Received BYE",
nua_callstate_terminated);
nua_dialog_usage_remove(nh, nh->nh_ds, du);
}
#endif
return retval;
}
@ -3799,9 +3930,10 @@ static void signal_call_state_change(nua_handle_t *nh,
if (next_state == nua_callstate_init) {
if (ss_state < nua_callstate_ready)
ss->ss_state = next_state;
else
/* Do not change state - we are ready, terminating, or terminated */
next_state = ss_state;
else if (ss->ss_state == nua_callstate_ready)
next_state = ss->ss_state;
else
ss->ss_state = next_state = nua_callstate_terminated;
}
else if (next_state > ss_state)
ss->ss_state = next_state;

View File

@ -861,7 +861,7 @@ void nua_stack_shutdown(nua_t *nua)
for (nh = nua->nua_handles; nh; nh = nh_next) {
nh_next = nh->nh_next;
while (nh->nh_ds && nh->nh_ds->ds_usage) {
nua_dialog_usage_remove(nh, nh->nh_ds, nh->nh_ds->ds_usage);
nua_dialog_usage_remove(nh, nh->nh_ds, nh->nh_ds->ds_usage, NULL, NULL);
}
}
su_timer_destroy(nua->nua_timer), nua->nua_timer = NULL;
@ -1867,14 +1867,14 @@ int nua_base_server_report(nua_server_request_t *sr, tagi_t const *tags)
else
terminated = sip_response_terminates_dialog(status, sr->sr_method, NULL);
if (usage && terminated)
nua_dialog_usage_remove(nh, nh->nh_ds, usage, NULL, sr);
nua_server_request_destroy(sr);
if (!terminated)
return 1;
if (usage)
nua_dialog_usage_remove(nh, nh->nh_ds, usage);
if (!initial) {
if (terminated > 0)
return 2;
@ -2351,7 +2351,7 @@ msg_t *nua_client_request_template(nua_client_request_t *cr)
/** Restart the request message.
*
* A restarted request has not completed successfully.
* A restarted request has not been completed successfully.
*
* @retval 0 if request is pending
* @retval >=1 if error event has been sent
@ -2690,6 +2690,7 @@ int nua_client_response(nua_client_request_t *cr,
return 0;
cr->cr_status = status;
cr->cr_phrase = phrase;
if (status < 200) {
/* Xyzzy */
@ -2735,6 +2736,7 @@ int nua_client_response(nua_client_request_t *cr,
cr->cr_methods->crm_preliminary(cr, status, phrase, sip);
else
nua_base_client_response(cr, status, phrase, sip, NULL);
cr->cr_phrase = NULL;
return 0;
}
@ -2853,6 +2855,7 @@ int nua_base_client_check_restart(nua_client_request_t *cr,
cr->cr_waiting = cr->cr_wait_for_cred = 1;
nua_client_report(cr, status, phrase, NULL, orq, NULL);
nta_outgoing_destroy(orq);
cr->cr_status = 0, cr->cr_phrase = NULL;
return 1;
}
@ -2877,6 +2880,7 @@ int nua_base_client_check_restart(nua_client_request_t *cr,
cr->cr_waiting = cr->cr_wait_for_timer = 1;
nua_client_report(cr, 100, phrase, NULL, orq, NULL);
nta_outgoing_destroy(orq);
cr->cr_status = 0, cr->cr_phrase = NULL;
return 1;
}
@ -3065,7 +3069,7 @@ int nua_base_client_response(nua_client_request_t *cr,
if (cr->cr_terminated ||
(!du->du_ready && status >= 300 && nua_client_is_bound(cr))) {
/* Usage has been destroyed */
nua_dialog_usage_remove(nh, nh->nh_ds, du), cr->cr_usage = NULL;
nua_dialog_usage_remove(nh, nh->nh_ds, du, cr, NULL), cr->cr_usage = NULL;
}
else if (cr->cr_graceful) {
/* Terminate usage gracefully */
@ -3078,6 +3082,7 @@ int nua_base_client_response(nua_client_request_t *cr,
nua_dialog_remove(nh, nh->nh_ds, NULL), cr->cr_usage = NULL;
}
cr->cr_phrase = NULL;
cr->cr_reporting = 0, nh->nh_ds->ds_reporting = 0;
if (!nua_client_is_queued(cr) && !nua_client_is_bound(cr))

View File

@ -74,7 +74,9 @@ static int nua_subscribe_usage_add(nua_handle_t *nh,
nua_dialog_usage_t *du);
static void nua_subscribe_usage_remove(nua_handle_t *nh,
nua_dialog_state_t *ds,
nua_dialog_usage_t *du);
nua_dialog_usage_t *du,
nua_client_request_t *cr,
nua_server_request_t *sr);
static void nua_subscribe_usage_refresh(nua_handle_t *,
nua_dialog_state_t *,
nua_dialog_usage_t *,
@ -113,7 +115,9 @@ int nua_subscribe_usage_add(nua_handle_t *nh,
static
void nua_subscribe_usage_remove(nua_handle_t *nh,
nua_dialog_state_t *ds,
nua_dialog_usage_t *du)
nua_dialog_usage_t *du,
nua_client_request_t *cr,
nua_server_request_t *sr)
{
ds->ds_has_events--;
ds->ds_has_subscribes--;
@ -446,7 +450,7 @@ static void nua_subscribe_usage_refresh(nua_handle_t *nh,
NUTAG_SUBSTATE(nua_substate_terminated),
SIPTAG_EVENT(du->du_event),
TAG_END());
nua_dialog_usage_remove(nh, ds, du);
nua_dialog_usage_remove(nh, ds, du, NULL, NULL);
return;
}
@ -469,7 +473,7 @@ static void nua_subscribe_usage_refresh(nua_handle_t *nh,
SIPTAG_EVENT(du->du_event),
TAG_END());
nua_dialog_usage_remove(nh, ds, du);
nua_dialog_usage_remove(nh, ds, du, NULL, NULL);
}
/** Terminate subscription.
@ -492,7 +496,7 @@ static int nua_subscribe_usage_shutdown(nua_handle_t *nh,
return 0;
}
nua_dialog_usage_remove(nh, ds, du);
nua_dialog_usage_remove(nh, ds, du, NULL, NULL);
return 200;
}
@ -874,7 +878,7 @@ static int nua_refer_client_request(nua_client_request_t *cr,
}
if (du0)
nua_dialog_usage_remove(nh, nh->nh_ds, du0);
nua_dialog_usage_remove(nh, nh->nh_ds, du0, NULL, NULL);
eu = nua_dialog_usage_private(cr->cr_usage = du);
eu ->eu_refer = 1;

View File

@ -1269,7 +1269,8 @@ tag_typedef_t nutag_autoack = BOOLTAG_TYPEDEF(autoACK);
/**@def NUTAG_ENABLEINVITE(x)
*
* Enable incoming INVITE
* Enable incoming INVITE.
*
*
* @par Used with
* nua_set_params() \n
@ -2570,7 +2571,8 @@ tag_typedef_t nutag_path_enable = BOOLTAG_TYPEDEF(path_enable);
/**@def NUTAG_SERVICE_ROUTE_ENABLE(x)
*
* Use route from @ServiceRoute header in response to REGISTER.
* Use route taken from the @ServiceRoute header in the 200 class response
* to REGISTER.
*
* @par Used with
* - nua_create(), nua_set_params(), nua_get_params()