📄 nta.c
字号:
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));}/* ====================================================================== *//* 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);#if HAVE_SIGCOMP if (stream && tport_can_send_sigcomp(tport) && tport_name(tport)->tpn_comp == NULL && sip->sip_via->v_comp && tport_has_compression(tport_parent(tport), sip->sip_via->v_comp)) { tport_set_compression(tport, sip->sip_via->v_comp); }#endif 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_method_ack) nta_msg_treply(agent, msg, SIP_501_NOT_IMPLEMENTED, NTATAG_TPORT(tport), TAG_END()); else msg_destroy(msg); }}/** Check Via header. * */staticint agent_check_request_via(nta_agent_t *agent, msg_t *msg, sip_t *sip, sip_via_t *v, tport_t *tport){ enum { receivedlen = sizeof("received=") - 1 }; char received[receivedlen + TPORT_HOSTPORTSIZE]; char *hostport = received + receivedlen; char const *rport; su_sockaddr_t *from; sip_via_t *tpv = tport_magic(tport); assert(tport); assert(msg); assert(sip); assert(sip->sip_request); assert(tpv); from = (su_sockaddr_t *)msg_addr(msg); if (v == NULL) { /* Make up a via line */ v = sip_via_format(msg_home(msg), "SIP/2.0/%s %s", tport_name(tport)->tpn_proto, tport_hostport(hostport, TPORT_HOSTPORTSIZE, from, 1)); msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t *)v); return v ? 0 : -1; } if (str0casecmp(v->v_protocol, tpv->v_protocol)) { tport_hostport(hostport, TPORT_HOSTPORTSIZE, from, 1); SU_DEBUG_1(("nta: Via check: invalid transport \"%s\" from %s\n", v->v_protocol, hostport)); return -1; } if (v->v_received) { /* Nasty, nasty */ tport_hostport(hostport, TPORT_HOSTPORTSIZE, from, 1); SU_DEBUG_1(("nta: Via check: extra received=%s from %s\n", v->v_received, hostport)); msg_header_remove_param(v->v_common, "received"); } if (!tport_hostport(hostport, TPORT_HOSTPORTSIZE, from, 0)) return -1; if (strcasecmp(hostport, v->v_host)) { int rlen; /* Add the "received" field */ memcpy(received, "received=", receivedlen); if (hostport[0] == '[') { rlen = strlen(hostport + 1) - 1; memmove(hostport, hostport + 1, rlen); hostport[rlen] = '\0'; } msg_header_replace_param(msg_home(msg), v->v_common, su_strdup(msg_home(msg), received)); SU_DEBUG_5(("nta: Via check: %s\n", received)); } if (!agent->sa_server_rport) { /*Xyzzy*/; } else if (v->v_rport) { rport = su_sprintf(msg_home(msg), "rport=%u", ntohs(from->su_port)); msg_header_replace_param(msg_home(msg), v->v_common, rport); } else if (tport_is_tcp(tport)) { rport = su_sprintf(msg_home(msg), "rport=%u", ntohs(from->su_port)); msg_header_replace_param(msg_home(msg), v->v_common, rport); } return 0;}/** @internal Handle aliases of local node. * * Return true if @a url is modified. */staticint agent_aliases(nta_agent_t const *agent, url_t url[], tport_t *tport){ sip_contact_t *m; sip_via_t *lv; char const *tport_port = ""; if (!url->url_host) return 0; if (tport) tport_port = tport_name(tport)->tpn_port; assert(tport_port); for (m = agent->sa_aliases ? agent->sa_aliases : agent->sa_contact; m; m = m->m_next) { if (url->url_type != m->m_url->url_type) continue; if (strcasecmp(url->url_host, m->m_url->url_host)) continue; if (u
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -