⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sip_util.c

📁 Sofia SIP is an open-source SIP User-Agent library, compliant with the IETF RFC3261 specification.
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * 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"/* Avoid casting sip_t to msg_pub_t and sip_header_t to msg_header_t */#define MSG_PUB_T       struct sip_s#define MSG_HDR_T       union sip_header_u#include <sofia-sip/su_alloc.h>#include <sofia-sip/su_strlst.h>#include <sofia-sip/string0.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>#include <sofia-sip/hostdomain.h>#include <stdio.h>#include <stddef.h>#include <stdlib.h>#include <string.h>#include <assert.h>#include <float.h>#include <limits.h>#include <ctype.h>/**  * Compare two SIP addresses ( @From or @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);}/**@ingroup sip_contact * * Create a contact header. * * Create a @Contact header object with the given URL and list of parameters. * * @param home      memory home * @param url       URL (string or pointer to url_t) * @param p,...     NULL-terminated list of @Contact parameters * * @return * A pointer to newly created @Contact header object when successful or NULL * upon an error. * */sip_contact_t * sip_contact_create(su_home_t *home,				   url_string_t const *url,				   char const *p, ...){  su_strlst_t *l;  su_home_t *lhome;  sip_contact_t *m;  if (url == NULL)    return NULL;  l = su_strlst_create_with(NULL, "<", NULL), lhome = su_strlst_home(l);  if (l == NULL)    return NULL;  if (url_is_string(url))    su_strlst_append(l, (char const *)url);  else    su_strlst_append(l, url_as_string(lhome, url->us_url));  su_strlst_append(l, ">");  if (p) {    va_list ap;    va_start(ap, p);    for (; p; p = va_arg(ap, char const *)) {      su_strlst_append(l, ";");      su_strlst_append(l, p);    }    va_end(ap);  }  m = sip_contact_make(home, su_strlst_join(l, lhome, ""));  su_strlst_destroy(l);  return m;}/** Convert a @Via header to @Contact header. * * The @Contact URI will contain the port number if needed. If transport * protocol name starts with "TLS", "SIPS:" URI schema is used. Transport * parameter is included in the URI unless the transport protocol is UDP. * * @param home      memory home * @param v         @Via header field structure  *                  (with <sent-protocol> and <sent-by> parameters) * @param user      username for @Contact URI (may be NULL) * * @retval contact header structure * @retval NULL upon an error * * @sa sip_contact_create_from_via_with_transport(),  *     sip_contact_string_from_via() */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 = v->v_protocol;  if (tp == sip_transport_udp ||      strcasecmp(tp, sip_transport_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. * * The @Contact URI will contain the port number and transport parameters if * needed. If transport protocol name starts with "TLS", "SIPS:" URI schema * is used. * * @param home      memory home * @param v         @Via header field structure *                  (with <sent-by> parameter containing host and port) * @param user      username for @Contact URI (may be NULL) * @param transport transport name for @Contact URI (may be NULL) * * @retval contact header structure * @retval NULL upon an error * * @sa sip_contact_create_from_via(), sip_contact_string_from_via() */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){  char *s = sip_contact_string_from_via(NULL, v, user, transport);  sip_contact_t *m = sip_contact_make(home, s);  su_free(NULL, s);  return m;}/** Convert a @Via header to @Contact URL string. * * The @Contact URI will contain the port number and transport parameters if * needed. If transport protocol name starts with "TLS", "SIPS:" URI schema * is used. * * The contact URI string returned will always have angle brackets ("<" and * ">") around it. * * @param home      memory home * @param v         @Via header field structure *                  (with <sent-by> parameter containing host and port) * @param user      username for @Contact URI (may be NULL) * @param transport transport name for @Contact URI (may be NULL) * * @retval string containing Contact URI with angle brackets * @retval NULL upon an error */char *sip_contact_string_from_via(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:";  int one = 1;  char _transport[16];  if (!v) return NULL;  host = v->v_host;  if (v->v_received)    host = v->v_received;  port = sip_via_port(v, &one);  maddr = v->v_maddr;  comp = v->v_comp;  if (host == NULL)    return NULL;  if (sip_transport_has_tls(v->v_protocol) ||      sip_transport_has_tls(transport)) {    scheme = "sips:";    if (port && strcmp(port, SIPS_DEFAULT_SERV) == 0)      port = NULL;    if (port || host_is_ip_address(host))      transport = NULL;  }  else if (port && strcmp(port, SIP_DEFAULT_SERV) == 0 &&	   (host_is_ip_address(host) || host_has_domain_invalid(host))) {    port = NULL;  }  if (transport && strncasecmp(transport, "SIP/2.0/", 8) == 0)    transport += 8;  /* Make transport parameter lowercase */  if (transport && strlen(transport) < (sizeof _transport)) {    char *s = strcpy(_transport, transport);    short c;    for (s = _transport; (c = *s) && c != ';'; s++)      if (isupper(c))	*s = tolower(c);    transport = _transport;  }  return su_strcat_all(home,		       "<",		       scheme,		       user ? user : "", user ? "@" : "",		       host,		       SIP_STRLOG(":", port),		       SIP_STRLOG(";transport=", transport),		       SIP_STRLOG(";maddr=", maddr),		       SIP_STRLOG(";comp=", comp),		       ">",		       NULL);}/** Check if tranport name refers to TLS */int sip_transport_has_tls(char const *transport_name){  if (!transport_name)    return 0;  if (transport_name == sip_transport_tls)    return 1;  /* transport name starts with TLS or SIP/2.0/TLS */  return    strncasecmp(transport_name, "TLS", 3) == 0 ||    strncasecmp(transport_name, sip_transport_tls, 11) == 0;}/**Perform sanity check on a SIP message *  * Check that the SIP message has all the mandatory fields.  * * @param sip SIP message to be checked * * @return  * When the SIP message fulfills the minimum requirements, return zero, * 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 a string containg header field. * * The header object is initialized with the contents of the string. The * string is modified when parsing. The home is used to allocate extra * memory required when parsing, e.g., for parameter list or when there * string contains multiple header fields. *  * @deprecated * Use msg_header_make() or header-specific make functions, e.g., * sip_via_make(). * * @retval 0 when successful * @retval -1 upon an error. */issize_t sip_header_field_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen){  if (h && s && s[slen] == '\0') {    size_t n = span_lws(s);    s += n; slen -= n;    for (n = slen; n >= 1 && IS_LWS(s[n - 1]); n--)      ;        s[n] = '\0';        assert(SIP_HDR_TEST(h));    return h->sh_class->hc_parse(home, h, s, slen);  }  else    return -1;}/** Encode a SIP header contents. * * @deprecated Use msg_header_field_e() instead. */issize_t sip_header_field_e(char *b, isize_t bsiz, sip_header_t const *h, int flags){  return msg_header_field_e(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 const *h){  ssize_t len;  char *rv, s[128];  if (h == NULL)    return NULL;  len = sip_header_field_e(s, sizeof(s), h, 0);  if (len >= 0 && (size_t)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)) {    ssize_t n = sip_header_field_e(rv, len, 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. */isize_t 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. *  * Convert 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 <code>("1" | "." 1,3DIGIT)</code> *  * @return 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;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -