📄 nua_stack.c
字号:
busy += nh_call_pending(nh, 0); if (nh->nh_soa) { soa_destroy(nh->nh_soa), nh->nh_soa = NULL; } if (nh->nh_cr->cr_orq || nh->nh_ss->ss_crequest->cr_orq) busy++; if (nh_notifier_shutdown(nh, NULL, NEATAG_REASON("noresource"), TAG_END())) busy++; } if (!busy) SET_STATUS(200, "Shutdown successful"); else if (now == nua->nua_shutdown) SET_STATUS(100, "Shutdown started"); else if (now - nua->nua_shutdown < 30) SET_STATUS(101, "Shutdown in progress"); else SET_STATUS(500, "Shutdown timeout"); if (status >= 200) { for (nh = nua->nua_handles; nh; nh = nh_next) { nh_next = nh->nh_next; while (nh->nh_ds && nh->nh_ds->ds_usage) { nua_dialog_usage_remove(nh, nh->nh_ds, nh->nh_ds->ds_usage); } } su_timer_destroy(nua->nua_timer), nua->nua_timer = NULL; nta_agent_destroy(nua->nua_nta), nua->nua_nta = NULL; } nua_stack_event(nua, NULL, NULL, nua_r_shutdown, status, phrase, TAG_END());}/* ---------------------------------------------------------------------- *//** @internal Create a handle */nua_handle_t *nh_create(nua_t *nua, tag_type_t tag, tag_value_t value, ...){ ta_list ta; nua_handle_t *nh; enter; ta_start(ta, tag, value); nh = nh_create_handle(nua, NULL, ta_args(ta)); ta_end(ta); if (nh) { nh->nh_ref_by_stack = 1; nh_append(nua, nh); } return nh;}/** @internal Append an handle to the list of handles */void nh_append(nua_t *nua, nua_handle_t *nh){ nh->nh_next = NULL; nh->nh_prev = nua->nua_handles_tail; *nua->nua_handles_tail = nh; nua->nua_handles_tail = &nh->nh_next;}nua_handle_t *nh_validate(nua_t *nua, nua_handle_t *maybe){ nua_handle_t *nh; if (maybe) for (nh = nua->nua_handles; nh; nh = nh->nh_next) if (nh == maybe) return nh; return NULL;}void nua_stack_destroy_handle(nua_t *nua, nua_handle_t *nh, tagi_t const *tags){ nh_call_pending(nh, 0); /* Call pending operations with 0 */ if (nh->nh_notifier) nua_stack_terminate(nua, nh, 0, NULL);#if 0 if (nh->nh_ref_by_user) { nh->nh_ref_by_user = 0; nua_handle_unref(nh); }#endif nh_destroy(nua, nh);}#define nh_is_inserted(nh) ((nh)->nh_prev != NULL)/** @internal Remove a handle from list of handles */staticvoid nh_remove(nua_t *nua, nua_handle_t *nh){ assert(nh_is_inserted(nh)); assert(*nh->nh_prev == nh); if (nh->nh_next) nh->nh_next->nh_prev = nh->nh_prev; else nua->nua_handles_tail = nh->nh_prev; *nh->nh_prev = nh->nh_next; nh->nh_prev = NULL; nh->nh_next = NULL;}void nh_destroy(nua_t *nua, nua_handle_t *nh){ assert(nh); assert(nh != nua->nua_dhandle); nh_enter; if (nh->nh_notifier) nea_server_destroy(nh->nh_notifier), nh->nh_notifier = NULL; nua_creq_deinit(nh->nh_cr, NULL); if (nh->nh_ss) nua_creq_deinit(nh->nh_ss->ss_crequest, NULL); if (nh->nh_ds->ds_leg) { nta_leg_destroy(nh->nh_ds->ds_leg), nh->nh_ds->ds_leg = NULL; } if (nh->nh_ss->ss_srequest->sr_irq) { nta_incoming_destroy(nh->nh_ss->ss_srequest->sr_irq); nh->nh_ss->ss_srequest->sr_irq = NULL; } if (nh->nh_soa) soa_destroy(nh->nh_soa), nh->nh_soa = NULL; if (nh_is_inserted(nh)) nh_remove(nua, nh); 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); }}/* ======================================================================== *//**@internal * 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;}/** @internal 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;}/** @internal 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;}/**@internal * 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;}/**@internal * Create a request message. * * @param nua * @param nh * @param cr * @param restart * @param method * @param name * @param tag, 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; ta_list ta; url_string_t const *url = NULL; long seq = -1; int copy = 1, use_dialog = 0, add_contact = 0, add_service_route; /* 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; /* ACK/CANCEL cannot be restarted so we do not copy message */ 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)); } ta_start(ta, tag, value); sip = sip_object(msg); if (!sip) goto error; { 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) { add_service_route = 0; /* 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) goto error; } else { if (sip_add_tl(msg, sip, 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)) goto error; if (use_dialog) { 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_CSEQ(sip->sip_cseq), TAG_END()); if (!ds->ds_leg) goto error; if (!sip->sip_from->a_tag && sip_from_tag(msg_home(msg), sip->sip_from, nta_leg_tag(ds->ds_leg, NULL)) < 0) goto error; } add_service_route = !restart; } /* * If application did not specify an empty contact, * use contact generated by stack. */ if (!add_contact || sip->sip_contact || 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)) add_contact = 0; if (add_contact || add_service_route) { if (nua_registration_add_contact(nh, msg, sip, add_contact, add_service_route) < 0) goto error; } 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) goto error; } } 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -