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); init_sdp_parser(); /* 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_ANY { status = PJMEDIA_SDP_EINRTCP; } PJ_END; pj_scan_fini(&scanner); return status; }
/* * 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; }
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); init_sdp_parser(); /* 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' && attr->value.ptr[attr->value.slen] != '\n') { 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_ANY { status = PJMEDIA_SDP_EINRTPMAP; } PJ_END; on_return: pj_scan_fini(&scanner); if (term) { attr->value.ptr[attr->value.slen] = term; } return status; }
/* * 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; pjmedia_sdp_attr *attr; pjmedia_sdp_conn *conn; pjmedia_sdp_bandw *bandw; 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_ZALLOC_T(pool, pjmedia_sdp_session); PJ_ASSERT_RETURN(session != NULL, PJ_ENOMEM); /* Ignore leading newlines */ while (*scanner.curptr=='\r' || *scanner.curptr=='\n') pj_scan_get_char(&scanner); 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) { if (media->attr_count < PJMEDIA_MAX_SDP_ATTR) pjmedia_sdp_media_add_attr(media, attr); else PJ_PERROR(2, (THIS_FILE, PJ_ETOOMANY, "Error adding media attribute, " "attribute is ignored")); } else { if (session->attr_count < PJMEDIA_MAX_SDP_ATTR) pjmedia_sdp_session_add_attr(session, attr); else PJ_PERROR(2, (THIS_FILE, PJ_ETOOMANY, "Error adding session attribute" ", attribute is ignored")); } } break; case 'o': parse_origin(&scanner, session, &ctx); break; case 's': parse_generic_line(&scanner, &session->name, &ctx); break; case 'c': conn = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_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_ZALLOC_T(pool, pjmedia_sdp_media); parse_media(&scanner, media, &ctx); if (session->media_count < PJMEDIA_MAX_SDP_MEDIA) session->media[ session->media_count++ ] = media; else PJ_PERROR(2,(THIS_FILE, PJ_ETOOMANY, "Error adding media, media is ignored")); break; case 'v': parse_version(&scanner, &ctx); break; case 13: case 10: pj_scan_get_char(&scanner); /* Allow empty newlines at the end of the message */ while (!pj_scan_is_eof(&scanner)) { if (*scanner.curptr != 13 && *scanner.curptr != 10) { ctx.last_error = PJMEDIA_SDP_EINSDP; on_scanner_error(&scanner); } pj_scan_get_char(&scanner); } break; case 'b': bandw = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_bandw); parse_bandwidth_info(&scanner, bandw, &ctx); if (media) { if (media->bandw_count < PJMEDIA_MAX_SDP_BANDW) media->bandw[media->bandw_count++] = bandw; else PJ_PERROR(2, (THIS_FILE, PJ_ETOOMANY, "Error adding media bandwidth " "info, info is ignored")); } else { if (session->bandw_count < PJMEDIA_MAX_SDP_BANDW) session->bandw[session->bandw_count++] = bandw; else PJ_PERROR(2, (THIS_FILE, PJ_ETOOMANY, "Error adding session bandwidth " "info, info is ignored")); } 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_ANY { 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); if (session) apply_media_direction(session); *p_sdp = session; return ctx.last_error; }