freeswitch/libs/sofia-sip/libsofia-sip-ua/sip/sip_pref_util.c

603 lines
15 KiB
C
Raw Normal View History

/*
* 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 sip_pref_util.c
*
* SIP callercaps and callerprefs utility functions.
*
* @author Pekka Pessi <Pekka.Pessi@nokia.com>.
*
* @date Created: Tue Nov 2 16:39:33 EET 2004 ppessi
*/
#include "config.h"
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <float.h>
#include "sofia-sip/sip_parser.h"
#include <sofia-sip/sip_header.h>
#include <sofia-sip/sip_util.h>
#include <sofia-sip/sip_status.h>
static double parse_number(char const *str, char **return_end);
/** Parse a single preference */
int sip_prefs_parse(union sip_pref *sp,
char const **in_out_s,
int *return_negation)
{
char const *s;
size_t n;
enum sp_type old_type;
assert(sp && in_out_s && *in_out_s && return_negation);
old_type = sp->sp_type;
sp->sp_type = sp_error;
s = *in_out_s;
if (!s)
return 0;
if (old_type == sp_init) {
if (s[0] == '\0' ||
strcasecmp(s, "TRUE") == 0 ||
strcasecmp(s, "\"TRUE\"") == 0) {
/* Boolean */
sp->sp_type = sp_literal;
sp->sp_literal.spl_value = "TRUE";
sp->sp_literal.spl_length = 4;
*return_negation = 0;
*in_out_s = s + strlen(s);
return 1;
} else if (strcasecmp(s, "FALSE") == 0 ||
strcasecmp(s, "\"FALSE\"") == 0) {
/* Boolean */
sp->sp_type = sp_literal;
sp->sp_literal.spl_value = "FALSE";
sp->sp_literal.spl_length = 5;
*return_negation = 0;
*in_out_s = s + strlen(s);
return 1;
} else if (s[0] == '"' && s[1] != '\0') {
for (s++; IS_LWS(s[0]); s++);
} else
old_type = sp_error;
} else if (!s[0]) {
sp->sp_type = sp_init;
return 0;
}
if (old_type == sp_error)
return 0;
if ((*return_negation = s[0] == '!'))
for (s++; IS_LWS(s[0]); s++);
if (*s == '#') {
/* Numeric */
double n1, n2;
char s0, *e;
for (s++; IS_LWS(s[0]); s++);
s0 = s[0];
if (s0 == '=')
sp->sp_type = sp_range, n1 = n2 = parse_number(s = s + 1, &e);
else if (s0 == '<' && s[1] == '=')
sp->sp_type = sp_range, n1 = -DBL_MAX, n2 = parse_number(s = s + 2, &e);
else if (s0 == '>' && s[1] == '=')
sp->sp_type = sp_range, n1 = parse_number(s = s + 2, &e), n2 = DBL_MAX;
else if (((n1 = parse_number(s, &e)) != 0.0 || s != e) && e[0] == ':')
sp->sp_type = sp_range, n2 = parse_number(s = e + 1, &e);
else
/* Error in conversion */
sp->sp_type = sp_error, n1 = DBL_MAX, n2 = -DBL_MAX;
if (s == e && (n1 == 0.0 || n2 == 0.0))
sp->sp_type = sp_error; /* Error in conversion */
sp->sp_range.spr_lower = n1;
sp->sp_range.spr_upper = n2;
s = e;
} else if (*s == '<') {
/* Quoted string */
n = strcspn(++s, ">");
sp->sp_type = sp_string;
sp->sp_string.sps_value = s;
sp->sp_string.sps_length = n;
s += n + 1;
} else if ((n = span_token(s))) {
/* Literal */
sp->sp_type = sp_literal;
sp->sp_literal.spl_value = s;
sp->sp_literal.spl_length = n;
s += n;
}
for (; IS_LWS(s[0]); s++);
if (s[0] == ',' || (s[0] == '"' && s[1] == '\0'))
for (s++; IS_LWS(s[0]); s++);
else
old_type = sp_error;
if (old_type != sp_init && old_type != sp->sp_type)
sp->sp_type = sp_error;
*in_out_s = s;
return sp->sp_type != sp_error;
}
/** Parse number:
* number = [ "+" / "-" ] 1*DIGIT ["." 0*DIGIT]
*/
static double parse_number(char const *str, char **return_end)
{
double value = 0.0;
double decimal = 0.1;
char d, sign = '+';
if (return_end)
*return_end = (char *)str;
d = *str;
if (d == '+' || d == '-')
sign = d, d = *++str;
if (!('0' <= d && d <= '9'))
return value;
for (; '0' <= d && d <= '9'; d = *++str)
value = value * 10 + (d - '0');
if (d == '.') for (d = *++str; '0' <= d && d <= '9'; d = *++str) {
value += (d - '0') * decimal; decimal *= 0.1;
}
if (value > DBL_MAX)
value = DBL_MAX;
if (sign == '-')
value = -value;
if (return_end)
*return_end = (char *)str;
return value;
}
/** Return true if preferences match */
int sip_prefs_match(union sip_pref const *a,
union sip_pref const *b)
{
if (!a || !b)
return 0;
if (a->sp_type != b->sp_type)
return 0;
switch (a->sp_type) {
default:
case sp_error:
return 0;
case sp_literal:
return
a->sp_literal.spl_length == b->sp_literal.spl_length &&
strncasecmp(a->sp_literal.spl_value, b->sp_literal.spl_value,
a->sp_literal.spl_length) == 0;
case sp_string:
return
a->sp_string.sps_length == b->sp_string.sps_length &&
strncmp(a->sp_string.sps_value, b->sp_string.sps_value,
a->sp_string.sps_length) == 0;
case sp_range:
return
a->sp_range.spr_lower <= b->sp_range.spr_upper &&
a->sp_range.spr_upper >= b->sp_range.spr_lower;
}
}
/**Find a matching parameter-value pair from a parameter list.
*
* Check if the given feature values match with each other.
*
* @param pvalue first feature parameter
* @param nvalue second feature parameter
* @param return_parse_error return-value parameter for error (may be NULL)
*
* @retval 1 if given feature parameters match
* @retval 0 if there is no match or a parse or type error occurred.
*
* If there is a parsing or type error, 0 is returned and @a
* *return_parse_error is set to -1.
*
* @sa sip_prefs_parse(), sip_prefs_match(), union #sip_pref.
*/
int sip_prefs_matching(char const *pvalue,
char const *nvalue,
int *return_parse_error)
{
int error;
char const *p;
union sip_pref np[1], pp[1];
int n_negated, p_negated;
if (!return_parse_error)
return_parse_error = &error;
if (!pvalue || !nvalue)
return 0;
memset(np, 0, sizeof np);
/* Usually nvalue is from Accept/Reject-Contact,
pvalue is from Contact */
while (sip_prefs_parse(np, &nvalue, &n_negated)) {
memset(pp, 0, sizeof pp);
p = pvalue;
while (sip_prefs_parse(pp, &p, &p_negated)) {
if (pp->sp_type != np->sp_type) /* Types do not match */
return 0;
if (sip_prefs_match(np, pp) /* We found matching value */
? !p_negated /* without negative */
: p_negated) /* Negative did not match */
break;
}
if (pp->sp_type == sp_error)
return *return_parse_error = -1, 0;
if (pp->sp_type != sp_init /* We found matching value */
? !n_negated /* and we expected one */
: n_negated) /* We found none and expected none */
return 1;
}
if (np->sp_type == sp_error)
*return_parse_error = -1;
return 0;
}
/** Check if the parameter is a valid feature tag.
*
* A feature tag is a parameter starting with a single plus, or a well-known
* feature tag listed in @RFC3841: "audio", "automata", "application",
* "class", "control", "duplex", "data", "description", "events", "isfocus",
* "language", "mobility", "methods", "priority", "schemes", "type", or
* "video". However, well-known feature tag can not start with plus. So,
* "+alarm" or "audio" is a feature tag, "alarm", "++alarm", or "+audio" are
* not.
*
* @retval 1 if string is a feature tag parameter
* @retval 0 otherwise
*/
int sip_is_callerpref(char const *param)
{
#define MATCH(s) \
(strncasecmp(param + 1, s + 1, strlen(s) - 1) == 0 && \
(param[strlen(s)] == '=' || param[strlen(s)] == '\0'))
int xor = 0, base = 0;
if (!param || !param[0])
return 0;
if (param[0] == '+')
param++, xor = 1;
switch (param[0]) {
case 'a': case 'A':
base = MATCH("audio") || MATCH("automata") || MATCH("application") ||
MATCH("actor");
break;
case 'c': case 'C':
base = MATCH("class") || MATCH("control");
break;
case 'd': case 'D':
base = MATCH("duplex") || MATCH("data") || MATCH("description");
break;
case 'e': case 'E':
base = MATCH("events");
break;
case 'i': case 'I':
base = MATCH("isfocus");
break;
case 'l': case 'L':
base = MATCH("language");
break;
case 'm': case 'M':
base = MATCH("mobility") || MATCH("methods");
break;
case 'p': case 'P':
base = MATCH("priority");
break;
case 's': case 'S':
base = MATCH("schemes");
break;
case 't': case 'T':
base = MATCH("type");
break;
case 'v': case 'V':
base = MATCH("video");
break;
default:
base = 0;
break;
}
#undef MATCH
return base ^ xor;
}
/** Check if @Contact is immune to callerprefs. */
int sip_contact_is_immune(sip_contact_t const *m)
{
unsigned i;
if (m->m_params)
for (i = 0; m->m_params[i]; i++) {
if (sip_is_callerpref(m->m_params[i]))
return 0;
}
return 1;
}
/**Check if @Contact matches by @AcceptContact.
*
* Matching @AcceptContact and @Contact headers is done as explained in
* @RFC3841 section 7.2.4. The caller score can be calculated from the
* returned S and N values.
*
* @par Matching
* The @AcceptContact header contains number of feature tag parameters. The
* count of feature tags is returned in @a return_N. For each feature tag in
* @AcceptContact, the feature tag with same name is searched from the
* @Contact header. If both headers contain the feature tag with same name,
* their values are compared. If the value in @AcceptContact does not match
* with the value in @Contact, there is mismatch and 0 is returned. If they
* match, S is increased by 1.
*
* @param m pointer to @Contact header structure
* @param cp pointer to @AcceptContact header structure
* @param return_N return-value parameter for number of
* feature tags in @AcceptContact
* @param return_S return-value parameter for number of
* matching feature tags
* @param return_error return-value parameter for parsing error
*
* For example,
* @code
* if (sip_contact_accept(contact, accept_contact, &S, &N, &error)) {
* if (N == 0)
* score == 1.0;
* else
* score = (double)S / (double)N;
* if (accept_contact->cp_explicit) {
* if (accept_contact->cp_require)
* goto drop;
* else
* score = 0.0;
* }
* }
* else if (!error) {
* score = 0.0;
* }
* @endcode
*
* @retval 1 if @Contact matches
* @return @a return_S contains number of matching feature tags
* @return @a return_N contains number of feature tags in @AcceptContact
* @retval 0 if @Contact does not match
* @return @a return_error contains -1 if feature tag value was malformed
*
* @sa @RFC3841 section 7.2.4, sip_contact_score(), sip_contact_reject(),
* sip_contact_is_immune(), sip_contact_immunize(), sip_is_callerpref(),
* sip_prefs_matching().
*/
int sip_contact_accept(sip_contact_t const *m,
sip_accept_contact_t const *cp,
unsigned *return_S,
unsigned *return_N,
int *return_error)
{
char const *cap, *acc;
unsigned i, S, N;
size_t eq;
if (!return_N) return_N = &N;
if (!return_S) return_S = &S;
*return_S = 0, *return_N = 0;
if (!m || !cp || !m->m_params || !cp->cp_params)
return 1;
for (i = 0, S = 0, N = 0; cp->cp_params[i]; i++) {
acc = cp->cp_params[i];
if (!sip_is_callerpref(acc))
continue;
N++;
cap = msg_params_find(m->m_params, acc);
if (cap) {
eq = strcspn(acc, "=");
acc += eq + (acc[eq] == '=');
if (!sip_prefs_matching(cap, acc, return_error))
return 0;
S++;
}
}
*return_S = S; /* Matched feature tags */
*return_N = N; /* Number of feature tags in @AcceptContact */
return 1;
}
/** Check if @Contact is rejected by @RejectContact.
*
* @param m pointer to @Contact header
* @param reject pointer to @RejectContact header
*
* @retval 1 when rejecting
* @retval 0 when @Contact does not match with @RejectContact
*
* @sa sip_contact_score(), sip_contact_accept(), sip_contact_immunize(),
* sip_contact_is_immune(), @RFC3841, @RejectContact, @Contact
*/
int sip_contact_reject(sip_contact_t const *m,
sip_reject_contact_t const *reject)
{
unsigned S, N;
int error;
if (!m || !m->m_params || !reject || !reject->cp_params)
return 0;
return sip_contact_accept(m, reject, &S, &N, &error) && S == N && N > 0;
}
/**Immunize @Contact to callerprefs.
*
* Make a copy of @Contact header @a m and remove all parameters which
* affect caller preferences.
*
* @param home home object used when allocating copy
* @param m pointer to @Contact header structure to immunize
*
* @retval pointer to immunized copy if successful
* @retval NULL upon an error
*
* @sa @RFC3841, sip_is_callerpref(), sip_contact_score(),
* sip_contact_accept(), sip_contact_reject(), @Contact
*/
sip_contact_t *sip_contact_immunize(su_home_t *home, sip_contact_t const *m)
{
unsigned i, j;
sip_contact_t m0[1], *m1;
msg_param_t *params;
if (!m)
return NULL;
*m0 = *m, m0->m_next = NULL;
m1 = sip_contact_copy(home, m0);
if (m1 == NULL || !m1->m_params)
return m1;
params = (msg_param_t *)m1->m_params;
for (i = 0, j = 0; params[i]; i++) {
if (!sip_is_callerpref(params[i]))
params[j++] = params[i];
}
params[j] = NULL;
return m1;
}
/** Calculate score for contact.
*
* The caller preference score is an integer in range of 0 to 1000.
*
* @retval -1 if the contact is rejected
* @retval 1000 if contact is immune to caller preferences
Sync to current darcs tree: Mon Sep 17 14:50:04 EDT 2007 Pekka.Pessi@nokia.com * sofia-sip/sip_util.h: updated documentation Mon Sep 17 14:50:18 EDT 2007 Pekka.Pessi@nokia.com * sofia-sip/tport_tag.h: updated documentation Mon Sep 17 14:50:28 EDT 2007 Pekka.Pessi@nokia.com * soa_tag.c: updated documentation Wed Sep 19 12:50:01 EDT 2007 Pekka.Pessi@nokia.com * msg: updated documentation Wed Sep 19 13:29:50 EDT 2007 Pekka.Pessi@nokia.com * url: updated documentation Wed Sep 19 13:32:14 EDT 2007 Pekka.Pessi@nokia.com * nth: updated documentation Wed Sep 19 13:32:27 EDT 2007 Pekka.Pessi@nokia.com * nea: updated documentation Wed Sep 19 13:33:36 EDT 2007 Pekka.Pessi@nokia.com * http: updated documentation Wed Sep 19 13:36:58 EDT 2007 Pekka.Pessi@nokia.com * bnf: updated documentation Wed Sep 19 13:38:58 EDT 2007 Pekka.Pessi@nokia.com * nua: updated nua_stack_init_handle() prototype Wed Sep 19 18:45:56 EDT 2007 Pekka.Pessi@nokia.com * sip: added sip_name_addr_xtra(), sip_name_addr_dup() Wed Sep 19 19:00:19 EDT 2007 Pekka.Pessi@nokia.com * sip_basic.c: cleaned old crud Thu Sep 20 13:34:04 EDT 2007 Pekka.Pessi@nokia.com * iptsec: updated documentation Thu Sep 20 13:36:22 EDT 2007 Pekka.Pessi@nokia.com * tport: updated documentation Thu Sep 20 13:36:56 EDT 2007 Pekka.Pessi@nokia.com * su: updated documentation Removed internal files from doxygen-generated documentation. Thu Sep 20 13:38:29 EDT 2007 Pekka.Pessi@nokia.com * soa: fixed documentation Thu Sep 20 13:39:56 EDT 2007 Pekka.Pessi@nokia.com * sdp: updated documentation Thu Sep 20 13:40:16 EDT 2007 Pekka.Pessi@nokia.com * ipt: updated documentation Thu Sep 20 14:24:20 EDT 2007 Pekka.Pessi@nokia.com * nta: updated documentation Thu Sep 20 14:41:04 EDT 2007 Pekka.Pessi@nokia.com * nua: updated documentation Updated tag documentation. Moved doxygen doc entries from sofia-sip/nua_tag.h to nua_tag.c. Removed internal datatypes and files from the generated documents. Wed Sep 19 13:34:20 EDT 2007 Pekka.Pessi@nokia.com * docs: updated the generation of documentation. Updated links to header files. Thu Sep 20 08:45:32 EDT 2007 Pekka.Pessi@nokia.com * sip/Makefile.am: added tags to <sofia-sip/sip_extra.h> Added check for extra tags in torture_sip.c. Thu Sep 20 14:45:22 EDT 2007 Pekka.Pessi@nokia.com * stun: updated documentation Wed Jul 4 18:55:20 EDT 2007 Pekka.Pessi@nokia.com * torture_heap.c: added tests for ##sort() and su_smoothsort() Wed Jul 4 18:56:59 EDT 2007 Pekka.Pessi@nokia.com * Makefile.am: added smoothsort.c Fri Jul 13 12:38:44 EDT 2007 Pekka.Pessi@nokia.com * sofia-sip/heap.h: heap_remove() now set()s index to 0 on removed item Mon Jul 23 11:14:22 EDT 2007 Pekka.Pessi@nokia.com * sofia-sip/heap.h: fixed bug in heap##remove() If left kid was in heap but right was not, left kid was ignored. Wed Jul 4 18:51:08 EDT 2007 Pekka.Pessi@nokia.com * smoothsort.c: added Wed Jul 4 18:51:34 EDT 2007 Pekka.Pessi@nokia.com * heap.h: using su_smoothsort() Fri Jul 6 10:20:27 EDT 2007 Pekka.Pessi@nokia.com * smoothsort.c: added Wed Sep 19 17:40:30 EDT 2007 Pekka.Pessi@nokia.com * msg_parser.awk: generate two parser tables, default and extended Wed Sep 19 18:39:45 EDT 2007 Pekka.Pessi@nokia.com * msg_parser.awk: just generate list of extra headers Allocate extended parser dynamically. Wed Sep 19 18:59:59 EDT 2007 Pekka.Pessi@nokia.com * sip: added Remote-Party-ID, P-Asserted-Identity, P-Preferred-Identity Added functions sip_update_default_mclass() and sip_extend_mclass() for handling the extended parser. Note that Reply-To and Alert-Info are only available with the extended parser. Wed Sep 19 19:05:44 EDT 2007 Pekka.Pessi@nokia.com * RELEASE: updated Thu Sep 20 13:38:59 EDT 2007 Pekka.Pessi@nokia.com * sip: updated documentation Thu Sep 20 14:17:28 EDT 2007 Pekka.Pessi@nokia.com * docs/conformance.docs: updated Mon Oct 1 10:11:14 EDT 2007 Pekka.Pessi@nokia.com * tport_tag.c: re-enabled tptag_trusted Thu Oct 4 09:21:07 EDT 2007 Pekka.Pessi@nokia.com * su_osx_runloop.c: moved virtual function table after struct definition Preparing for su_port_vtable_t refactoring. Thu Oct 4 10:22:03 EDT 2007 Pekka.Pessi@nokia.com * su_source.c: refactored initialization/deinitialization Fri Oct 5 04:58:18 EDT 2007 Pekka Pessi <Pekka.Pessi@nokia.com> * sip_extra.c: fixed prototypes with isize_t Fri Oct 5 04:58:45 EDT 2007 Pekka Pessi <Pekka.Pessi@nokia.com> * test_nta_api.c: removed warnings about signedness Fri Oct 5 04:59:02 EDT 2007 Pekka Pessi <Pekka.Pessi@nokia.com> * test_nua_params.c: removed warnings about constness Fri Oct 5 07:20:26 EDT 2007 Pekka Pessi <first.lastname@nokia.com> * su_port.h, su_root.c: cleaned argument checking The su_root_*() and su_port_*() functions now check their arguments once and do not assert() with NULL arguments. The sur_task->sut_port should always be valid while su_root_t is alive. Fri Oct 5 07:22:09 EDT 2007 Pekka Pessi <first.lastname@nokia.com> * su: added su_root_obtain(), su_root_release() and su_root_has_thread() When root is created with su_root_create() or cloned with su_clone_start(), the resulting root is obtained by the calling or created thread, respectively. The root can be released with su_root_release() and another thread can obtain it. The function su_root_has_thread() can be used to check if a thread has obtained or released the root. Implementation upgraded the su_port_own_thread() method as su_port_thread(). Fri Oct 5 07:28:10 EDT 2007 Pekka Pessi <first.lastname@nokia.com> * su_port.h: removed su_port_threadsafe() and su_port_yield() methods su_port_wait_events() replaces su_port_yield(). Fri Oct 5 13:26:04 EDT 2007 Pekka Pessi <Pekka.Pessi@nokia.com> * msg_parser.awk: not extending header structure unless needed. Removed gawk-ish /* comments */. Fri Oct 5 14:32:25 EDT 2007 Pekka Pessi <Pekka.Pessi@nokia.com> * run_test_su: removed GNUisms Fri Oct 5 14:32:47 EDT 2007 Pekka Pessi <Pekka.Pessi@nokia.com> * Makefile.am: removed implicit check target test_urlmap Fri Oct 5 14:22:32 EDT 2007 Pekka Pessi <first.lastname@nokia.com> * torture_sresolv.c: use CLOCK_REALTIME if no CLOCK_PROCESS_CPUTIME_ID available Casting timespec tv_sec to unsigned long. Fri Oct * nua_s added handling nua_prack() Thanks to Fabio Margarido for the patch. Mon Oct 8 10:24:35 EDT 2007 Pekka.Pessi@nokia.com * test_nua: added test for sf.net bug #1803686 Mon Oct 8 08:15:23 EDT 2007 Pekka.Pessi@nokia.com * RELEASE: updated. Mon Oct 8 09:30:36 EDT 2007 Pekka.Pessi@nokia.com * nua_stack: added handling nua_prack() Thanks to Fabio Margarido for the patch. Mon Oct 8 10:24:35 EDT 2007 Pekka.Pessi@nokia.com * test_nua: added test for sf.net bug #1803686 Mon Oct 8 10:26:31 EDT 2007 Pekka.Pessi@nokia.com * nua: added test for nua_prack() (sf.net bug #1804248) Avoid sending nua_i_state after nua_prack() if no SDP O/A is happening, too. Mon Oct 8 10:32:04 EDT 2007 Mikhail Zabaluev <mikhail.zabaluev@nokia.com> * su_source.c: don t leak the wait arrays Mon Oct 8 10:37:11 EDT 2007 Pekka.Pessi@nokia.com * RELEASE: updated Wed Oct 10 11:55:21 EDT 2007 Pekka.Pessi@nokia.com * sip_parser.c: silenced warning about extra const in sip_extend_mclass() Wed Oct 10 11:57:08 EDT 2007 Pekka.Pessi@nokia.com * nta_tag.c: updated tag documentation Wed Oct 10 13:16:40 EDT 2007 Pekka.Pessi@nokia.com * nua: fix logging crash if outbound used with application contact Silenced warnings. Wed Oct 10 13:30:45 EDT 2007 Pekka.Pessi@nokia.com * msg_parser.awk: removed extra "const" Wed Oct 10 13:31:45 EDT 2007 Pekka.Pessi@nokia.com * Makefile.am's: fixed distclean of documentation git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@5840 d0543943-73ff-0310-b7d9-9358b9ac24b2
2007-10-11 14:16:59 +00:00
* @retval 0..1000 reflecting @RFC3841 score in 0.000 - 1.000.
*
* @sa sip_q_value(),
* sip_contact_accept(), sip_contact_reject(), sip_contact_is_immune(),
* sip_contact_immunize(), sip_is_callerpref(), sip_prefs_matching(),
Sync to current darcs tree: Mon Sep 17 14:50:04 EDT 2007 Pekka.Pessi@nokia.com * sofia-sip/sip_util.h: updated documentation Mon Sep 17 14:50:18 EDT 2007 Pekka.Pessi@nokia.com * sofia-sip/tport_tag.h: updated documentation Mon Sep 17 14:50:28 EDT 2007 Pekka.Pessi@nokia.com * soa_tag.c: updated documentation Wed Sep 19 12:50:01 EDT 2007 Pekka.Pessi@nokia.com * msg: updated documentation Wed Sep 19 13:29:50 EDT 2007 Pekka.Pessi@nokia.com * url: updated documentation Wed Sep 19 13:32:14 EDT 2007 Pekka.Pessi@nokia.com * nth: updated documentation Wed Sep 19 13:32:27 EDT 2007 Pekka.Pessi@nokia.com * nea: updated documentation Wed Sep 19 13:33:36 EDT 2007 Pekka.Pessi@nokia.com * http: updated documentation Wed Sep 19 13:36:58 EDT 2007 Pekka.Pessi@nokia.com * bnf: updated documentation Wed Sep 19 13:38:58 EDT 2007 Pekka.Pessi@nokia.com * nua: updated nua_stack_init_handle() prototype Wed Sep 19 18:45:56 EDT 2007 Pekka.Pessi@nokia.com * sip: added sip_name_addr_xtra(), sip_name_addr_dup() Wed Sep 19 19:00:19 EDT 2007 Pekka.Pessi@nokia.com * sip_basic.c: cleaned old crud Thu Sep 20 13:34:04 EDT 2007 Pekka.Pessi@nokia.com * iptsec: updated documentation Thu Sep 20 13:36:22 EDT 2007 Pekka.Pessi@nokia.com * tport: updated documentation Thu Sep 20 13:36:56 EDT 2007 Pekka.Pessi@nokia.com * su: updated documentation Removed internal files from doxygen-generated documentation. Thu Sep 20 13:38:29 EDT 2007 Pekka.Pessi@nokia.com * soa: fixed documentation Thu Sep 20 13:39:56 EDT 2007 Pekka.Pessi@nokia.com * sdp: updated documentation Thu Sep 20 13:40:16 EDT 2007 Pekka.Pessi@nokia.com * ipt: updated documentation Thu Sep 20 14:24:20 EDT 2007 Pekka.Pessi@nokia.com * nta: updated documentation Thu Sep 20 14:41:04 EDT 2007 Pekka.Pessi@nokia.com * nua: updated documentation Updated tag documentation. Moved doxygen doc entries from sofia-sip/nua_tag.h to nua_tag.c. Removed internal datatypes and files from the generated documents. Wed Sep 19 13:34:20 EDT 2007 Pekka.Pessi@nokia.com * docs: updated the generation of documentation. Updated links to header files. Thu Sep 20 08:45:32 EDT 2007 Pekka.Pessi@nokia.com * sip/Makefile.am: added tags to <sofia-sip/sip_extra.h> Added check for extra tags in torture_sip.c. Thu Sep 20 14:45:22 EDT 2007 Pekka.Pessi@nokia.com * stun: updated documentation Wed Jul 4 18:55:20 EDT 2007 Pekka.Pessi@nokia.com * torture_heap.c: added tests for ##sort() and su_smoothsort() Wed Jul 4 18:56:59 EDT 2007 Pekka.Pessi@nokia.com * Makefile.am: added smoothsort.c Fri Jul 13 12:38:44 EDT 2007 Pekka.Pessi@nokia.com * sofia-sip/heap.h: heap_remove() now set()s index to 0 on removed item Mon Jul 23 11:14:22 EDT 2007 Pekka.Pessi@nokia.com * sofia-sip/heap.h: fixed bug in heap##remove() If left kid was in heap but right was not, left kid was ignored. Wed Jul 4 18:51:08 EDT 2007 Pekka.Pessi@nokia.com * smoothsort.c: added Wed Jul 4 18:51:34 EDT 2007 Pekka.Pessi@nokia.com * heap.h: using su_smoothsort() Fri Jul 6 10:20:27 EDT 2007 Pekka.Pessi@nokia.com * smoothsort.c: added Wed Sep 19 17:40:30 EDT 2007 Pekka.Pessi@nokia.com * msg_parser.awk: generate two parser tables, default and extended Wed Sep 19 18:39:45 EDT 2007 Pekka.Pessi@nokia.com * msg_parser.awk: just generate list of extra headers Allocate extended parser dynamically. Wed Sep 19 18:59:59 EDT 2007 Pekka.Pessi@nokia.com * sip: added Remote-Party-ID, P-Asserted-Identity, P-Preferred-Identity Added functions sip_update_default_mclass() and sip_extend_mclass() for handling the extended parser. Note that Reply-To and Alert-Info are only available with the extended parser. Wed Sep 19 19:05:44 EDT 2007 Pekka.Pessi@nokia.com * RELEASE: updated Thu Sep 20 13:38:59 EDT 2007 Pekka.Pessi@nokia.com * sip: updated documentation Thu Sep 20 14:17:28 EDT 2007 Pekka.Pessi@nokia.com * docs/conformance.docs: updated Mon Oct 1 10:11:14 EDT 2007 Pekka.Pessi@nokia.com * tport_tag.c: re-enabled tptag_trusted Thu Oct 4 09:21:07 EDT 2007 Pekka.Pessi@nokia.com * su_osx_runloop.c: moved virtual function table after struct definition Preparing for su_port_vtable_t refactoring. Thu Oct 4 10:22:03 EDT 2007 Pekka.Pessi@nokia.com * su_source.c: refactored initialization/deinitialization Fri Oct 5 04:58:18 EDT 2007 Pekka Pessi <Pekka.Pessi@nokia.com> * sip_extra.c: fixed prototypes with isize_t Fri Oct 5 04:58:45 EDT 2007 Pekka Pessi <Pekka.Pessi@nokia.com> * test_nta_api.c: removed warnings about signedness Fri Oct 5 04:59:02 EDT 2007 Pekka Pessi <Pekka.Pessi@nokia.com> * test_nua_params.c: removed warnings about constness Fri Oct 5 07:20:26 EDT 2007 Pekka Pessi <first.lastname@nokia.com> * su_port.h, su_root.c: cleaned argument checking The su_root_*() and su_port_*() functions now check their arguments once and do not assert() with NULL arguments. The sur_task->sut_port should always be valid while su_root_t is alive. Fri Oct 5 07:22:09 EDT 2007 Pekka Pessi <first.lastname@nokia.com> * su: added su_root_obtain(), su_root_release() and su_root_has_thread() When root is created with su_root_create() or cloned with su_clone_start(), the resulting root is obtained by the calling or created thread, respectively. The root can be released with su_root_release() and another thread can obtain it. The function su_root_has_thread() can be used to check if a thread has obtained or released the root. Implementation upgraded the su_port_own_thread() method as su_port_thread(). Fri Oct 5 07:28:10 EDT 2007 Pekka Pessi <first.lastname@nokia.com> * su_port.h: removed su_port_threadsafe() and su_port_yield() methods su_port_wait_events() replaces su_port_yield(). Fri Oct 5 13:26:04 EDT 2007 Pekka Pessi <Pekka.Pessi@nokia.com> * msg_parser.awk: not extending header structure unless needed. Removed gawk-ish /* comments */. Fri Oct 5 14:32:25 EDT 2007 Pekka Pessi <Pekka.Pessi@nokia.com> * run_test_su: removed GNUisms Fri Oct 5 14:32:47 EDT 2007 Pekka Pessi <Pekka.Pessi@nokia.com> * Makefile.am: removed implicit check target test_urlmap Fri Oct 5 14:22:32 EDT 2007 Pekka Pessi <first.lastname@nokia.com> * torture_sresolv.c: use CLOCK_REALTIME if no CLOCK_PROCESS_CPUTIME_ID available Casting timespec tv_sec to unsigned long. Fri Oct * nua_s added handling nua_prack() Thanks to Fabio Margarido for the patch. Mon Oct 8 10:24:35 EDT 2007 Pekka.Pessi@nokia.com * test_nua: added test for sf.net bug #1803686 Mon Oct 8 08:15:23 EDT 2007 Pekka.Pessi@nokia.com * RELEASE: updated. Mon Oct 8 09:30:36 EDT 2007 Pekka.Pessi@nokia.com * nua_stack: added handling nua_prack() Thanks to Fabio Margarido for the patch. Mon Oct 8 10:24:35 EDT 2007 Pekka.Pessi@nokia.com * test_nua: added test for sf.net bug #1803686 Mon Oct 8 10:26:31 EDT 2007 Pekka.Pessi@nokia.com * nua: added test for nua_prack() (sf.net bug #1804248) Avoid sending nua_i_state after nua_prack() if no SDP O/A is happening, too. Mon Oct 8 10:32:04 EDT 2007 Mikhail Zabaluev <mikhail.zabaluev@nokia.com> * su_source.c: don t leak the wait arrays Mon Oct 8 10:37:11 EDT 2007 Pekka.Pessi@nokia.com * RELEASE: updated Wed Oct 10 11:55:21 EDT 2007 Pekka.Pessi@nokia.com * sip_parser.c: silenced warning about extra const in sip_extend_mclass() Wed Oct 10 11:57:08 EDT 2007 Pekka.Pessi@nokia.com * nta_tag.c: updated tag documentation Wed Oct 10 13:16:40 EDT 2007 Pekka.Pessi@nokia.com * nua: fix logging crash if outbound used with application contact Silenced warnings. Wed Oct 10 13:30:45 EDT 2007 Pekka.Pessi@nokia.com * msg_parser.awk: removed extra "const" Wed Oct 10 13:31:45 EDT 2007 Pekka.Pessi@nokia.com * Makefile.am's: fixed distclean of documentation git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@5840 d0543943-73ff-0310-b7d9-9358b9ac24b2
2007-10-11 14:16:59 +00:00
* @RFC3841, @AcceptContact, @RejectContact, @Contact
*/
int sip_contact_score(sip_contact_t const *m,
sip_accept_contact_t const *ac,
sip_reject_contact_t const *rc)
{
unsigned long S_total = 0;
unsigned M = 0, scale = 1000;
int error = 0;
if (sip_contact_is_immune(m))
return 1000; /* Immune */
for (; rc; rc = rc->cp_next)
if (sip_contact_reject(m, rc))
break;
if (rc)
return -1; /* Rejected */
for (; ac; ac = ac->cp_next) {
unsigned S, N;
if (!sip_contact_accept(m, ac, &S, &N, &error)) {
if (ac->cp_require)
return 0; /* Discarded */
continue;
}
M++;
/* Apply score */
if (S < N && ac->cp_explicit) {
S = 0;
if (ac->cp_require)
return 0; /* Dropped */
}
if (S > 0 && N > 0)
S_total += sip_q_value(ac->cp_q) * (scale * S / N + (2 * S >= N));
}
if (!M)
return 0;
S_total /= M;
if (S_total < scale * 1000)
return S_total / scale;
else
return 1000;
}