📄 nua_register.c
字号:
/* * This file is part of the Sofia-SIP package * * Copyright (C) 2006 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 nua_register.c * @brief REGISTER and registrations * * @author Pekka Pessi <Pekka.Pessi@nokia.com> * @author Martti Mela <Martti.Mela@nokia.com> * @author Kai Vehmanen <Kai.Vehmanen@nokia.com> * * @date Created: Wed Mar 8 11:48:49 EET 2006 ppessi */#include "config.h"/** @internal SU network changed detector argument pointer type */#define SU_NETWORK_CHANGED_MAGIC_T struct nua_s#define TP_CLIENT_T struct register_usage#include <sofia-sip/string0.h>#include <sofia-sip/su_strlst.h>#include <sofia-sip/su_uniqueid.h>#include <sofia-sip/su_tagarg.h>#include <sofia-sip/sip_protos.h>#include <sofia-sip/sip_util.h>#include <sofia-sip/sip_status.h>#define NTA_UPDATE_MAGIC_T struct nua_s#include "nua_stack.h"#include <sofia-sip/hostdomain.h>#include <sofia-sip/nta_tport.h>#include <sofia-sip/tport.h>#include <sofia-sip/tport_tag.h>#define OUTBOUND_OWNER_T struct nua_handle_s#include "outbound.h"#if HAVE_SIGCOMP#include <sigcomp.h>#endif#include <stddef.h>#include <stdlib.h>#include <string.h>#include <limits.h>#include <assert.h>/* ======================================================================== *//* Registrations and contacts */int nua_registration_from_via(nua_registration_t **list, nua_handle_t *nh, sip_via_t const *via, int public);int nua_registration_add(nua_registration_t **list, nua_registration_t *nr);void nua_registration_remove(nua_registration_t *nr);int nua_registration_set_aor(su_home_t *, nua_registration_t *nr, sip_from_t const *aor);int nua_registration_set_contact(nua_handle_t *, nua_registration_t *nr, sip_contact_t const *m, int terminating);void nua_registration_set_ready(nua_registration_t *nr, int ready);/* ====================================================================== *//* REGISTER usage */static char const *nua_register_usage_name(nua_dialog_usage_t const *du);static int nua_register_usage_add(nua_handle_t *nh, nua_dialog_state_t *ds, nua_dialog_usage_t *du);static void nua_register_usage_remove(nua_handle_t *nh, nua_dialog_state_t *ds, nua_dialog_usage_t *du, nua_client_request_t *cr, nua_server_request_t *sr);static void nua_register_usage_update_params(nua_dialog_usage_t const *du, nua_handle_preferences_t const *, nua_handle_preferences_t const *, nua_handle_preferences_t const *);static void nua_register_usage_peer_info(nua_dialog_usage_t *du, nua_dialog_state_t const *ds, sip_t const *sip);static void nua_register_usage_refresh(nua_handle_t *, nua_dialog_state_t *, nua_dialog_usage_t *, sip_time_t);static int nua_register_usage_shutdown(nua_handle_t *, nua_dialog_state_t *, nua_dialog_usage_t *);/** @internal @brief REGISTER usage, aka nua_registration_t. */struct register_usage { nua_registration_t *nr_next, **nr_prev, **nr_list; /* Doubly linked list and its head */ sip_from_t *nr_aor; /**< AoR for this registration, NULL if none */ sip_contact_t *nr_contact; /**< Our Contact */ sip_contact_t nr_dcontact[1]; /**< Contact in dialog */ sip_via_t *nr_via; /**< Corresponding Via headers */ unsigned long nr_min_expires; /**< Value from 423 negotiation */ /** Status of registration */ unsigned nr_ready:1; /** Kind of registration. * * If nr_default is true, this is not a real registration but placeholder * for Contact header derived from a transport address. * * If nr_secure is true, this registration supports SIPS/TLS. * * If nr_public is true, transport should have public address. */ unsigned nr_default:1, nr_secure:1, nr_public:1, nr_ip4:1, nr_ip6:1; /** Stack-generated contact */ unsigned nr_by_stack:1; unsigned:0; int nr_error_report_id; /**< ID used to ask for error reports from tport */ sip_route_t *nr_route; /**< Outgoing Service-Route */ sip_path_t *nr_path; /**< Incoming Path */ tport_t *nr_tport; /**< Transport to be used when registered */ nua_dialog_state_t *nr_dialogs; /**< List of our dialogs */#if HAVE_SIGCOMP struct sigcomp_compartment *nr_compartment;#endif outbound_t *nr_ob; /**< Outbound connection */};nua_usage_class const nua_register_usage[1] = { { sizeof (struct register_usage), (sizeof nua_register_usage), nua_register_usage_add, nua_register_usage_remove, nua_register_usage_name, nua_register_usage_update_params, nua_register_usage_peer_info, nua_register_usage_refresh, nua_register_usage_shutdown }};static char const *nua_register_usage_name(nua_dialog_usage_t const *du){ return "register";}static int nua_register_usage_add(nua_handle_t *nh, nua_dialog_state_t *ds, nua_dialog_usage_t *du){ nua_registration_t *nr = NUA_DIALOG_USAGE_PRIVATE(du); if (ds->ds_has_register) return -1; /* There can be only one usage */ ds->ds_has_register = 1; nr->nr_public = 1; /* */ return 0;}static void nua_register_usage_remove(nua_handle_t *nh, nua_dialog_state_t *ds, nua_dialog_usage_t *du, nua_client_request_t *cr, nua_server_request_t *sr){ nua_registration_t *nr = NUA_DIALOG_USAGE_PRIVATE(du); if (nr->nr_list) nua_registration_remove(nr); /* Remove from list of registrations */ if (nr->nr_ob) outbound_unref(nr->nr_ob);#if HAVE_SIGCOMP if (nr->nr_compartment) sigcomp_compartment_unref(nr->nr_compartment); nr->nr_compartment = NULL;#endif if (nr->nr_error_report_id) tport_release(nr->nr_tport, nr->nr_error_report_id, NULL, NULL, nr, 0); if (nr->nr_tport) tport_unref(nr->nr_tport), nr->nr_tport = NULL; ds->ds_has_register = 0; /* There can be only one */}/** @internal Store information about registrar. */static void nua_register_usage_peer_info(nua_dialog_usage_t *du, nua_dialog_state_t const *ds, sip_t const *sip){ nua_registration_t *nr = NUA_DIALOG_USAGE_PRIVATE(du); if (nr->nr_ob) outbound_peer_info(nr->nr_ob, sip);}/* ======================================================================== *//* REGISTER */static void nua_register_connection_closed(tp_stack_t *sip_stack, nua_registration_t *nr, tport_t *tport, msg_t *msg, int error);/* Interface towards outbound_t */sip_contact_t *nua_handle_contact_by_via(nua_handle_t *nh, su_home_t *home, int in_dialog, sip_via_t const *v, char const *transport, char const *m_param, ...);static int nua_stack_outbound_refresh(nua_handle_t *, outbound_t *ob);static int nua_stack_outbound_status(nua_handle_t *, outbound_t *ob, int status, char const *phrase, tag_type_t tag, tag_value_t value, ...);static int nua_stack_outbound_failed(nua_handle_t *, outbound_t *ob, int status, char const *phrase, tag_type_t tag, tag_value_t value, ...);static int nua_stack_outbound_credentials(nua_handle_t *, auth_client_t **auc);outbound_owner_vtable nua_stack_outbound_callbacks = { sizeof nua_stack_outbound_callbacks, /* oo_contact */ nua_handle_contact_by_via, /* oo_refresh */ nua_stack_outbound_refresh, /* oo_status */ nua_stack_outbound_status, /* oo_probe_error */ nua_stack_outbound_failed, /* oo_keepalive_error */ nua_stack_outbound_failed, /* oo_credentials */ nua_stack_outbound_credentials };/**@fn void nua_register(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...); * * Send SIP REGISTER request to the registrar. * * Request status will be delivered to the application using #nua_r_register * event. When successful the registration will be updated periodically. * * The handle used for registration cannot be used for any other purposes. * * @param nh Pointer to operation handle * @param tag, value, ... List of tagged parameters * * @return * nothing * * @par Related tags: * NUTAG_REGISTRAR(), NUTAG_INSTANCE(), NUTAG_OUTBOUND(), * NUTAG_KEEPALIVE(), NUTAG_KEEPALIVE_STREAM(), NUTAG_M_USERNAME(), * NUTAG_M_DISPLAY(), NUTAG_M_PARAMS(), NUTAG_M_FEATURES() * * @par Events: * #nua_r_register, #nua_i_outbound * * @par Generating Contact Header * * If the application did not specify the Contact header in the tags, * nua_register() will generate one. It will obtain the schema, IP address * for the host and port number for the Contact URI from the transport * socket. The diplay name is taken from NUTAG_M_DISPLAY(), URL username * part is taken from NUTAG_M_USERNAME(), URI parameters from * NUTAG_M_PARAMS(), and Contact header parameters from NUTAG_M_FEATURES(). * If NUTAG_CALLEE_CAPS(1) is specified, additional Contact header * parameters are generated based on SDP capabilities and SIP @Allow header. * * Note that @b nua may append a identifier of its own to the @Contact URI * username. Such nua-generated identifier trailer always starts with "=" * (equal sign), rest of the nua-generated identifier may contain any * url-unreserved characters except "=". * * Likewise, nua may add transport parameters (such as "transport=tcp" or * "maddr") to the @Contact URI. It can add addtional header parameters, like * "+sip.instance" or "reg-id", too. * * For instance, if application uses tags like * @code * nua_register(nh, * NUTAG_M_DISPLAY("1"), * NUTAG_M_USERNAME("line-1"), * NUTAG_M_PARAMS("user=phone"), * NUTAG_M_FEATURES("audio"), * NUTAG_CALLEE_CAPS(0), * TAG_END()) * @endcode * @b nua can generate a Contact header like * @code * Contact: 1 <sip:line-1=SSQAIbjv@192.168.1.200;transport=tcp;user=phone> * ;audio;reg-id=1 * ;+sip.instance=urn:uuid:97701ad9-39df-1229-1083-dbc0a85f029c * @endcode * * The incoming request from the proxy should contain the registered contact * URI as the request URI. The application can use the username prefix set * by NUTAG_M_USERNAME() and the non-transport parameters of the request URI * set by NUTAG_M_PARAMS() when determining to which registration the * incoming request belongs. * * For example, a request line correspoding to the @Contact in above example * may look like: * @code * INVITE sip:line-1=SSQAIbjv@192.168.1.200;user=phone SIP/2.0 * @endcode * * @sa NUTAG_M_DISPLAY(), NUTAG_M_USERNAME(), NUTAG_M_PARAMS(), * NUTAG_M_FEATURES(), NUTAG_CALLEE_CAPS(). * * @par NAT, Firewall and Outbound Support * * Normally, @b nua will start start a protocol engine for outbound * connections used for NAT and firewall traversal and connectivity checks * when registering. * * @note If the application provides @b nua with a * @Contact header of its own (or includes a SIPTAG_CONTACT(NULL) tag in * nua_register() tags), the outbound protocol engine is not started. It is * assumed that the application knows better what it is doing when it sets * the @Contact, or it is using experimental CPL upload as specified in * <a href="http://www.ietf.org/internet-drafts/draft-lennox-sip-reg-payload-01.txt"> * draft-lennox-sip-reg-payload-01.txt</a>. * * First, outbound engine will probe for NATs in between UA and registrar. * It will send a REGISTER request as usual. Upon receiving the response it * checks for the presence of "received" and "rport" parameters in the Via * header returned by registrar. The presence of NAT is determined from the * "received" parameter in a Via header. When a REGISTER request was sent, * the stack inserted the actual source IP address in the Via header: if * that is different from the source IP address seen by the registrar, the * registrar inserts the source IP address it sees into the "received" * parameter. * * Please note that an ALG (application-level gateway) modifying the Via * headers in outbound requests and again in incoming responses will make * the above-described NAT check to fail. * * The response to the initial REGISTER should also include option tags * indicating whether registrar supports various SIP extension options: @e * outbound, @e pref, @e path, @e gruu. * * Basically, @e outbound means that instead of registering its contact URI * with a particular address-of-record URI, the user-agent registers a * transport-level connection. Such a connection is identified on the * Contact header field with an instance identifier, application-provided * @ref NUTAG_INSTANCE() "unique string" identifying the user-agent instance * and a stack-generated numeric index identifying the transport-level * connection. * * If the @e outbound extension is supported, NUTAG_OUTBOUND() contains * option string "outbound" and the application has provided an instance * identifer to the stack with NUTAG_INSTANCE(), the nua_register() will try * to use outbound. * * If @e outbound is not supported, nua_register() has to generate a URI * that can be used to reach it from outside. It will check for public * transport addresses detected by underlying stack with, e.g., STUN, UPnP * or SOCKS. If there are public addresses, nua_register() will use them. If * there is no public address, it will try to generate a Contact URI from * the "received" and "rport" parameters found in the Via header of the * response message. * * @todo Actually generate public addresses. * * You can disable this kind of NAT traversal by setting "no-natify" into * NUTAG_OUTBOUND() options string. * * @par GRUU and Service-Route * * After a successful response to the REGISTER request has been received, * nua_register() will update the information about the registration based * on it. If there is a "gruu" parameter included in the response, * nua_register() will save it and use the gruu URI in the Contact header
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -