📄 outbound.c
字号:
} if (status < 200) return 0; if (sip == NULL) { SU_DEBUG_3(("outbound(%p): keepalive %u %s\n", (void *)ob->ob_owner, status, phrase)); ob->ob_oo->oo_keepalive_error(ob->ob_owner, ob, status, phrase, TAG_END()); return 0; } if (status == 401 || status == 407) { if (sip->sip_www_authenticate) challenged += auc_challenge(ob->ob_keepalive.auc, ob->ob_home, sip->sip_www_authenticate, sip_authorization_class) > 0; if (sip->sip_proxy_authenticate) challenged += auc_challenge(ob->ob_keepalive.auc, ob->ob_home, sip->sip_proxy_authenticate, sip_proxy_authorization_class) > 0; if (ob->ob_oo->oo_credentials) credentials = ob->ob_oo->oo_credentials(ob->ob_owner, ob->ob_keepalive.auc); } binding_check = outbound_nat_detect(ob, request, sip); if (orq == ob->ob_keepalive.orq) ob->ob_keepalive.orq = NULL; nta_outgoing_destroy(orq); if (binding_check > 1) { /* Bindings have changed */ if (outbound_contacts_from_via(ob, sip->sip_via) == 0) { /* XXX - Destroy old keepalive template message */ /* re-REGISTER */ ob->ob_oo->oo_refresh(ob->ob_owner, ob); return 0; } } if (binding_check <= 1 && ob->ob_registered && ob->ob_keepalive.validating) { int failed = 0; unsigned loglevel = 3; if (challenged > 0 && credentials > 0) { keepalive_options_with_registration_probe(ob); return 0; } if (status < 300 && ob->ob_keepalive.validated) { loglevel = 5; if (ob->ob_validated) loglevel = 99; /* only once */ ob->ob_validated = ob->ob_once_validated = 1; } else if (status == 401 || status == 407 || status == 403) loglevel = 5, failed = 1; else loglevel = 3, failed = 1; if (loglevel >= SU_LOG->log_level) { sip_contact_t const *m = ob->ob_rcontact; if (m) su_llog(SU_LOG, loglevel, "outbound(%p): %s <" URL_PRINT_FORMAT ">\n", (void *)ob->ob_owner, failed ? "FAILED to validate" : "validated", URL_PRINT_ARGS(m->m_url)); else su_llog(SU_LOG, loglevel, "outbound(%p): %s registration\n", (void *)ob->ob_owner, failed ? "FAILED to validate" : "validated"); if (failed) su_llog(SU_LOG, loglevel, "outbound(%p): FAILED with %u %s\n", (void *)ob->ob_owner, status, phrase); } if (failed) ob->ob_oo->oo_probe_error(ob->ob_owner, ob, status, phrase, TAG_END()); } else if (status == 408) { SU_DEBUG_3(("outbound(%p): keepalive timeout\n", (void *)ob->ob_owner)); ob->ob_oo->oo_keepalive_error(ob->ob_owner, ob, status, phrase, TAG_END()); return 0; } ob->ob_keepalive.validating = 0; if (ob->ob_keepalive.timer) su_timer_set(ob->ob_keepalive.timer, keepalive_timer, ob); return 0;}static void keepalive_timer(su_root_magic_t *root_magic, su_timer_t *t, su_timer_arg_t *ob_casted_as_timer_arg){ outbound_t *ob = (outbound_t *)ob_casted_as_timer_arg; (void)root_magic; if (keepalive_options(ob) < 0) su_timer_set(t, keepalive_timer, ob_casted_as_timer_arg); /* XXX */}/** @internal Send a keepalive OPTIONS that probes the registration */static int keepalive_options_with_registration_probe(outbound_t *ob){ msg_t *req; sip_t *sip; void *request_uri; if (ob->ob_keepalive.orq) return 0; req = msg_copy(ob->ob_keepalive.msg); if (!req) return -1; sip = sip_object(req); assert(sip); request_uri = sip->sip_to->a_url; if (nta_msg_request_complete(req, nta_default_leg(ob->ob_nta), SIP_METHOD_OPTIONS, request_uri) < 0) return msg_destroy(req), -1; if (ob->ob_keepalive.auc[0]) auc_authorization(ob->ob_keepalive.auc, req, (void *)sip, "OPTIONS", request_uri, sip->sip_payload); ob->ob_keepalive.orq = nta_outgoing_mcreate(ob->ob_nta, response_to_keepalive_options, ob, NULL, req, TAG_IF(ob->ob_proxy_override, NTATAG_DEFAULT_PROXY(ob->ob_proxy)), SIPTAG_SUBJECT_STR("REGISTRATION PROBE"), /* NONE is used to remove Max-Forwards: 0 found in ordinary keepalives */ SIPTAG_MAX_FORWARDS(SIP_NONE), TAG_END()); if (!ob->ob_keepalive.orq) return msg_destroy(req), -1; ob->ob_keepalive.validating = 1; ob->ob_keepalive.validated = 0; return 0;}/** Check if request should be processed by outbound */int outbound_targeted_request(sip_t const *sip){ return sip && sip->sip_request && sip->sip_request->rq_method == sip_method_options && sip->sip_accept && sip->sip_accept->ac_type && strcasecmp(sip->sip_accept->ac_type, outbound_content_type) == 0;}/** Answer to the connectivity probe OPTIONS */int outbound_process_request(outbound_t *ob, nta_incoming_t *irq, sip_t const *sip){ /* XXX - We assume that Call-ID is not modified. */ if (strcmp(sip->sip_call_id->i_id, ob->ob_cookie)) return 0; if (ob->ob_keepalive.validating) { SU_DEBUG_5(("outbound(%p): registration check OPTIONS received\n", (void *)ob->ob_owner)); ob->ob_keepalive.validated = 1; } nta_incoming_treply(irq, SIP_200_OK, SIPTAG_CONTENT_TYPE_STR(outbound_content_type), SIPTAG_PAYLOAD_STR(ob->ob_cookie), TAG_END()); return 200;}/* ---------------------------------------------------------------------- *//**@internal * Create contacts for outbound. * * There are two contacts: * one suitable for registrations (ob_rcontact) and another that can be used * in dialogs (ob_dcontact). */int outbound_contacts_from_via(outbound_t *ob, sip_via_t const *via){ su_home_t *home = ob->ob_home; sip_contact_t *rcontact, *dcontact; int reg_id = 0; char reg_id_param[20] = ""; sip_contact_t *previous_previous, *previous_rcontact, *previous_dcontact; sip_via_t *v, v0[1], *previous_via; int contact_uri_changed; if (!via) return -1; v = v0; *v0 = *via; v0->v_next = NULL; dcontact = ob->ob_oo->oo_contact(ob->ob_owner, home, 1, v, v->v_protocol, NULL); if (ob->ob_instance && ob->ob_reg_id != 0) snprintf(reg_id_param, sizeof reg_id_param, ";reg-id=%u", ob->ob_reg_id); rcontact = ob->ob_oo->oo_contact(ob->ob_owner, home, 0, v, v->v_protocol, ob->ob_instance, reg_id_param, NULL); v = sip_via_dup(home, v); if (!rcontact || !dcontact || !v) { msg_header_free(home, (void *)dcontact); if (rcontact != dcontact) msg_header_free(home, (void *)rcontact); msg_header_free(home, (void *)v); return -1; } contact_uri_changed = !ob->ob_rcontact || url_cmp_all(ob->ob_rcontact->m_url, rcontact->m_url); if (contact_uri_changed) { previous_previous = ob->ob_previous; previous_dcontact = ob->ob_dcontact; previous_via = ob->ob_via; if (ob->ob_registering && (reg_id == 0 || ob->ob_info.outbound < outbound_feature_supported)) previous_rcontact = NULL, ob->ob_previous = ob->ob_rcontact; else previous_rcontact = ob->ob_rcontact, ob->ob_previous = NULL; if (ob->ob_previous) msg_header_replace_param(home, (void*)ob->ob_previous, "expires=0"); } else { previous_previous = ob->ob_rcontact; previous_rcontact = NULL; previous_dcontact = ob->ob_dcontact; previous_via = ob->ob_via; } ob->ob_contacts = 1; ob->ob_rcontact = rcontact; ob->ob_dcontact = dcontact; ob->ob_via = v; if (contact_uri_changed) { ob->ob_registering = 0; ob->ob_registered = 0; ob->ob_validated = 0; } msg_header_free(home, (void *)previous_rcontact); msg_header_free(home, (void *)previous_previous); if (previous_dcontact != ob->ob_previous && previous_dcontact != previous_rcontact && previous_dcontact != previous_previous) msg_header_free(home, (void *)previous_dcontact); msg_header_free(home, (void *)previous_via); return 0;}/**Set new contact. * * @retval 0 when successful * @retval -1 error setting contact */int outbound_set_contact(outbound_t *ob, sip_contact_t const *application_contact, sip_via_t const *v, int terminating){ su_home_t *home = ob->ob_home; sip_contact_t *rcontact = NULL, *dcontact = NULL, *previous = NULL; sip_contact_t *m1, *m2, *m3; int contact_uri_changed = 0; m1 = ob->ob_rcontact; m2 = ob->ob_dcontact; m3 = ob->ob_previous; if (terminating) { if (ob->ob_by_stack && application_contact == NULL) return 0; if (ob->ob_contacts) previous = ob->ob_rcontact; } else if (application_contact) { rcontact = sip_contact_dup(home, application_contact); if (!ob->ob_rcontact || url_cmp_all(ob->ob_rcontact->m_url, application_contact->m_url)) { contact_uri_changed = 1; previous = ob->ob_contacts ? ob->ob_rcontact : NULL; } } else if (ob->ob_by_stack) { return 0; /* Xyzzy - nothing happens */ } else if (v) { char const *tport = !v->v_next ? v->v_protocol : NULL; char reg_id_param[20]; dcontact = ob->ob_oo->oo_contact(ob->ob_owner, home, 1, v, tport, NULL); if (!dcontact) return -1; if (ob->ob_instance && ob->ob_reg_id != 0) snprintf(reg_id_param, sizeof reg_id_param, ";reg-id=%u", ob->ob_reg_id); rcontact = ob->ob_oo->oo_contact(ob->ob_owner, home, 0, v, v->v_protocol, ob->ob_instance, reg_id_param, NULL); if (!rcontact) return -1; if (!ob->ob_rcontact || url_cmp_all(ob->ob_rcontact->m_url, rcontact->m_url)) { contact_uri_changed = 1; previous = ob->ob_contacts ? ob->ob_rcontact : NULL; } } ob->ob_by_stack = application_contact == NULL; ob->ob_contacts = rcontact != NULL; ob->ob_rcontact = rcontact; ob->ob_dcontact = dcontact; ob->ob_previous = previous; if (contact_uri_changed) { ob->ob_registering = 0; ob->ob_registered = 0; ob->ob_validated = 0; ob->ob_once_validated = 0; } if (m1 != previous) msg_header_free(home, (void *)m1); if (m2 != m1 && m2 != m3) msg_header_free(home, (void *)m2); msg_header_free(home, (void *)m3); return 0;}sip_contact_t const *outbound_dialog_contact(outbound_t const *ob){ if (ob == NULL) return NULL; else if (ob->ob_gruu) return ob->ob_gruu; else return ob->ob_dcontact;}sip_contact_t const *outbound_dialog_gruu(outbound_t const *ob){ return ob ? ob->ob_gruu : NULL;}/* ---------------------------------------------------------------------- */static enum outbound_featurefeature_level(sip_t const *sip, char const *tag, int level){ if (sip_has_feature(sip->sip_require, tag)) return outbound_feature_required; else if (sip_has_feature(sip->sip_supported, tag)) return outbound_feature_supported; else if (sip_has_feature(sip->sip_unsupported, tag)) return outbound_feature_unsupported; else return level;}void outbound_peer_info(outbound_t *ob, sip_t const *sip){ if (sip == NULL) { ob->ob_info.outbound = outbound_feature_unsure; ob->ob_info.gruu = outbound_feature_unsure; ob->ob_info.pref = outbound_feature_unsure; return; } ob->ob_info.outbound = feature_level(sip, "outbound", ob->ob_info.outbound); ob->ob_info.gruu = feature_level(sip, "gruu", ob->ob_info.gruu); ob->ob_info.pref = feature_level(sip, "pref", ob->ob_info.pref);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -