📄 nua_session.c
字号:
session_include_description(nh->nh_soa, msg, sip) < 0) { reason = soa_error_as_sip_reason(nh->nh_soa); status = 900, phrase = "Internal media error"; reason = "SIP;cause=500;text=\"Internal media error\""; } else { cr->cr_answer_sent = 1; soa_activate(nh->nh_soa, NULL); /* signal that O/A round is complete */ sent = "answer"; } } if (!reason && /* ss->ss_offer_sent && !ss->ss_answer_recv */ !soa_is_complete(nh->nh_soa)) { /* No SDP answer in 2XX response -> terminate call */ status = 988, phrase = "Incomplete offer/answer"; reason = "SIP;cause=488;text=\"Incomplete offer/answer\""; } } if (sip) ack = nta_outgoing_mcreate(nua->nua_nta, NULL, NULL, NULL, msg, SIPTAG_END(), TAG_NEXT(tags)); if (!ack) { if (!reason) { status = 900, phrase = "Cannot send ACK"; reason = "SIP;cause=500;text=\"Internal Error\""; } msg_destroy(msg); } nua_creq_deinit(cr, NULL); /* Destroy INVITE transaction */ nta_outgoing_destroy(ack); /* TR engine keeps this around for T2 */ if (status < 300) { signal_call_state_change(nh, status, phrase, nua_callstate_ready, received, sent); } else { signal_call_state_change(nh, status, phrase, nua_callstate_terminating, 0, 0); nua_stack_post_signal(nh, nua_r_bye, SIPTAG_REASON_STR(reason), TAG_END()); } return 0;}static intprocess_100rel(nua_handle_t *nh, nta_outgoing_t *orq, sip_t const *sip){ struct nua_session_state *ss = nh->nh_ss; struct nua_client_request *cr_invite = ss->ss_crequest; struct nua_client_request *cr_prack = nh->nh_cr; /* Reliable provisional response */ sip_content_disposition_t *cd = NULL; sip_content_type_t *ct = NULL; sip_payload_t *pl = NULL; nta_outgoing_t *prack; char const *recv = NULL, *sent = NULL; int status = 408; int offer_sent_in_prack = 0, answer_sent_in_prack = 0; su_home_t home[1] = { SU_HOME_INIT(home) }; if (cr_prack->cr_orq) { SU_DEBUG_3(("nua(%p): cannot send PRACK because %s is pending\n", nh, nta_outgoing_method_name(cr_prack->cr_orq))); return 0; /* We have to wait! */ } if (sip && sip->sip_status) status = sip->sip_status->st_status; if (!nua_dialog_is_established(nh->nh_ds)) { /* Tag the INVITE request */ nua_dialog_uac_route(nh, nh->nh_ds, sip, 1); nua_dialog_store_peer_info(nh, nh->nh_ds, sip); cr_invite->cr_orq = nta_outgoing_tagged(orq, process_response_to_invite, nh, sip->sip_to->a_tag, sip->sip_rseq); nta_outgoing_destroy(orq); orq = cr_invite->cr_orq; } if (session_process_response(nh, cr_invite, orq, sip, &recv) < 0) { /* XXX */ } else if (cr_invite->cr_offer_recv && !cr_invite->cr_answer_sent) { if (soa_generate_answer(nh->nh_soa, NULL) < 0 || session_make_description(home, nh->nh_soa, &cd, &ct, &pl) < 0) /* XXX */; else { answer_sent_in_prack = 1, sent = "answer"; soa_activate(nh->nh_soa, NULL); } } else if (ss->ss_precondition && status == 183) { /* XXX */ if (soa_generate_offer(nh->nh_soa, 0, NULL) < 0 || session_make_description(home, nh->nh_soa, &cd, &ct, &pl) < 0) /* XXX */; else offer_sent_in_prack = 1, sent = "offer"; } prack = nta_outgoing_prack(nh->nh_ds->ds_leg, orq, process_response_to_prack, nh, NULL, sip, SIPTAG_CONTENT_DISPOSITION(cd), SIPTAG_CONTENT_TYPE(ct), SIPTAG_PAYLOAD(pl), TAG_END()); if (prack) { cr_prack->cr_event = nua_r_prack; cr_prack->cr_orq = prack; if (answer_sent_in_prack) cr_invite->cr_answer_sent = 1; else if (offer_sent_in_prack) cr_prack->cr_offer_sent = 1; signal_call_state_change(nh, sip->sip_status->st_status, sip->sip_status->st_phrase, nua_callstate_proceeding, recv, sent); } else { /* XXX - call state? */ nua_stack_event(nh->nh_nua, nh, NULL, nua_i_error, 900, "Cannot PRACK", TAG_END()); } su_home_deinit(home); return 0;}static intprocess_response_to_prack(nua_handle_t *nh, nta_outgoing_t *orq, sip_t const *sip){ struct nua_client_request *cr = nh->nh_cr; int status; char const *phrase = "OK", *reason = NULL, *recv = NULL; if (sip) status = sip->sip_status->st_status, phrase = sip->sip_status->st_phrase; else status = 408, phrase = sip_408_Request_timeout; SU_DEBUG_5(("nua: process_response_to_prack: %u %s\n", status, phrase));#if 0 if (nua_creq_check_restart(nh, cr, orq, sip, restart_prack)) return 0;#endif if (status < 200) return 0; if (status < 300) { if (session_process_response(nh, cr, orq, sip, &recv) < 0) { status = 900, phrase = "Malformed Session in Response"; reason = "SIP;status=400;phrase=\"Malformed Session in Response\""; } } else nua_stack_process_response(nh, cr, orq, sip, TAG_END()); if (recv) signal_call_state_change(nh, status, phrase, nua_callstate_proceeding, recv, NULL); if (status < 300 && nh->nh_ss->ss_update_needed) nua_stack_update(nh->nh_nua, nh, nua_r_update, NULL); return 0;}staticchar const reason_timeout[] = "SIP;cause=408;text=\"Session timeout\"";void cancel_invite(nua_handle_t *nh, nua_dialog_usage_t *du, sip_time_t now){ static tagi_t const timeout_tags[] = { { siptag_reason_str, (tag_value_t)reason_timeout }, { NULL } }; signal_call_state_change(nh, 487, "Call Canceled", nua_callstate_init, NULL, NULL); nua_stack_cancel(nh->nh_nua, nh, nua_r_destroy, timeout_tags);}voidrefresh_invite(nua_handle_t *nh, nua_dialog_usage_t *du, sip_time_t now){ tagi_t tags[2] = {{ SIPTAG_SUBJECT_STR("Session refresh") }, { TAG_END() }}; if (now > 0 && NH_PGET(nh, update_refresh)) nua_stack_update(nh->nh_nua, nh, nua_r_update, tags); else if (now > 0) nua_stack_invite(nh->nh_nua, nh, nua_r_invite, tags); else session_timeout(nh, du, SIP_TIME_MAX);}static voidsession_timeout(nua_handle_t *nh, nua_dialog_usage_t *du, sip_time_t now){ if (now > 1) { signal_call_state_change(nh, 408, "Session Timeout", nua_callstate_terminating, NULL, NULL); nua_stack_post_signal(nh, nua_r_bye, SIPTAG_REASON_STR(reason_timeout), TAG_END()); }}/** Restart invite (e.g., after 302 or 407) */voidrestart_invite(nua_handle_t *nh, tagi_t *tags){ ua_invite2(nh->nh_nua, nh, nua_r_invite, 1, tags);}static int process_response_to_cancel(nua_handle_t *nh, nta_outgoing_t *orq, sip_t const *sip);/* CANCEL */intnua_stack_cancel(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *tags){ nua_session_state_t *ss = nh->nh_ss; nua_client_request_t *cri = ss->ss_crequest; nua_client_request_t *crc = nh->nh_cr; if (nh && cri->cr_orq && cri->cr_usage && cri->cr_usage->du_pending == cancel_invite) { nua_dialog_usage_t *du = cri->cr_usage; nta_outgoing_t *orq; du->du_pending = NULL; /* nh_referral_respond(nh, SIP_487_REQUEST_TERMINATED); */ if (e) orq = nta_outgoing_tcancel(cri->cr_orq, process_response_to_cancel, nh, TAG_NEXT(tags)); else orq = nta_outgoing_tcancel(cri->cr_orq, NULL, NULL, TAG_NEXT(tags)); if (orq == NULL) return nua_stack_event(nua, nh, NULL, e, 400, "Internal error", TAG_END()); if (e && crc->cr_orq == NULL) crc->cr_orq = orq, crc->cr_event = e; return 0; } return UA_EVENT2(e, 481, "No transaction to CANCEL");}static int process_response_to_cancel(nua_handle_t *nh, nta_outgoing_t *orq, sip_t const *sip){ return nua_stack_process_response(nh, nh->nh_cr, orq, sip, TAG_END());}/* ---------------------------------------------------------------------- *//* UAS side of INVITE */static void respond_to_invite(nua_t *nua, nua_handle_t *nh, int status, char const *phrase, tagi_t const *tags);static int process_invite1(nua_t *, nua_handle_t**, nta_incoming_t *, msg_t *, sip_t *), process_invite2(nua_t *, nua_handle_t *, nta_incoming_t *, sip_t *), process_prack(nua_handle_t *, nta_reliable_t *, nta_incoming_t *, sip_t const *), process_ack_or_cancel(nua_handle_t *, nta_incoming_t *, sip_t const *), process_ack(nua_handle_t *, nta_incoming_t *, sip_t const *), process_cancel(nua_handle_t *, nta_incoming_t *, sip_t const *), process_timeout(nua_handle_t *, nta_incoming_t *);/** @internal Process incoming INVITE. */int nua_stack_process_invite(nua_t *nua, nua_handle_t *nh0, nta_incoming_t *irq, sip_t const *sip){ nua_handle_t *nh = nh0; msg_t *msg = nta_incoming_getrequest(irq); int status; status = process_invite1(nua, &nh, irq, msg, (sip_t *)sip); if (status) { msg_destroy(msg); if (nh != nh0) nh_destroy(nua, nh); return status; } return process_invite2(nua, nh, irq, (sip_t *)sip);}/** @internal Preprocess incoming invite - sure we have a valid request. */staticint process_invite1(nua_t *nua, nua_handle_t **return_nh, nta_incoming_t *irq, msg_t *msg, sip_t *sip){ nua_handle_t *nh = *return_nh; nua_handle_t *dnh = nua->nua_dhandle, *nh0 = nh ? nh : dnh; nua_server_request_t *sr; int have_sdp; char const *sdp; size_t len; sip_user_agent_t const *user_agent = NH_PGET(nh0, user_agent);#if HAVE_SOFIA_SMIME int sm_status; sm_status = sm_decode_message(nua->sm, msg, sip); switch(sm_status) { case SM_SMIME_DISABLED: case SM_ERROR: nta_incoming_treply(irq, 493, "Undecipherable", TAG_END()); return 493; case SM_SUCCESS: break; default: break; }#endif if (nh0->nh_soa) { /* Make sure caller uses application/sdp without compression */ if (nta_check_session_content(irq, sip, nua->nua_invite_accept, SIPTAG_USER_AGENT(user_agent), SIPTAG_ACCEPT_ENCODING_STR(""), TAG_END())) return 415; /* Make sure caller accepts application/sdp */ if (nta_check_accept(irq, sip, nua->nua_invite_accept, NULL, SIPTAG_USER_AGENT(user_agent), SIPTAG_ACCEPT_ENCODING_STR(""), TAG_END())) return 406; } if (sip->sip_session_expires) { unsigned min_se = nh ? nh->nh_ss->ss_min_se : DNH_PGET(dnh, min_se); if (nta_check_session_expires(irq, sip, min_se, SIPTAG_USER_AGENT(user_agent), TAG_END())) return 500; /* respond with 500 Internal Server Error */ } if (!nh) { if (!DNH_PGET(dnh, invite_enable)) return 403; if (!(nh = nua_stack_incoming_handle(nua, irq, sip, nh_has_invite, 1))) return 500; } have_sdp = session_get_description(msg, sip, &sdp, &len); if (nh->nh_ss->ss_srequest->sr_irq /* XXX || (have_sdp && nh->nh_sr->sr_offer_recv) XXX */) { /* Overlapping invites - RFC 3261 14.2 */ sip_retry_after_t af[1]; /* Random delay of 0..10 seconds */ sip_retry_after_init(af)->af_delta = (unsigned)random() % 11U; af->af_comment = "Overlapping INVITE Request"; nta_incoming_treply(irq, 500, af->af_comment, SIPTAG_RETRY_AFTER(af), TAG_END()); return 500; } if (nh->nh_ss->ss_crequest->cr_orq || (have_sdp && nh->nh_cr->cr_orq && nh->nh_cr->cr_offer_sent)) { /* Glare - RFC 3261 14.2 and RFC 3311 section 5.2 */ nta_incoming_treply(irq, SIP_491_REQUEST_PENDING, TAG_END()); return 491; } *return_nh = nh; sr = nh->nh_ss->ss_srequest; memset(sr, 0, sizeof *sr); if (nh->nh_soa) { soa_init_offer_answer(nh->nh_soa); if (have_sdp) { if (soa_set_remote_sdp(nh->nh_soa, NULL, sdp, len) < 0) { SU_DEBUG_5(("nua(%p): error parsing SDP in INVITE\n", nh)); nta_incoming_treply(irq, 400, "Bad Session Description", TAG_END()); return 400; } sr->sr_offer_recv = 1; } } /** Add a dialog usage */ if (!nh->nh_ss->ss_usage) nh->nh_ss->ss_usage = nua_dialog_usage_add(nh, nh->nh_ds, nua_session_usage, NULL); if (!nh->nh_ss->ss_usage) { nta_incoming_treply(irq, SIP_500_INTERNAL_SERVER_ERROR, TAG_END()); return 500; } sr->sr_msg = msg; sr->sr_irq = irq; return 0;}/** @internal Process incoming invite - initiate media, etc. */staticint process_invite2(nua_t *nua, nua_handle_t *nh, nta_incoming_t *irq, sip_t *sip){ nua_session_state_t *ss = nh->nh_ss; nua_server_request_t *sr = ss->ss_srequest; ss->ss_100rel = NH_PGET(nh, early_media); ss->ss_precondition = sip_has_feature(sip->sip_require, "precondition"); if (ss->ss_precondition) ss->ss_100rel = 1; /* Session Timer negotiation */ init_session_timer(nh, sip); nua_dialog_uas_route(nh, nh->nh_ds, sip, 1); /* Set route and tags */ nta_incoming_bind(irq, process_ack_or_cancel, nh); assert(ss->ss_state >= nua_callstate_ready || ss->ss_state == nua_callstate_init); /* Magical value indicating autoanswer within respond_to_invite() */#define AUTOANSWER ((void*)-1) if (NH_PGET(nh, auto_answer) || /* Auto-answert to re-INVITE unless auto_answer is set to 0 */ (ss->ss_state == nua_callstate_ready &&
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -