📄 nua_session.c
字号:
ss->ss_reporting = 1; /* We report terminated state here if BYE fails */ error = nua_client_create(nh, nua_r_bye, &nua_bye_client_methods, NULL); ss->ss_reporting = 0; signal_call_state_change(nh, ss, 500, "Internal Error", error ? nua_callstate_terminated : nua_callstate_terminating); } else if (ss) signal_call_state_change(nh, ss, 200, "ACK sent", nua_callstate_ready); if (!nua_client_is_queued(cr) && !nua_client_is_bound(cr)) nua_client_request_destroy(cr); nua_client_next_request(nh->nh_ds->ds_cr, 1); return 0;}/** Send ACK, destroy INVITE transaction. * * @retval 1 if successful * @retval < 0 if an error occurred */staticint nua_invite_client_ack(nua_client_request_t *cr, tagi_t const *tags){ nua_handle_t *nh = cr->cr_owner; nua_dialog_state_t *ds = nh->nh_ds; nua_session_usage_t *ss = nua_dialog_usage_private(cr->cr_usage); msg_t *msg; sip_t *sip; int error = -1; sip_authorization_t *wa; sip_proxy_authorization_t *pa; sip_cseq_t *cseq; int proxy_is_set; url_string_t *proxy; nta_outgoing_t *ack; int status = 200; char const *phrase = "OK", *reason = NULL; char const *invite_branch; assert(cr->cr_orq); assert(cr->cr_method == sip_method_invite); if (!ds->ds_leg) { /* XXX - fix nua_dialog_usage_remove_at() instead! */ nta_outgoing_destroy(cr->cr_orq); return -1; } assert(ds->ds_leg); msg = nta_outgoing_getrequest(cr->cr_orq); sip = sip_object(msg); if (!msg) return -1; invite_branch = nta_outgoing_branch(cr->cr_orq); wa = sip_authorization(sip); pa = sip_proxy_authorization(sip); msg_destroy(msg); msg = nta_msg_create(nh->nh_nua->nua_nta, 0); sip = sip_object(msg); if (!msg) return -1; cseq = sip_cseq_create(msg_home(msg), cr->cr_seq, SIP_METHOD_ACK); if (!cseq) ; else if (nh->nh_tags && sip_add_tl(msg, sip, TAG_NEXT(nh->nh_tags)) < 0) ; else if (tags && sip_add_tl(msg, sip, TAG_NEXT(tags)) < 0) ; else if (wa && sip_add_dup(msg, sip, (sip_header_t *)wa) < 0) ; else if (pa && sip_add_dup(msg, sip, (sip_header_t *)pa) < 0) ; else if (sip_header_insert(msg, sip, (sip_header_t *)cseq) < 0) ; else if (nta_msg_request_complete(msg, ds->ds_leg, SIP_METHOD_ACK, NULL) < 0) ; else { /* Remove extra headers */ while (sip->sip_allow) sip_header_remove(msg, sip, (sip_header_t*)sip->sip_allow); while (sip->sip_priority) sip_header_remove(msg, sip, (sip_header_t*)sip->sip_priority); while (sip->sip_proxy_require) sip_header_remove(msg, sip, (sip_header_t*)sip->sip_proxy_require); while (sip->sip_require) sip_header_remove(msg, sip, (sip_header_t*)sip->sip_require); while (sip->sip_subject) sip_header_remove(msg, sip, (sip_header_t*)sip->sip_subject); while (sip->sip_supported) sip_header_remove(msg, sip, (sip_header_t*)sip->sip_supported); if (ss == NULL || ss->ss_state >= nua_callstate_ready) ; else if (cr->cr_offer_recv && !cr->cr_answer_sent) { if (nh->nh_soa == NULL) { if (session_get_description(sip, NULL, NULL)) cr->cr_answer_sent = 1, ss->ss_oa_sent = Answer; } else if (soa_generate_answer(nh->nh_soa, NULL) < 0 || session_include_description(nh->nh_soa, 1, msg, sip) < 0) { status = 900, phrase = "Internal media error"; reason = "SIP;cause=500;text=\"Internal media error\""; /* reason = soa_error_as_sip_reason(nh->nh_soa); */ } else { cr->cr_answer_sent = 1, ss->ss_oa_sent = Answer; } } if (ss == NULL || ss->ss_state >= nua_callstate_ready || reason) ; else if (nh->nh_soa && soa_is_complete(nh->nh_soa)) { /* signal SOA that O/A round(s) is (are) complete */ soa_activate(nh->nh_soa, NULL); } else if (nh->nh_soa == NULL /* NUA does not necessarily know dirty details */ /* && !(cr->cr_offer_sent && !cr->cr_answer_recv) */) { ; } else { nua_client_request_t *cru; /* Final response to UPDATE or PRACK may be on its way ... */ for (cru = ds->ds_cr; cru; cru = cru->cr_next) { if (cr != cru && cru->cr_offer_sent && !cru->cr_answer_recv) break; } if (cru == NULL) { /* No SDP answer -> terminate call */ status = 988, phrase = "Incomplete offer/answer"; reason = "SIP;cause=488;text=\"Incomplete offer/answer\""; } } proxy_is_set = NH_PISSET(nh, proxy); proxy = NH_PGET(nh, proxy); if ((ack = nta_outgoing_mcreate(nh->nh_nua->nua_nta, NULL, NULL, NULL, msg, NTATAG_ACK_BRANCH(invite_branch), TAG_IF(proxy_is_set, NTATAG_DEFAULT_PROXY(proxy)), SIPTAG_END(), TAG_NEXT(tags)))) { /* TR engine keeps this around for T2 so it catches all 2XX retransmissions */ nta_outgoing_destroy(ack); if (nh->nh_soa && reason && ss && ss->ss_state <= nua_callstate_ready) nua_stack_event(nh->nh_nua, nh, NULL, nua_i_media_error, status, phrase, NULL); } else if (!reason) { status = 900, phrase = "Cannot send ACK"; reason = "SIP;cause=500;text=\"Internal Error\""; } if (ss && reason) ss->ss_reason = reason; if (status < 300) error = 1; else error = -2; } if (error == -1) msg_destroy(msg); nta_outgoing_destroy(cr->cr_orq), cr->cr_orq = NULL; nua_client_request_remove(cr); return error;}/** Complete client request */static int nua_invite_client_complete(nua_client_request_t *cr){ if (cr->cr_orq == NULL) /* Xyzzy */; else if (cr->cr_status < 200) nta_outgoing_cancel(cr->cr_orq); else nua_invite_client_ack(cr, NULL); return 0;}/**@fn void nua_cancel(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...); * * Cancel an INVITE operation * * @param nh Pointer to operation handle * @param tag, value, ... List of tagged parameters * * @return * nothing * * @par Related Tags: * Header tags defined in <sofia-sip/sip_tag.h> * * @par Events: * #nua_r_cancel, #nua_i_state (#nua_i_active, #nua_i_terminated) * * @sa @ref nua_call_model, nua_invite(), #nua_i_cancel */static int nua_cancel_client_request(nua_client_request_t *cr, msg_t *msg, sip_t *sip, tagi_t const *tags);nua_client_methods_t const nua_cancel_client_methods = { SIP_METHOD_CANCEL, /* crm_method, crm_method_name */ 0, /* crm_extra */ { /* crm_flags */ /* create_dialog */ 0, /* in_dialog */ 1, /* target refresh */ 0 }, NULL, /* crm_template */ NULL, /* crm_init */ nua_cancel_client_request, /* crm_send */ NULL, /* crm_check_restart */ NULL, /* crm_recv */ NULL, /* crm_preliminary */ NULL, /* crm_report */ NULL, /* crm_complete */};int nua_stack_cancel(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *tags){ return nua_client_create(nh, e, &nua_cancel_client_methods, tags);}static int nua_cancel_client_request(nua_client_request_t *cr, msg_t *msg, sip_t *sip, tagi_t const *tags){ nua_handle_t *nh = cr->cr_owner; nua_dialog_usage_t *du = nua_dialog_usage_for_session(nh->nh_ds); if (!du || !du->du_cr || !du->du_cr->cr_orq || nta_outgoing_status(du->du_cr->cr_orq) >= 200) { return nua_client_return(cr, 481, "No transaction to CANCEL", msg); } cr->cr_orq = nta_outgoing_tcancel(du->du_cr->cr_orq, nua_client_orq_response, cr, TAG_NEXT(tags)); return cr->cr_orq ? 0 : -1;}/** @NUA_EVENT nua_r_cancel * * Answer to outgoing CANCEL. * * The CANCEL may be sent explicitly by nua_cancel() or implicitly by NUA * state machine. * * @param status response status code * @param phrase a short textual description of @a status code * @param nh operation handle associated with the call * @param hmagic application context associated with the call * @param sip response to CANCEL request or NULL upon an error * (status code is in @a status and * descriptive message in @a phrase parameters) * @param tags empty * * @sa nua_cancel(), @ref nua_uac_call_model, #nua_r_invite, nua_invite(), * #nua_i_state * * @END_NUA_EVENT */static void nua_session_usage_refresh(nua_handle_t *nh, nua_dialog_state_t *ds, nua_dialog_usage_t *du, sip_time_t now){ nua_session_usage_t *ss = NUA_DIALOG_USAGE_PRIVATE(du); nua_client_request_t const *cr = du->du_cr; nua_server_request_t const *sr; if (ss->ss_state >= nua_callstate_terminating || /* INVITE is in progress or being authenticated */ (cr && (cr->cr_orq || cr->cr_wait_for_cred))) return; /* UPDATE has been queued */ for (cr = ds->ds_cr; cr; cr = cr->cr_next) if (cr->cr_method == sip_method_update) return; /* INVITE or UPDATE in progress on server side */ for (sr = ds->ds_sr; sr; sr = sr->sr_next) if (sr->sr_usage == du && (sr->sr_method == sip_method_invite || sr->sr_method == sip_method_update)) return; if (ss->ss_timer->refresher == nua_remote_refresher) { ss->ss_reason = "SIP;cause=408;text=\"Session timeout\""; nua_stack_bye(nh->nh_nua, nh, nua_r_bye, NULL); return; } else if (NH_PGET(nh, update_refresh)) { nua_stack_update(nh->nh_nua, nh, nua_r_update, NULL); } else if (du->du_cr) { nua_client_resend_request(du->du_cr, 0); } else { nua_stack_invite(nh->nh_nua, nh, nua_r_invite, NULL); }}/** @interal Shut down session usage. * * @retval >0 shutdown done * @retval 0 shutdown in progress * @retval <0 try again later */static int nua_session_usage_shutdown(nua_handle_t *nh, nua_dialog_state_t *ds, nua_dialog_usage_t *du){ nua_session_usage_t *ss = NUA_DIALOG_USAGE_PRIVATE(du); nua_server_request_t *sr, *sr_next; nua_client_request_t *cri; assert(ss == nua_session_usage_for_dialog(nh->nh_ds)); /* Zap server-side transactions */ for (sr = ds->ds_sr; sr; sr = sr_next) { sr_next = sr->sr_next; if (sr->sr_usage == du) { assert(sr->sr_usage == du); sr->sr_usage = NULL; if (nua_server_request_is_pending(sr)) { SR_STATUS1(sr, SIP_480_TEMPORARILY_UNAVAILABLE); nua_server_respond(sr, NULL); if (nua_server_report(sr) >= 2) return 480; } else nua_server_request_destroy(sr); } } cri = du->du_cr; switch (ss->ss_state) { case nua_callstate_calling: case nua_callstate_proceeding: return nua_client_create(nh, nua_r_cancel, &nua_cancel_client_methods, NULL); case nua_callstate_completing: case nua_callstate_completed: case nua_callstate_ready: if (cri && cri->cr_orq) { if (cri->cr_status < 200) nua_client_create(nh, nua_r_cancel, &nua_cancel_client_methods, NULL); else if (cri->cr_status < 300) nua_invite_client_ack(cri, NULL); } if (nua_client_create(nh, nua_r_bye, &nua_bye_client_methods, NULL) != 0) break; signal_call_state_change(nh, ss, 487, "BYE sent", nua_callstate_terminating); return 0; case nua_callstate_terminating: case nua_callstate_terminated: /* XXX */ return 0; default: break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -