📄 sip_util.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 sip_util.c * * SIP utility functions. * * @author Pekka Pessi <Pekka.Pessi@nokia.com>. * * @date Created: Tue Jun 13 02:57:51 2000 ppessi */#include "config.h"#include <stddef.h>#include <stdlib.h>#include <string.h>#include <assert.h>#include <float.h>#include <limits.h>#include <ctype.h>#include <sofia-sip/su_alloc.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>#include "sofia-sip/bnf.h"#ifndef STRING0_H#include <sofia-sip/string0.h>#endif/** * Compare two SIP addresses (@b From or @b To headers). * * @retval nonzero if matching. * @retval zero if not matching. */int sip_addr_match(sip_addr_t const *a, sip_addr_t const *b){ return (a->a_tag == NULL || b->a_tag == NULL || strcmp(a->a_tag, b->a_tag) == 0) && str0casecmp(a->a_host, b->a_host) == 0 && str0cmp(a->a_user, b->a_user) == 0 && str0cmp(a->a_url->url_scheme, b->a_url->url_scheme);}/** Convert a Via header to Contact header */sip_contact_t *sip_contact_create_from_via(su_home_t *home, sip_via_t const *v, char const *user){ const char *tp; if (!v) return NULL; tp = strrchr(v->v_protocol, '/'); if (!tp++) return NULL; if (strcasecmp(tp, "udp") == 0) /* Default is UDP */ tp = NULL; return sip_contact_create_from_via_with_transport(home, v, user, tp);}/** Convert a Via header to Contact header */sip_contact_t *sip_contact_create_from_via_with_transport(su_home_t *home, sip_via_t const *v, char const *user, char const *transport){ const char *host, *port, *maddr, *comp; char const *scheme = "sip"; sip_contact_t *m; if (!v) return NULL; host = v->v_host; port = v->v_port; maddr = v->v_maddr; if (host == NULL) return NULL; if (transport && strcasecmp(transport, "tls") == 0) { scheme = "sips", transport = NULL; if (port && strcmp(port, "5061") == 0) port = NULL; } comp = v->v_comp; m = sip_contact_format(home, "<%s:%s%s%s%s%s%s%s%s%s%s%s>", scheme, user ? user : "", user ? "@" : "", host, SIP_STRLOG(":", port), SIP_STRLOG(";transport=", transport), SIP_STRLOG(";maddr=", maddr), SIP_STRLOG(";comp=", comp)); /* Convert transport to lowercase */ if (transport && m && m->m_url->url_params) { char *s = (char *)m->m_url->url_params + strlen("transport="); while (*s && *s != ';') { if (isupper(*s)) *s = tolower(*s); s++; } } return m;}/**Perform sanity check on a SIP message * * The function sip_sanity_check() checks that the SIP message has all the * mandatory fields. When the SIP message fulfills the minimum * requirements, it returns zero, otherwise a negative status code. * * @param sip SIP message to be checked * * @return * The function sip_sanity_check() returns zero when the SIP message * has all the mandatory fields, and otherwise a negative status code. */intsip_sanity_check(sip_t const *sip){ if (!sip || !((sip->sip_request != NULL) ^ (sip->sip_status != NULL)) || !sip->sip_to || !sip->sip_from || !sip->sip_call_id || !sip->sip_cseq || !sip->sip_via || (sip->sip_flags & MSG_FLG_TRUNC)) return -1; /* Bad request */ if (sip->sip_request) { url_t const *ruri = sip->sip_request->rq_url; switch (ruri->url_type) { case url_invalid: return -1; case url_sip: case url_sips: case url_im: case url_pres: if (!ruri->url_host || strlen(ruri->url_host) == 0) return -1; break; case url_tel: if (!ruri->url_user || strlen(ruri->url_user) == 0) return -1; break; } if (sip->sip_request->rq_method != sip->sip_cseq->cs_method) return -1; if (sip->sip_request->rq_method == sip_method_unknown && str0casecmp(sip->sip_request->rq_method_name, sip->sip_cseq->cs_method_name)) return -1; } return 0;}/** Decode the header string */int sip_header_field_d(su_home_t *home, sip_header_t *h, char *s, int slen){ assert(SIP_HDR_TEST(h)); if (h && s && s[slen] == '\0') { int n = span_lws(s); s += n; slen -= n; for (n = slen - 1; n >= 0 && IS_LWS(s[n]); n--) ; s[n + 1] = '\0'; return h->sh_class->hc_parse(home, h, s, slen); } else return -1;}/** Encode a SIP header contents. */int sip_header_field_e(char *b, int bsiz, sip_header_t const *h, int flags){ assert(h); assert(h->sh_class); return h->sh_class->hc_print(b, bsiz, h, flags);}/** Convert the header @a h to a string allocated from @a home. */char *sip_header_as_string(su_home_t *home, sip_header_t *h){ int len; char *rv, s[128]; if (h == NULL) return NULL; len = sip_header_field_e(s, sizeof(s), h, 0); if (len >= 0 && len < sizeof(s)) return su_strdup(home, s); if (len == -1) len = 2 * sizeof(s); else len += 1; for (rv = su_alloc(home, len); rv; rv = su_realloc(home, rv, len)) { int n = sip_header_field_e(s, sizeof(s), h, 0); if (n > -1 && n + 1 <= len) break; if (n > -1) /* glibc >2.1 */ len = n + 1; else /* glibc 2.0 */ len *= 2; } return rv;}/** Calculate size of a SIP header. */int sip_header_size(sip_header_t const *h){ assert(h == NULL || h == SIP_NONE || h->sh_class); if (h == NULL || h == SIP_NONE) return 0; else return h->sh_class->hc_dxtra(h, h->sh_class->hc_size);}/** Duplicate a url or make a url out of string. * @deprecated Use url_hdup() instead. */url_t *sip_url_dup(su_home_t *home, url_t const *o){ return url_hdup(home, o);}/**Calculate Q value. * * The function sip_q_value() converts q-value string @a q to numeric value * in range (0..1000). Q values are used, for instance, to describe * relative priorities of registered contacts. * * @param q q-value string ("1" | "." 1,3DIGIT) * * @return * The function sip_q_value() returns an integer in range 0 .. 1000. */unsigned sip_q_value(char const *q){ unsigned value = 0; if (!q) return 1000; if (q[0] != '0' && q[0] != '.' && q[0] != '1') return 500; /* Garbage... */ while (q[0] == '0') q++; if (q[0] >= '1' && q[0] <= '9') return 1000; if (q[0] == '\0') return 0; if (q[0] != '.') return 500; /* Garbage... */ if (q[1] >= '0' && q[1] <= '9') { value = (q[1] - '0') * 100; if (q[2] >= '0' && q[2] <= '9') { value += (q[2] - '0') * 10; if (q[3] >= '0' && q[3] <= '9') { value += (q[3] - '0'); if (q[4] > '5' && q[4] <= '9') /* Round upwards */ value += 1; else if (q[4] == '5') value += value & 1; /* Round to even */ } } } return value;}/**@ingroup sip_route * * Get first route header and remove it from its fragment chain. * */sip_route_t *sip_route_remove(msg_t *msg, sip_t *sip){ sip_route_t *r; if ((r = sip->sip_route)) msg_header_remove(msg, (msg_pub_t *)sip, (msg_header_t *)r); return r;}/**@ingroup sip_route * * Get last route header and remove it from its fragment chain. * */sip_route_t *sip_route_pop(msg_t *msg, sip_t *sip){ sip_route_t *r; for (r = sip->sip_route; r; r = r->r_next) if (r->r_next == NULL) { msg_header_remove(msg, (msg_pub_t *)sip, (msg_header_t *)r); return r; } return NULL;}/**@ingroup sip_route * * Get first route header and rewrite the RequestURI. */sip_route_t *sip_route_follow(msg_t *msg, sip_t *sip){ if (sip->sip_route) { /* XXX - in case of outbound proxy, route may contain our address */ sip_route_t *r = sip_route_remove(msg, sip); sip_request_t *rq = sip->sip_request; rq = sip_request_create(msg_home(msg), rq->rq_method, rq->rq_method_name, (url_string_t const *)r->r_url, rq->rq_version); url_strip_transport(rq->rq_url); msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t *)rq); return r; } return NULL;}/**@ingroup sip_route * * Check if route header has lr param. * * "lr" param can be either URL or header parameter. */int sip_route_is_loose(sip_route_t const *r){ if (!r) return 0; if (r->r_url->url_params) return url_has_param(r->r_url, "lr"); else return r->r_params && msg_params_find(r->r_params, "lr") != NULL;}/**@ingroup sip_route * * Reverse a route header. *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -