📄 outbound.c
字号:
return 0;}/** @internal Check if there is a NAT between us and registrar. * * @retval -1 upon an error * @retval #ob_register_ok (0) if the registration was OK * @retval #ob_reregister (1) if client needs to re-register * @retval #ob_reregister_now (2) if client needs to re-register immediately */staticint outbound_check_for_nat(outbound_t *ob, sip_t const *request, sip_t const *response){ int binding_changed; sip_contact_t *m = ob->ob_rcontact; /* Update NAT information */ binding_changed = outbound_nat_detect(ob, request, response); if (!ob->ob_nat_detected) return ob_no_nat; /* Contact was set by application, do not change it */ if (!ob->ob_by_stack) return ob_no_nat; /* Application does not want us to do any NAT traversal */ if (!ob->ob_prefs.natify) return ob_no_nat; /* We have detected NAT. Now, what to do? * 1) do nothing - register as usual and let proxy take care of it? * 2) try to detect our public nat binding and use it * 2A) use public vias from nta generated by STUN or UPnP * 2B) use SIP Via header */ /* Do we have to ask for reregistration */ if (!m || binding_changed >= ob_nat_changed) { if (ob->ob_stun) { /* Use STUN? */ return ob_reregister; } else if (ob->ob_upnp) { /* Use UPnP */ return ob_reregister; } else { if (outbound_contacts_from_via(ob, response->sip_via) < 0) return -1; } return ob_reregister_now; } return 0;}/**@internal * * Detect NAT. * * Based on "received" and possible "rport" parameters in the top-most Via, * check and update our NAT status. * * @retval ob_nat_changed (2) change in public NAT binding detected * @retval ob_nat_detected (1) NAT binding detected * @retval ob_no_nat (0) no NAT binding detected * @retval -1 an error occurred */staticint outbound_nat_detect(outbound_t *ob, sip_t const *request, sip_t const *response){ sip_via_t const *v; int one = 1; char const *received, *rport; char *nat_detected, *nat_port; char *new_detected, *new_port; assert(request && request->sip_request); assert(response && response->sip_status); if (!ob || !response || !response->sip_via || !request->sip_via) return -1; v = response->sip_via; received = v->v_received; if (!received || !strcmp(received, request->sip_via->v_host)) return 0; if (!host_is_ip_address(received)) { if (received[0]) SU_DEBUG_3(("outbound(%p): Via with invalid received=%s\n", (void *)ob->ob_owner, received)); return 0; } rport = sip_via_port(v, &one); assert(rport); nat_detected = ob->ob_nat_detected; nat_port = ob->ob_nat_port; if (nat_detected && host_cmp(received, nat_detected) == 0) { if (nat_port && strcasecmp(rport, nat_port) == 0) return 1; if (!v->v_rport || !v->v_rport[0]) return 1; } if (!nat_detected) { SU_DEBUG_5(("outbound(%p): detected NAT: %s != %s\n", (void *)ob->ob_owner, v->v_host, received)); if (ob->ob_oo && ob->ob_oo->oo_status) ob->ob_oo->oo_status(ob->ob_owner, ob, 101, "NAT detected", TAG_END()); } else { SU_DEBUG_5(("outbound(%p): NAT binding changed: " "[%s]:%s != [%s]:%s\n", (void *)ob->ob_owner, nat_detected, nat_port, received, rport)); if (ob->ob_oo && ob->ob_oo->oo_status) ob->ob_oo->oo_status(ob->ob_owner, ob, 102, "NAT binding changed", TAG_END()); } /* Save our nat binding */ new_detected = su_strdup(ob->ob_home, received); new_port = su_strdup(ob->ob_home, rport); if (!new_detected || !new_port) { su_free(ob->ob_home, new_detected); su_free(ob->ob_home, new_port); return -1; } ob->ob_nat_detected = new_detected; ob->ob_nat_port = new_port; su_free(ob->ob_home, nat_detected); su_free(ob->ob_home, nat_port); return 2;}/* ---------------------------------------------------------------------- *//** Convert "gruu" parameter returned by registrar to Contact header. */int outbound_gruuize(outbound_t *ob, sip_t const *sip){ sip_contact_t *m = NULL; char *gruu; if (!ob) return 0; if (ob->ob_rcontact == NULL) return -1; if (!ob->ob_prefs.gruuize && ob->ob_instance) { char const *my_instance, *my_reg_id = NULL; char const *instance, *reg_id; m = ob->ob_rcontact; my_instance = msg_header_find_param(m->m_common, "+sip.instance="); if (my_instance) my_reg_id = msg_header_find_param(m->m_common, "reg-id="); for (m = sip->sip_contact; m; m = m->m_next) { if (my_instance) { instance = msg_header_find_param(m->m_common, "+sip.instance="); if (!instance || strcmp(instance, my_instance)) continue; if (my_reg_id) { reg_id = msg_header_find_param(m->m_common, "reg-id="); if (!reg_id || strcmp(reg_id, my_reg_id)) continue; } } if (url_cmp_all(ob->ob_rcontact->m_url, m->m_url) == 0) break; } } if (m == NULL) { if (ob->ob_gruu) msg_header_free(ob->ob_home, (void *)ob->ob_gruu), ob->ob_gruu = NULL; return 0; } gruu = (char *)msg_header_find_param(m->m_common, "pub-gruu="); if (gruu == NULL || gruu[0] == '\0') gruu = (char *)msg_header_find_param(m->m_common, "gruu="); if (gruu == NULL || gruu[0] == '\0') return 0; gruu = msg_unquote_dup(NULL, gruu); m = gruu ? sip_contact_format(ob->ob_home, "<%s>", gruu) : NULL; su_free(NULL, gruu); if (!m) return -1; if (ob->ob_gruu) msg_header_free(ob->ob_home, (void *)ob->ob_gruu); ob->ob_gruu = m; return 0;}/* ---------------------------------------------------------------------- */static int create_keepalive_message(outbound_t *ob, sip_t const *register_request);static int keepalive_options(outbound_t *ob);static int keepalive_options_with_registration_probe(outbound_t *ob);static int response_to_keepalive_options(outbound_t *ob, nta_outgoing_t *orq, sip_t const *sip);static void keepalive_timer(su_root_magic_t *root_magic, su_timer_t *t, su_timer_arg_t *ob_as_timer_arg);/** Start OPTIONS keepalive or contact validation process */void outbound_start_keepalive(outbound_t *ob, nta_outgoing_t *register_transaction){ unsigned interval = 0; int need_to_validate; if (!ob) return; if (ob->ob_prefs.natify && ob->ob_prefs.okeepalive) interval = ob->ob_prefs.interval; need_to_validate = ob->ob_prefs.validate && !ob->ob_validated; if (!ob->ob_nat_detected || !register_transaction || !(need_to_validate || interval != 0)) { outbound_stop_keepalive(ob); return; } if (ob->ob_keepalive.timer) su_timer_destroy(ob->ob_keepalive.timer), ob->ob_keepalive.timer = NULL; if (interval) ob->ob_keepalive.timer = su_timer_create(su_root_task(ob->ob_root), interval); ob->ob_keepalive.interval = interval; if (!ob->ob_validated && ob->ob_keepalive.sipstun && 0 /* Stun is disabled for now */) { nta_tport_keepalive(register_transaction); } else { if (register_transaction) { msg_t *msg = nta_outgoing_getrequest(register_transaction); sip_t const *register_request = sip_object(msg); create_keepalive_message(ob, register_request); msg_destroy(msg); } keepalive_options(ob); }}void outbound_stop_keepalive(outbound_t *ob){ if (!ob) return; ob->ob_keepalive.interval = 0; if (ob->ob_keepalive.timer) su_timer_destroy(ob->ob_keepalive.timer), ob->ob_keepalive.timer = NULL; if (ob->ob_keepalive.orq) nta_outgoing_destroy(ob->ob_keepalive.orq), ob->ob_keepalive.orq = NULL; if (ob->ob_keepalive.msg) msg_destroy(ob->ob_keepalive.msg), ob->ob_keepalive.msg = NULL;}/** @internal Create a message template for keepalive. */static int create_keepalive_message(outbound_t *ob, sip_t const *regsip){ msg_t *msg = nta_msg_create(ob->ob_nta, MSG_FLG_COMPACT), *previous; sip_t *osip = sip_object(msg); sip_contact_t *m = ob->ob_rcontact; unsigned d = ob->ob_keepalive.interval; if (msg == NULL) return -1; assert(regsip); assert(regsip->sip_request); if (m && m->m_params) { sip_accept_contact_t *ac; size_t i; int features = 0; ac = sip_accept_contact_make(msg_home(msg), "*;require;explicit"); for (i = 0; m->m_params[i]; i++) { char const *s = m->m_params[i]; if (!sip_is_callerpref(s)) continue; features++; s = su_strdup(msg_home(msg), s); msg_header_add_param(msg_home(msg), ac->cp_common, s); } if (features) msg_header_insert(msg, NULL, (void *)ac); else msg_header_free(msg_home(msg), (void *)ac); } if (0 > /* Duplicate essential headers from REGISTER request: */ sip_add_tl(msg, osip, SIPTAG_TO(regsip->sip_to), SIPTAG_FROM(regsip->sip_from), /* XXX - we should only use loose routing here */ /* XXX - if we used strict routing, the route header/request_uri must be restored */ SIPTAG_ROUTE(regsip->sip_route), /* Add Max-Forwards 0 */ TAG_IF(d, SIPTAG_MAX_FORWARDS_STR("0")), TAG_IF(d, SIPTAG_SUBJECT_STR("KEEPALIVE")), SIPTAG_CALL_ID_STR(ob->ob_cookie), SIPTAG_ACCEPT_STR(outbound_content_type), TAG_END()) || /* Create request-line, Call-ID, CSeq */ nta_msg_request_complete(msg, nta_default_leg(ob->ob_nta), SIP_METHOD_OPTIONS, (void *)regsip->sip_to->a_url) < 0 || msg_serialize(msg, (void *)osip) < 0 || msg_prepare(msg) < 0) return msg_destroy(msg), -1; previous = ob->ob_keepalive.msg; ob->ob_keepalive.msg = msg; msg_destroy(previous); return 0;}static int keepalive_options(outbound_t *ob){ msg_t *req; sip_t *sip; if (ob->ob_keepalive.orq) return 0; if (ob->ob_prefs.validate && ob->ob_registered && !ob->ob_validated) return keepalive_options_with_registration_probe(ob); req = msg_copy(ob->ob_keepalive.msg); if (!req) return -1; sip = sip_object(req); assert(sip); assert(sip->sip_request); if (nta_msg_request_complete(req, nta_default_leg(ob->ob_nta), SIP_METHOD_UNKNOWN, NULL) < 0) return msg_destroy(req), -1; if (ob->ob_keepalive.auc[0]) auc_authorization(ob->ob_keepalive.auc, req, (void *)sip, "OPTIONS", sip->sip_request->rq_url, 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)), TAG_END()); if (!ob->ob_keepalive.orq) return msg_destroy(req), -1; return 0;}static int response_to_keepalive_options(outbound_t *ob, nta_outgoing_t *orq, sip_t const *sip){ int status = 408; char const *phrase = sip_408_Request_timeout; int binding_check; int challenged = 0, credentials = 0; msg_t *_reqmsg = nta_outgoing_getrequest(orq); sip_t *request = sip_object(_reqmsg); msg_destroy(_reqmsg); if (sip && sip->sip_status) { status = sip->sip_status->st_status; phrase = sip->sip_status->st_phrase; } if (status == 100) { /* This probably means that we are in trouble. whattodo, whattodo */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -