📄 soa.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 soa.c * @brief Sofia SDP Offer/Answer Engine interface * * @author Pekka Pessi <Pekka.Pessi@nokia.com> * * @date Created: Wed Aug 3 20:27:15 EEST 2005 */#include "config.h"#include <stddef.h>#include <stdlib.h>#include <string.h>#include <errno.h>#include <assert.h>#include <sofia-sip/su_tag_class.h>#include <sofia-sip/su_wait.h>#include "sofia-sip/soa.h"#include "sofia-sip/sdp.h"#include "sofia-sip/soa_session.h"#include "sofia-sip/soa_add.h"#include <sofia-sip/hostdomain.h>#include <sofia-sip/su_tagarg.h>#include <sofia-sip/su_localinfo.h>#include <sofia-sip/su_uniqueid.h>#include <sofia-sip/string0.h>#include <sofia-sip/su_errno.h>#define NONE ((void *)-1)#define XXX assert(!"implemented")typedef unsigned longlong ull;#if HAVE_FUNC#elif HAVE_FUNCTION#define __func__ __FUNCTION__#elsestatic char const __func__[] = "soa";#endif/* ======================================================================== *//* Internal prototypes */void soa_set_activity(soa_session_t *ss, sdp_media_t const *, int remote);static inline int soa_media_is_ready(soa_session_t const *ss);enum soa_sdp_kind { soa_capability_sdp_kind, soa_user_sdp_kind, soa_remote_sdp_kind};static int soa_set_sdp(soa_session_t *ss, enum soa_sdp_kind what, sdp_session_t const *sdp0, char const *sdp_str, int str_len);/* ======================================================================== */#define SOA_VALID_ACTIONS(a) \ ((a)->sizeof_soa_session_actions >= sizeof (*actions) && \ (a)->sizeof_soa_session >= sizeof(soa_session_t) && \ (a)->soa_name != NULL && \ (a)->soa_init != NULL && \ (a)->soa_deinit != NULL && \ (a)->soa_set_params != NULL && \ (a)->soa_get_params != NULL && \ (a)->soa_get_paramlist != NULL && \ (a)->soa_media_features != NULL && \ (a)->soa_sip_require != NULL && \ (a)->soa_sip_supported != NULL && \ (a)->soa_remote_sip_features != NULL && \ (a)->soa_set_capability_sdp != NULL && \ (a)->soa_set_remote_sdp != NULL && \ (a)->soa_set_user_sdp != NULL && \ (a)->soa_generate_offer != NULL && \ (a)->soa_generate_answer != NULL && \ (a)->soa_process_answer != NULL && \ (a)->soa_process_reject != NULL && \ (a)->soa_activate_session != NULL && \ (a)->soa_deactivate_session != NULL && \ (a)->soa_terminate_session != NULL)/* ======================================================================== *//**@var SOA_DEBUG * * Environment variable determining the default debug log level. * * The SOA_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 SOA_DEBUG[];#ifndef SU_DEBUG#define SU_DEBUG 3#endif/**Debug log for @b soa module. * * The soa_log is the log object used by @b soa module. The level of * #soa_log is set using #SOA_DEBUG environment variable. */su_log_t soa_log[] = { SU_LOG_INIT("soa", "SOA_DEBUG", SU_DEBUG) };/* Add " around string */#define NICE(s) s ? "\"" : "", s ? s : "(nil)", s ? "\"" : ""/* ======================================================================== *//* API Functions */struct soa_namenode{ struct soa_namenode const *next; char const *basename; struct soa_session_actions const *actions;};#define SOA_NAMELISTLEN (16)static struct soa_namenode const soa_default_node = { NULL, "default", &soa_default_actions };static struct soa_namenode const *soa_namelist = &soa_default_node;/** Add a named soa backend */int soa_add(char const *name, struct soa_session_actions const *actions){ struct soa_namenode const *n; struct soa_namenode *e; SU_DEBUG_9(("soa_add(%s%s%s, %p) called\n", NICE(name), actions)); if (name == NULL || actions == NULL) return su_seterrno(EFAULT); if (!SOA_VALID_ACTIONS(actions)) return su_seterrno(EINVAL); for (n = soa_namelist; n; n = n->next) { if (strcasecmp(name, n->basename) == 0) return 0; } e = malloc(sizeof *e); if (!e) return -1; e->next = soa_namelist; e->basename = name; e->actions = actions; soa_namelist = e; return 0;}/** Search for a named backend */struct soa_session_actions const *soa_find(char const *name){ SU_DEBUG_9(("soa_find(%s%s%s) called\n", NICE(name))); if (name) { struct soa_namenode const *n; size_t baselen = strcspn(name, ":/"); for (n = soa_namelist; n; n = n->next) { if (strncasecmp(name, n->basename, baselen) == 0) break; } if (n == NULL) return (void)su_seterrno(ENOENT), NULL; return n->actions; } return NULL;}/* ======================================================================== */soa_session_t *soa_create(char const *name, su_root_t *root, soa_magic_t *magic){ struct soa_session_actions const *actions = &soa_default_actions; soa_session_t *ss; size_t namelen; SU_DEBUG_9(("soa_create(\"%s\", %p, %p) called\n", name ? name : "default", root, magic)); if (name && name[0]) { struct soa_namenode const *n; size_t baselen = strcspn(name, ":/"); for (n = soa_namelist; n; n = n->next) { if (strncasecmp(name, n->basename, baselen) == 0) break; } if (n == NULL) return (void)su_seterrno(ENOENT), NULL; actions = n->actions; assert(actions); } else name = "default"; assert(SOA_VALID_ACTIONS(actions)); if (root == NULL) return (void)su_seterrno(EFAULT), NULL; namelen = strlen(name) + 1; ss = su_home_new(actions->sizeof_soa_session + namelen); if (ss) { ss->ss_root = root; ss->ss_magic = magic; ss->ss_actions = actions; ss->ss_name = strcpy((char *)ss + actions->sizeof_soa_session, name); if (ss->ss_actions->soa_init(name, ss, NULL) < 0) ss->ss_actions->soa_deinit(ss), ss = NULL; } return ss;}soa_session_t *soa_clone(soa_session_t *parent_ss, su_root_t *root, soa_magic_t *magic){ soa_session_t *ss; size_t namelen; SU_DEBUG_9(("soa_clone(%s::%p, %p, %p) called\n", parent_ss ? parent_ss->ss_actions->soa_name : "", parent_ss, root, magic)); if (parent_ss == NULL || root == NULL) return (void)su_seterrno(EFAULT), NULL; namelen = strlen(parent_ss->ss_name) + 1; ss = su_home_new(parent_ss->ss_actions->sizeof_soa_session + namelen); if (ss) { ss->ss_root = root; ss->ss_magic = magic; ss->ss_actions = parent_ss->ss_actions; ss->ss_name = strcpy((char *)ss + ss->ss_actions->sizeof_soa_session, parent_ss->ss_name); if (ss->ss_actions->soa_init(NULL, ss, parent_ss) < 0) ss->ss_actions->soa_deinit(ss), ss = NULL; } return ss;}/** Increase reference count */soa_session_t *soa_session_ref(soa_session_t *ss){ SU_DEBUG_9(("soa_session_ref(%s::%p) called\n", ss ? ss->ss_actions->soa_name : "", ss)); return su_home_ref(ss->ss_home);}/** Decrease reference count */void soa_session_unref(soa_session_t *ss){ SU_DEBUG_9(("soa_session_unref(%s::%p) called\n", ss ? ss->ss_actions->soa_name : "", ss)); su_home_unref(ss->ss_home);}/* Initialize session */int soa_base_init(char const *name, soa_session_t *ss, soa_session_t *parent){ if (parent) {#define DUP(d, dup, s) if ((s) && !((d) = dup(ss->ss_home, (s)))) return -1 su_home_t *home = ss->ss_home; if (soa_description_dup(home, ss->ss_caps, parent->ss_caps) < 0) return -1; if (soa_description_dup(home, ss->ss_user, parent->ss_user) < 0) return -1; if (soa_description_dup(home, ss->ss_local, parent->ss_local) < 0) return -1; if (soa_description_dup(home, ss->ss_remote, parent->ss_remote) < 0) return -1; DUP(ss->ss_address, su_strdup, parent->ss_address); ss->ss_af = parent->ss_af; DUP(ss->ss_hold, su_strdup, parent->ss_hold); DUP(ss->ss_cname, su_strdup, parent->ss_cname); ss->ss_srtp_enable = parent->ss_srtp_enable; ss->ss_srtp_confidentiality = parent->ss_srtp_confidentiality; ss->ss_srtp_integrity = parent->ss_srtp_integrity; } return 0;}/** Destroy a session. */void soa_destroy(soa_session_t *ss){ SU_DEBUG_9(("soa_destroy(%s::%p) called\n", ss ? ss->ss_actions->soa_name : "", ss)); if (ss) { ss->ss_active = 0; ss->ss_terminated++; ss->ss_actions->soa_deinit(ss); su_home_unref(ss->ss_home); }}void soa_base_deinit(soa_session_t *ss){ (void)ss;}/** Set tagged parameters */int soa_set_params(soa_session_t *ss, tag_type_t tag, tag_value_t value, ...){ ta_list ta; int n; SU_DEBUG_9(("soa_set_params(%s::%p, ...) called\n", ss ? ss->ss_actions->soa_name : "", ss)); if (ss == NULL) return su_seterrno(EFAULT), -1; ta_start(ta, tag, value); n = ss->ss_actions->soa_set_params(ss, ta_args(ta)); ta_end(ta); return n;}int soa_base_set_params(soa_session_t *ss, tagi_t const *tags){ int n, change_session = 0; sdp_session_t const *caps_sdp, *user_sdp; char const *caps_sdp_str, *user_sdp_str; int af; char const *media_address, *hold; unsigned rtp_select, rtp_sort; int rtp_mismatch; int srtp_enable, srtp_confidentiality, srtp_integrity; af = ss->ss_af; hold = ss->ss_hold; media_address = ss->ss_address; rtp_select = ss->ss_rtp_select; rtp_sort = ss->ss_rtp_sort; rtp_mismatch = ss->ss_rtp_mismatch; srtp_enable = ss->ss_srtp_enable; srtp_confidentiality = ss->ss_srtp_confidentiality; srtp_integrity = ss->ss_srtp_integrity; caps_sdp = user_sdp = NONE; caps_sdp_str = user_sdp_str = NONE; n = tl_gets(tags, SOATAG_CAPS_SDP_REF(caps_sdp), SOATAG_CAPS_SDP_STR_REF(caps_sdp_str), SOATAG_USER_SDP_REF(user_sdp), SOATAG_USER_SDP_STR_REF(user_sdp_str), SOATAG_AF_REF(af), SOATAG_ADDRESS_REF(media_address), SOATAG_HOLD_REF(hold), SOATAG_RTP_SELECT_REF(rtp_select), SOATAG_RTP_SORT_REF(rtp_sort), SOATAG_RTP_MISMATCH_REF(rtp_mismatch), SOATAG_SRTP_ENABLE_REF(srtp_enable), SOATAG_SRTP_CONFIDENTIALITY_REF(srtp_confidentiality), SOATAG_SRTP_INTEGRITY_REF(srtp_integrity), TAG_END()); if (n <= 0) return n; if (caps_sdp != NONE || caps_sdp_str != NONE) { if (caps_sdp == NONE) caps_sdp = NULL; if (caps_sdp_str == NONE) caps_sdp_str = NULL; if (caps_sdp || caps_sdp_str) { if (soa_set_capability_sdp(ss, caps_sdp, caps_sdp_str, -1) < 0) { return -1; } } else { soa_description_free(ss, ss->ss_caps); } } if (user_sdp != NONE || user_sdp_str != NONE) { if (user_sdp == NONE) user_sdp = NULL; if (user_sdp_str == NONE) user_sdp_str = NULL; if (user_sdp || user_sdp_str) { if (soa_set_user_sdp(ss, user_sdp, user_sdp_str, -1) < 0) { return -1; } if (ss->ss_caps->ssd_str == NULL) soa_set_capability_sdp(ss, user_sdp, user_sdp_str, -1); } else { soa_description_free(ss, ss->ss_user); } } if (af < SOA_AF_ANY || af > SOA_AF_IP6_IP4) af = ss->ss_af; if (rtp_select < SOA_RTP_SELECT_SINGLE || rtp_select > SOA_RTP_SELECT_ALL) rtp_select = ss->ss_rtp_select;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -