📄 nta.c
字号:
staticsip_via_t const *agent_tport_via(tport_t *tport){ sip_via_t *v = tport_magic(tport); while (v && v->v_next) v = v->v_next; return v;}/** Insert Via to a request message */staticint outgoing_insert_via(nta_outgoing_t *orq, sip_via_t const *via){ nta_agent_t *self = orq->orq_agent; msg_t *msg = orq->orq_request; sip_t *sip = sip_object(msg); char const *branch = orq->orq_via_branch; int user_via = orq->orq_user_via; sip_via_t *v; int clear = 0; assert(sip); assert(via); if (user_via && sip->sip_via) { /* Use existing Via provided by application */ v = sip->sip_via; } else if (msg && via && sip->sip_request && (v = sip_via_copy(msg_home(msg), via))) { msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t *)v); } else return -1; if (!v->v_rport && ((self->sa_rport && v->v_protocol == sip_transport_udp) || (self->sa_tcp_rport && v->v_protocol == sip_transport_tcp))) msg_header_add_param(msg_home(msg), v->v_common, "rport"); if (!orq->orq_tpn->tpn_comp) msg_header_remove_param(v->v_common, "comp"); if (branch && branch != v->v_branch) { char const *bvalue = branch + strcspn(branch, "="); if (*bvalue) bvalue++; if (!v->v_branch || strcasecmp(bvalue, v->v_branch)) msg_header_replace_param(msg_home(msg), v->v_common, branch); } if (via->v_protocol != v->v_protocol && strcasecmp(via->v_protocol, v->v_protocol)) clear = 1, v->v_protocol = via->v_protocol; /* XXX - should we do this? */ if (via->v_host != v->v_host && str0cmp(via->v_host, v->v_host)) clear = 1, v->v_host = via->v_host; if (via->v_port != v->v_port && str0cmp(via->v_port, v->v_port)) clear = 1, v->v_port = via->v_port; if (clear) msg_fragment_clear(v->v_common); return 0;}/** Get destination name from Via. * * If @a using_rport is non-null, try rport. * If *using_rport is non-zero, try rport even if <protocol> is not UDP. * If <protocol> is UDP, set *using_rport to zero. */staticint nta_tpn_by_via(tp_name_t *tpn, sip_via_t const *v, int *using_rport){ if (!v) return -1; tpn->tpn_proto = sip_via_transport(v); tpn->tpn_canon = v->v_host; if (v->v_maddr) tpn->tpn_host = v->v_maddr; else if (v->v_received) tpn->tpn_host = v->v_received; else tpn->tpn_host = v->v_host; tpn->tpn_port = sip_via_port(v, using_rport); tpn->tpn_comp = v->v_comp; tpn->tpn_ident = NULL; return 0;}/** Get transport name from URL. */int nta_tpn_by_url(su_home_t *home, tp_name_t *tpn, char const **scheme, char const **port, url_string_t const *us){ url_t url[1]; int n; char *b; n = url_xtra(us->us_url); b = su_alloc(home, n); if (b == NULL || url_dup(b, n, url, us->us_url) < 0) { su_free(home, b); return -1; } if (url->url_type != url_sip && url->url_type != url_sips && url->url_type != url_im && url->url_type != url_pres) { su_free(home, b); return -1; } SU_DEBUG_7(("nta: selecting scheme %s\n", url->url_scheme)); *scheme = url->url_scheme; if (strcasecmp(url->url_scheme, "sips") == 0) tpn->tpn_proto = "tls"; else tpn->tpn_proto = "*"; tpn->tpn_canon = url->url_host; tpn->tpn_host = url->url_host; if (url->url_params) { for (b = (char *)url->url_params; b[0]; b += n) { n = strcspn(b, ";"); if (n > 10 && strncasecmp(b, "transport=", 10) == 0) tpn->tpn_proto = b + 10; else if (n > 5 && strncasecmp(b, "comp=", 5) == 0) tpn->tpn_comp = b + 5; else if (n > 6 && strncasecmp(b, "maddr=", 6) == 0) tpn->tpn_host = b + 6; if (b[n]) b[n++] = '\0'; } } if ((*port = url->url_port)) tpn->tpn_port = url->url_port; tpn->tpn_ident = NULL; return 0;}/** Handle transport errors. */staticvoid agent_tp_error(nta_agent_t *agent, tport_t *tport, int errcode, char const *remote){ su_llog(nta_log, 1, "nta_agent: tport: %s%s%s\n", remote ? remote : "", remote ? ": " : "", su_strerror(errcode));}/** Handle updated transport addresses */static void agent_update_tport(nta_agent_t *self, tport_t *tport){ /* Initialize local Vias first */ agent_init_via(self, tport_primaries(self->sa_tports), 0); if (self->sa_update_tport) { self->sa_update_tport(self->sa_update_magic, self); } else { /* XXX - we should do something else? */ SU_DEBUG_3(("nta(%p): transport address updated\n", self)); }}/* ====================================================================== *//* 3) Message dispatch */static void agent_recv_request(nta_agent_t *agent, msg_t *msg, sip_t *sip, tport_t *tport);static int agent_check_request_via(nta_agent_t *agent, msg_t *msg, sip_t *sip, sip_via_t *v, tport_t *tport);static int agent_aliases(nta_agent_t const *, url_t [], tport_t *);static void agent_recv_response(nta_agent_t*, msg_t *, sip_t *, sip_via_t *, tport_t*);static void agent_recv_garbage(nta_agent_t*, msg_t*, tport_t*);/** Handle incoming message. */staticvoid agent_recv_message(nta_agent_t *agent, tport_t *tport, msg_t *msg, sip_via_t *tport_via, su_time_t now){ sip_t *sip = sip_object(msg); agent->sa_millisec = su_time_ms(agent->sa_now = now); if (sip && sip->sip_request) { agent_recv_request(agent, msg, sip, tport); } else if (sip && sip->sip_status) { agent_recv_response(agent, msg, sip, tport_via, tport); } else { agent_recv_garbage(agent, msg, tport); } agent->sa_millisec = 0;}/** @internal Handle incoming requests. */staticvoid agent_recv_request(nta_agent_t *agent, msg_t *msg, sip_t *sip, tport_t *tport){ nta_leg_t *leg; nta_incoming_t *irq, *merge = NULL, *ack = NULL; sip_method_t method = sip->sip_request->rq_method; char const *method_name = sip->sip_request->rq_method_name; url_t url[1]; unsigned cseq = sip->sip_cseq ? sip->sip_cseq->cs_seq : 0; int insane, errors, stream; agent->sa_stats->as_recv_msg++; agent->sa_stats->as_recv_request++; SU_DEBUG_5(("nta: received %s " URL_PRINT_FORMAT " %s (CSeq %u)\n", method_name, URL_PRINT_ARGS(sip->sip_request->rq_url), sip->sip_request->rq_version, cseq)); stream = tport_is_stream(tport); /* Try to use compression on reverse direction if Via has comp=sigcomp */ if (stream && sip->sip_via->v_comp && tport_can_send_sigcomp(tport) && tport_name(tport)->tpn_comp == NULL && tport_has_compression(tport_parent(tport), sip->sip_via->v_comp)) { tport_set_compression(tport, sip->sip_via->v_comp); } if (sip->sip_flags & MSG_FLG_TOOLARGE) { SU_DEBUG_5(("nta: %s (%u) is %s\n", method_name, cseq, sip_413_Request_too_large)); agent->sa_stats->as_bad_request++; nta_msg_treply(agent, msg, SIP_413_REQUEST_TOO_LARGE, NTATAG_TPORT(tport), NTATAG_INCOMPLETE(1), TPTAG_SDWN_AFTER(stream), TAG_END()); return; } insane = 0; if (agent->sa_bad_req_mask) errors = msg_extract_errors(msg) & agent->sa_bad_req_mask; else errors = sip->sip_error != NULL; if (errors || (sip->sip_flags & MSG_FLG_ERROR) /* Fatal error */ || (insane = (sip_sanity_check(sip) < 0))) { sip_header_t const *h; char const *badname = NULL, *phrase; agent->sa_stats->as_bad_message++; agent->sa_stats->as_bad_request++; if (insane) SU_DEBUG_5(("nta: %s (%u) %s\n", method_name, cseq, "failed sanity check")); for (h = (sip_header_t const *)sip->sip_error; h; h = h->sh_next) { char const *bad; if (h->sh_class == sip_error_class) bad = h->sh_error->er_name; else bad = h->sh_class->hc_name; if (bad) SU_DEBUG_5(("nta: %s has bad %s header\n", method_name, bad)); if (!badname) badname = bad; } if (sip->sip_via && method != sip_method_ack) { msg_t *reply = nta_msg_create(agent, 0); if (reply) { agent_check_request_via(agent, msg, sip, sip->sip_via, tport); if (badname) phrase = su_sprintf(msg_home(reply), "Bad %s Header", badname); else phrase = sip_400_Bad_request; SU_DEBUG_5(("nta: %s (%u) is %s\n", method_name, cseq, phrase)); nta_msg_mreply(agent, reply, sip_object(reply), 400, phrase, msg, NTATAG_TPORT(tport), NTATAG_INCOMPLETE(1), TPTAG_SDWN_AFTER(stream), TAG_END()); } } else { msg_destroy(msg); if (stream) /* Send FIN */ tport_shutdown(tport, 1); } return; } if (str0casecmp(sip->sip_request->rq_version, sip_version_2_0) != 0) { agent->sa_stats->as_bad_request++; agent->sa_stats->as_bad_message++; SU_DEBUG_5(("nta: bad version %s for %s (%u)\n", sip->sip_request->rq_version, method_name, cseq)); nta_msg_treply(agent, msg, SIP_505_VERSION_NOT_SUPPORTED, NTATAG_TPORT(tport), TPTAG_SDWN_AFTER(stream), TAG_END()); return; } if (agent_check_request_via(agent, msg, sip, sip->sip_via, tport) < 0) { agent->sa_stats->as_bad_message++; agent->sa_stats->as_bad_request++; SU_DEBUG_5(("nta: %s (%u) %s\n", method_name, cseq, "has invalid Via")); msg_destroy(msg); return; } /* First, try existing incoming requests */ irq = incoming_find(agent, sip, sip->sip_via, &merge, &ack); if (irq) { /* Match - this is a retransmission */ SU_DEBUG_5(("nta: %s (%u) going to existing %s transaction\n", method_name, cseq, irq->irq_rq->rq_method_name)); if (incoming_recv(irq, msg, sip, tport) >= 0) return; } else if (ack) { /* Match - this is an ACK or CANCEL or PRACK */ SU_DEBUG_5(("nta: %s (%u) is going to %s (%u)\n", method_name, cseq, ack->irq_rq->rq_method_name, ack->irq_cseq->cs_seq)); if (method == sip_method_ack) { if (incoming_ack(ack, msg, sip, tport) >= 0) return; } else if (method == sip_method_cancel) { if (incoming_cancel(ack, msg, sip, tport) >= 0) return; } else if (method == sip_method_prack) { if (reliable_recv(ack, msg, sip, tport) >= 0) return; } else { assert(!method); } } else if (merge) { SU_DEBUG_5(("nta: %s (%u) %s\n", method_name, cseq, "is a merged request")); if (incoming_merge(merge, msg, sip, tport) >= 0) return; } *url = *sip->sip_request->rq_url; url->url_params = NULL; agent_aliases(agent, url, tport); /* canonize urls */ if ((leg = leg_find(agent, method_name, url, sip->sip_call_id, sip->sip_from->a_tag, sip->sip_from->a_url, sip->sip_to->a_tag, sip->sip_to->a_url))) { /* Try existing dialog */ SU_DEBUG_5(("nta: %s (%u) %s\n", method_name, cseq, "going to existing leg")); leg_recv(leg, msg, sip, tport); return; } else if (!agent->sa_is_stateless && (leg = dst_find(agent, url, method_name))) { /* Dialogless legs - let application process transactions statefully */ SU_DEBUG_5(("nta: %s (%u) %s\n", method_name, cseq, "going to a dialogless leg")); leg_recv(leg, msg, sip, tport); } else if (!agent->sa_is_stateless && (leg = agent->sa_default_leg)) { SU_DEBUG_5(("nta: %s (%u) %s\n", method_name, cseq, "going to a default leg")); leg_recv(leg, msg, sip, tport); } else if (agent->sa_callback) { /* Stateless processing for request */ agent->sa_stats->as_trless_request++; SU_DEBUG_5(("nta: %s (%u) %s\n", method_name, cseq, "to message callback")); (void)agent->sa_callback(agent->sa_magic, agent, msg, sip); } else { agent->sa_stats->as_trless_request++; SU_DEBUG_5(("nta: %s (%u) no place to go: %d %s\n", method_name, cseq, SIP_501_NOT_IMPLEMENTED)); if (method != sip
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -