From bbb36378b259917b1ffde60252f7a32077d0252c Mon Sep 17 00:00:00 2001 From: Michael Jerris Date: Fri, 7 Mar 2008 17:41:29 +0000 Subject: [PATCH] * 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 --- .../libsofia-sip-ua/nua/nua_dialog.c | 27 +- .../libsofia-sip-ua/nua/nua_dialog.h | 14 +- .../libsofia-sip-ua/nua/nua_notifier.c | 20 +- .../libsofia-sip-ua/nua/nua_publish.c | 17 +- .../libsofia-sip-ua/nua/nua_register.c | 12 +- .../libsofia-sip-ua/nua/nua_session.c | 282 +++++++++++++----- .../sofia-sip/libsofia-sip-ua/nua/nua_stack.c | 17 +- .../libsofia-sip-ua/nua/nua_subnotref.c | 16 +- libs/sofia-sip/libsofia-sip-ua/nua/nua_tag.c | 6 +- 9 files changed, 290 insertions(+), 121 deletions(-) diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.c b/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.c index e52316bbd1..165eabc223 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.c +++ b/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.c @@ -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); diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.h b/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.h index 064c90d67e..6620810483 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.h +++ b/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.h @@ -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); diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_notifier.c b/libs/sofia-sip/libsofia-sip-ua/nua/nua_notifier.c index 35b59d16ed..a2b7a405cb 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_notifier.c +++ b/libs/sofia-sip/libsofia-sip-ua/nua/nua_notifier.c @@ -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; } diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_publish.c b/libs/sofia-sip/libsofia-sip-ua/nua/nua_publish.c index 9cd71c17bf..8b4331c508 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_publish.c +++ b/libs/sofia-sip/libsofia-sip-ua/nua/nua_publish.c @@ -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; } diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_register.c b/libs/sofia-sip/libsofia-sip-ua/nua/nua_register.c index 4afffb7a88..3d0b85f126 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_register.c +++ b/libs/sofia-sip/libsofia-sip-ua/nua/nua_register.c @@ -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; } diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c b/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c index 393f9e11e0..3fad0eb50c 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c +++ b/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c @@ -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 SIP session. + * + * 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 180 Ringing. 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 Media Session + * Handling 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 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; diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.c b/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.c index bc5e626277..a216fc447b 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.c +++ b/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.c @@ -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)) diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_subnotref.c b/libs/sofia-sip/libsofia-sip-ua/nua/nua_subnotref.c index 56d294dfe9..de3e5d4928 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_subnotref.c +++ b/libs/sofia-sip/libsofia-sip-ua/nua/nua_subnotref.c @@ -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; diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_tag.c b/libs/sofia-sip/libsofia-sip-ua/nua/nua_tag.c index cf40cd890f..3b7e3cb6aa 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_tag.c +++ b/libs/sofia-sip/libsofia-sip-ua/nua/nua_tag.c @@ -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()