📄 nua_stack.c
字号:
if (!ds->ds_remote) ds->ds_remote = sip_to_dup(nh->nh_home, sip->sip_to); if (!ds->ds_local) ds->ds_local = sip_from_dup(nh->nh_home, sip->sip_from); if (copy) { cr->cr_msg = msg; msg = msg_copy(msg); } } return msg; error: ta_end(ta); msg_destroy(msg); return NULL;}/**@internal * Create a response message. * * @param nua * @param nh * @param irq * @param status * @param phrase * @param tag, value, ... list of tag-value pairs */msg_t *nh_make_response(nua_t *nua, nua_handle_t *nh, nta_incoming_t *irq, int status, char const *phrase, tag_type_t tag, tag_value_t value, ...){ ta_list ta; msg_t *msg = nta_msg_create(nua->nua_nta, 0); sip_t *sip = sip_object(msg); tagi_t const *t; ta_start(ta, tag, value); if (!msg) return NULL; else if (nta_msg_response_complete(msg, irq, status, phrase) < 0) msg_destroy(msg); else if (sip_add_tl(msg, sip, ta_tags(ta)) < 0) msg_destroy(msg); else if (sip_complete_message(msg) < 0) msg_destroy(msg); else if (!sip->sip_supported && NH_PGET(nh, supported) && sip_add_dup(msg, sip, (sip_header_t *)NH_PGET(nh, supported)) < 0) msg_destroy(msg); else if (!sip->sip_user_agent && NH_PGET(nh, user_agent) && sip_add_dup(msg, sip, (sip_header_t *)NH_PGET(nh, user_agent)) < 0) msg_destroy(msg); else if (!sip->sip_organization && NH_PGET(nh, organization) && sip_add_dup(msg, sip, (sip_header_t *)NH_PGET(nh, organization)) < 0) msg_destroy(msg); else if (!sip->sip_allow && NH_PGET(nh, allow) && sip_add_dup(msg, sip, (sip_header_t*)NH_PGET(nh, allow)) < 0) msg_destroy(msg); else if (!sip->sip_contact && (t = tl_find(ta_args(ta), _nutag_add_contact)) && nua_registration_add_contact(nh, msg, sip, t->t_value, 0) < 0) msg_destroy(msg); else return msg; return NULL;}/* ======================================================================== *//* Generic processing */int nua_stack_process_unknown(nua_t *nua, nua_handle_t *nh, nta_incoming_t *irq, sip_t const *sip){ return 501;}intnua_stack_method(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *tags){ return UA_EVENT1(e, SIP_501_NOT_IMPLEMENTED);}/**@internal * Relay response message to the application. * * If handle has already been marked as destroyed by nua_handle_destroy(), * release the handle with nh_destroy(). */int nua_stack_process_response(nua_handle_t *nh, struct nua_client_request *cr, nta_outgoing_t *orq, sip_t const *sip, tag_type_t tag, tag_value_t value, ...){ msg_t *msg = nta_outgoing_getresponse(orq); int status = sip->sip_status->st_status; char const *phrase = sip->sip_status->st_phrase; ta_list ta; int final; if (status >= 200 && status < 300) nh_challenge(nh, sip); /* Collect nextnonce */ if (nta_outgoing_method(orq) == sip_method_invite) final = status >= 300; else final = status >= 200; if (final) { nua_creq_deinit(cr, orq); if (cr->cr_usage && nh->nh_cr == cr) { if ((status >= 300 && !cr->cr_usage->du_ready) || cr->cr_usage->du_terminating) nua_dialog_usage_remove(nh, nh->nh_ds, cr->cr_usage); } cr->cr_usage = NULL; } ta_start(ta, tag, value); nua_stack_event(nh->nh_nua, nh, msg, cr->cr_event, status, phrase, ta_tags(ta)); if (final) cr->cr_event = nua_i_error; ta_end(ta); return 0;}static inlineint can_redirect(sip_contact_t const *m, sip_method_t method){ if (m && m->m_url->url_host) { enum url_type_e type = m->m_url->url_type; return type == url_sip || type == url_sips || (type == url_tel && (method == sip_method_invite || method == sip_method_message)) || (type == url_im && method == sip_method_message) || (type == url_pres && method == sip_method_subscribe); } return 0;}int nua_creq_restart_with(nua_handle_t *nh, struct nua_client_request *cr, nta_outgoing_t *orq, int status, char const *phrase, nua_creq_restart_f *f, TAG_LIST){ ta_list ta; msg_t *msg = nta_outgoing_getresponse(orq); nua_stack_event(nh->nh_nua, nh, msg, cr->cr_event, status, phrase, TAG_END()); nta_outgoing_destroy(orq); if (f) { ta_start(ta, tag, value); f(nh, ta_args(ta)); ta_end(ta); } return 1;}/** @internal Save operation until it can be restarted */int nua_creq_save_restart(nua_handle_t *nh, struct nua_client_request *cr, nta_outgoing_t *orq, int status, char const *phrase, nua_creq_restart_f *restart_function){ nua_dialog_usage_t *du = cr->cr_usage; msg_t *msg = nta_outgoing_getresponse(orq); nua_stack_event(nh->nh_nua, nh, msg, cr->cr_event, status, phrase, TAG_END()); nta_outgoing_destroy(orq); if (du) { du->du_pending = NULL; du->du_refresh = 0; } cr->cr_restart = restart_function; return 1;}/**@internal * Check response, return true if we can restart the request. * */int nua_creq_check_restart(nua_handle_t *nh, struct nua_client_request *cr, nta_outgoing_t *orq, sip_t const *sip, nua_creq_restart_f *restart_function){ int status = sip->sip_status->st_status; sip_method_t method = nta_outgoing_method(orq); int removed = 0; nua_dialog_usage_t *du = cr->cr_usage; assert(restart_function); if (orq == cr->cr_orq) removed = 1, cr->cr_orq = NULL; cr->cr_restart = NULL; if (cr->cr_msg == NULL || status < 200) ; else if (++cr->cr_retry_count > NH_PGET(nh, retry_count)) ; else if (status == 302) { if (can_redirect(sip->sip_contact, method)) { return nua_creq_restart_with(nh, cr, orq, 100, "Redirected", restart_function, NUTAG_URL(sip->sip_contact->m_url), TAG_END()); } } else if (status == 423) { sip_t *req = sip_object(cr->cr_msg); unsigned my_expires = 0; if (req->sip_expires) my_expires = req->sip_expires->ex_delta; if (sip->sip_min_expires && sip->sip_min_expires->me_delta > my_expires) { sip_expires_t ex[1]; sip_expires_init(ex); ex->ex_delta = sip->sip_min_expires->me_delta; return nua_creq_restart_with(nh, cr, orq, 100, "Re-Negotiating Subscription Expiration", restart_function, SIPTAG_EXPIRES(ex), TAG_END()); } } else if (method != sip_method_ack && method != sip_method_cancel && ((status == 401 && sip->sip_www_authenticate) || (status == 407 && sip->sip_proxy_authenticate)) && nh_challenge(nh, sip) > 0) { msg_t *request = nta_outgoing_getrequest(orq); sip_t *rsip = sip_object(request); int done; /* XXX - check for instant restart */ done = auc_authorization(&nh->nh_auth, cr->cr_msg, (msg_pub_t*)NULL, rsip->sip_request->rq_method_name, rsip->sip_request->rq_url, rsip->sip_payload); msg_destroy(request); if (done > 0) { return nua_creq_restart_with(nh, cr, orq, 100, "Request Authorized by Cache", restart_function, TAG_END()); } else if (done == 0) { /* Operation waits for application to call nua_authenticate() */ return nua_creq_save_restart(nh, cr, orq, status, sip->sip_status->st_phrase, restart_function); } else { SU_DEBUG_5(("nua(%p): auc_authorization failed\n", nh)); } }#if HAVE_SOFIA_SMIME else if (status == 493) /* try detached signature */ ;#endif else if (status == 422 && method == sip_method_invite) { if (sip->sip_min_se && nh->nh_ss->ss_min_se < sip->sip_min_se->min_delta) nh->nh_ss->ss_min_se = sip->sip_min_se->min_delta; if (nh->nh_ss->ss_min_se > nh->nh_ss->ss_session_timer) nh->nh_ss->ss_session_timer = nh->nh_ss->ss_min_se; return nua_creq_restart_with(nh, cr, orq, 100, "Re-Negotiating Session Timer", restart_function, TAG_END()); } /* This was final response that cannot be restarted. */ if (removed) cr->cr_orq = orq; if (du) { du->du_pending = NULL; du->du_refresh = 0; } cr->cr_retry_count = 0; if (cr->cr_msg) msg_destroy(cr->cr_msg), cr->cr_msg = NULL; return 0;}/** @internal Restart a request */int nua_creq_restart(nua_handle_t *nh, struct nua_client_request *cr, nta_response_f *cb, tagi_t *tags){ msg_t *msg; cr->cr_restart = NULL; if (!cr->cr_msg) return 0; msg = nua_creq_msg(nh->nh_nua, nh, cr, 1, SIP_METHOD_UNKNOWN, TAG_NEXT(tags)); cr->cr_orq = nta_outgoing_mcreate(nh->nh_nua->nua_nta, cb, nh, NULL, msg, SIPTAG_END(), TAG_NEXT(tags)); if (!cr->cr_orq) { msg_destroy(msg); return 0; } return 1;}/* ======================================================================== *//* Authentication */voidnua_stack_authenticate(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *tags){ int status = nh_authorize(nh, TAG_NEXT(tags)); if (status > 0) { nua_creq_restart_f *restart = NULL; nua_stack_event(nua, nh, NULL, e, SIP_200_OK, TAG_END()); if (nh->nh_cr->cr_restart) { restart = nh->nh_cr->cr_restart; nh->nh_cr->cr_restart = NULL; } else if (nh->nh_ss->ss_crequest->cr_restart) { restart = nh->nh_ss->ss_crequest->cr_restart; nh->nh_ss->ss_crequest->cr_restart = NULL; } if (restart) restart(nh, (tagi_t *)tags); /* Restart operation */ } else if (status < 0) { nua_stack_event(nua, nh, NULL, e, 500, "Cannot add credentials", TAG_END()); } else { nua_stack_event(nua, nh, NULL, e, 404, "No matching challenge", TAG_END()); }}/* ======================================================================== *//* * Process incoming requests */int nua_stack_process_request(nua_handle_t *nh, nta_leg_t *leg, nta_incoming_t *irq, sip_t const *sip){ nua_t *nua = nh->nh_nua; sip_method_t method = sip->sip_request->rq_method; sip_user_agent_t const *user_agent = NH_PGET(nh, user_agent); sip_supported_t const *supported = NH_PGET(nh, supported); sip_allow_t const *allow = NH_PGET(nh, allow); enter; nta_incoming_tag(irq, NULL); if (nta_check_method(irq, sip, allow, SIPTAG_SUPPORTED(supported), SIPTAG_USER_AGENT(user_agent), TAG_END())) return 405; switch (sip->sip_request->rq_url->url_type) { case url_sip: case url_sips: case url_im: case url_pres: case url_tel: break; default: nta_incoming_treply(irq, SIP_416_UNSUPPORTED_URI, SIPTAG_ALLOW(allow), SIPTAG_SUPPORTED(supported), SIPTAG_USER_AGENT(user_agent), TAG_END()); } if (nta_check_required(irq, sip, supported, SIPTAG_ALLOW(allow), SIPTAG_USER_AGENT(user_agent), TAG_END())) return 420; if (nh == nua->nua_dhandle) { if (!sip->sip_to->a_tag) ; else if (method == sip_method_message && NH_PGET(nh, win_messenger_enable)) ; else { nta_incoming_treply(irq, 481, "Initial transaction with a To tag", TAG_END()); return 481; } nh = NULL; } if (sip->sip_timestamp) nta_incoming_treply(irq, SIP_100_TRYING, TAG_END()); switch (method) { case sip_method_invite: return nua_stack_process_invite(nua, nh, irq, sip); case sip_method_info: if (nh) return nua_stack_process_info(nua, nh, irq, sip); /*FALLTHROUGH*/ case sip_method_update: if (nh) return nua_stack_process_update(nua, nh, irq, sip); /*FALLTHROUGH*/ case sip_method_bye: if (nh) return nua_stack_process_bye(nua, nh, irq, sip); nta_incoming_treply(irq, 481, "Call Does Not Exist", SIPTAG_ALLOW(allow), SIPTAG_SUPPORTED(supported), SIPTAG_USER_AGENT(user_agent), TAG_END()); return 481; case sip_method_message: return nua_stack_process_message(nua, nh, irq, sip); case sip_method_notify: return nua_stack_process_notify(nua, nh, irq, sip); case sip_method_subscribe: return nua_stack_process_subsribe(nua, nh, irq, sip); case sip_method_options: return nua_stack_process_options(nua, nh, irq, sip); case sip_method_refer: return nua_stack_process_refer(nua, nh, irq, sip); case sip_method_publish: return nua_stack_process_publish(nua, nh, irq, sip); case sip_method_ack: case sip_method_cancel: SU_DEBUG_1(("nua(%p): strange %s from <" URL_PRINT_FORMAT ">\n", nh, sip->sip_request->rq_method_name, URL_PRINT_ARGS(sip->sip_from->a_url))); /* Send nua_i_error ? */ return 481; default: return nua_stack_process_unknown(nua, nh, irq, sip); }}voidnua_stack_respond(nua_t *nua, nua_handle_t *nh, int status, char const *phrase, tagi_t const *tags){ struct nua_session_state *ss = nh->nh_ss; nua_server_request_t *sr = ss->ss_srequest; if (sr->sr_respond) { sr->sr_respond(nua, nh, status, phrase, tags); }#if 0 else if (nta_incoming_status(nh->nh_irq) < 200) { int add_contact = 0; sip_contact_t *m; if (nta_incoming_url(nh->nh_irq)->url_type == url_sips && nua->nua_sips_contact) m = nua->nua_sips_contact; else m = nua->nua_contact; SU_DEBUG_1(("nua: anonymous response %u %s\n", status, phrase)); tl_gets(tags, NUTAG_ADD_CONTACT_REF(add_contact), TAG_END()); nta_incoming_treply(nh->nh_irq, status, phrase, TAG_IF(add_contact, SIPTAG_CONTACT(m)), TAG_NEXT(tags)); if (status >= 200) nta_incoming_destroy(nh->nh_irq), nh->nh_irq = NULL; }#endif else if (ss->ss_srequest->sr_irq) { nua_stack_event(nua, nh, NULL, nua_i_error, 500, "Already Sent Final Response", TAG_END()); } else { nua_stack_event(nua, nh, NULL, nua_i_error, 500, "Responding to a Non-Existing Request", TAG_END()); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -