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

📄 sdp_parse.c

📁 Sofia SIP is an open-source SIP User-Agent library, compliant with the IETF RFC3261 specification.
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * 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 * *//**@ingroup sdp_parser * @CFILE sdp_parse.c  * @brief Simple SDP parser interface. * * @author Pekka Pessi <Pekka.Pessi@nokia.com> * @author Kai Vehmanen <kai.vehmanen@nokia.com> * * @date  Created: Fri Feb 18 10:25:08 2000 ppessi */#include "config.h"#include <sofia-sip/su_alloc.h>#include "sofia-sip/sdp.h"#include <stddef.h>#include <stdlib.h>#include <string.h>#include <stdarg.h>#include <stdio.h>#include <limits.h>#include <assert.h>/** @typedef struct sdp_parser_s sdp_parser_t;  * * SDP parser handle. * * The SDP parser handle is returned by sdp_parse(). It contains either * successfully parse SDP session #sdp_session_t or an error message. * If sdp_session() returns non-NULL, parsing was successful. * * @sa #sdp_session_t, sdp_parse(), sdp_session(), sdp_parsing_error(), * sdp_sanity_check(), sdp_parser_home(), sdp_parser_free(). */struct sdp_parser_s {  su_home_t       pr_home[1];  union {    char          pru_error[128];    sdp_session_t pru_session[1];  } pr_output;  char      *pr_message;  sdp_mode_t pr_session_mode;  unsigned   pr_ok : 1;  unsigned   pr_strict : 1;  unsigned   pr_anynet : 1;  unsigned   pr_mode_0000 : 1;  unsigned   pr_mode_manual : 1;  unsigned   pr_insane : 1;  unsigned   pr_c_missing : 1;  unsigned   pr_config : 1;};#define is_posdigit(c) ((c) >= '1' && (c) <= '9')#define is_digit(c) ((c) >= '0' && (c) <= '9')#define is_space(c) ((c) == ' ')#define is_tab(c) ((c) == '\t')#define pr_error   pr_output.pru_error#define pr_session pr_output.pru_session#define STRICT(pr) (pr->pr_strict)/* Static parser object used when running out of memory */static const struct sdp_parser_s no_mem_error ={  { SU_HOME_INIT(no_mem_error) },  { "sdp: not enough memory" }};/* Internal prototypes */static void parse_message(sdp_parser_t *p);static int parsing_error(sdp_parser_t *p, char const *fmt, ...);/** Parse an SDP message. * * The function sdp_parse() parses an SDP message @a msg of size @a * msgsize. Parsing is done according to the given @a flags. The SDP message * may not contain a NUL. *  * The parsing result is stored to an #sdp_session_t structure. * * @param home    memory home * @param msg     pointer to message * @param msgsize size of the message (excluding final NUL, if any) * @param flags   flags affecting the parsing. * * The following flags are used by parser: * * @li #sdp_f_strict Parser should accept only messages conforming strictly  *                   to the specification. * @li #sdp_f_anynet Parser accepts unknown network or address types. * @li #sdp_f_insane Do not run sanity check. * @li #sdp_f_c_missing  Sanity check does not require c= for each m= line * @li #sdp_f_mode_0000 Parser regards "c=IN IP4 0.0.0.0" as "a=inactive" *                      (likewise with c=IN IP6 ::) * @li #sdp_f_mode_manual Do not generate or parse SDP mode * @li #sdp_f_config   Parse config files (any line can be missing) * * @return * Always a valid parser handle. * * @todo Parser accepts some non-conforming SDP even with #sdp_f_strict. */sdp_parser_t *sdp_parse(su_home_t *home, char const msg[], issize_t msgsize, int flags){  sdp_parser_t *p;  char *b;  size_t len;  if (msgsize == -1 || msg == NULL) {    p = su_home_clone(home, sizeof(*p));    if (p)       parsing_error(p, "invalid input message");    else      p = (sdp_parser_t*)&no_mem_error;    return p;  }  if (msgsize == -1 && msg)    len = strlen(msg);  else    len = msgsize;  if (len > ISSIZE_MAX)    len = ISSIZE_MAX;  p = su_home_clone(home, sizeof(*p) + len + 1);  if (p) {    b = strncpy((void *)(p + 1), msg, len);    b[len] = 0;    p->pr_message = b;    p->pr_strict = (flags & sdp_f_strict) != 0;    p->pr_anynet = (flags & sdp_f_anynet) != 0;    p->pr_mode_0000 = (flags & sdp_f_mode_0000) != 0;    p->pr_insane = (flags & sdp_f_insane) != 0;    p->pr_c_missing = (flags & sdp_f_c_missing) != 0;    if (flags & sdp_f_config)      p->pr_c_missing = 1, p->pr_config = 1;    p->pr_mode_manual = (flags & sdp_f_mode_manual) != 0;    p->pr_session_mode = sdp_sendrecv;    parse_message(p);        return p;  }  if (p)    sdp_parser_free(p);  return (sdp_parser_t*)&no_mem_error;}/** Obtain memory home used by parser */su_home_t *sdp_parser_home(sdp_parser_t *parser){  if (parser != &no_mem_error)    return parser->pr_home;  else    return NULL;}/** Retrieve an SDP session structure. * * The function sdp_session() returns a pointer to the SDP session * structure associated with the SDP parser @a p. The pointer and all the * data in the structure are valid until sdp_parser_free() is called. * * @param p SDP parser * * @return *   The function sdp_session() returns a pointer to an parsed SDP message *   or NULL, if an error has occurred.  */sdp_session_t *sdp_session(sdp_parser_t *p){  return p && p->pr_ok ? p->pr_session : NULL;}/** Get a parsing error message. * * The function sdp_parsing_error() returns the error message associated * with an SDP parser @a p. * * @param p SDP parser * * @return  * The function sdp_parsing_error() returns a C string describing parsing * error, or NULL if no error occurred. */char const *sdp_parsing_error(sdp_parser_t *p){  return !p->pr_ok ? p->pr_error : NULL;}/** Free an SDP parser. * * The function sdp_parser_free() frees an SDP parser object along with * the memory blocks associated with it. * * @param p pointer to the SDP parser to be freed  */void sdp_parser_free(sdp_parser_t *p){  if (p && p != &no_mem_error)    su_home_unref(p->pr_home);}/* ========================================================================= *//* ========================================================================= * Private part *//* Parsing tokens */#define SPACE " "#define TAB   "\011"#define CRLF  "\015\012"#define ALPHA "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"#define DIGIT "0123456789"/* ========================================================================= *//* Parsing functions */static void post_session(sdp_parser_t *p, sdp_session_t *sdp);static void parse_origin(sdp_parser_t *p, char *r, sdp_origin_t **result);static void parse_subject(sdp_parser_t *p, char *r, sdp_text_t **result);static void parse_information(sdp_parser_t *p, char *r, sdp_text_t **result);static void parse_uri(sdp_parser_t *p, char *r, sdp_text_t **result);static void parse_email(sdp_parser_t *p, char *r, sdp_list_t **result);static void parse_phone(sdp_parser_t *p, char *r, sdp_list_t **result);static void parse_connection(sdp_parser_t *p, char *r, sdp_connection_t **result);static void parse_bandwidth(sdp_parser_t *p, char *r, sdp_bandwidth_t **result);static void parse_time(sdp_parser_t *p, char *r, sdp_time_t **result);static void parse_repeat(sdp_parser_t *p, char *r, sdp_repeat_t **result);static void parse_zone(sdp_parser_t *p, char *r, sdp_zone_t **result);static void parse_key(sdp_parser_t *p, char *r, sdp_key_t **result);static void parse_session_attr(sdp_parser_t *p, char *r, sdp_attribute_t **result);static void parse_media(sdp_parser_t *p, char *r, sdp_media_t **result);static void parse_payload(sdp_parser_t *p, char *r, sdp_rtpmap_t **result);static void parse_media_attr(sdp_parser_t *p, char *r, sdp_media_t *m, 			     sdp_attribute_t **result);static int parse_rtpmap(sdp_parser_t *p, char *r, sdp_media_t *m);static int parse_fmtp(sdp_parser_t *p, char *r, sdp_media_t *m);static void parse_text_list(sdp_parser_t *p, char *r, sdp_list_t **result);static void parse_descs(sdp_parser_t *p, char *r, char *m, sdp_media_t **result);static int parse_ul(sdp_parser_t *p, char **r, unsigned long *result, 		    unsigned long max_value);static int parse_ull(sdp_parser_t *p, char **r, uint64_t *result, 		     uint64_t max_value);static void parse_alloc_error(sdp_parser_t *p, const char *typename);static char *next(char **message, const char *sep, const char *strip);static char *token(char **message, const char *sep, const char *legal, 		   const char *strip);#if 0static void check_mandatory(sdp_parser_t *p, sdp_session_t *sdp);#endif/* ------------------------------------------------------------------------- * Macro PARSE_ALLOC * * Description: *   This macro declares a pointer (v) of given type (t). It then allocates *   an structure of given type (t). If allocation was succesful, it assigns *   the XX_size member with appropriate value. */#define PARSE_ALLOC(p, t, v) \ t *v = su_salloc(p->pr_home, sizeof(*v)); \ if (!v && (parse_alloc_error(p, #t), 1)) return; /* ------------------------------------------------------------------------- * Macro PARSE_CHECK_REST * * Description: *   This macro check if there is extra data at the end of field. */#define PARSE_CHECK_REST(p, s, n)\ if (*s && (parsing_error(p, "extra data after %s (\"%.04s\")", n, s), 1)) \    return/* ------------------------------------------------------------------------- * Function parse_message() - parse an SDP message  * * Description: *   This function parses an SDP message, which is copied into the  *   p->pr_message. The p->pr_message is modified during the parsing, *   and parts of it are returned in p->pr_session. * * Parameters: *   p - pointer to SDP parser object */static void parse_message(sdp_parser_t *p){/*   announcement =        proto-version                         origin-field                         session-name-field                         information-field                         uri-field                         email-fields                         phone-fields                         connection-field                         bandwidth-fields                         time-fields                         key-field                         attribute-fields                         media-descriptions*/  sdp_session_t *sdp = p->pr_session;  char *record, *rest;  char const *strip;  char *message = p->pr_message;  char field = '\0';  sdp_list_t **emails = &sdp->sdp_emails;  sdp_list_t **phones = &sdp->sdp_phones;  sdp_bandwidth_t **bandwidths = &sdp->sdp_bandwidths;  sdp_time_t **times = &sdp->sdp_time;  sdp_repeat_t **repeats = NULL;  sdp_zone_t **zones = NULL;  sdp_attribute_t **attributes = &sdp->sdp_attributes;  if (!STRICT(p))    strip = SPACE TAB;		/* skip initial whitespace */  else    strip = "";  p->pr_ok = 1;  p->pr_session->sdp_size = sizeof(p->pr_session);  /* Require that version comes first */  record = next(&message, CRLF, strip);  if (!record || strcmp(record, "v=0")) {    if (!p->pr_config || !record || record[1] != '=') {      parsing_error(p, "bad SDP message");      return;    }  }  else {    record = next(&message, CRLF, strip);  }  /*    XXX - the lines in SDP are in certain order, which we don't check here.     For stricter parsing we might want to parse o= and s= next.  */  for (;       record && p->pr_ok;       record = next(&message, CRLF, strip)) {    field = record[0];     rest = record + 2; rest += strspn(rest, strip);    if (record[1] != '=') {      parsing_error(p, "bad line \"%s\"", record);      return;    }    switch (field) {    case 'o':      parse_origin(p, rest, &sdp->sdp_origin);      break;    case 's':      parse_subject(p, rest, &sdp->sdp_subject);      break;    case 'i':      parse_information(p, rest, &sdp->sdp_information);      break;    case 'u':      parse_uri(p, rest, &sdp->sdp_uri);      break;    case 'e':      parse_email(p, rest, emails);      emails = &(*emails)->l_next;      break;    case 'p':      parse_phone(p, rest, phones);      phones = &(*phones)->l_next;      break;    case 'c':      parse_connection(p, rest, &sdp->sdp_connection);      break;    case 'b':      parse_bandwidth(p, rest, bandwidths);      bandwidths = &(*bandwidths)->b_next;      break;    case 't':      parse_time(p, rest, times);      repeats = &(*times)->t_repeat;      zones = &(*times)->t_zone;      times = &(*times)->t_next;      break;    case 'r':      if (repeats)	parse_repeat(p, rest, repeats);      else	parsing_error(p, "repeat field without time field");      break;    case 'z':      if (zones)	parse_zone(p, rest, zones), zones = NULL;      else	parsing_error(p, "zone field without time field");      break;    case 'k':      parse_key(p, rest, &sdp->sdp_key);      break;    case 'a':      parse_session_attr(p, rest, attributes);      if (*attributes)	attributes = &(*attributes)->a_next;      break;    case 'm':      parse_descs(p, record, message, &sdp->sdp_media);      post_session(p, sdp);      return;    default:      parsing_error(p, "unknown field \"%s\"", record);      return;    }  }

⌨️ 快捷键说明

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