📄 nua_stack.c
字号:
void nh_destroy(nua_t *nua, nua_handle_t *nh){ assert(nh); assert(nh != nua->nua_dhandle); if (nh->nh_notifier) nea_server_destroy(nh->nh_notifier), nh->nh_notifier = NULL; while (nh->nh_ds->ds_cr) nua_client_request_destroy(nh->nh_ds->ds_cr); while (nh->nh_ds->ds_sr) nua_server_request_destroy(nh->nh_ds->ds_sr); nua_dialog_deinit(nh, nh->nh_ds); 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 */}/* ======================================================================== *//**@internal * Save handle parameters and initial authentication info. * * @retval -1 upon an error * @retval 0 when successful */int nua_stack_init_handle(nua_t *nua, nua_handle_t *nh, tagi_t const *tags){ int retval = 0; if (nh == NULL) return -1; assert(nh != nua->nua_dhandle); if (nua_stack_set_params(nua, nh, nua_i_error, tags) < 0) retval = -1; if (retval || nh->nh_init) /* Already initialized? */ return retval; if (nh->nh_tags) nh_authorize(nh, TAG_NEXT(nh->nh_tags)); 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, int create_dialog){ nua_handle_t *nh; url_t const *url; 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; /* Strip away parameters */ 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), /* Remote target */ SIPTAG_TO(to), /* Local AoR */ SIPTAG_FROM(from), /* Remote AoR */ TAG_END()); if (nh && nua_stack_init_handle(nua, nh, NULL) < 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;}/** Set flags and special event on handle. * * @retval 0 when successful * @retval -1 upon an error */int nua_stack_set_handle_special(nua_handle_t *nh, enum nh_kind kind, nua_event_t special){ if (nh == NULL) return -1; if (special && nh->nh_special && nh->nh_special != special) return -1; if (!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_nothing: default: break; } if (special) nh->nh_special = special; } return 0;}sip_replaces_t *nua_stack_handle_make_replaces(nua_handle_t *nh, su_home_t *home, int early_only){ if (nh && nh->nh_ds && nh->nh_ds->ds_leg) return nta_leg_make_replaces(nh->nh_ds->ds_leg, home, early_only); else return NULL;}nua_handle_t *nua_stack_handle_by_replaces(nua_t *nua, sip_replaces_t const *r){ if (nua) { nta_leg_t *leg = nta_leg_by_replaces(nua->nua_nta, r); if (leg) return nta_leg_magic(leg, nua_stack_process_request); } return NULL;}nua_handle_t *nua_stack_handle_by_call_id(nua_t *nua, const char *call_id){ if (nua) { nta_leg_t *leg = nta_leg_by_call_id(nua->nua_nta, call_id); if (leg) return nta_leg_magic(leg, nua_stack_process_request); } return NULL;}/** @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;}su_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;}/* ======================================================================== *//* Authentication *//** @NUA_EVENT nua_r_authenticate * * Response to nua_authenticate(). Under normal operation, this event is * never sent but rather the unauthenticated operation is completed. * However, if there is no operation to authentication or if there is an * authentication error the #nua_r_authenticate event is sent to the * application with the status code as follows: * - <i>202 No operation to restart</i>:\n * The authenticator associated with the handle was updated, but there was * no operation to retry with the new credentials. * - <i>900 Cannot add credentials</i>:\n * There was internal problem updating authenticator. * - <i>904 No matching challenge</i>:\n * There was no challenge matching with the credentials provided by * nua_authenticate(), e.g., their realm did not match with the one * received with the challenge. * * @param status status code from authentication * @param phrase a short textual description of @a status code * @param nh operation handle authenticated * @param hmagic application context associated with the handle * @param sip NULL * @param tags empty * * @sa nua_terminate(), nua_handle_destroy() * * @END_NUA_EVENT */voidnua_stack_authenticate(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *tags){ nua_client_request_t *cr = nh->nh_ds->ds_cr; int status = nh_authorize(nh, TAG_NEXT(tags)); if (status > 0) { if (cr && cr->cr_wait_for_cred) { cr->cr_waiting = cr->cr_wait_for_cred = 0; nua_client_restart_request(cr, cr->cr_terminating, tags); } else { nua_stack_event(nua, nh, NULL, e, 202, "No operation to restart", NULL); } } else if (cr && cr->cr_wait_for_cred) { cr->cr_waiting = cr->cr_wait_for_cred = 0; if (status < 0) nua_client_response(cr, 900, "Operation cannot add credentials", NULL); else nua_client_response(cr, 904, "Operation has no matching challenge ", NULL); } else if (status < 0) { nua_stack_event(nua, nh, NULL, e, 900, "Cannot add credentials", NULL); } else { nua_stack_event(nua, nh, NULL, e, 904, "No matching challenge", NULL); }}/* ======================================================================== *//* * Process incoming requests */nua_server_methods_t const *nua_server_methods[] = { /* These must be in same order as in sip_method_t */ &nua_extension_server_methods, &nua_invite_server_methods, /**< INVITE */ NULL, /**< ACK */ NULL, /**< CANCEL */ &nua_bye_server_methods, /**< BYE */ &nua_options_server_methods, /**< OPTIONS */ &nua_register_server_methods, /**< REGISTER */ &nua_info_server_methods, /**< INFO */ &nua_prack_server_methods, /**< PRACK */ &nua_update_server_methods, /**< UPDATE */ &nua_message_server_methods, /**< MESSAGE */ &nua_subscribe_server_methods,/**< SUBSCRIBE */ &nua_notify_server_methods, /**< NOTIFY */ &nua_refer_server_methods, /**< REFER */ &nua_publish_server_methods, /**< PUBLISH */ NULL};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; char const *name = sip->sip_request->rq_method_name; nua_server_methods_t const *sm; nua_server_request_t *sr, sr0[1]; int status, initial = 1; int create_dialog; char 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 (method == sip_method_cancel) return 481; /* Hook to outbound */ if (method == sip_method_options) { status = nua_registration_process_request(nua->nua_registrations, irq, sip); if (status) return status; } if (nta_check_method(irq, sip, allow, SIPTAG_SUPPORTED(supported), SIPTAG_USER_AGENT_STR(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, status = SIP_416_UNSUPPORTED_URI, SIPTAG_ALLOW(allow), SIPTAG_SUPPORTED(supported), SIPTAG_USER_AGENT_STR(user_agent), TAG_END()); return status; } if (nta_check_required(irq, sip, supported, SIPTAG_ALLOW(allow), SIPTAG_USER_AGENT_STR(user_agent), TAG_END())) return 420; if (method > sip_method_unknown && method <= sip_method_publish) sm = nua_server_methods[method]; else sm = nua_server_methods[0]; initial = nh == nua->nua_dhandle; if (sm == NULL) { SU_DEBUG_1(("nua(%p): strange %s from <" URL_PRINT_FORMAT ">\n", (void *)nh, sip->sip_request->rq_method_name, URL_PRINT_ARGS(sip->sip_from->a_url))); } else if (initial && sm->sm_flags.in_dialog) { /* These must be in-dialog */ sm = NULL; } else if (initial && sip->sip_to->a_tag) { /* RFC 3261 section 12.2.2: If the UAS wishes to reject the request because it does not wish to recreate the dialog, it MUST respond to the request with a 481 (Call/Transaction Does Not Exist) status code and pass that to the server transaction. */ if (method == sip_method_info) /* accept out-of-dialog info */; else if (method != sip_method_message || !NH_PGET(nh, win_messenger_enable)) sm = NULL; } if (!sm) { nta_incoming_treply(irq, status = 481, "Call Does Not Exist", SIPTAG_ALLOW(allow), SIPTAG_SUPPORTED(supported), SIPTAG_USER_AGENT_STR(user_agent), TAG_END()); return 481; } create_dialog = sm->sm_flags.create_dialog; if (method == sip_method_message && NH_PGET(nh, win_messenger_enable)) create_dialog = 1; sr = memset(sr0, 0, (sizeof sr0)); sr->sr_methods = sm; sr->sr_method = method = sip->sip_request->rq_method; sr->sr_add_contact = sm->sm_flags.add_contact; sr->sr_target_refresh = sm->sm_flags.target_refresh; sr->sr_owner = nh; sr->sr_initial = initial; sr->sr_irq = irq; SR_STATUS1(sr, SIP_100_TRYING); sr->sr_request.msg = nta_incoming_getrequest(irq); sr->sr_request.sip = sip; assert(sr->sr_request.msg); sr->sr_response.msg = nta_incoming_create_response(irq, 0, NULL); sr->sr_response.sip = sip_object(sr->sr_response.msg); if (sr->sr_response.msg == NULL) { SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR); } else if (sm->sm_init && sm->sm_init(sr)) { if (sr->sr_status < 200) /* Init may have set response status */ SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR); } /* Create handle if request does not fail */ else if (initial && sr->sr_status < 300) { if ((nh = nua_stack_incoming_handle(nua, irq, sip, create_dialog))) sr->sr_owner = nh; else SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR); } if (sr->sr_status < 300 && sm->sm_preprocess && sm->sm_preprocess(sr)) { if (sr->sr_status < 200) /* Set response status if preprocess did not */ SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR); } if (sr->sr_status < 300) { if (sr->sr_target_refresh) nua_dialog_uas_route(nh, nh->nh_ds, sip, 1); /* Set route and tags */ nua_dialog_store_peer_info(nh, nh->nh_ds, sip); } if (sr->sr_status == 100 && method != sip_method_unknown && !sip_is_allowed(NH_PGET(sr->sr_owner, appl_method), method, name)) { if (method == sip_method_refer || method == sip_method_subscribe) SR_STATUS1(sr, SIP_202_ACCEPTED); else SR_STATUS1(sr, SIP_200_OK); } /* INVITE server request is not finalized after 2XX response */ if (sr->sr_status < (method == sip_method_invite ? 300 : 200)) { sr = su_alloc(nh->nh_home, (sizeof *sr)); if (sr) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -