📄 nua_session.c
字号:
/* * This file is part of the Sofia-SIP package * * Copyright (C) 2006 Nokia Corporation. * * Contact: Pekka Pessi <pekka.pessi@nokia.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * *//**@CFILE nua_session.c * @brief SIP session handling * * @author Pekka Pessi <Pekka.Pessi@nokia.com> * * @date Created: Wed Mar 8 16:17:27 EET 2006 ppessi */#include "config.h"#include <stddef.h>#include <stdlib.h>#include <string.h>#include <limits.h>#include <assert.h>#include <sofia-sip/string0.h>#include <sofia-sip/sip_protos.h>#include <sofia-sip/sip_status.h>#include <sofia-sip/sip_util.h>#include <sofia-sip/su_uniqueid.h>#define NTA_INCOMING_MAGIC_T struct nua_server_request#define NTA_OUTGOING_MAGIC_T struct nua_client_request#define NTA_RELIABLE_MAGIC_T struct nua_server_request#include "nua_stack.h"#include <sofia-sip/soa.h>#ifndef SDP_Htypedef struct sdp_session_s sdp_session_t;#endif/* ---------------------------------------------------------------------- *//** @enum nua_callstateThe states for SIP session established with INVITE.Initially the call states follow the state of the INVITE transaction. If theinitial INVITE transaction fails, the call is terminated. The status codes401 and 407 are an exception: if the client (on the left side in the diagrambelow) receives them, it enters in #nua_callstate_authenticating state.If a re-INVITE transaction fails, the result depends on the status code infailure. The call can return to the ready state, be terminated immediately,or be terminated gracefully. The proper action to take is determined withsip_response_terminates_dialog(). @sa @ref nua_call_model, #nua_i_state, nua_invite(), #nua_i_invite @par Session State Diagram @code +----------+ | |---------------------+ | Init | | | |----------+ | +----------+ | | | | | | --/INVITE| |INVITE/100 | | V V | | +----------+ +----------+ | | +--------| | | | | | | 18X +-| Calling | | Received | |INVITE/ | | /- | | | | | | /18X | | V +----------+ +----------+ V | | +----------+ | | | +----------+ | |---| | |2XX -/ | -/ | | | | | | Proceed- | | /- 2XX| 18X| | Early | |INVITE/ | | ing | | | +->| | | /200 | +----------+ V V +----------+ | | | +----------+ +----------+ | -/ | | 2XX| | | | |<--+ 2XX | | /-| | Complet- | | Complete |<-----------+ | +->| ing | | |------+ | +----------+ +----------+ | | | | | | |401,407/ -/ACK| |ACK/- |timeout/ | | /ACK V V | /BYE | | +----------+ | | | | | | | | +--| Ready | | | | | | | | | | | +----------+ | | | | | | | | BYE/ | |-/BYE | |BYE/ V /200 | V | |/200 +----------+ | +----------+ | | | | | | | | | |Authentic-| | | Terminat-|<----+ | | ating | | | ing | | +----------+ | +----------+ | | | | | |[23456]XX/- | | V | | +----------+ | | | | | +->|Terminated|<--------------+ | | +----------+ | V +----------+ | | | Init | | | +----------+@endcode */ /* ---------------------------------------------------------------------- *//* Session event usage *//** @internal @brief Session-related state. */typedef struct nua_session_usage{ enum nua_callstate ss_state; /**< Session status (enum nua_callstate) */ unsigned ss_100rel:1; /**< Use 100rel, send 183 */ unsigned ss_alerting:1; /**< 180 is sent/received */ unsigned ss_update_needed:2; /**< Send an UPDATE (do O/A if > 1) */ unsigned ss_precondition:1; /**< Precondition required */ unsigned ss_reporting:1; /**< True if reporting state */ unsigned : 0; struct session_timer { unsigned interval; /**< Negotiated expiration time */ enum nua_session_refresher refresher; /**< Our Negotiated role */ struct { unsigned expires, defaults; /**< Value of Session-Expires (delta) */ unsigned min_se; /**< Minimum session expires */ /** none, local or remote */ enum nua_session_refresher refresher; unsigned supported:1, require:1, :0; } local, remote; unsigned timer_set:1; /**< We have active session timer. */ } ss_timer[1]; char const *ss_reason; /**< Reason for termination. */ /* Offer-Answer status */ char const *ss_oa_recv, *ss_oa_sent;} nua_session_usage_t;static char const Offer[] = "offer", Answer[] = "answer";static char const *nua_session_usage_name(nua_dialog_usage_t const *du);static int nua_session_usage_add(nua_handle_t *nh, nua_dialog_state_t *ds, 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_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 *, sip_time_t now);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);static nua_usage_class const nua_session_usage[1] = { { sizeof (nua_session_usage_t), sizeof nua_session_usage, nua_session_usage_add, nua_session_usage_remove, nua_session_usage_name, nua_base_usage_update_params, NULL, nua_session_usage_refresh, nua_session_usage_shutdown }};static char const *nua_session_usage_name(nua_dialog_usage_t const *du){ return "session";}staticint nua_session_usage_add(nua_handle_t *nh, nua_dialog_state_t *ds, nua_dialog_usage_t *du){ nua_session_usage_t *ss = NUA_DIALOG_USAGE_PRIVATE(du); if (ds->ds_has_session) return -1; ds->ds_has_session = 1; ds->ds_got_session = 1; ss->ss_timer->local.refresher = nua_any_refresher; ss->ss_timer->remote.refresher = nua_any_refresher; return 0;}staticvoid nua_session_usage_remove(nua_handle_t *nh, 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; nua_server_request_t *sr; cr = du->du_cr; 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); ss->ss_reporting = 0; } /* Destroy queued INVITE transactions */ for (cr = ds->ds_cr; cr; cr = cr_next) { cr_next = cr->cr_next; if (cr->cr_method != sip_method_invite) continue; if (cr == cr0) continue; if (cr == du->du_cr && cr->cr_orq) continue; if (cr->cr_status < 200) { nua_stack_event(nh->nh_nua, nh, NULL, cr->cr_event, SIP_481_NO_TRANSACTION, NULL); } nua_client_request_destroy(cr); 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); } /* Application can respond to BYE after the session usage has terminated */ for (sr = ds->ds_sr; sr; sr = sr->sr_next) { if (sr->sr_usage == du && sr->sr_method == sip_method_bye) sr->sr_usage = NULL; } ds->ds_has_session = 0; nh->nh_has_invite = 0; nh->nh_active_call = 0; nh->nh_hold_remote = 0; if (nh->nh_soa) soa_destroy(nh->nh_soa), nh->nh_soa = NULL;}staticnua_dialog_usage_t *nua_dialog_usage_for_session(nua_dialog_state_t const *ds){ if (ds == ((nua_handle_t *)NULL)->nh_ds) return NULL; return nua_dialog_usage_get(ds, nua_session_usage, NULL);}staticnua_session_usage_t *nua_session_usage_for_dialog(nua_dialog_state_t const *ds){ nua_dialog_usage_t *du; if (ds == ((nua_handle_t *)NULL)->nh_ds) return NULL; du = nua_dialog_usage_get(ds, nua_session_usage, NULL); return (nua_session_usage_t *)nua_dialog_usage_private(du);}/** Zap the session associated with the handle */staticvoid 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), NULL, NULL); SU_DEBUG_5(("nua: terminated session %p\n", (void *)nh));}/* ======================================================================== *//* INVITE and call (session) processing */static int session_timer_is_supported(struct session_timer const *t);static void session_timer_preferences(struct session_timer *t, sip_t const *sip, sip_supported_t const *supported, unsigned expires, int isset, enum nua_session_refresher refresher, unsigned min_se);static void session_timer_store(struct session_timer *t, sip_t const *sip);static int session_timer_check_min_se(msg_t *msg, sip_t *sip, sip_t const *request, unsigned long min_se);static int session_timer_add_headers(struct session_timer *t, int initial, msg_t *msg, sip_t *sip);static void session_timer_negotiate(struct session_timer *t);static void session_timer_set(nua_session_usage_t *ss);static int session_timer_check_restart(nua_client_request_t *cr, int status, char const *phrase, sip_t const *sip);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);staticint session_get_description(sip_t const *sip, char const **return_sdp, size_t *return_len);staticint session_include_description(soa_session_t *soa, int session, msg_t *msg, sip_t *sip);staticint session_make_description(su_home_t *home, soa_session_t *soa, int session,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -