sdp.c

来自「基于sip协议的网络电话源码」· C语言 代码 · 共 1,286 行 · 第 1/3 页

C
1,286
字号
/* $Id: sdp.c 1195 2007-04-15 10:09:35Z bennylp $ *//*  * Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  */#include <pjmedia/sdp.h>#include <pjmedia/errno.h>#include <pjlib-util/scanner.h>#include <pj/array.h>#include <pj/except.h>#include <pj/log.h>#include <pj/os.h>#include <pj/string.h>#include <pj/pool.h>#include <pj/assert.h>#include <pj/ctype.h>enum {    SKIP_WS = 0,    SYNTAX_ERROR = 1,};#define TOKEN		"-.!%*_=`'~"//#define TOKEN		"'`-./:?\"#$&*;=@[]^_`{|}+~!"#define NTP_OFFSET	((pj_uint32_t)2208988800)#define THIS_FILE	"sdp.c"typedef struct parse_context{     pj_status_t last_error;} parse_context;/* * Prototypes for line parser. */static void parse_version(pj_scanner *scanner, parse_context *ctx);static void parse_origin(pj_scanner *scanner, pjmedia_sdp_session *ses,			 parse_context *ctx);static void parse_time(pj_scanner *scanner, pjmedia_sdp_session *ses,		       parse_context *ctx);static void parse_generic_line(pj_scanner *scanner, pj_str_t *str,			       parse_context *ctx);static void parse_connection_info(pj_scanner *scanner, pjmedia_sdp_conn *conn,				  parse_context *ctx);static pjmedia_sdp_attr *parse_attr(pj_pool_t *pool, pj_scanner *scanner,				    parse_context *ctx);static void parse_media(pj_scanner *scanner, pjmedia_sdp_media *med,			parse_context *ctx);static void on_scanner_error(pj_scanner *scanner);/* * Scanner character specification. */static int is_initialized;static pj_cis_buf_t cis_buf;static pj_cis_t cs_digit, cs_token;static void init_sdp_parser(void){    if (is_initialized != 0)	return;    pj_enter_critical_section();    if (is_initialized != 0) {	pj_leave_critical_section();	return;    }        pj_cis_buf_init(&cis_buf);    pj_cis_init(&cis_buf, &cs_token);    pj_cis_add_alpha(&cs_token);    pj_cis_add_num(&cs_token);    pj_cis_add_str(&cs_token, TOKEN);    pj_cis_init(&cis_buf, &cs_digit);    pj_cis_add_num(&cs_digit);    is_initialized = 1;    pj_leave_critical_section();}PJ_DEF(pjmedia_sdp_attr*) pjmedia_sdp_attr_create( pj_pool_t *pool,						   const char *name,						   const pj_str_t *value){    pjmedia_sdp_attr *attr;    PJ_ASSERT_RETURN(pool && name, NULL);    attr = pj_pool_alloc(pool, sizeof(pjmedia_sdp_attr));    pj_strdup2(pool, &attr->name, name);    if (value)	pj_strdup_with_null(pool, &attr->value, value);    else {	attr->value.ptr = NULL;	attr->value.slen = 0;    }    return attr;}PJ_DEF(pjmedia_sdp_attr*) pjmedia_sdp_attr_clone(pj_pool_t *pool, 						 const pjmedia_sdp_attr *rhs){    pjmedia_sdp_attr *attr;        PJ_ASSERT_RETURN(pool && rhs, NULL);    attr = pj_pool_alloc(pool, sizeof(pjmedia_sdp_attr));    pj_strdup(pool, &attr->name, &rhs->name);    pj_strdup_with_null(pool, &attr->value, &rhs->value);    return attr;}PJ_DEF(pjmedia_sdp_attr*) pjmedia_sdp_attr_find (unsigned count, 		       pjmedia_sdp_attr *const attr_array[],		       const pj_str_t *name,		       const pj_str_t *c_fmt){    unsigned i;    unsigned c_pt = 0xFFFF;    if (c_fmt)	c_pt = pj_strtoul(c_fmt);    for (i=0; i<count; ++i) {	if (pj_strcmp(&attr_array[i]->name, name) == 0) {	    const pjmedia_sdp_attr *a = attr_array[i];	    if (c_fmt) {		unsigned pt = (unsigned) pj_strtoul2(&a->value, NULL, 10);		if (pt == c_pt) {		    return (pjmedia_sdp_attr*)a;		}	    } else 		return (pjmedia_sdp_attr*)a;	}    }    return NULL;}PJ_DEF(pjmedia_sdp_attr*) pjmedia_sdp_attr_find2(unsigned count, 		       pjmedia_sdp_attr *const attr_array[],		       const char *c_name,		       const pj_str_t *c_fmt){    pj_str_t name;    name.ptr = (char*)c_name;    name.slen = pj_ansi_strlen(c_name);    return pjmedia_sdp_attr_find(count, attr_array, &name, c_fmt);}PJ_DEF(pj_status_t) pjmedia_sdp_attr_add(unsigned *count,					 pjmedia_sdp_attr *attr_array[],					 pjmedia_sdp_attr *attr){    PJ_ASSERT_RETURN(count && attr_array && attr, PJ_EINVAL);    PJ_ASSERT_RETURN(*count < PJMEDIA_MAX_SDP_ATTR, PJ_ETOOMANY);    attr_array[*count] = attr;    (*count)++;    return PJ_SUCCESS;}PJ_DEF(unsigned) pjmedia_sdp_attr_remove_all(unsigned *count,					     pjmedia_sdp_attr *attr_array[],					     const char *name){    unsigned i, removed = 0;    pj_str_t attr_name;    PJ_ASSERT_RETURN(count && attr_array && name, PJ_EINVAL);    attr_name.ptr = (char*)name;    attr_name.slen = pj_ansi_strlen(name);    for (i=0; i<*count; ) {	if (pj_strcmp(&attr_array[i]->name, &attr_name)==0) {	    pj_array_erase(attr_array, sizeof(pjmedia_sdp_attr*),			   *count, i);	    --(*count);	    ++removed;	} else {	    ++i;	}       }    return removed;}PJ_DEF(pj_status_t) pjmedia_sdp_attr_remove( unsigned *count,					     pjmedia_sdp_attr *attr_array[],					     pjmedia_sdp_attr *attr ){    unsigned i, removed=0;    PJ_ASSERT_RETURN(count && attr_array && attr, PJ_EINVAL);    for (i=0; i<*count; ) {	if (attr_array[i] == attr) {	    pj_array_erase(attr_array, sizeof(pjmedia_sdp_attr*),			   *count, i);	    --(*count);	    ++removed;	} else {	    ++i;	}    }    return removed ? PJ_SUCCESS : PJ_ENOTFOUND;}PJ_DEF(pj_status_t) pjmedia_sdp_attr_get_rtpmap( const pjmedia_sdp_attr *attr,						 pjmedia_sdp_rtpmap *rtpmap){    pj_scanner scanner;    pj_str_t token;    pj_status_t status = -1;    char term = 0;    PJ_USE_EXCEPTION;    PJ_ASSERT_RETURN(pj_strcmp2(&attr->name, "rtpmap")==0, PJ_EINVALIDOP);    PJ_ASSERT_RETURN(attr->value.slen != 0, PJMEDIA_SDP_EINATTR);    /* Check if input is null terminated, and null terminate if     * necessary. Unfortunately this may crash the application if     * attribute was allocated from a read-only memory location.     * But this shouldn't happen as attribute's value normally is     * null terminated.     */    if (attr->value.ptr[attr->value.slen] != 0 &&	attr->value.ptr[attr->value.slen] != '\r')    {	pj_assert(!"Shouldn't happen");	term = attr->value.ptr[attr->value.slen];	attr->value.ptr[attr->value.slen] = '\0';    }    pj_scan_init(&scanner, (char*)attr->value.ptr, attr->value.slen,		 PJ_SCAN_AUTOSKIP_WS, &on_scanner_error);    /* rtpmap sample:     *	a=rtpmap:98 L16/16000/2.     */    /* Init */    rtpmap->pt.slen = rtpmap->param.slen = rtpmap->enc_name.slen = 0;    rtpmap->clock_rate = 0;    /* Parse */    PJ_TRY {	/* Get payload type. */	pj_scan_get(&scanner, &cs_token, &rtpmap->pt);	/* Get encoding name. */	pj_scan_get(&scanner, &cs_token, &rtpmap->enc_name);	/* Expecting '/' after encoding name. */	if (pj_scan_get_char(&scanner) != '/') {	    status = PJMEDIA_SDP_EINRTPMAP;	    goto on_return;	}	/* Get the clock rate. */	pj_scan_get(&scanner, &cs_digit, &token);	rtpmap->clock_rate = pj_strtoul(&token);	/* Expecting either '/' or EOF */	if (*scanner.curptr == '/') {	    pj_scan_get_char(&scanner);	    rtpmap->param.ptr = scanner.curptr;	    rtpmap->param.slen = scanner.end - scanner.curptr;	} else {	    rtpmap->param.slen = 0;	}	status = PJ_SUCCESS;    }    PJ_CATCH(SYNTAX_ERROR) {	status = PJMEDIA_SDP_EINRTPMAP;    }    PJ_END;on_return:    pj_scan_fini(&scanner);    if (term) {	attr->value.ptr[attr->value.slen] = term;    }    return status;}PJ_DEF(pj_status_t) pjmedia_sdp_attr_get_fmtp( const pjmedia_sdp_attr *attr,					       pjmedia_sdp_fmtp *fmtp){    const char *p = attr->value.ptr;    const char *end = attr->value.ptr + attr->value.slen;    pj_str_t token;    PJ_ASSERT_RETURN(pj_strcmp2(&attr->name, "fmtp")==0, PJ_EINVALIDOP);    /* fmtp BNF:     *	a=fmtp:<format> <format specific parameter>     */    /* Get format. */    token.ptr = (char*)p;    while (pj_isdigit(*p) && p!=end)	++p;    token.slen = p - token.ptr;    if (token.slen == 0)	return PJMEDIA_SDP_EINFMTP;    fmtp->fmt = token;    /* Expecting space after format. */    if (*p != ' ') return PJMEDIA_SDP_EINFMTP;    /* Get space. */    ++p;    /* Set the remaining string as fmtp format parameter. */    fmtp->fmt_param.ptr = (char*)p;    fmtp->fmt_param.slen = end - p;    return PJ_SUCCESS;}PJ_DEF(pj_status_t) pjmedia_sdp_attr_get_rtcp(const pjmedia_sdp_attr *attr,					      pjmedia_sdp_rtcp_attr *rtcp){    pj_scanner scanner;    pj_str_t token;    pj_status_t status = -1;    PJ_USE_EXCEPTION;    PJ_ASSERT_RETURN(pj_strcmp2(&attr->name, "rtcp")==0, PJ_EINVALIDOP);    /* fmtp BNF:     *	a=rtcp:<port> [nettype addrtype address]     */    pj_scan_init(&scanner, (char*)attr->value.ptr, attr->value.slen,		 PJ_SCAN_AUTOSKIP_WS, &on_scanner_error);    /* Init */    rtcp->net_type.slen = rtcp->addr_type.slen = rtcp->addr.slen = 0;    /* Parse */    PJ_TRY {	/* Get the port */	pj_scan_get(&scanner, &cs_token, &token);	rtcp->port = pj_strtoul(&token);	/* Have address? */	if (!pj_scan_is_eof(&scanner)) {	    /* Get network type */	    pj_scan_get(&scanner, &cs_token, &rtcp->net_type);	    /* Get address type */	    pj_scan_get(&scanner, &cs_token, &rtcp->addr_type);	    /* Get the address */	    pj_scan_get(&scanner, &cs_token, &rtcp->addr);	}	status = PJ_SUCCESS;    }    PJ_CATCH(SYNTAX_ERROR) {	status = PJMEDIA_SDP_EINRTCP;    }    PJ_END;    pj_scan_fini(&scanner);    return status;}PJ_DEF(pj_status_t) pjmedia_sdp_attr_to_rtpmap(pj_pool_t *pool,					       const pjmedia_sdp_attr *attr,					       pjmedia_sdp_rtpmap **p_rtpmap){    PJ_ASSERT_RETURN(pool && attr && p_rtpmap, PJ_EINVAL);    *p_rtpmap = pj_pool_alloc(pool, sizeof(pjmedia_sdp_rtpmap));    PJ_ASSERT_RETURN(*p_rtpmap, PJ_ENOMEM);    return pjmedia_sdp_attr_get_rtpmap(attr, *p_rtpmap);}PJ_DEF(pj_status_t) pjmedia_sdp_rtpmap_to_attr(pj_pool_t *pool,

⌨️ 快捷键说明

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