📄 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 and message utility functions * 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_wait.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/hostdomain.h>#include <sofia-sip/msg_addr.h>#include <sofia-sip/msg_parser.h>#include "nta_internal.h"#include "sofia-sip/nta_stateless.h"#include "sofia-sip/url_tag.h"#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, usize_t 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[], usize_t dlen, tport_t const *tport, tp_client_t *via);static int complete_response(msg_t *response, int status, char const *phrase, msg_t *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)#ifndef UINT32_MAX#define UINT32_MAX (0xffffffffU)#endifHTABLE_PROTOS_WITH(leg_htable, lht, nta_leg_t, size_t, hash_value_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, char const *to_tag);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_WITH(incoming_htable, iht, nta_incoming_t, size_t, hash_value_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);su_inline void incoming_cut_off(nta_incoming_t *irq);su_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 nta_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, nta_incoming_t **cancel);static int incoming_reply(nta_incoming_t *irq, msg_t *msg, sip_t *sip);su_inline int incoming_recv(nta_incoming_t *irq, msg_t *msg, sip_t *sip, tport_t *tport);su_inline int incoming_ack(nta_incoming_t *irq, msg_t *msg, sip_t *sip, tport_t *tport);su_inline int incoming_cancel(nta_incoming_t *irq, msg_t *msg, sip_t *sip, tport_t *tport);static void request_merge(nta_agent_t *, msg_t *msg, sip_t *sip, tport_t *tport, char const *to_tag);su_inline int incoming_timestamp(nta_incoming_t *, msg_t *, sip_t *);static void incoming_timer(nta_agent_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 nta_reliable_t *reliable_find(nta_agent_t const *, sip_t const *);static int reliable_recv(nta_reliable_t *rel, 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_WITH(outgoing_htable, oht, nta_outgoing_t, size_t, hash_value_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);su_inline void outgoing_cut_off(nta_outgoing_t *orq);su_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 void outgoing_timer(nta_agent_t *);static int outgoing_recv_reliable(nta_outgoing_t *orq, msg_t *msg, sip_t *sip);/* Internal message passing */union sm_arg_u { 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 char const 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 <sofia-sip/su_debug.h>, #su_log_global, #SOFIA_DEBUG */#ifdef DOXYGENextern char const NTA_DEBUG[]; /* dummy declaration for Doxygen */#endif#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. * * Create 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 @e url is @c NONE (iow, (void*)-1), no server sockets are bound. * @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 when it generates * @Contact and @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,... tagged arguments * * @TAGS * NTATAG_ALIASES(), * NTATAG_BAD_REQ_MASK(), NTATAG_BAD_RESP_MASK(), NTATAG_BLACKLIST(), * NTATAG_CANCEL_2543(), NTATAG_CANCEL_487(), NTATAG_CLIENT_RPORT(), * NTATAG_DEBUG_DROP_PROB(), NTATAG_DEFAULT_PROXY(), * NTATAG_EXTRA_100(), NTATAG_GRAYLIST(), * NTATAG_MAXSIZE(), NTATAG_MAX_FORWARDS(), NTATAG_MERGE_482(), NTATAG_MCLASS() * NTATAG_PASS_100(), NTATAG_PASS_408(), NTATAG_PRELOAD(), NTATAG_PROGRESS(), * NTATAG_REL100(), * NTATAG_SERVER_RPORT(), * NTATAG_SIPFLAGS(), * NTATAG_SIP_T1X64(), NTATAG_SIP_T1(), NTATAG_SIP_T2(), NTATAG_SIP_T4(), * NTATAG_STATELESS(), * NTATAG_TAG_3261(), NTATAG_TCP_RPORT(), NTATAG_TIMEOUT_408(), * NTATAG_TIMER_C(), NTATAG_MAX_PROCEEDING(), * NTATAG_UA(), NTATAG_UDP_MTU(), NTATAG_USER_VIA(), * NTATAG_USE_NAPTR(), NTATAG_USE_SRV() and NTATAG_USE_TIMESTAMP(). * * @note The value from following tags are stored, but they currently do nothing: * NTATAG_SIGCOMP_ALGORITHM(), NTATAG_SIGCOMP_OPTIONS(), NTATAG_SMIME() * * @note It is possible to provide @c (url_string_t*)-1 as @a contact_url. * In that case, no server sockets are bound. * * @retval handle to the agent when successful, * @retval NULL upon an error. * * @sa NUTAG_ */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)))) { unsigned timer_c; agent->sa_root = root; agent->sa_callback = callback; agent->sa_magic = magic; agent->sa_flags = MSG_DO_CANONIC; agent->sa_maxsize = 2 * 1024 * 1024; /* 2 MB */ agent->sa_bad_req_mask = /* * Bit-wise not of these - what is left is suitable for UAs with * 100rel, timer, events, publish */ (unsigned) ~(sip_mask_response | sip_mask_proxy | sip_mask_registrar | sip_mask_pref | sip_mask_privacy); agent->sa_bad_resp_mask = (unsigned) ~(sip_mask_request | sip_mask_proxy | sip_mask_registrar | sip_mask_pref | sip_mask_privacy); 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_timer_c = 185 * 1000; agent->sa_graylist = 600; 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); if (getenv("SIPCOMPACT")) agent->sa_flags |= MSG_DO_COMPACT;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -