Commit 61198fd7 authored by Pekka Pessi's avatar Pekka Pessi
Browse files

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.

darcs-hash:20080307163336-65a35-cd2e979af405323e2131c7c8dc662e0ab645bbac.gz
parent 62aac1fa
......@@ -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);
......
......@@ -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);
......
......@@ -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;
}
......
......@@ -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;
}
......
......@@ -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;
}
......
......@@ -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().
*
* 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
* 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.
*
* 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
}