📄 nua_session.c
字号:
/** Add timer featuretag and Session-Expires/Min-SE headers */static intuse_session_timer(nua_handle_t *nh, int uas, msg_t *msg, sip_t *sip){ struct nua_session_state *ss = nh->nh_ss; sip_min_se_t min_se[1]; sip_session_expires_t session_expires[1]; static sip_param_t const x_params_uac[] = {"refresher=uac", NULL}; static sip_param_t const x_params_uas[] = {"refresher=uas", NULL}; /* Session-Expires timer */ if ((NH_PGET(nh, refresher) == 0 && NH_PGET(nh, session_timer) == 0) || /* Is timer feature supported? */ !sip_has_supported(NH_PGET(nh, supported), "timer")) return 0; sip_min_se_init(min_se)->min_delta = ss->ss_min_se; sip_session_expires_init(session_expires)->x_delta = ss->ss_session_timer; if (ss->ss_refresher == nua_remote_refresher) session_expires->x_params = uas ? x_params_uac : x_params_uas; else if (ss->ss_refresher == nua_local_refresher) session_expires->x_params = uas ? x_params_uas : x_params_uac; sip_add_tl(msg, sip, TAG_IF(ss->ss_session_timer, SIPTAG_SESSION_EXPIRES(session_expires)), TAG_IF(ss->ss_min_se != 0 /* Min-SE: 0 is optional with initial INVITE */ || ss->ss_state != nua_callstate_init, SIPTAG_MIN_SE(min_se)), TAG_IF(ss->ss_refresher == nua_remote_refresher, SIPTAG_REQUIRE_STR("timer")), TAG_END()); return 1;}static intinit_session_timer(nua_handle_t *nh, sip_t const *sip){ struct nua_session_state *ss = nh->nh_ss; int server; ss->ss_refresher = nua_no_refresher; /* Check if we support the timer feature */ if (!sip->sip_session_expires || !sip_has_supported(NH_PGET(nh, supported), "timer")) { return 0; } ss->ss_session_timer = sip->sip_session_expires->x_delta; if (sip->sip_min_se != NULL && sip->sip_min_se->min_delta > ss->ss_min_se) ss->ss_min_se = sip->sip_min_se->min_delta; server = sip->sip_request != NULL; if (!str0casecmp("uac", sip->sip_session_expires->x_refresher)) ss->ss_refresher = server ? nua_remote_refresher : nua_local_refresher; else if (!str0casecmp("uas", sip->sip_session_expires->x_refresher)) ss->ss_refresher = server ? nua_local_refresher : nua_remote_refresher; else if (!server) return 0; /* XXX */ /* User preferences */ else if (nua_local_refresher == NH_PGET(nh, refresher)) ss->ss_refresher = nua_local_refresher; else ss->ss_refresher = nua_remote_refresher; return 0;}static voidset_session_timer(nua_handle_t *nh){ struct nua_session_state *ss = nh->nh_ss; nua_dialog_usage_t *du = ss->ss_usage; assert(du); if (du == NULL) ; else if (ss->ss_refresher == nua_local_refresher) { nua_dialog_usage_set_refresh(du, ss->ss_session_timer); du->du_pending = refresh_invite; /* Set timer */ } else if (ss->ss_refresher == nua_remote_refresher) { nua_dialog_usage_set_refresh(du, ss->ss_session_timer + 32); du->du_pending = session_timeout; /* Set timer */ } else { du->du_refresh = 0; du->du_pending = NULL; }}static intis_session_timer_set(nua_session_state_t *ss){ return ss->ss_usage && (ss->ss_usage->du_pending == refresh_invite || ss->ss_usage->du_pending == session_timeout);}/* ---------------------------------------------------------------------- *//* Automatic notifications from a referral */static intnh_referral_check(nua_handle_t *nh, tagi_t const *tags){ sip_event_t const *event = NULL; int pause = 1; struct nua_referral *ref = nh->nh_referral; nua_handle_t *ref_handle = ref->ref_handle; if (!ref_handle && tl_gets(tags, NUTAG_NOTIFY_REFER_REF(ref_handle), NUTAG_REFER_EVENT_REF(event), NUTAG_REFER_PAUSE_REF(pause), TAG_END()) == 0 && tl_gets(nh->nh_tags, NUTAG_NOTIFY_REFER_REF(ref_handle), NUTAG_REFER_EVENT_REF(event), NUTAG_REFER_PAUSE_REF(pause), TAG_END()) == 0) return 0; if (!ref_handle) return 0; /* Remove nh_referral and nh_notevent */ tl_tremove(nh->nh_tags, NUTAG_NOTIFY_REFER(ref_handle), TAG_IF(event, NUTAG_REFER_EVENT(event)), TAG_END()); if (event) ref->ref_event = sip_event_dup(nh->nh_home, event); if (!nh_validate(nh->nh_nua, ref_handle)) { SU_DEBUG_3(("nua: invalid NOTIFY_REFER handle\n")); return -1; } else if (!ref->ref_event) { SU_DEBUG_3(("nua: NOTIFY event missing\n")); return -1; } if (ref_handle != ref->ref_handle) { if (ref->ref_handle) nua_handle_unref(ref->ref_handle); ref->ref_handle = nua_handle_ref(ref_handle); }#if 0 if (pause) { /* Pause media on REFER handle */ nmedia_pause(nua, ref_handle->nh_nm, NULL); }#endif return 0;}static voidnh_referral_respond(nua_handle_t *nh, int status, char const *phrase){ char payload[128]; char const *substate; struct nua_referral *ref = nh->nh_referral; if (!nh_validate(nh->nh_nua, ref->ref_handle)) { if (ref) { if (ref->ref_handle) SU_DEBUG_1(("nh_handle_referral: stale referral handle %p\n", ref->ref_handle)); ref->ref_handle = NULL; } return; } /* XXX - we should have a policy here whether to send 101..199 */ assert(ref->ref_event); if (status >= 300) status = 503, phrase = sip_503_Service_unavailable; snprintf(payload, sizeof(payload), "SIP/2.0 %03u %s\r\n", status, phrase); if (status < 200) substate = "active"; else substate = "terminated ;reason=noresource"; nua_stack_post_signal(ref->ref_handle, nua_r_notify, SIPTAG_EVENT(ref->ref_event), SIPTAG_SUBSCRIPTION_STATE_STR(substate), SIPTAG_CONTENT_TYPE_STR("message/sipfrag"), SIPTAG_PAYLOAD_STR(payload), TAG_END()); if (status < 200) return; su_free(nh->nh_home, ref->ref_event), ref->ref_event = NULL; nua_handle_unref(ref->ref_handle), ref->ref_handle = NULL;}/** Zap the session associated with the handle */staticvoid nsession_destroy(nua_handle_t *nh){ struct nua_session_state *ss = nh->nh_ss; ss->ss_active = 0; ss->ss_state = nua_callstate_init; /* Remove usage */ if (ss->ss_usage) nua_dialog_usage_remove(nh, nh->nh_ds, ss->ss_usage); ss->ss_usage = 0; nh->nh_has_invite = 0; if (nh->nh_soa) soa_destroy(nh->nh_soa), nh->nh_soa = NULL; ss->ss_srequest->sr_respond = NULL; SU_DEBUG_5(("nua: terminated session %p\n", nh));}/* ======================================================================== *//* INFO */static int process_response_to_info(nua_handle_t *nh, nta_outgoing_t *orq, sip_t const *sip);intnua_stack_info(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *tags){ struct nua_client_request *cr = nh->nh_cr; msg_t *msg; if (nh_is_special(nh)) { return UA_EVENT2(e, 900, "Invalid handle for INFO"); } else if (cr->cr_orq) { return UA_EVENT2(e, 900, "Request already in progress"); } nua_stack_init_handle(nua, nh, nh_has_nothing, NULL, TAG_NEXT(tags)); msg = nua_creq_msg(nua, nh, cr, cr->cr_retry_count, SIP_METHOD_INFO , NUTAG_ADD_CONTACT(1), TAG_NEXT(tags)); cr->cr_orq = nta_outgoing_mcreate(nua->nua_nta, process_response_to_info, nh, NULL, msg, SIPTAG_END(), TAG_NEXT(tags)); if (!cr->cr_orq) { msg_destroy(msg); return UA_EVENT1(e, NUA_INTERNAL_ERROR); } return cr->cr_event = e;}void restart_info(nua_handle_t *nh, tagi_t *tags){ nua_creq_restart(nh, nh->nh_cr, process_response_to_info, tags);}static int process_response_to_info(nua_handle_t *nh, nta_outgoing_t *orq, sip_t const *sip){ if (nua_creq_check_restart(nh, nh->nh_cr, orq, sip, restart_info)) return 0; return nua_stack_process_response(nh, nh->nh_cr, orq, sip, TAG_END());}int nua_stack_process_info(nua_t *nua, nua_handle_t *nh, nta_incoming_t *irq, sip_t const *sip){ nua_stack_event(nh->nh_nua, nh, nta_incoming_getrequest(irq), nua_i_info, SIP_200_OK, TAG_END()); return 200; /* Respond automatically with 200 Ok */}/* ======================================================================== *//* UPDATE */static int process_response_to_update(nua_handle_t *nh, nta_outgoing_t *orq, sip_t const *sip);intnua_stack_update(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *tags){ struct nua_session_state *ss = nh->nh_ss; struct nua_client_request *cr = nh->nh_cr; struct nua_client_request *cri = ss->ss_crequest; struct nua_server_request *sri = ss->ss_srequest; msg_t *msg; sip_t *sip; char const *offer_sent = 0; if (!nh_has_session(nh)) return UA_EVENT2(e, 900, "Invalid handle for UPDATE"); else if (cr->cr_orq) return UA_EVENT2(e, 900, "Request already in progress"); nua_stack_init_handle(nua, nh, nh_has_nothing, NULL, TAG_NEXT(tags)); msg = nua_creq_msg(nua, nh, cr, cr->cr_retry_count, SIP_METHOD_UPDATE, NUTAG_USE_DIALOG(1), NUTAG_ADD_CONTACT(1), TAG_NEXT(tags)); sip = sip_object(msg); if (sip) { if (nh->nh_soa && !sip->sip_payload && !(cri->cr_offer_sent && !cri->cr_answer_recv) && !(cri->cr_offer_recv && !cri->cr_answer_sent) && !(sri->sr_offer_sent && !sri->sr_answer_recv) && !(sri->sr_offer_recv && !sri->sr_answer_sent)) { soa_init_offer_answer(nh->nh_soa); if (soa_generate_offer(nh->nh_soa, 0, NULL) < 0 || session_include_description(nh->nh_soa, msg, sip) < 0) { if (ss->ss_state < nua_callstate_ready) { /* XXX */ } msg_destroy(msg); return UA_EVENT2(e, 900, "Local media failed"); } offer_sent = "offer"; } if (is_session_timer_set(ss)) /* Add session timer headers */ use_session_timer(nh, 0, msg, sip); if (nh->nh_auth) { if (auc_authorize(&nh->nh_auth, msg, sip) < 0) /* xyzzy */; } cr->cr_orq = nta_outgoing_mcreate(nua->nua_nta, process_response_to_update, nh, NULL, msg, SIPTAG_END(), TAG_NEXT(tags)); if (cr->cr_orq) { if (offer_sent) cr->cr_offer_sent = 1; ss->ss_update_needed = 0; signal_call_state_change(nh, 0, "UPDATE sent", ss->ss_state, 0, offer_sent); return cr->cr_event = e; } } msg_destroy(msg); return UA_EVENT1(e, NUA_INTERNAL_ERROR);}void restart_update(nua_handle_t *nh, tagi_t *tags){ nua_creq_restart(nh, nh->nh_cr, process_response_to_update, tags);}static int process_response_to_update(nua_handle_t *nh, nta_outgoing_t *orq, sip_t const *sip){ nua_t *nua = nh->nh_nua; struct nua_session_state *ss = nh->nh_ss; struct nua_client_request *cr = nh->nh_cr; int status = sip->sip_status->st_status; char const *phrase = sip->sip_status->st_phrase; char const *recv = NULL; int terminate = 0, gracefully = 1; if (status >= 300) { if (sip->sip_retry_after) gracefully = 0; terminate = sip_response_terminates_dialog(status, sip_method_invite, &gracefully); if (!terminate && nua_creq_check_restart(nh, cr, orq, sip, restart_update)) { return 0; } /* XXX - if we have a concurrent INVITE, what we do with it? */ } else if (status >= 200) { /* XXX - check remote tag, handle forks */ /* Set (route), contact, (remote tag) */ nua_dialog_uac_route(nh, nh->nh_ds, sip, 1); nua_dialog_store_peer_info(nh, nh->nh_ds, sip); if (is_session_timer_set(ss)) { init_session_timer(nh, sip); set_session_timer(nh); } if (session_process_response(nh, cr, orq, sip, &recv) < 0) { nua_stack_event(nua, nh, NULL, nua_i_error, 400, "Bad Session Description", TAG_END()); } signal_call_state_change(nh, status, phrase, ss->ss_state, recv, 0); return 0; } else gracefully = 0; nua_stack_process_response(nh, cr, orq, sip, TAG_END()); if (terminate || gracefully) nh_referral_respond(nh, status, phrase); if (terminate) { signal_call_state_change(nh, status, phrase, nua_callstate_terminated, recv, 0); nsession_destroy(nh); } else if (gracefully) { signal_call_state_change(nh, status, phrase, nua_callstate_terminating, recv, 0);#if 0 if (nh->nh_ss->ss_crequest->cr_orq) nua_stack_post_signal(nh, nua_r_cancel, TAG_END()); else#endif nua_stack_post_signal(nh, nua_r_bye, TAG_END()); } return 0;}int nua_stack_process_update(nua_t *nua, nua_handle_t *nh, nta_incoming_t *irq, sip_t const *sip){ struct nua_session_state *ss = nh->nh_ss; nua_dialog_usage_t *du = ss->ss_usage; msg_t *msg = nta_incoming_getrequest(irq); char const *sdp; size_t len; int original_status = 200, status = 200;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -