📄 nua_stack.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 nua_stack.c * @brief Nokia User Agent (NUA) implementation * * @author Pekka Pessi <Pekka.Pessi@nokia.com> * @author Kai Vehmanen <Kai.Vehmanen@nokia.com> * @author Martti Mela <Martti Mela@nokia.com> * @author Remeres Jacobs <Remeres.Jacobs@nokia.com> * @author Tat Chan <Tat.Chan@nokia.com> * * @date Created: Wed Feb 14 18:32:58 2001 ppessi */#include "config.h"#include <sofia-sip/su_tag_class.h>#include <sofia-sip/su_tag_class.h>#include <sofia-sip/su_tagarg.h>#include <sofia-sip/su_strlst.h>#include <sofia-sip/su_uniqueid.h>#include <sofia-sip/su_tag_io.h>#define SU_ROOT_MAGIC_T struct nua_s#define SU_MSG_ARG_T struct event_s#define NUA_SAVED_EVENT_T su_msg_t *#define NTA_AGENT_MAGIC_T struct nua_s#define NTA_LEG_MAGIC_T struct nua_handle_s#define NTA_OUTGOING_MAGIC_T struct nua_handle_s#define NTA_INCOMING_MAGIC_T struct nua_handle_s#include <sofia-sip/sip.h>#include <sofia-sip/sip_header.h>#include <sofia-sip/sip_status.h>#include <sofia-sip/sip_util.h>#include <sofia-sip/tport_tag.h>#include <sofia-sip/nta.h>#include <sofia-sip/nta_tport.h>#include <sofia-sip/auth_client.h>#include <sofia-sip/soa.h>#include "sofia-sip/nua.h"#include "sofia-sip/nua_tag.h"#include "nua_stack.h"#include <stddef.h>#include <stdlib.h>#include <string.h>#include <limits.h>#include <stdio.h>#include <assert.h>/* ======================================================================== * * Protocol stack side * * ======================================================================== */nua_handle_t *nh_create(nua_t *nua, tag_type_t t, tag_value_t v, ...);static void nh_append(nua_t *nua, nua_handle_t *nh);static void nh_remove(nua_t *nua, nua_handle_t *nh);static int nh_authorize(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);static int nh_challenge(nua_handle_t *nh, sip_t const *sip);static void nua_stack_timer(nua_t *nua, su_timer_t *t, su_timer_arg_t *a);static void ua_set_from(nua_t *nua, sip_from_t const *f, char const *fromstr);static void ua_init_instance(nua_t *nua);static void ua_init_contact(nua_t *nua);/* ---------------------------------------------------------------------- *//* Constant data *//** Methods allowed by default. */static char const nua_allow_str[] ="INVITE, ACK, BYE, CANCEL, OPTIONS, PRACK, ""MESSAGE, SUBSCRIBE, NOTIFY, REFER, UPDATE";/** Default internal error */char const nua_500_error[] = "Internal NUA Error";char const nua_application_sdp[] = "application/sdp";#define NUA_STACK_TIMER_INTERVAL (1000)/* ---------------------------------------------------------------------- * Initialization & deinitialization */int nua_stack_init(su_root_t *root, nua_t *nua){ su_home_t *home; void *sip_parser = NULL; url_string_t const *contact = NULL; url_string_t const *sips_contact = NULL; sip_from_t const *from = NULL; char const *from_str = NULL; char const *certificate_dir = NULL; char const *uicc_name = "default"; nua_handle_t *dnh; nua_handle_preferences_t *dnhp; int media_enable = 1; soa_session_t *soa = NULL; char const *soa_name = NULL; static int initialized_logs = 0; enter; if (!initialized_logs) { extern su_log_t tport_log[]; extern su_log_t nta_log[]; extern su_log_t nea_log[]; extern su_log_t iptsec_log[]; su_log_init(tport_log); su_log_init(nta_log); su_log_init(nea_log); su_log_init(iptsec_log); initialized_logs = 1; } home = nua->nua_home; dnh = su_home_clone(home, sizeof (*dnh) + sizeof(*dnhp)); if (!dnh) return -1; nua_handle_ref(dnh); nua->nua_root = root; nua->nua_handles_tail = &nua->nua_handles; nh_append(nua, dnh); dnh->nh_valid = nua_handle; dnh->nh_nua = nua; dnh->nh_ds->ds_local = sip_from_init(nua->nua_from); dnh->nh_ds->ds_remote = nua->nua_from; dnh->nh_ref_by_stack = 1; dnh->nh_ref_by_user = 1; dnh->nh_prefs = dnhp = (void *)(dnh + 1); /* Set some defaults */ DNHP_SET(dnhp, retry_count, 3); DNHP_SET(dnhp, max_subscriptions, 20); DNHP_SET(dnhp, invite_enable, 1); DNHP_SET(dnhp, auto_alert, 0); DNHP_SET(dnhp, early_media, 0); DNHP_SET(dnhp, auto_answer, 0); DNHP_SET(dnhp, auto_ack, 1); DNHP_SET(dnhp, invite_timeout, 120); DNHP_SET(dnhp, natify, 1); DNHP_SET(dnhp, gruuize, 1); DNHP_SET(dnhp, session_timer, 1800); DNHP_SET(dnhp, min_se, 120); DNHP_SET(dnhp, refresher, nua_no_refresher); DNHP_SET(dnhp, update_refresh, 0); DNHP_SET(dnhp, message_enable, 1); DNHP_SET(dnhp, win_messenger_enable, 0); if (getenv("PIMIW_HACK") != 0) DNHP_SET(dnhp, message_auto_respond, 1); DNHP_SET(dnhp, media_features, 0); DNHP_SET(dnhp, callee_caps, 0); DNHP_SET(dnhp, service_route_enable, 1); DNHP_SET(dnhp, path_enable, 1); DNHP_SET(dnhp, refer_expires, 300); DNHP_SET(dnhp, substate, nua_substate_active); DNHP_SET(dnhp, allow, sip_allow_make(dnh->nh_home, nua_allow_str)); DNHP_SET(dnhp, supported, sip_supported_make(dnh->nh_home, "timer, 100rel")); DNHP_SET(dnhp, user_agent, sip_user_agent_make(dnh->nh_home, PACKAGE_NAME "/" PACKAGE_VERSION)); /* Set initial nta parameters */ tl_gets(nua->nua_args, NUTAG_URL_REF(contact), SIPTAG_FROM_REF(from), SIPTAG_FROM_STR_REF(from_str), NUTAG_SIPS_URL_REF(sips_contact), NUTAG_CERTIFICATE_DIR_REF(certificate_dir), NUTAG_SIP_PARSER_REF(sip_parser), NUTAG_UICC_REF(uicc_name), NUTAG_MEDIA_ENABLE_REF(media_enable), /* NUTAG_SOA_SESSION_REF(soa), */ NUTAG_SOA_NAME_REF(soa_name), TAG_NULL());#if HAVE_UICC_H if (uicc_name) nua->nua_uicc = uicc_create(root, uicc_name);#endif nua->nua_nta = nta_agent_create(root, NONE, NULL, NULL, TPTAG_CERTIFICATE(certificate_dir), NTATAG_TAG_3261(0), TAG_NEXT(nua->nua_args)); if (!nua->nua_nta) return -1; if (!contact && !sips_contact) { if (nta_agent_add_tport(nua->nua_nta, NULL, TAG_NEXT(nua->nua_args)) < 0 && nta_agent_add_tport(nua->nua_nta, URL_STRING_MAKE("sip:*:*"), TAG_NEXT(nua->nua_args)) < 0) return -1; } else if ((!contact || nta_agent_add_tport(nua->nua_nta, contact, TAG_NEXT(nua->nua_args)) < 0) && (!sips_contact || nta_agent_add_tport(nua->nua_nta, sips_contact, TAG_NEXT(nua->nua_args)) < 0)) { return -1; } nua->nua_media_enable = media_enable; nta_agent_set_params(nua->nua_nta, NTATAG_UA(1), NTATAG_MERGE_482(1), NTATAG_RPORT(1), /* XXX */#if HAVE_SOFIA_SMIME NTATAG_SMIME(nua->sm),#endif TAG_NEXT(nua->nua_args)); nua->nua_invite_accept = sip_accept_make(home, SDP_MIME_TYPE); if (media_enable) { if (soa == NULL) soa = soa_create(soa_name, nua->nua_root, nua->nua_dhandle); dnh->nh_soa = soa; soa_set_params(soa, TAG_NEXT(nua->nua_args)); } dnh->nh_ds->ds_leg = nta_leg_tcreate(nua->nua_nta, nua_stack_process_request, dnh, NTATAG_NO_DIALOG(1), TAG_END()); ua_init_instance(nua); ua_init_contact(nua); ua_set_from(nua, from, from_str); nua->nua_timer = su_timer_create(su_root_task(root), NUA_STACK_TIMER_INTERVAL); if (!(dnh->nh_ds->ds_leg && dnhp->nhp_allow && dnhp->nhp_supported && (nua->nua_contact || nua->nua_sips_contact) && nua->nua_from && nua->nua_timer)) return -1; nua_stack_timer(nua, nua->nua_timer, NULL); nua->nua_args = NULL; return 0;}void nua_stack_deinit(su_root_t *root, nua_t *nua){ enter; su_timer_destroy(nua->nua_timer), nua->nua_timer = NULL; nta_agent_destroy(nua->nua_nta), nua->nua_nta = NULL;}/** Set the default from field */void ua_set_from(nua_t *nua, sip_from_t const *f, char const *str){ sip_from_t from[1], *f0;#if HAVE_UICC_H /* XXX: add */#endif sip_from_init(from); if (f) { from->a_display = f->a_display; *from->a_url = *f->a_url; f0 = sip_from_dup(nua->nua_home, from); } else if (str) { f0 = sip_from_make(nua->nua_home, str); if (f0) *from = *f0, f0 = from, f0->a_params = NULL; } else { sip_contact_t *m; m = nua->nua_contact ? nua->nua_contact : nua->nua_sips_contact; from->a_display = m->m_display; *from->a_url = *m->m_url; f0 = sip_from_dup(nua->nua_home, from); } if (f0) *nua->nua_from = *f0;}/** Initialize instance ID. */staticvoid ua_init_instance(nua_t *nua){ nua_handle_t *dnh = nua->nua_dhandle; nua_handle_preferences_t *dnhp = dnh->nh_prefs; char str[su_guid_strlen + 1]; su_guid_t guid[1]; su_guid_generate(guid); /* * Guid looks like "NNNNNNNN-NNNN-NNNN-NNNN-XXXXXXXXXXXX" * where NNNNNNNN-NNNN-NNNN-NNNN is timestamp and XX is MAC address * (but we use usually random ID for MAC because we do not have * guid generator available for all processes within node) */ su_guid_sprintf(str, su_guid_strlen + 1, guid); DNHP_SET(dnhp, instance, su_sprintf(dnh->nh_home, "urn:uuid:%s", str));}staticvoid ua_init_a_contact(nua_t *nua, su_home_t *home, sip_contact_t *m);/** Initialize our contacts. */void ua_init_contact(nua_t *nua){ su_home_t home[1] = { SU_HOME_INIT(home) }; sip_via_t *v; int sip = 0, sips = 0; sip_contact_t *m; for (v = nta_agent_via(nua->nua_nta); v; v = v->v_next) { if (strcasecmp(v->v_protocol, sip_transport_tls) != 0) { if (!sip) { m = sip_contact_create_from_via(home, v, NULL); if (m) { ua_init_a_contact(nua, home, m); sip = 1; } } } else if (!sips) { m = sip_contact_create_from_via(home, v, NULL); if (m) { ua_init_a_contact(nua, home, m); sips = 1; } } if (sip && sips) break; } su_home_deinit(home);}staticvoid ua_init_a_contact(nua_t *nua, su_home_t *home, sip_contact_t *m){ su_strlst_t *l = su_strlst_create(home); nua_handle_t *dnh = nua->nua_dhandle; int i; if (DNH_PGET(dnh, instance)) { char const *instance = DNH_PGET(dnh, instance); instance = su_sprintf(home, "+sip.instance=\"<%s>\"", instance); msg_header_replace_param(home, m->m_common, instance); } if (DNH_PGET(dnh, callee_caps)) { sip_allow_t const *allow = DNH_PGET(dnh, allow); if (allow) { char *methods; if (allow->k_items) for (i = 0; allow->k_items[i]; i++) su_strlst_append(l, allow->k_items[i]); methods = su_strlst_join(l, home, ","); methods = su_sprintf(home, "methods=\"%s\"", methods); msg_header_replace_param(home, m->m_common, methods); } if (dnh->nh_soa) { char **media = soa_media_features(dnh->nh_soa, 0, home); while (*media) { msg_header_replace_param(home, m->m_common, *media); media++; } } } m = sip_contact_dup(nua->nua_home, m); if (m) { if (m->m_url->url_type == url_sip) su_free(nua->nua_home, nua->nua_contact), nua->nua_contact = m; else su_free(nua->nua_home, nua->nua_sips_contact), nua->nua_sips_contact = m; }}/* ---------------------------------------------------------------------- * Sending events to client application */static void nua_stack_shutdown(nua_t *);void nua_stack_authenticate(nua_t *, nua_handle_t *, nua_event_t, tagi_t const *), nua_stack_respond(nua_t *, nua_handle_t *, int , char const *, tagi_t const *), nua_stack_destroy_handle(nua_t *, nua_handle_t *, tagi_t const *);/* Notifier */void nua_stack_authorize(nua_t *, nua_handle_t *, nua_event_t, tagi_t const *),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -