sdp.c

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

C
1,286
字号
    ctx->last_error = PJMEDIA_SDP_EINSDP;    /* check equal sign */    if (*(scanner->curptr+1) != '=') {	on_scanner_error(scanner);	return;    }    /* x= */    pj_scan_advance_n(scanner, 2, SKIP_WS);    /* get anything until newline (including whitespaces). */    pj_scan_get_until_ch(scanner, '\r', str);    /* newline. */    pj_scan_get_newline(scanner);}static void parse_connection_info(pj_scanner *scanner, pjmedia_sdp_conn *conn,				  parse_context *ctx){    ctx->last_error = PJMEDIA_SDP_EINCONN;    /* c= */    pj_scan_advance_n(scanner, 2, SKIP_WS);    /* network-type */    pj_scan_get_until_ch(scanner, ' ', &conn->net_type);    pj_scan_get_char(scanner);    /* addr-type */    pj_scan_get_until_ch(scanner, ' ', &conn->addr_type);    pj_scan_get_char(scanner);    /* address. */    pj_scan_get_until_chr(scanner, " \t\r", &conn->addr);    /* We've got what we're looking for, skip anything until newline */    pj_scan_skip_line(scanner);}static void parse_media(pj_scanner *scanner, pjmedia_sdp_media *med,			parse_context *ctx){    pj_str_t str;    ctx->last_error = PJMEDIA_SDP_EINMEDIA;    /* check the equal sign */    if (*(scanner->curptr+1) != '=') {	on_scanner_error(scanner);	return;    }    /* m= */    pj_scan_advance_n(scanner, 2, SKIP_WS);    /* type */    pj_scan_get_until_ch(scanner, ' ', &med->desc.media);    pj_scan_get_char(scanner);    /* port */    pj_scan_get(scanner, &cs_token, &str);    med->desc.port = (unsigned short)pj_strtoul(&str);    if (*scanner->curptr == '/') {	/* port count */	pj_scan_get_char(scanner);	pj_scan_get(scanner, &cs_token, &str);	med->desc.port_count = pj_strtoul(&str);    } else {	med->desc.port_count = 0;    }    if (pj_scan_get_char(scanner) != ' ') {	PJ_THROW(SYNTAX_ERROR);    }    /* transport */    pj_scan_get_until_ch(scanner, ' ', &med->desc.transport);    /* format list */    med->desc.fmt_count = 0;    while (*scanner->curptr == ' ') {	pj_scan_get_char(scanner);	/* Check again for the end of the line */	if ((*scanner->curptr == '\r') || (*scanner->curptr == '\n'))		break;	pj_scan_get(scanner, &cs_token, &med->desc.fmt[med->desc.fmt_count++]);    }    /* We've got what we're looking for, skip anything until newline */    pj_scan_skip_line(scanner);}static void on_scanner_error(pj_scanner *scanner){    PJ_UNUSED_ARG(scanner);    PJ_THROW(SYNTAX_ERROR);}static pjmedia_sdp_attr *parse_attr( pj_pool_t *pool, pj_scanner *scanner,				    parse_context *ctx){    pjmedia_sdp_attr *attr;    ctx->last_error = PJMEDIA_SDP_EINATTR;    attr = pj_pool_alloc(pool, sizeof(pjmedia_sdp_attr));    /* check equal sign */    if (*(scanner->curptr+1) != '=') {	on_scanner_error(scanner);	return NULL;    }    /* skip a= */    pj_scan_advance_n(scanner, 2, SKIP_WS);        /* get attr name. */    pj_scan_get(scanner, &cs_token, &attr->name);    if (*scanner->curptr != '\r' && *scanner->curptr != '\n') {	/* skip ':' if present. */	if (*scanner->curptr == ':')	    pj_scan_get_char(scanner);	/* get value */	if (*scanner->curptr != '\r') {	    pj_scan_get_until_ch(scanner, '\r', &attr->value);	} else {	    attr->value.ptr = NULL;	    attr->value.slen = 0;	}    } else {	attr->value.ptr = NULL;	attr->value.slen = 0;    }    /* We've got what we're looking for, skip anything until newline */    pj_scan_skip_line(scanner);    return attr;}/* * Parse SDP message. */PJ_DEF(pj_status_t) pjmedia_sdp_parse( pj_pool_t *pool,				       char *buf, pj_size_t len, 				       pjmedia_sdp_session **p_sdp){    pj_scanner scanner;    pjmedia_sdp_session *session;    pjmedia_sdp_media *media = NULL;    void *attr;    pjmedia_sdp_conn *conn;    pj_str_t dummy;    int cur_name = 254;    parse_context ctx;    PJ_USE_EXCEPTION;    ctx.last_error = PJ_SUCCESS;    init_sdp_parser();    pj_scan_init(&scanner, buf, len, 0, &on_scanner_error);    session = pj_pool_calloc(pool, 1, sizeof(pjmedia_sdp_session));    PJ_ASSERT_RETURN(session != NULL, PJ_ENOMEM);    PJ_TRY {	while (!pj_scan_is_eof(&scanner)) {		cur_name = *scanner.curptr;		switch (cur_name) {		case 'a':		    attr = parse_attr(pool, &scanner, &ctx);		    if (attr) {			if (media) {			    media->attr[media->attr_count++] = attr;			} else {			    session->attr[session->attr_count++] = attr;			}		    }		    break;		case 'o':		    parse_origin(&scanner, session, &ctx);		    break;		case 's':		    parse_generic_line(&scanner, &session->name, &ctx);		    break;		case 'c':		    conn = pj_pool_calloc(pool, 1, sizeof(*conn));		    parse_connection_info(&scanner, conn, &ctx);		    if (media) {			media->conn = conn;		    } else {			session->conn = conn;		    }		    break;		case 't':		    parse_time(&scanner, session, &ctx);		    break;		case 'm':		    media = pj_pool_calloc(pool, 1, sizeof(*media));		    parse_media(&scanner, media, &ctx);		    session->media[ session->media_count++ ] = media;		    break;		case 'v':		    parse_version(&scanner, &ctx);		    break;		case 13:		    /* Allow empty newline at the end of the message */		    pj_scan_get_char(&scanner);		    /* Continue below */		case 10:		    pj_scan_get_char(&scanner);		    if (!pj_scan_is_eof(&scanner)) {			on_scanner_error(&scanner);		    }		    break;		default:		    if (cur_name >= 'a' && cur_name <= 'z')			parse_generic_line(&scanner, &dummy, &ctx);		    else  {			ctx.last_error = PJMEDIA_SDP_EINSDP;			on_scanner_error(&scanner);		    }		    break;		}	}	ctx.last_error = PJ_SUCCESS;    }    PJ_CATCH(SYNTAX_ERROR) {		char errmsg[PJ_ERR_MSG_SIZE];	pj_strerror(ctx.last_error, errmsg, sizeof(errmsg));	PJ_LOG(4, (THIS_FILE, "Error parsing SDP in line %d col %d: %s",		   scanner.line, pj_scan_get_col(&scanner),		   errmsg));	session = NULL;	pj_assert(ctx.last_error != PJ_SUCCESS);    }    PJ_END;    pj_scan_fini(&scanner);    *p_sdp = session;    return ctx.last_error;}/* * Print SDP description. */PJ_DEF(int) pjmedia_sdp_print( const pjmedia_sdp_session *desc, 			       char *buf, pj_size_t size){    return print_session(desc, buf, size);}/* * Clone session */PJ_DEF(pjmedia_sdp_session*) pjmedia_sdp_session_clone( pj_pool_t *pool,			   const pjmedia_sdp_session *rhs){    pjmedia_sdp_session *sess;    unsigned i;    PJ_ASSERT_RETURN(pool && rhs, NULL);    sess = pj_pool_zalloc(pool, sizeof(pjmedia_sdp_session));    PJ_ASSERT_RETURN(sess != NULL, NULL);    /* Clone origin line. */    pj_strdup(pool, &sess->origin.user, &rhs->origin.user);    sess->origin.id = rhs->origin.id;    sess->origin.version = rhs->origin.version;    pj_strdup(pool, &sess->origin.net_type, &rhs->origin.net_type);    pj_strdup(pool, &sess->origin.addr_type, &rhs->origin.addr_type);    pj_strdup(pool, &sess->origin.addr, &rhs->origin.addr);    /* Clone subject line. */    pj_strdup(pool, &sess->name, &rhs->name);    /* Clone connection line */    if (rhs->conn) {	sess->conn = pjmedia_sdp_conn_clone(pool, rhs->conn);	PJ_ASSERT_RETURN(sess->conn != NULL, NULL);    }    /* Clone time line. */    sess->time.start = rhs->time.start;    sess->time.stop = rhs->time.stop;    /* Duplicate session attributes. */    sess->attr_count = rhs->attr_count;    for (i=0; i<rhs->attr_count; ++i) {	sess->attr[i] = pjmedia_sdp_attr_clone(pool, rhs->attr[i]);    }    /* Duplicate media descriptors. */    sess->media_count = rhs->media_count;    for (i=0; i<rhs->media_count; ++i) {	sess->media[i] = pjmedia_sdp_media_clone(pool, rhs->media[i]);    }    return sess;}#define CHECK(exp,ret)	do {			\			    /*pj_assert(exp);*/	\			    if (!(exp))		\				return ret;	\			} while (0)/* Validate SDP connetion info. */static pj_status_t validate_sdp_conn(const pjmedia_sdp_conn *c){    CHECK( c, PJ_EINVAL);    CHECK( pj_strcmp2(&c->net_type, "IN")==0, PJMEDIA_SDP_EINCONN);    CHECK( pj_strcmp2(&c->addr_type, "IP4")==0 ||	   pj_strcmp2(&c->addr_type, "IP6")==0, 	   PJMEDIA_SDP_EINCONN);    CHECK( c->addr.slen != 0, PJMEDIA_SDP_EINCONN);    return PJ_SUCCESS;}/* Validate SDP session descriptor. */PJ_DEF(pj_status_t) pjmedia_sdp_validate(const pjmedia_sdp_session *sdp){    unsigned i;    const pj_str_t STR_RTPMAP = { "rtpmap", 6 };    CHECK( sdp != NULL, PJ_EINVAL);    /* Validate origin line. */    CHECK( sdp->origin.user.slen != 0, PJMEDIA_SDP_EINORIGIN);    CHECK( pj_strcmp2(&sdp->origin.net_type, "IN")==0, 	   PJMEDIA_SDP_EINORIGIN);    CHECK( pj_strcmp2(&sdp->origin.addr_type, "IP4")==0 ||	   pj_strcmp2(&sdp->origin.addr_type, "IP6")==0, 	   PJMEDIA_SDP_EINORIGIN);    CHECK( sdp->origin.addr.slen != 0, PJMEDIA_SDP_EINORIGIN);    /* Validate subject line. */    CHECK( sdp->name.slen != 0, PJMEDIA_SDP_EINNAME);    /* Ignore start and stop time. */    /* If session level connection info is present, validate it. */    if (sdp->conn) {	pj_status_t status = validate_sdp_conn(sdp->conn);	if (status != PJ_SUCCESS)	    return status;    }    /* Validate each media. */    for (i=0; i<sdp->media_count; ++i) {	const pjmedia_sdp_media *m = sdp->media[i];	unsigned j;	/* Validate the m= line. */	CHECK( m->desc.media.slen != 0, PJMEDIA_SDP_EINMEDIA);	CHECK( m->desc.transport.slen != 0, PJMEDIA_SDP_EINMEDIA);	CHECK( m->desc.fmt_count != 0 || m->desc.port==0, PJMEDIA_SDP_ENOFMT);	/* If media level connection info is present, validate it. */	if (m->conn) {	    pj_status_t status = validate_sdp_conn(m->conn);	    if (status != PJ_SUCCESS)		return status;	}	/* If media doesn't have connection info, then connection info	 * must be present in the session.	 */	if (m->conn == NULL) {	    if (sdp->conn == NULL)		return PJMEDIA_SDP_EMISSINGCONN;	}	/* Verify payload type. */	for (j=0; j<m->desc.fmt_count; ++j) {	    /* Arrgh noo!! Payload type can be non-numeric!!	     * RTC based programs sends "null" for instant messaging!	     */	    if (pj_isdigit(*m->desc.fmt[j].ptr)) {		unsigned pt = pj_strtoul(&m->desc.fmt[j]);		/* Payload type is between 0 and 127. 		 */		CHECK( pt <= 127, PJMEDIA_SDP_EINPT);		/* If port is not zero, then for each dynamic payload type, an		 * rtpmap attribute must be specified.		 */		if (m->desc.port != 0 && pt >= 96) {		    const pjmedia_sdp_attr *a;		    a = pjmedia_sdp_media_find_attr(m, &STR_RTPMAP, 						    &m->desc.fmt[j]);		    CHECK( a != NULL, PJMEDIA_SDP_EMISSINGRTPMAP);		}	    }	}    }    /* Looks good. */    return PJ_SUCCESS;}

⌨️ 快捷键说明

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