📄 nua_session.c
字号:
!NH_PISSET(nh, auto_answer))) { respond_to_invite(nua, nh, SIP_200_OK, AUTOANSWER); return 0; } ss->ss_srequest->sr_respond = respond_to_invite; if (NH_PGET(nh, auto_alert)) { if (ss->ss_100rel && (sip_has_feature(nh->nh_ds->ds_remote_ua->nr_supported, "100rel") || sip_has_feature(nh->nh_ds->ds_remote_ua->nr_require, "100rel"))) { respond_to_invite(nua, nh, SIP_183_SESSION_PROGRESS, AUTOANSWER); } else { respond_to_invite(nua, nh, SIP_180_RINGING, AUTOANSWER); } } else { nta_incoming_treply(irq, SIP_100_TRYING, TAG_END()); nua_stack_event(nh->nh_nua, nh, sr->sr_msg, nua_i_invite, SIP_100_TRYING, NH_ACTIVE_MEDIA_TAGS(1, nh->nh_soa), TAG_END()); sr->sr_msg = NULL; signal_call_state_change(nh, SIP_100_TRYING, nua_callstate_received, sr->sr_offer_recv ? "offer" : 0, 0); } return 0;}/** @internal Respond to an INVITE request. * * XXX - use tags to indicate when to use reliable responses. * XXX - change prototype. */staticvoid respond_to_invite(nua_t *nua, nua_handle_t *nh, int status, char const *phrase, tagi_t const *tags){ su_home_t home[1] = { SU_HOME_INIT(home) }; msg_t *msg; sip_t *sip; int reliable; int original_status = status; sip_warning_t *warning = NULL; nua_dialog_state_t *ds = nh->nh_ds; nua_session_state_t *ss = nh->nh_ss; nua_server_request_t *sr = ss->ss_srequest; int autoanswer = 0, offer = 0, answer = 0; enter; if (ss->ss_srequest->sr_irq == NULL || nta_incoming_status(ss->ss_srequest->sr_irq) >= 200) { nua_stack_event(nh->nh_nua, nh, NULL, nua_i_error, 900, "No INVITE request to response", TAG_END()); return; } if (tags == AUTOANSWER) autoanswer = 1, tags = NULL; assert(ss->ss_usage); if (nh->nh_soa) soa_set_params(nh->nh_soa, TAG_NEXT(tags)); reliable = (status >= 200) || (status > 100 && ds->ds_remote_ua->nr_require && sip_has_feature(ds->ds_remote_ua->nr_require, "100rel")) || (status > 100 && !NH_PGET(nh, only183_100rel) && (NH_PGET(nh, early_media) || (ds->ds_remote_ua->nr_require && sip_has_feature(ds->ds_remote_ua->nr_require, "precondition"))) && ds->ds_remote_ua->nr_supported && sip_has_feature(ds->ds_remote_ua->nr_supported, "100rel")) || (status == 183 && ds->ds_remote_ua->nr_supported && sip_has_feature(ds->ds_remote_ua->nr_supported, "100rel")) || (status == 183 && ds->ds_remote_ua->nr_require && sip_has_feature(ds->ds_remote_ua->nr_require, "precondition")) || (status > 100 && ds->ds_remote_ua->nr_require && sip_has_feature(ds->ds_remote_ua->nr_require, "precondition") && sr->sr_offer_recv && !sr->sr_answer_sent); msg = nh_make_response(nua, nh, ss->ss_srequest->sr_irq, status, phrase, TAG_IF(status < 300, NUTAG_ADD_CONTACT(1)), SIPTAG_SUPPORTED(NH_PGET(nh, supported)), TAG_NEXT(tags)); sip = sip_object(msg); assert(sip); /* XXX */ if (!nh->nh_soa) /* Xyzzy */; else if (status >= 300) { soa_clear_remote_sdp(nh->nh_soa); } else if (status >= 200 || ss->ss_100rel) { if ((sr->sr_offer_recv && sr->sr_answer_sent) || (sr->sr_offer_sent && !sr->sr_answer_recv)) /* Nothing to do */; else if (sr->sr_offer_recv && !sr->sr_answer_sent) { if (soa_generate_answer(nh->nh_soa, NULL) < 0) { int wcode; char const *text; char const *host = "invalid."; status = soa_error_as_sip_response(nh->nh_soa, &phrase); wcode = soa_get_warning(nh->nh_soa, &text); if (wcode) { if (sip->sip_contact) host = sip->sip_contact->m_url->url_host; warning = sip_warning_format(home, "%u %s \"%s\"", wcode, host, text); } } else { answer = 1; soa_activate(nh->nh_soa, NULL); /* signal that O/A answer sent (answer to invite) */ } } else if (!sr->sr_offer_recv && !sr->sr_offer_sent) { if (soa_generate_offer(nh->nh_soa, 0, NULL) < 0) status = soa_error_as_sip_response(nh->nh_soa, &phrase); else offer = 1; } if (offer || answer) { if (session_include_description(nh->nh_soa, msg, sip) < 0) SET_STATUS1(SIP_500_INTERNAL_SERVER_ERROR); } } if (ss->ss_refresher && 200 <= status && status < 300) use_session_timer(nh, 1, msg, sip);#if HAVE_SOFIA_SMIME if (nua->sm->sm_enable && sdp) { int sm_status; sm_status = sm_encode_message(nua->sm, msg, sip, SM_ID_NULL); switch (sm_status) { case SM_SUCCESS: break; case SM_ERROR: status = 500, phrase = "S/MIME processing error"; break; case SM_CERT_NOTFOUND: case SM_CERTFILE_NOTFOUND: status = 500, phrase = "S/MIME certificate error"; break; } }#endif if (reliable && status < 200) { nta_reliable_t *rel; rel = nta_reliable_mreply(ss->ss_srequest->sr_irq, process_prack, nh, msg); if (!rel) SET_STATUS1(SIP_500_INTERNAL_SERVER_ERROR); } if (reliable && status < 200) /* we are done */; else if (status != original_status) { /* Error responding */ assert(status >= 200); ss->ss_srequest->sr_respond = NULL; nta_incoming_treply(ss->ss_srequest->sr_irq, status, phrase, SIPTAG_WARNING(warning), TAG_END()); msg_destroy(msg), msg = NULL; } else { if (status >= 200) ss->ss_srequest->sr_respond = NULL; nta_incoming_mreply(ss->ss_srequest->sr_irq, msg); } if (autoanswer) { nua_stack_event(nh->nh_nua, nh, sr->sr_msg, nua_i_invite, status, phrase, NH_ACTIVE_MEDIA_TAGS(1, nh->nh_soa), TAG_END()); sr->sr_msg = NULL; } else if (status != original_status) nua_stack_event(nua, nh, NULL, nua_i_error, status, phrase, TAG_END()); if (status >= 300) offer = 0, answer = 0; if (offer) sr->sr_offer_sent = 1; else if (answer) sr->sr_answer_sent = 1 + reliable; /* Update session state */ assert(ss->ss_state != nua_callstate_calling); assert(ss->ss_state != nua_callstate_proceeding); signal_call_state_change(nh, status, phrase, status >= 300 ? nua_callstate_init : status >= 200 ? nua_callstate_completed : nua_callstate_early, autoanswer && sr->sr_offer_recv ? "offer" : 0, offer ? "offer" : answer ? "answer" : 0); if (status == 180) ss->ss_alerting = 1; else if (status >= 200) ss->ss_alerting = 0; if (status >= 200) { ss->ss_usage->du_ready = 1; } if (status >= 300) { if (nh->nh_soa) soa_init_offer_answer(nh->nh_soa); nta_incoming_destroy(ss->ss_srequest->sr_irq); ss->ss_srequest->sr_irq = NULL; ss->ss_srequest->sr_respond = NULL; } su_home_deinit(home); if (ss->ss_state == nua_callstate_init) nsession_destroy(nh);}/** @internal Process ACK or CANCEL or timeout (no ACK) for incoming INVITE */staticint process_ack_or_cancel(nua_handle_t *nh, nta_incoming_t *irq, sip_t const *sip){ int retval; nua_server_request_t *sr = nh->nh_ss->ss_srequest; enter; if (sip && sip->sip_request->rq_method == sip_method_ack) retval = process_ack(nh, irq, sip); else if (sip && sip->sip_request->rq_method == sip_method_cancel) retval = process_cancel(nh, irq, sip); else retval = process_timeout(nh, irq); assert(sr->sr_irq == irq); nta_incoming_destroy(sr->sr_irq); memset(sr, 0, sizeof *sr); return retval;}/** @internal Process PRACK or (timeout from 100rel) */staticint process_prack(nua_handle_t *nh, nta_reliable_t *rel, nta_incoming_t *irq, sip_t const *sip){ struct nua_session_state *ss = nh->nh_ss; nua_server_request_t *sr = ss->ss_srequest; int status = 200; char const *phrase = sip_200_OK; char const *recv = NULL, *sent = NULL; nta_reliable_destroy(rel); if (!sr->sr_irq) /* XXX */ return 481; if (sip) /* received PRACK */; else if (sr->sr_respond == NULL) { /* Final response interrupted 100rel */ /* Ignore */ return 200; } else if (sip == NULL) { SET_STATUS(504, "Reliable Response Timeout"); respond_to_invite(nh->nh_nua, nh, status, phrase, NULL); nua_stack_event(nh->nh_nua, nh, NULL, nua_i_error, status, phrase, TAG_END()); return status; } if (nh->nh_soa) { msg_t *msg = nta_incoming_getrequest(irq); char const *sdp; size_t len; if (session_get_description(msg, sip, &sdp, &len)) { su_home_t home[1] = { SU_HOME_INIT(home) }; sip_content_disposition_t *cd = NULL; sip_content_type_t *ct = NULL; sip_payload_t *pl = NULL; if (soa_set_remote_sdp(nh->nh_soa, NULL, sdp, len) < 0) { SU_DEBUG_5(("nua(%p): error parsing SDP in INVITE\n", nh)); msg_destroy(msg); status = 400, phrase = "Bad Session Description"; } /* Respond to PRACK */ if (status >= 300) ; else if (sr->sr_offer_sent) { recv = "answer"; sr->sr_answer_recv = 1; if (soa_process_answer(nh->nh_soa, NULL) < 0) status = soa_error_as_sip_response(nh->nh_soa, &phrase); } else { recv = "offer"; if (soa_generate_answer(nh->nh_soa, NULL) < 0) { status = soa_error_as_sip_response(nh->nh_soa, &phrase); } else { session_make_description(home, nh->nh_soa, &cd, &ct, &pl); sent = "answer"; } } if (nta_incoming_treply(irq, status, phrase, SIPTAG_CONTENT_DISPOSITION(cd), SIPTAG_CONTENT_TYPE(ct), SIPTAG_PAYLOAD(pl), TAG_END()) < 0) /* Respond with 500 if nta_incoming_treply() failed */ SET_STATUS1(SIP_500_INTERNAL_SERVER_ERROR); su_home_deinit(home); } msg_destroy(msg); } nua_stack_event(nh->nh_nua, nh, nta_incoming_getrequest(irq), nua_i_prack, status, phrase, TAG_END()); if (status < 300 && (recv || sent)) { soa_activate(nh->nh_soa, NULL); signal_call_state_change(nh, status, phrase, nua_callstate_early, recv, sent); } if (status < 300 && NH_PGET(nh, auto_alert) && !ss->ss_alerting && !ss->ss_precondition) respond_to_invite(nh->nh_nua, nh, SIP_180_RINGING, NULL); return status;}int process_ack(nua_handle_t *nh, nta_incoming_t *irq, sip_t const *sip){ struct nua_session_state *ss = nh->nh_ss; nua_server_request_t *sr = ss->ss_srequest; msg_t *msg = nta_incoming_getrequest_ackcancel(irq); char const *recv = NULL; if (nh->nh_soa && sr->sr_offer_sent && !sr->sr_answer_recv) { char const *sdp; size_t len; if (!session_get_description(msg, sip, &sdp, &len) || !(recv = "answer") || soa_set_remote_sdp(nh->nh_soa, NULL, sdp, len) < 0 || soa_process_answer(nh->nh_soa, NULL) < 0 || soa_activate(nh->nh_soa, NULL)) { int status; char const *phrase, *reason; status = soa_error_as_sip_response(nh->nh_soa, &phrase); reason = soa_error_as_sip_reason(nh->nh_soa); nua_stack_event(nh->nh_nua, nh, msg, nua_i_ack, status, phrase, TAG_END()); nua_stack_event(nh->nh_nua, nh, NULL, nua_i_media_error, status, phrase, TAG_END()); signal_call_state_change(nh, 488, "Offer-Answer Error", nua_callstate_terminating, recv, 0); nua_stack_post_signal(nh, nua_r_bye, SIPTAG_REASON_STR(reason), TAG_END()); return 0; } } soa_clear_remote_sdp(nh->nh_soa); nua_stack_event(nh->nh_nua, nh, msg, nua_i_ack, SIP_200_OK, TAG_END()); signal_call_state_change(nh, 200, "OK", nua_callstate_ready, recv, 0); set_session_timer(nh); return 0;}/* CANCEL */staticint process_cancel(nua_handle_t *nh, nta_incoming_t *irq, sip_t const *sip){ struct nua_session_state *ss = nh->nh_ss; msg_t *msg = nta_incoming_getrequest_ackcancel(irq); nua_stack_event(nh->nh_nua, nh, msg, nua_i_cancel, SIP_200_OK, TAG_END()); signal_call_state_change(nh, 0, "Received CANCEL", nua_callstate_init, 0, 0); if (nh->nh_soa && ss->ss_state < nua_callstate_ready) { soa_terminate(nh->nh_soa, NULL); nsession_destroy(nh); } return 0;}/* Timeout (no ACK or PRACK received) */staticint process_timeout(nua_handle_t *nh, nta_incoming_t *irq){ struct nua_session_state *ss = nh->nh_ss; nua_stack_event(nh->nh_nua, nh, 0, nua_i_error, 408, "Response timeout", TAG_END()); soa_terminate(nh->nh_soa, NULL); if (ss->ss_state == nua_callstate_ready) { /* send BYE if 200 OK (or 183 to re-INVITE) timeouts */ signal_call_state_change(nh, 0, "Timeout", nua_callstate_terminating, 0, 0); nua_stack_post_signal(nh, nua_r_bye, SIPTAG_REASON_STR("SIP;cause=408;text=\"ACK Timeout\""), TAG_END()); } else { nta_incoming_treply(irq, SIP_504_GATEWAY_TIME_OUT, SIPTAG_REASON_STR("SIP;cause=504;" "text=\"PRACK Timeout\""), TAG_END()); signal_call_state_change(nh, 0, "Timeout", nua_callstate_init, 0, 0); } return 0;}/* ---------------------------------------------------------------------- *//* Session timer */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -