📄 nua_session.c
字号:
char const *phrase = sip_200_OK; char const *offer_recv = NULL, *answer_sent = NULL; int do_timer = 0; msg_t *rmsg; sip_t *rsip; assert(nh); if (!du) { nua_dialog_state_t *ds = nh->nh_ds; /* No session for this dialog */ nta_incoming_treply(irq, SET_STATUS1(SIP_405_METHOD_NOT_ALLOWED), TAG_IF(ds->ds_has_subscribes, SIPTAG_ALLOW_STR("NOTIFY")), TAG_IF(ds->ds_has_notifys, SIPTAG_ALLOW_STR("SUBSCRIBE, REFER")), TAG_END()); } /* Do session timer negotiation if there is no ongoing INVITE transaction */ if (status < 300 && sip->sip_session_expires && is_session_timer_set(ss)) do_timer = 1, init_session_timer(nh, sip); if (status < 300 && nh->nh_soa && session_get_description(msg, sip, &sdp, &len)) { offer_recv = "offer"; if (soa_set_remote_sdp(nh->nh_soa, NULL, sdp, len) < 0) { SU_DEBUG_5(("nua(%p): error parsing SDP in UPDATE\n", nh)); msg_destroy(msg); status = soa_error_as_sip_response(nh->nh_soa, &phrase); offer_recv = NULL; } /* Respond to UPDATE */ else if (soa_generate_answer(nh->nh_soa, NULL) < 0) { SU_DEBUG_5(("nua(%p): error processing SDP in UPDATE\n", nh)); msg_destroy(msg); status = soa_error_as_sip_response(nh->nh_soa, &phrase); } else if (soa_activate(nh->nh_soa, NULL) < 0) { SU_DEBUG_5(("nua(%p): error activating media after %s\n", nh, "UPDATE")); /* XXX */ } else { answer_sent = "answer"; } } rmsg = nh_make_response(nua, nh, irq, status, phrase, TAG_IF(status < 300, NUTAG_ADD_CONTACT(1)), SIPTAG_SUPPORTED(NH_PGET(nh, supported)), TAG_NEXT(NULL)); rsip = sip_object(rmsg); assert(sip); /* XXX */ if (answer_sent && session_include_description(nh->nh_soa, rmsg, rsip) < 0) { status = 500, phrase = sip_500_Internal_server_error; answer_sent = NULL; } if (do_timer && 200 <= status && status < 300) { use_session_timer(nh, 1, rmsg, rsip); set_session_timer(nh); } if (status == original_status) { if (nta_incoming_mreply(irq, rmsg) < 0) status = 500, phrase = sip_500_Internal_server_error; } if (status != original_status) { nua_stack_event(nua, nh, NULL, nua_i_error, status, phrase, TAG_END()); nta_incoming_treply(irq, status, phrase, TAG_END()); msg_destroy(rmsg), rmsg = NULL; } nua_stack_event(nh->nh_nua, nh, msg, nua_i_update, status, phrase, TAG_END()); if (offer_recv || answer_sent) /* signal offer received, answer sent */ signal_call_state_change(nh, 200, "OK", ss->ss_state, offer_recv, answer_sent); if (NH_PGET(nh, auto_alert) && ss->ss_state < nua_callstate_ready && !ss->ss_alerting && ss->ss_precondition) respond_to_invite(nh->nh_nua, nh, SIP_180_RINGING, NULL); return status;}/* ======================================================================== *//* BYE */static int process_response_to_bye(nua_handle_t *nh, nta_outgoing_t *orq, sip_t const *sip);intnua_stack_bye(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 *cr = nh->nh_cr; nua_client_request_t *cr_invite = ss->ss_crequest; msg_t *msg; nta_outgoing_t *orq; if (nh_is_special(nh)) return UA_EVENT2(e, 900, "Invalid handle for BYE"); if (!nua_dialog_is_established(nh->nh_ds)) { if (cr_invite->cr_orq == NULL) return UA_EVENT2(e, 900, "No session to BYE"); /* No (early) dialog. BYE is invalid action, do CANCEL instead */ orq = nta_outgoing_tcancel(cr_invite->cr_orq, process_response_to_bye, nh, TAG_NEXT(tags)); if (!cr->cr_orq) cr->cr_orq = orq, cr->cr_event = e; return 0; } 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_BYE, TAG_NEXT(tags)); orq = nta_outgoing_mcreate(nua->nua_nta, process_response_to_bye, nh, NULL, msg, SIPTAG_END(), TAG_NEXT(tags)); ss->ss_state = nua_callstate_terminating; if (nh->nh_soa) soa_terminate(nh->nh_soa, 0); if (!orq) { msg_destroy(msg); UA_EVENT2(e, 400, "Internal error"); if (cr_invite->cr_orq == NULL) signal_call_state_change(nh, 400, "Failure sending BYE", nua_callstate_terminated, 0, 0); return 0; } if (cr->cr_orq == NULL) cr->cr_orq = orq, cr->cr_event = e; return 0;}void restart_bye(nua_handle_t *nh, tagi_t *tags){ nua_creq_restart(nh, nh->nh_cr, process_response_to_bye, tags);}static int process_response_to_bye(nua_handle_t *nh, nta_outgoing_t *orq, sip_t const *sip){ nua_session_state_t *ss = nh->nh_ss; nua_client_request_t *cr_invite = ss->ss_crequest; nua_client_request_t *cr = nh->nh_cr; int status = sip ? sip->sip_status->st_status : 400; if (nua_creq_check_restart(nh, cr, orq, sip, restart_bye)) return 0; nua_stack_process_response(nh, cr, orq, sip, TAG_END()); if (status >= 200 && cr_invite->cr_orq == NULL) { signal_call_state_change(nh, status, "to BYE", nua_callstate_terminated, 0, 0); nsession_destroy(nh); } return 0;}int nua_stack_process_bye(nua_t *nua, 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; int early = 0; assert(nh); nua_stack_event(nh->nh_nua, nh, nta_incoming_getrequest(irq), nua_i_bye, SIP_200_OK, TAG_END()); nta_incoming_treply(irq, SIP_200_OK, TAG_END()); nta_incoming_destroy(irq), irq = NULL; if (sr->sr_irq) { char const *phrase; early = ss->ss_state < nua_callstate_ready; phrase = early ? "Early Session Terminated" : "Session Terminated"; nta_incoming_treply(sr->sr_irq, 487, phrase, TAG_END()); nta_incoming_destroy(sr->sr_irq); memset(sr, 0, sizeof *sr); } nsession_destroy(nh); signal_call_state_change(nh, 200, early ? "Received early BYE" : "Received BYE", nua_callstate_terminated, 0, 0); return 200; /* Respond automatically with 200 Ok */}/* ---------------------------------------------------------------------- *//** * Delivers call state changed event to the nua client. * * @param nh call handle * @param status status code * @param tr_event SIP transaction event triggering this change * @param oa_recv Received SDP * @param oa_sent Sent SDP */static void signal_call_state_change(nua_handle_t *nh, int status, char const *phrase, enum nua_callstate next_state, char const *oa_recv, char const *oa_sent){ struct nua_session_state *ss = nh->nh_ss; nua_server_request_t *sr = ss->ss_srequest; enum nua_callstate ss_state = ss->ss_state; sdp_session_t const *remote_sdp = NULL; char const *remote_sdp_str = NULL; sdp_session_t const *local_sdp = NULL; char const *local_sdp_str = NULL; int offer_recv = 0, answer_recv = 0, offer_sent = 0, answer_sent = 0; if (ss_state != nua_callstate_ready || next_state > nua_callstate_ready) SU_DEBUG_5(("nua(%p): call state changed: %s -> %s%s%s%s%s\n", nh, nua_callstate_name(ss_state), nua_callstate_name(next_state), oa_recv ? ", received " : "", oa_recv ? oa_recv : "", oa_sent && oa_recv ? ", and sent " : oa_sent ? ", sent " : "", oa_sent ? oa_sent : "")); else SU_DEBUG_5(("nua(%p): ready call updated: %s%s%s%s%s\n", nh, nua_callstate_name(next_state), oa_recv ? " received " : "", oa_recv ? oa_recv : "", oa_sent && oa_recv ? ", sent " : oa_sent ? " sent " : "", oa_sent ? oa_sent : "")); if (oa_recv) { soa_get_remote_sdp(nh->nh_soa, &remote_sdp, &remote_sdp_str, 0); offer_recv = strcasecmp(oa_recv, "offer") == 0; answer_recv = strcasecmp(oa_recv, "answer") == 0; } if (oa_sent) { soa_get_local_sdp(nh->nh_soa, &local_sdp, &local_sdp_str, 0); offer_sent = strcasecmp(oa_sent, "offer") == 0; answer_sent = strcasecmp(oa_sent, "answer") == 0; } if (answer_recv || answer_sent) { /* Update ss->ss_hold_remote */ char const *held; soa_get_params(nh->nh_soa, SOATAG_HOLD_REF(held), TAG_END()); ss->ss_hold_remote = held && strlen(held) > 0; } (void)sr; /* Update state variables */ if (next_state > ss_state) ss->ss_state = next_state; else if (next_state == nua_callstate_init && ss_state < nua_callstate_ready) ss->ss_state = nua_callstate_init, next_state = nua_callstate_terminated; if (next_state == nua_callstate_ready) ss->ss_active = 1; else if (next_state == nua_callstate_terminated) ss->ss_active = 0; /* Send events */ if (phrase == NULL) phrase = "Call state"; nua_stack_event(nh->nh_nua, nh, NULL, nua_i_state, status, phrase, NUTAG_CALLSTATE(next_state), NH_ACTIVE_MEDIA_TAGS(1, nh->nh_soa), /* NUTAG_SOA_SESSION(nh->nh_soa), */ TAG_IF(offer_recv, NUTAG_OFFER_RECV(offer_recv)), TAG_IF(answer_recv, NUTAG_ANSWER_RECV(answer_recv)), TAG_IF(offer_sent, NUTAG_OFFER_SENT(offer_sent)), TAG_IF(answer_sent, NUTAG_ANSWER_SENT(answer_sent)), TAG_IF(oa_recv, SOATAG_REMOTE_SDP(remote_sdp)), TAG_IF(oa_recv, SOATAG_REMOTE_SDP_STR(remote_sdp_str)), TAG_IF(oa_sent, SOATAG_LOCAL_SDP(local_sdp)), TAG_IF(oa_sent, SOATAG_LOCAL_SDP_STR(local_sdp_str)), TAG_END()); if (next_state == nua_callstate_ready && ss_state <= nua_callstate_ready) { nua_stack_event(nh->nh_nua, nh, NULL, nua_i_active, status, "Call active", NH_ACTIVE_MEDIA_TAGS(1, nh->nh_soa), /* NUTAG_SOA_SESSION(nh->nh_soa), */ TAG_END()); } else if (next_state == nua_callstate_terminated) { nua_stack_event(nh->nh_nua, nh, NULL, nua_i_terminated, status, phrase, TAG_END()); }}/* ======================================================================== *//** Get SDP from a SIP message */staticint session_get_description(msg_t *msg, sip_t const *sip, char const **return_sdp, size_t *return_len){ sip_payload_t const *pl = sip->sip_payload; sip_content_type_t const *ct = sip->sip_content_type; int matching_content_type = 0; if (pl == NULL) return 0; else if (pl->pl_len == 0 || pl->pl_data == NULL) return 0; else if (ct == NULL) /* Be bug-compatible with our old gateways */ SU_DEBUG_3(("nua: no %s, assuming %s\n", "Content-Type", SDP_MIME_TYPE)); else if (ct->c_type == NULL) SU_DEBUG_3(("nua: empty %s, assuming %s\n", "Content-Type", SDP_MIME_TYPE)); else if (strcasecmp(ct->c_type, SDP_MIME_TYPE)) { SU_DEBUG_5(("nua: unknown %s: %s\n", "Content-Type", ct->c_type)); return 0; } else matching_content_type = 1; if (pl == NULL) return 0; if (!matching_content_type) { /* Make sure we got SDP */ if (pl->pl_len < 3 || strncasecmp(pl->pl_data, "v=0", 3)) return 0; } *return_sdp = pl->pl_data; *return_len = pl->pl_len; return 1;}/** Insert SDP into SIP message */staticint session_include_description(soa_session_t *soa, msg_t *msg, sip_t *sip){ su_home_t *home = msg_home(msg); sip_content_disposition_t *cd; sip_content_type_t *ct; sip_payload_t *pl; if (!soa) return 0; if (session_make_description(home, soa, &cd, &ct, &pl) < 0) return -1; if (pl == NULL || ct == NULL || cd == NULL || sip_header_insert(msg, sip, (sip_header_t *)cd) < 0 || sip_header_insert(msg, sip, (sip_header_t *)ct) < 0 || sip_header_insert(msg, sip, (sip_header_t *)pl) < 0) return -1; return 0;}/** Generate SDP headers */staticint session_make_description(su_home_t *home, soa_session_t *soa, sip_content_disposition_t **return_cd, sip_content_type_t **return_ct, sip_payload_t **return_pl){ char const *sdp; int len; if (!soa) return 0; if (soa_get_local_sdp(soa, 0, &sdp, &len) < 0) return -1; *return_pl = sip_payload_create(home, sdp, len); *return_ct = sip_content_type_make(home, SDP_MIME_TYPE); *return_cd = sip_content_disposition_make(home, "session"); return 0;}/** * Stores and processes SDP from incoming response, then calls * nua_stack_process_response(). * * @retval 1 if there was SDP to process. */staticint session_process_response(nua_handle_t *nh, struct nua_client_request *cr, nta_outgoing_t *orq, sip_t const *sip, char const **return_received){ char const *method = nta_outgoing_method_name(orq); msg_t *msg = nta_outgoing_getresponse(orq); int retval = 0; char const *sdp = NULL; size_t len; if (nh->nh_soa == NULL) /* Xyzzy */; else if (!session_get_description(msg, sip, &sdp, &len)) /* No SDP */; else if (cr->cr_answer_recv) { /* Ignore spurious answers after completing O/A */ SU_DEBUG_3(("nua(%p): %s: ignoring duplicate SDP in %u %s\n", nh, method, sip->sip_status->st_status, sip->sip_status->st_phrase)); sdp = NULL; } else if (!cr->cr_offer_sent && nta_outgoing_method(orq) != sip_method_invite) { /* If non-invite request did not have offer, ignore SDP in response */ SU_DEBUG_3(("nua(%p): %s: ignoring extra SDP in %u %s\n", nh, method, sip->sip_status->st_status, sip->sip_status->st_phrase)); sdp = NULL; } else { if (cr->cr_offer_sent) { cr->cr_answer_recv = sip->sip_status->st_status; *return_received = "answer"; } else { cr->cr_offer_recv = 1, cr->cr_answer_sent = 0; *return_received = "offer"; } if (soa_s
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -