📄 nta.c
字号:
/* * This file is part of the Sofia-SIP package * * Copyright (C) 2005 Nokia Corporation. * * Contact: Pekka Pessi <pekka.pessi@nokia.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * *//**@CFILE nta.c * @brief Sofia SIP Transaction API implementation * * This source file has been divided into sections as follows: * 1) agent * 2) tport handling * 3) dispatching messages received from network * 4) message creation, message utility * 5) stateless operation * 6) dialogs (legs) * 7) server transactions (incoming) * 8) client transactions (outgoing) * 9) resolving URLs for client transactions * 10) 100rel reliable responses (reliable) * 11) SigComp handling and public transport interface * * @author Pekka Pessi <Pekka.Pessi@nokia.com> * * @date Created: Tue Jun 13 02:57:51 2000 ppessi */#include "config.h"#include <sofia-sip/string0.h>/** @internal SU message argument structure type */#define SU_MSG_ARG_T union sm_arg_u/** @internal SU timer argument pointer type */#define SU_TIMER_ARG_T struct nta_agent_s#include <sofia-sip/su_alloc.h>#include <sofia-sip/su.h>#include <sofia-sip/su_time.h>#include <sofia-sip/su_tagarg.h>#include <sofia-sip/base64.h>#include <sofia-sip/su_uniqueid.h>#include <sofia-sip/sip.h>#include <sofia-sip/sip_header.h>#include <sofia-sip/sip_util.h>#include <sofia-sip/sip_status.h>#include <sofia-sip/msg_addr.h>#include "nta_internal.h"#include "sofia-sip/nta_stateless.h"#include "sofia-sip/url_tag.h"#if !defined(random) && defined(_WIN32)#define random rand#endif#if !defined(EMSGSIZE) && defined(_WIN32)#define EMSGSIZE WSAEMSGSIZE#endif#include <stddef.h>#include <stdlib.h>#include <stdio.h>#include <stdarg.h>#include <assert.h>#include <limits.h>#include <errno.h>/* From AM_INIT/AC_INIT in our "config.h" */char const nta_version[] = PACKAGE_VERSION;#if HAVE_FUNC#elif HAVE_FUNCTION#define __func__ __FUNCTION__#elsestatic char const __func__[] = "nta";#endif#define NONE ((void *)-1)/* Internal tags *//* Delay sending of request */#define NTATAG_DELAY_SENDING(x) ntatag_delay_sending, tag_bool_v((x))#define NTATAG_DELAY_SENDING_REF(x) \ntatag_delay_sending_ref, tag_bool_vr(&(x))extern tag_typedef_t ntatag_delay_sending;extern tag_typedef_t ntatag_delay_sending_ref;/* Allow sending incomplete responses */#define NTATAG_INCOMPLETE(x) ntatag_incomplete, tag_bool_v((x))#define NTATAG_INCOMPLETE_REF(x) \ntatag_incomplete_ref, tag_bool_vr(&(x))extern tag_typedef_t ntatag_incomplete;extern tag_typedef_t ntatag_incomplete_ref;nta_compressor_vtable_t *nta_compressor_vtable = NULL;/* Agent */static int agent_tag_init(nta_agent_t *self);static int agent_timer_init(nta_agent_t *agent);static void agent_timer(su_root_magic_t *rm, su_timer_t *, nta_agent_t *);static int agent_launch_terminator(nta_agent_t *agent);static void agent_kill_terminator(nta_agent_t *agent);static int agent_set_params(nta_agent_t *agent, tagi_t *tags);static void agent_set_udp_params(nta_agent_t *self, unsigned udp_mtu);static int agent_get_params(nta_agent_t *agent, tagi_t *tags);/* Transport interface */static sip_via_t const *agent_tport_via(tport_t *tport);static int outgoing_insert_via(nta_outgoing_t *orq, sip_via_t const *);static int nta_tpn_by_via(tp_name_t *tpn, sip_via_t const *v, int *using_rport);static msg_t *nta_msg_create_for_transport(nta_agent_t *agent, int flags, char const data[], unsigned dlen);static int complete_response(msg_t *response, int status, char const *phrase, msg_t const *request);#define IF_SIGCOMP_TPTAG_COMPARTMENT(cc) TAG_IF(cc, TPTAG_COMPARTMENT(cc)),#define IF_SIGCOMP_TPTAG_COMPARTMENT_REF(cc) TPTAG_COMPARTMENT_REF(cc),struct sigcomp_compartment;struct sigcomp_compartment *nta_compartment_ref(struct sigcomp_compartment *cc);staticstruct sigcomp_compartment *agent_compression_compartment(nta_agent_t *sa, tport_t *tp, tp_name_t const *tpn, int new_if_needed);staticint agent_accept_compressed(nta_agent_t *sa, msg_t *msg, struct sigcomp_compartment *cc);static int agent_close_compressor(nta_agent_t *sa, struct sigcomp_compartment *cc);static int agent_zap_compressor(nta_agent_t *sa, struct sigcomp_compartment *cc);static char const * stateful_branch(su_home_t *home, nta_agent_t *);static char const * stateless_branch(nta_agent_t *, msg_t *, sip_t const *, tp_name_t const *tp);#define NTA_BRANCH_PRIME SU_U64_C(0xB9591D1C361C6521)#define NTA_TAG_PRIME SU_U64_C(0xB9591D1C361C6521)HTABLE_PROTOS(leg_htable, lht, nta_leg_t);static nta_leg_t *leg_find(nta_agent_t const *sa, char const *method_name, url_t const *request_uri, sip_call_id_t const *i, char const *from_tag, url_t const *from_uri, char const *to_tag, url_t const *to_uri);static nta_leg_t *dst_find(nta_agent_t const *sa, url_t const *u0, char const *method);static void leg_recv(nta_leg_t *, msg_t *, sip_t *, tport_t *);static void leg_free(nta_agent_t *sa, nta_leg_t *leg);#define NTA_HASH(i, cs) ((i)->i_hash + 26839U * (uint32_t)(cs))HTABLE_PROTOS(incoming_htable, iht, nta_incoming_t);static nta_incoming_t *incoming_create(nta_agent_t *agent, msg_t *request, sip_t *sip, tport_t *tport, char const *tag);static int incoming_callback(nta_leg_t *leg, nta_incoming_t *irq, sip_t *sip);static void incoming_free(nta_incoming_t *irq);static inline void incoming_cut_off(nta_incoming_t *irq);static inline void incoming_reclaim(nta_incoming_t *irq);static void incoming_queue_init(incoming_queue_t *, unsigned timeout);static void incoming_queue_adjust(nta_agent_t *sa, incoming_queue_t *queue, unsigned timeout);static inlinenta_incoming_t *incoming_find(nta_agent_t const *agent, sip_t const *sip, sip_via_t const *v, nta_incoming_t **merge, nta_incoming_t **ack);static int incoming_reply(nta_incoming_t *irq, msg_t *msg, sip_t *sip);static inline int incoming_recv(nta_incoming_t *irq, msg_t *msg, sip_t *sip, tport_t *tport);static inline int incoming_ack(nta_incoming_t *irq, msg_t *msg, sip_t *sip, tport_t *tport);static inline int incoming_cancel(nta_incoming_t *irq, msg_t *msg, sip_t *sip, tport_t *tport);static inline int incoming_merge(nta_incoming_t *irq, msg_t *msg, sip_t *sip, tport_t *tport);static inline int incoming_timestamp(nta_incoming_t *, msg_t *, sip_t *);static inline int incoming_timer(nta_agent_t *, su_duration_t);static nta_reliable_t *reliable_mreply(nta_incoming_t *, nta_prack_f *, nta_reliable_magic_t *, msg_t *, sip_t *);static int reliable_send(nta_incoming_t *, nta_reliable_t *, msg_t *, sip_t *);static int reliable_final(nta_incoming_t *irq, msg_t *msg, sip_t *sip);static msg_t *reliable_response(nta_incoming_t *irq);static int reliable_recv(nta_incoming_t *, msg_t *, sip_t *, tport_t *);static void reliable_flush(nta_incoming_t *irq);static void reliable_timeout(nta_incoming_t *irq, int timeout);HTABLE_PROTOS(outgoing_htable, oht, nta_outgoing_t);static nta_outgoing_t *outgoing_create(nta_agent_t *agent, nta_response_f *callback, nta_outgoing_magic_t *magic, url_string_t const *route_url, tp_name_t const *tpn, msg_t *msg, tag_type_t tag, tag_value_t value, ...);static void outgoing_queue_init(outgoing_queue_t *, unsigned timeout);static void outgoing_queue_adjust(nta_agent_t *sa, outgoing_queue_t *queue, unsigned timeout);static void outgoing_free(nta_outgoing_t *orq);static inline void outgoing_cut_off(nta_outgoing_t *orq);static inline void outgoing_reclaim(nta_outgoing_t *orq);static nta_outgoing_t *outgoing_find(nta_agent_t const *sa, msg_t const *msg, sip_t const *sip, sip_via_t const *v);static int outgoing_recv(nta_outgoing_t *orq, int status, msg_t *, sip_t *);static void outgoing_default_recv(nta_outgoing_t *, int, msg_t *, sip_t *);static inline int outgoing_timer(nta_agent_t *, su_duration_t);static int outgoing_recv_reliable(nta_outgoing_t *orq, msg_t *msg, sip_t *sip);/* Internal message passing */union sm_arg_u { struct leg_recv_s { nta_leg_t *leg; msg_t *msg; tport_t *tport; } a_leg_recv[1]; struct outgoing_recv_s { nta_outgoing_t *orq; msg_t *msg; sip_t *sip; int status; } a_outgoing_recv[1]; incoming_queue_t a_incoming_queue[1]; outgoing_queue_t a_outgoing_queue[1];};/* Global module data *//**@var NTA_DEBUG * * Environment variable determining the default debug log level. * * The NTA_DEBUG environment variable is used to determine the default * debug logging level. The normal level is 3. * * @sa <su_debug.h>, su_log_global, SOFIA_DEBUG */extern char const NTA_DEBUG[];#ifndef SU_DEBUG#define SU_DEBUG 3#endif/**Debug log for @b nta module. * * The nta_log is the log object used by @b nta module. The level of * #nta_log is set using #NTA_DEBUG environment variable. */su_log_t nta_log[] = { SU_LOG_INIT("nta", "NTA_DEBUG", SU_DEBUG) };/* ====================================================================== *//* 1) Agent *//** * Create an NTA agent object. * * The function nta_agent_create() creates an NTA agent object. The agent * object creates and binds a server socket with address specified in @e url. * If the @e host portion of the @e url is @c "*", the agent listens to all * addresses available on the host. * * When a message is received, the agent object parses it. If the result is * a valid SIP message, the agent object passes the message to the * application by invoking the nta_message_f @e callback function. * * @note * The @e url can be either parsed url (of type url_t ()), or a valid * SIP URL as a string. * * @note * If @e url is @c NULL, the default @e url @c "sip:*" is used. * @par * If @p transport parameters are specified in @a url, agent uses only * specified transport type. * * @par * If an @p maddr parameter is specified in @e url, agent binds to the * specified address, but uses @e host part of @e url in @b Contact and @b * Via headers. The @p maddr parameter is also included, unless it equals * to @c INADDR_ANY (@p 0.0.0.0 or @p [::]). * * @param root pointer to a su_root_t used for synchronization * @param contact_url URL that agent uses to bind the server sockets * @param callback pointer to callback function * @param magic pointer to user data * @param tag,value,... other arguments * * @note It is possible to provide -1 as @a contact_url. * * @retval handle to the agent when successful, * @retval NULL upon an error. * */nta_agent_t *nta_agent_create(su_root_t *root, url_string_t const *contact_url, nta_message_f *callback, nta_agent_magic_t *magic, tag_type_t tag, tag_value_t value, ...){ nta_agent_t *agent; ta_list ta; if (root == NULL) return su_seterrno(EINVAL), NULL; ta_start(ta, tag, value); if ((agent = su_home_new(sizeof(*agent)))) { agent->sa_root = root; agent->sa_callback = callback; agent->sa_magic = magic; agent->sa_flags = MSG_DO_CANONIC; agent->sa_maxsize = 2 * 1024 * 1024; agent->sa_t1 = NTA_SIP_T1; agent->sa_t2 = NTA_SIP_T2; agent->sa_t4 = NTA_SIP_T4; agent->sa_t1x64 = 64 * NTA_SIP_T1; agent->sa_drop_prob = 0; agent->sa_is_a_uas = 0; agent->sa_progress = 60 * 1000; agent->sa_user_via = 0; agent->sa_extra_100 = 0; agent->sa_pass_100 = 0; agent->sa_timeout_408 = 1; agent->sa_pass_408 = 0; agent->sa_merge_482 = 0; agent->sa_cancel_2543 = 0; agent->sa_cancel_487 = 1; agent->sa_invite_100rel = 0; agent->sa_timestamp = 0; agent->sa_use_naptr = 1; agent->sa_use_srv = 1; agent->sa_auto_comp = 0; agent->sa_server_rport = 1; /* RFC 3261 section 8.1.1.6 */ sip_max_forwards_init(agent->sa_max_forwards)->mf_count = 70; if (getenv("SIPCOMPACT")) agent->sa_flags |= MSG_DO_COMPACT; 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 */ outgoing_queue_init(agent->sa_out.inv_proceeding, 0); 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"));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -