📄 nta.c
字号:
agent_set_params(agent, ta_args(ta)); if (agent->sa_mclass == NULL) agent->sa_mclass = sip_default_mclass(); agent->sa_in.re_t1 = &agent->sa_in.re_list; incoming_queue_init(agent->sa_in.proceeding, 0); incoming_queue_init(agent->sa_in.preliminary, agent->sa_t1x64); /* P1 */ incoming_queue_init(agent->sa_in.inv_completed, agent->sa_t1x64); /* H */ incoming_queue_init(agent->sa_in.inv_confirmed, agent->sa_t4); /* I */ incoming_queue_init(agent->sa_in.completed, agent->sa_t1x64); /* J */ incoming_queue_init(agent->sa_in.terminated, 0); incoming_queue_init(agent->sa_in.final_failed, 0); agent->sa_out.re_t1 = &agent->sa_out.re_list; outgoing_queue_init(agent->sa_out.delayed, 0); outgoing_queue_init(agent->sa_out.resolving, 0); outgoing_queue_init(agent->sa_out.trying, agent->sa_t1x64); /* F */ outgoing_queue_init(agent->sa_out.completed, agent->sa_t4); /* K */ outgoing_queue_init(agent->sa_out.terminated, 0); /* Special queues (states) for outgoing INVITE transactions */ outgoing_queue_init(agent->sa_out.inv_calling, agent->sa_t1x64); /* B */ timer_c = (agent->sa_use_timer_c || !agent->sa_is_a_uas) ? agent->sa_timer_c : 0; outgoing_queue_init(agent->sa_out.inv_proceeding, timer_c); /* C */ outgoing_queue_init(agent->sa_out.inv_completed, 32000); /* Timer D */ if (leg_htable_resize(agent->sa_home, agent->sa_dialogs, 0) < 0 || leg_htable_resize(agent->sa_home, agent->sa_defaults, 0) < 0 || outgoing_htable_resize(agent->sa_home, agent->sa_outgoing, 0) < 0 || incoming_htable_resize(agent->sa_home, agent->sa_incoming, 0) < 0) { SU_DEBUG_0(("nta_agent_create: failure with %s\n", "hash tables")); goto deinit; } SU_DEBUG_9(("nta_agent_create: initialized %s\n", "hash tables")); if (contact_url != (url_string_t *)-1 && nta_agent_add_tport(agent, contact_url, ta_tags(ta)) < 0) { SU_DEBUG_7(("nta_agent_create: failure with %s\n", "transport")); goto deinit; } SU_DEBUG_9(("nta_agent_create: initialized %s\n", "transports")); if (agent_tag_init(agent) < 0) { SU_DEBUG_3(("nta_agent_create: failure with %s\n", "random identifiers")); goto deinit; } SU_DEBUG_9(("nta_agent_create: initialized %s\n", "random identifiers")); if (agent_timer_init(agent) < 0) { SU_DEBUG_0(("nta_agent_create: failure with %s\n", "timer")); goto deinit; } SU_DEBUG_9(("nta_agent_create: initialized %s\n", "timer")); if (agent_launch_terminator(agent) == 0) SU_DEBUG_9(("nta_agent_create: initialized %s\n", "threads"));#if HAVE_SOFIA_SRESOLV agent->sa_resolver = sres_resolver_create(root, NULL, ta_tags(ta)); if (!agent->sa_resolver) { SU_DEBUG_0(("nta_agent_create: failure with %s\n", "resolver")); } SU_DEBUG_9(("nta_agent_create: initialized %s\n", "resolver"));#endif ta_end(ta); return agent; deinit: nta_agent_destroy(agent); } ta_end(ta); return NULL;}/** * Destroy an NTA agent object. * * @param agent the NTA agent object to be destroyed. * */void nta_agent_destroy(nta_agent_t *agent){ if (agent) { size_t i; outgoing_htable_t *oht = agent->sa_outgoing; incoming_htable_t *iht = agent->sa_incoming; /* Currently, this is pretty pointless, as legs don't keep any resources */ leg_htable_t *lht; nta_leg_t *leg; for (i = 0, lht = agent->sa_dialogs; i < lht->lht_size; i++) { if ((leg = lht->lht_table[i])) { SU_DEBUG_3(("nta_agent_destroy: destroying dialog with <" URL_PRINT_FORMAT ">\n", URL_PRINT_ARGS(leg->leg_remote->a_url))); leg_free(agent, leg); } } for (i = 0, lht = agent->sa_defaults; i < lht->lht_size; i++) { if ((leg = lht->lht_table[i])) { SU_DEBUG_3(("%s: destroying leg for <" URL_PRINT_FORMAT ">\n", __func__, URL_PRINT_ARGS(leg->leg_url))); leg_free(agent, leg); } } if (agent->sa_default_leg) leg_free(agent, agent->sa_default_leg); for (i = iht->iht_size; i-- > 0; ) while (iht->iht_table[i]) { nta_incoming_t *irq = iht->iht_table[i]; if (!irq->irq_destroyed) SU_DEBUG_3(("%s: destroying %s server transaction from <" URL_PRINT_FORMAT ">\n", __func__, irq->irq_rq->rq_method_name, URL_PRINT_ARGS(irq->irq_from->a_url))); incoming_free(irq); } for (i = oht->oht_size; i-- > 0;) while (oht->oht_table[i]) { nta_outgoing_t *orq = oht->oht_table[i]; if (!orq->orq_destroyed) SU_DEBUG_3(("%s: destroying %s client transaction to <" URL_PRINT_FORMAT ">\n", __func__, orq->orq_method_name, URL_PRINT_ARGS(orq->orq_to->a_url))); outgoing_free(orq); } su_timer_destroy(agent->sa_timer), agent->sa_timer = NULL;# if HAVE_SOFIA_SRESOLV sres_resolver_destroy(agent->sa_resolver), agent->sa_resolver = NULL;# endif tport_destroy(agent->sa_tports), agent->sa_tports = NULL; agent_kill_terminator(agent); su_home_unref(agent->sa_home); }}/** Return agent context. */nta_agent_magic_t *nta_agent_magic(nta_agent_t const *agent){ return agent ? agent->sa_magic : NULL;}/** Return @Contact header. * * Get a @Contact header, which can be used to reach @a agent. * * @param agent NTA agent object * * User agents can insert the @Contact header in the outgoing REGISTER, * INVITE, and ACK requests and replies to incoming INVITE and OPTIONS * transactions. * * Proxies can use the @Contact header to create appropriate @RecordRoute * headers: * @code * r_r = sip_record_route_create(msg_home(msg), * sip->sip_request->rq_url, * contact->m_url); * @endcode * * @return A sip_contact_t object corresponding to the @a agent. */sip_contact_t *nta_agent_contact(nta_agent_t const *agent){ return agent ? agent->sa_contact : NULL;}/** Return a list of @Via headers. * * Get @Via headers for all activated transport. * * @param agent NTA agent object * * @return A list of #sip_via_t objects used by the @a agent. */sip_via_t *nta_agent_via(nta_agent_t const *agent){ return agent ? agent->sa_vias : NULL;}/** Return a list of public (UPnP, STUN) @Via headers. * * Get public @Via headers for all activated transports. * * @param agent NTA agent object * * @return A list of #sip_via_t objects used by the @a agent. */sip_via_t *nta_agent_public_via(nta_agent_t const *agent){ return agent ? agent->sa_public_vias : NULL;}/** Match a @Via header @a v with @Via headers in @a agent. * */staticsip_via_t *agent_has_via(nta_agent_t const *agent, sip_via_t const *via){ sip_via_t const *v; for (v = agent->sa_public_vias; v; v = v->v_next) { if (strcasecmp(via->v_host, v->v_host)) continue; if (str0cmp(via->v_port, v->v_port)) continue; if (strcasecmp(via->v_protocol, v->v_protocol)) continue; return (sip_via_t *)v; } for (v = agent->sa_vias; v; v = v->v_next) { if (strcasecmp(via->v_host, v->v_host)) continue; if (str0cmp(via->v_port, v->v_port)) continue; if (strcasecmp(via->v_protocol, v->v_protocol)) continue; return (sip_via_t *)v; } return NULL;}/** Return @UserAgent header. * * Get @UserAgent information with NTA version. * * @param agent NTA agent object (may be NULL) * * @return A string containing the @a agent version. */char const *nta_agent_version(nta_agent_t const *agent){ return "nta" "/" VERSION;}/** Initialize default tag */static int agent_tag_init(nta_agent_t *self){ sip_contact_t *m = self->sa_contact; uint32_t hash = 1; if (m) { if (m->m_url->url_user) hash = 914715421U * hash + msg_hash_string(m->m_url->url_user); if (m->m_url->url_host) hash = 914715421U * hash + msg_hash_string(m->m_url->url_host); if (m->m_url->url_port) hash = 914715421U * hash + msg_hash_string(m->m_url->url_port); if (m->m_url->url_params) hash = 914715421U * hash + msg_hash_string(m->m_url->url_params); } if (hash == 0) hash = 914715421U; self->sa_branch = NTA_BRANCH_PRIME * su_ntp_now(); self->sa_branch *= hash; self->sa_tags = NTA_TAG_PRIME * self->sa_branch; return 0;}/** Initialize agent timer. */staticint agent_timer_init(nta_agent_t *agent){ agent->sa_timer = su_timer_create(su_root_task(agent->sa_root), NTA_SIP_T1 / 8);#if 0 return su_timer_set(agent->sa_timer, agent_timer, agent);#endif return -(agent->sa_timer == NULL);}/** * Agent timer routine. */staticvoid agent_timer(su_root_magic_t *rm, su_timer_t *timer, nta_agent_t *agent){ su_time_t stamp = su_now(); uint32_t now = su_time_ms(stamp), next, latest; now += now == 0; agent->sa_next = 0; agent->sa_now = stamp; agent->sa_millisec = now; agent->sa_in_timer = 1; outgoing_timer(agent); incoming_timer(agent); /* agent->sa_now is used only if sa_millisec != 0 */ agent->sa_millisec = 0; agent->sa_in_timer = 0; /* Calculate next timeout */ next = latest = now + NTA_TIME_MAX + 1;#define NEXT_TIMEOUT(next, p, f, now) \ (void)(p && (int32_t)(p->f - (next)) < 0 && \ ((next) = ((int32_t)(p->f - (now)) > 0 ? p->f : (now)))) NEXT_TIMEOUT(next, agent->sa_out.re_list, orq_retry, now); NEXT_TIMEOUT(next, agent->sa_out.inv_completed->q_head, orq_timeout, now); NEXT_TIMEOUT(next, agent->sa_out.completed->q_head, orq_timeout, now); NEXT_TIMEOUT(next, agent->sa_out.inv_calling->q_head, orq_timeout, now); if (agent->sa_out.inv_proceeding->q_timeout) NEXT_TIMEOUT(next, agent->sa_out.inv_proceeding->q_head, orq_timeout, now); NEXT_TIMEOUT(next, agent->sa_out.trying->q_head, orq_timeout, now); NEXT_TIMEOUT(next, agent->sa_in.preliminary->q_head, irq_timeout, now); NEXT_TIMEOUT(next, agent->sa_in.inv_completed->q_head, irq_timeout, now); NEXT_TIMEOUT(next, agent->sa_in.inv_confirmed->q_head, irq_timeout, now); NEXT_TIMEOUT(next, agent->sa_in.completed->q_head, irq_timeout, now); NEXT_TIMEOUT(next, agent->sa_in.re_list, irq_retry, now); if (agent->sa_next) NEXT_TIMEOUT(next, agent, sa_next, now);#undef NEXT_TIMEOUT if (next == latest) { /* Do not set timer? */ SU_DEBUG_9(("nta: timer not set\n")); assert(!agent->sa_out.completed->q_head); assert(!agent->sa_out.trying->q_head); assert(!agent->sa_out.inv_calling->q_head); assert(!agent->sa_out.re_list); assert(!agent->sa_in.inv_confirmed->q_head); assert(!agent->sa_in.preliminary->q_head); assert(!agent->sa_in.completed->q_head); assert(!agent->sa_in.inv_completed->q_head); assert(!agent->sa_in.re_list); return; } if (next == now) if (++next == 0) ++next; SU_DEBUG_9(("nta: timer %s to %ld ms\n", "set next", (long)(next - now))); agent->sa_next = next; su_timer_set_at(timer, agent_timer, agent, su_time_add(stamp, next - now));}/** Add uin32_t milliseconds to the time. */static su_time_t add_milliseconds(su_time_t t0, uint32_t ms){ unsigned long sec = ms / 1000, usec = (ms % 1000) * 1000; t0.tv_usec += usec; t0.tv_sec += sec; if (t0.tv_usec >= 1000000) { t0.tv_sec += 1; t0.tv_usec -= 1000000; } return t0;}/** Calculate nonzero value for timeout. * * Sets or adjusts agent timer when needed. * * @retval 0 if offset is 0 * @retval timeout (millisecond counter) otherwise */staticuint32_t set_timeout(nta_agent_t *agent, uint32_t offset){ su_time_t now; uint32_t next, ms; if (offset == 0) return 0; if (agent->sa_millisec) /* Avoid expensive call to su_now() */ now = agent->sa_now, ms = agent->sa_millisec; else now = su_now(), ms = su_time_ms(now); next = ms + offset; if (next == 0) next = 1; if (agent->sa_in_timer) /* Currently executing timer */ return next; if (agent->sa_next == 0 || (int32_t)(agent->sa_next - next - 5L) > 0) { /* Set timer */ if (agent->sa_next) SU_DEBUG_9(("nta: timer %s to %ld ms\n", "shortened", (long)offset)); else SU_DEBUG_9(("nta: timer %s to %ld ms\n", "set", (long)offset)); su_timer_set_at(agent->sa_timer, agent_timer, agent, add_milliseconds(now, offset)); agent->sa_next = next; } return next;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -