📄 nua_stack.c
字号:
nua_handle_unref(nh); /* Remove stack reference */}void nua_creq_deinit(struct nua_client_request *cr, nta_outgoing_t *orq){ if (orq == NULL || orq == cr->cr_orq) { cr->cr_retry_count = 0; cr->cr_offer_sent = cr->cr_answer_recv = 0; if (cr->cr_msg) msg_destroy(cr->cr_msg); cr->cr_msg = NULL; if (cr->cr_orq) nta_outgoing_destroy(cr->cr_orq); cr->cr_orq = NULL; } else { nta_outgoing_destroy(orq); }}/* ======================================================================== *//** Initialize handle Allow and authentication info. * * @retval -1 upon an error * @retval 0 when successful */int nua_stack_init_handle(nua_t *nua, nua_handle_t *nh, enum nh_kind kind, char const *default_allow, tag_type_t tag, tag_value_t value, ...){ ta_list ta; int retval = 0; if (nh == NULL) return -1; if (kind && !nh_is_special(nh) && !nh->nh_has_invite) { switch (kind) { case nh_has_invite: nh->nh_has_invite = 1; break; case nh_has_subscribe: nh->nh_has_subscribe = 1; break; case nh_has_notify: nh->nh_has_notify = 1; break; case nh_has_register: nh->nh_has_register = 1; break; case nh_has_streaming: nh->nh_has_streaming = 1; break; case nh_has_nothing: default: break; } } assert(nh != nua->nua_dhandle); ta_start(ta, tag, value); if (nua_stack_set_params(nua, nh, nua_i_error, ta_args(ta)) < 0) retval = -1; if (!retval && !nh->nh_soa && nua->nua_dhandle->nh_soa) { nh->nh_soa = soa_clone(nua->nua_dhandle->nh_soa, nua->nua_root, nh); if (nh->nh_soa && nh->nh_tags) if (soa_set_params(nh->nh_soa, TAG_NEXT(nh->nh_tags))) retval = -1; } if (!retval && nh->nh_soa) if (soa_set_params(nh->nh_soa, ta_tags(ta)) < 0) retval = -1; ta_end(ta); if (retval || nh->nh_init) /* Already initialized? */ return retval;#if HAVE_UICC_H if (nh->nh_has_register && nua->nua_uicc) auc_with_uicc(&nh->nh_auth, nh->nh_home, nua->nua_uicc);#endif if (nh->nh_tags) nh_authorize(nh, TAG_NEXT(nh->nh_tags)); nh->nh_ss->ss_min_se = NH_PGET(nh, min_se); nh->nh_ss->ss_session_timer = NH_PGET(nh, session_timer); nh->nh_ss->ss_refresher = NH_PGET(nh, refresher); nh->nh_init = 1; return 0;}/** Create a handle for processing incoming request */nua_handle_t *nua_stack_incoming_handle(nua_t *nua, nta_incoming_t *irq, sip_t const *sip, enum nh_kind kind, int create_dialog){ nua_handle_t *nh; url_t const *url; char const *default_allow = NULL; /* XXX - should be argument? */ sip_to_t to[1]; sip_from_t from[1]; assert(sip && sip->sip_from && sip->sip_to); if (sip->sip_contact) url = sip->sip_contact->m_url; else url = sip->sip_from->a_url; sip_from_init(from)->a_display = sip->sip_to->a_display; *from->a_url = *sip->sip_to->a_url; sip_to_init(to)->a_display = sip->sip_from->a_display; *to->a_url = *sip->sip_from->a_url; nh = nh_create(nua, NUTAG_URL((url_string_t *)url), SIPTAG_TO(to), /* Local address */ SIPTAG_FROM(from), /* Remote address */ TAG_END()); if (nua_stack_init_handle(nh->nh_nua, nh, kind, default_allow, TAG_END()) < 0) nh_destroy(nua, nh), nh = NULL; if (nh && create_dialog) { struct nua_dialog_state *ds = nh->nh_ds; nua_dialog_store_peer_info(nh, ds, sip); ds->ds_leg = nta_leg_tcreate(nua->nua_nta, nua_stack_process_request, nh, SIPTAG_CALL_ID(sip->sip_call_id), SIPTAG_FROM(sip->sip_to), SIPTAG_TO(sip->sip_from), NTATAG_REMOTE_CSEQ(sip->sip_cseq->cs_seq), TAG_END()); if (!ds->ds_leg || !nta_leg_tag(ds->ds_leg, nta_incoming_tag(irq, NULL))) nh_destroy(nua, nh), nh = NULL; } if (nh) nua_dialog_uas_route(nh, nh->nh_ds, sip, 1); return nh;}/** Add authorization data */int nh_authorize(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...){ int retval = 0; tagi_t const *ti; ta_list ta; ta_start(ta, tag, value); for (ti = ta_args(ta); ti; ti = tl_next(ti)) { if (ti->t_tag == nutag_auth && ti->t_value) { char *data = (char *)ti->t_value; int rv = auc_credentials(&nh->nh_auth, nh->nh_home, data); if (rv > 0) { retval = 1; } else if (rv < 0) { retval = -1; break; } } } ta_end(ta); return retval;}/** Collect challenges from response. * * @return Number of updated challenges, 0 if no updates found. * @retval -1 upon error. */staticint nh_challenge(nua_handle_t *nh, sip_t const *sip){ int server = 0, proxy = 0; if (sip->sip_www_authenticate) server = auc_challenge(&nh->nh_auth, nh->nh_home, sip->sip_www_authenticate, sip_authorization_class); if (sip->sip_proxy_authenticate) proxy = auc_challenge(&nh->nh_auth, nh->nh_home, sip->sip_proxy_authenticate, sip_proxy_authorization_class); if (server < 0 || proxy < 0) return -1; return server + proxy;}/** Create request message. * * @param nua * @param nh * @param method * @param name * @param tag @a value list of tag-value pairs */msg_t *nua_creq_msg(nua_t *nua, nua_handle_t *nh, struct nua_client_request *cr, int restart, sip_method_t method, char const *name, tag_type_t tag, tag_value_t value, ...){ struct nua_dialog_state *ds = nh->nh_ds; msg_t *msg; sip_t *sip; url_string_t const *url = NULL; long seq = -1; int copy = 1; /* If restarting, use existing message */ if (restart) { msg = cr->cr_msg; sip = sip_object(msg); /* Trying to restart different method? */ if (sip && method && sip->sip_request->rq_method != method) { SU_DEBUG_3(("nua(%p): trying to %s " "but there is already %s waiting to restart\n", nh, name, sip->sip_request->rq_method_name)); restart = 0, msg = NULL; sip = NULL; } /* Remove CSeq */ if (sip && sip->sip_cseq) sip_header_remove(msg, sip, (sip_header_t *)sip->sip_cseq); if (sip && sip->sip_request) method = sip->sip_request->rq_method, name = sip->sip_request->rq_method_name; } if (!restart) { if (cr->cr_msg) { /* If method is ACK or CANCEL, use existing CSeq */ if (method == sip_method_ack || method == sip_method_cancel) { sip_t *nh_sip = sip_object(cr->cr_msg); if (nh_sip && nh_sip->sip_cseq) seq = nh_sip->sip_cseq->cs_seq; copy = 0; } else msg_destroy(cr->cr_msg), cr->cr_msg = NULL; } msg = nta_msg_create(nua->nua_nta, 0); tl_gets(nh->nh_tags, NUTAG_URL_REF(url), TAG_END()); sip_add_tl(msg, sip_object(msg), TAG_NEXT(nh->nh_tags)); } if (msg) { ta_list ta; int use_dialog = 0, add_contact = 0; sip = sip_object(msg); ta_start(ta, tag, value); tl_gets(ta_args(ta), NUTAG_URL_REF(url), NUTAG_USE_DIALOG_REF(use_dialog), /* NUTAG_COPY_REF(copy), */ NUTAG_ADD_CONTACT_REF(add_contact), TAG_END()); if (method == sip_method_register && url == NULL) { tl_gets(ta_args(ta), NUTAG_REGISTRAR_REF(url), TAG_END()); if (url == NULL) tl_gets(nh->nh_tags, NUTAG_REGISTRAR_REF(url), TAG_END()); if (url == NULL) url = (url_string_t *)nua->nua_registrar; } if (seq != -1) { sip_cseq_t *cseq = sip_cseq_create(msg_home(msg), seq, method, name); sip_header_insert(msg, sip, (sip_header_t *)cseq); } if (ds->ds_leg) { /* If leg has established route, use it, not original URL */ if (ds->ds_route) url = NULL; if (sip_add_tl(msg, sip, ta_tags(ta)) < 0 || nta_msg_request_complete(msg, ds->ds_leg, method, name, url) < 0) msg_destroy(msg), msg = NULL; } else { // tl_gets(ta_args(ta), TAG_END()); if ((sip_add_tl(msg, sip, TAG_IF(method != sip_method_register, SIPTAG_ROUTE(nua->nua_service_route)), ta_tags(ta)) < 0) || (ds->ds_remote_tag && sip_to_tag(nh->nh_home, sip->sip_to, ds->ds_remote_tag) < 0) || nta_msg_request_complete(msg, nua->nua_dhandle->nh_ds->ds_leg, method, name, url) < 0 || (sip->sip_from == NULL && sip_add_dup(msg, sip, (sip_header_t *)nua->nua_from) < 0)) msg_destroy(msg), msg = NULL; if (use_dialog && msg) { sip_route_t *route = sip->sip_route; if (method == sip_method_invite || method == sip_method_subscribe || method == sip_method_notify) route = NULL; ds->ds_leg = nta_leg_tcreate(nua->nua_nta, nua_stack_process_request, nh, SIPTAG_CALL_ID(sip->sip_call_id), SIPTAG_FROM(sip->sip_from), SIPTAG_TO(sip->sip_to), SIPTAG_ROUTE(route), SIPTAG_CSEQ(sip->sip_cseq), TAG_END()); if (!sip->sip_from->a_tag) { nta_leg_tag(ds->ds_leg, NULL); sip_from_tag(msg_home(msg), sip->sip_from, nta_leg_get_tag(ds->ds_leg)); } /* XXX - check error */ } } if (add_contact && msg && !sip->sip_contact) { /* We are missing contact */ /* If application did not specify an empty contact, use ours */ if (!tl_find(nh->nh_tags, siptag_contact) && !tl_find(nh->nh_tags, siptag_contact_str) && !tl_find(ta_args(ta), siptag_contact) && !tl_find(ta_args(ta), siptag_contact_str)) { if (sip->sip_request->rq_url->url_type == url_sips && nua->nua_sips_contact) sip_add_dup(msg, sip, (sip_header_t *)nua->nua_sips_contact); else sip_add_dup(msg, sip, (sip_header_t *)nua->nua_contact); } } if (!sip->sip_user_agent && NH_PGET(nh, user_agent)) sip_add_dup(msg, sip, (sip_header_t *)NH_PGET(nh, user_agent)); if (method != sip_method_ack) { if (!sip->sip_allow && !ds->ds_remote_tag) sip_add_dup(msg, sip, (sip_header_t*)NH_PGET(nh, allow)); if (!sip->sip_supported && NH_PGET(nh, supported)) sip_add_dup(msg, sip, (sip_header_t *)NH_PGET(nh, supported)); if (method == sip_method_register && NH_PGET(nh, path_enable) && !sip_has_feature(sip->sip_supported, "path") && !sip_has_feature(sip->sip_require, "path")) sip_add_make(msg, sip, sip_supported_class, "path"); if (!sip->sip_organization && NH_PGET(nh, organization)) sip_add_dup(msg, sip, (sip_header_t *)NH_PGET(nh, organization)); if (nh->nh_auth) { nh_authorize(nh, ta_tags(ta)); if (method != sip_method_invite && method != sip_method_update && /* auc_authorize() removes existing authentication headers */ auc_authorize(&nh->nh_auth, msg, sip) < 0) msg_destroy(msg), msg = NULL; } } else /* ACK */ { 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); } ta_end(ta); 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;}/** Create response message. * * @param nua * @param nh * @param irq * @param status * @param phrase * @param tag, @a 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); sip_header_t *m; int add_contact = 0; if (nta_incoming_url(irq)->url_type == url_sips && nua->nua_sips_contact) m = (sip_header_t*)nua->nua_sips_contact; else m = (sip_header_t*)nua->nua_contact; ta_start(ta, tag, value); tl_gets(ta_args(ta), NUTAG_ADD_CONTACT_REF(add_contact), TAG_END()); 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 (add_contact && !sip->sip_contact && sip_add_dup(msg, sip, m) < 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -