pjsip_hdr* parse_hdr_p_charging_function_addresses(pjsip_parse_ctx* ctx) { // The P-Charging-Function-Addresses header has the following ABNF: // // P-Charging-Addr = "P-Charging-Function-Addresses" HCOLON // charge-addr-params // *(SEMI charge-addr-params) // charge-addr-params = ccf / ecf / generic-param // ccf = "ccf" EQUAL gen-value // ecf = "ecf" EQUAL gen-value // // Where the ccf and ecf elements may be repeated to specify backup CDFs // for redundancy. pj_pool_t* pool = ctx->pool; pj_scanner* scanner = ctx->scanner; pjsip_p_c_f_a_hdr* hdr = pjsip_p_c_f_a_hdr_create(pool); pj_str_t name; pj_str_t value; pjsip_param *param; for (;;) { pjsip_parse_param_imp(scanner, pool, &name, &value, PJSIP_PARSE_REMOVE_QUOTE); param = PJ_POOL_ALLOC_T(pool, pjsip_param); param->name = name; param->value = value; if (!pj_stricmp2(&name, "ccf")) { pj_list_insert_before(&hdr->ccf, param); } else if (!pj_stricmp2(&name, "ecf")) { pj_list_insert_before(&hdr->ecf, param); } else { pj_list_insert_before(&hdr->other_param, param); } // We might need to swallow the ';'. if (!pj_scan_is_eof(scanner) && *scanner->curptr == ';') { pj_scan_get_char(scanner); } // If we're EOF or looking at a newline, we're done. pj_scan_skip_whitespace(scanner); if (pj_scan_is_eof(scanner) || (*scanner->curptr == '\r') || (*scanner->curptr == '\n')) { break; } } // We're done parsing this header. pjsip_parse_end_hdr_imp(scanner); return (pjsip_hdr*)hdr; }
pjsip_hdr* parse_hdr_reject_contact(pjsip_parse_ctx* ctx) { // The Reject-Contact header has the following ABNF: // // Reject-Contact = ("Reject-Contact" / "j") HCOLON rc-value // *(COMMA rc-value) // rc-value = "*" *(SEMI rc-params) // rc-params = feature-param / generic-param // // But we allow any value for the header (not just *). pj_pool_t* pool = ctx->pool; pj_scanner* scanner = ctx->scanner; const pjsip_parser_const_t* pc = pjsip_parser_const(); pjsip_reject_contact_hdr* hdr = pjsip_reject_contact_hdr_create(pool); pj_str_t name; pj_str_t value; pjsip_param *param; // Read and ignore the value. pj_str_t header_value; pj_scan_get(scanner, &pc->pjsip_TOKEN_SPEC, &header_value); for (;;) { // We might need to swallow the ';'. if (!pj_scan_is_eof(scanner) && *scanner->curptr == ';') { pj_scan_get_char(scanner); } pjsip_parse_param_imp(scanner, pool, &name, &value, 0); param = PJ_POOL_ALLOC_T(pool, pjsip_param); param->name = name; param->value = value; pj_list_insert_before(&hdr->feature_set, param); // If we're EOF or looking at a newline, we're done. pj_scan_skip_whitespace(scanner); if (pj_scan_is_eof(scanner) || (*scanner->curptr == '\r') || (*scanner->curptr == '\n')) { break; } } // We're done parsing this header. pjsip_parse_end_hdr_imp(scanner); return (pjsip_hdr*)hdr; }
static void parse_digest_credential( pj_scanner *scanner, pj_pool_t *pool, pjsip_digest_credential *cred) { pj_list_init(&cred->other_param); for (;;) { pj_str_t name, value; pjsip_parse_param_imp(scanner, pool, &name, &value, PJSIP_PARSE_REMOVE_QUOTE); if (!pj_stricmp(&name, &pjsip_USERNAME_STR)) { cred->username = value; } else if (!pj_stricmp(&name, &pjsip_REALM_STR)) { cred->realm = value; } else if (!pj_stricmp(&name, &pjsip_NONCE_STR)) { cred->nonce = value; } else if (!pj_stricmp(&name, &pjsip_URI_STR)) { cred->uri = value; } else if (!pj_stricmp(&name, &pjsip_RESPONSE_STR)) { cred->response = value; } else if (!pj_stricmp(&name, &pjsip_ALGORITHM_STR)) { cred->algorithm = value; } else if (!pj_stricmp(&name, &pjsip_CNONCE_STR)) { cred->cnonce = value; } else if (!pj_stricmp(&name, &pjsip_OPAQUE_STR)) { cred->opaque = value; } else if (!pj_stricmp(&name, &pjsip_QOP_STR)) { cred->qop = value; } else if (!pj_stricmp(&name, &pjsip_NC_STR)) { cred->nc = value; } else { pjsip_param *p = PJ_POOL_ALLOC_T(pool, pjsip_param); p->name = name; p->value = value; pj_list_insert_before(&cred->other_param, p); } /* Eat comma */ if (!pj_scan_is_eof(scanner) && *scanner->curptr == ',') pj_scan_get_char(scanner); else break; } }
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; }
static void parse_digest_challenge( pj_scanner *scanner, pj_pool_t *pool, pjsip_digest_challenge *chal) { pj_list_init(&chal->other_param); for (;;) { pj_str_t name, value; pjsip_parse_param_imp(scanner, pool, &name, &value, PJSIP_PARSE_REMOVE_QUOTE); if (!pj_stricmp(&name, &pjsip_REALM_STR)) { chal->realm = value; } else if (!pj_stricmp(&name, &pjsip_DOMAIN_STR)) { chal->domain = value; } else if (!pj_stricmp(&name, &pjsip_NONCE_STR)) { chal->nonce = value; } else if (!pj_stricmp(&name, &pjsip_OPAQUE_STR)) { chal->opaque = value; } else if (!pj_stricmp(&name, &pjsip_STALE_STR)) { if (!pj_stricmp(&value, &pjsip_TRUE_STR) || !pj_stricmp(&value, &pjsip_QUOTED_TRUE_STR)) { chal->stale = 1; } } else if (!pj_stricmp(&name, &pjsip_ALGORITHM_STR)) { chal->algorithm = value; } else if (!pj_stricmp(&name, &pjsip_QOP_STR)) { chal->qop = value; } else { pjsip_param *p = PJ_POOL_ALLOC_T(pool, pjsip_param); p->name = name; p->value = value; pj_list_insert_before(&chal->other_param, p); } /* Eat comma */ if (!pj_scan_is_eof(scanner) && *scanner->curptr == ',') pj_scan_get_char(scanner); else break; } }
pjsip_hdr* parse_hdr_p_charging_vector(pjsip_parse_ctx* ctx) { // The P-Charging-Vector header has the following ABNF: // // P-Charging-Vector = "P-Charging-Vector" HCOLON icid-value // *(SEMI charge-params) // charge-params = icid-gen-addr / orig-ioi / // term-ioi / generic-param // icid-value = "icid-value" EQUAL gen-value // icid-gen-addr = "icid-generated-at" EQUAL host // orig-ioi = "orig-ioi" EQUAL gen-value // term-ioi = "term-ioi" EQUAL gen-value pj_pool_t* pool = ctx->pool; pj_scanner* scanner = ctx->scanner; pjsip_p_c_v_hdr* hdr = pjsip_p_c_v_hdr_create(pool); pj_str_t name; pj_str_t value; // Parse the required icid-value parameter first. pjsip_parse_param_imp(scanner, pool, &name, &value, PJSIP_PARSE_REMOVE_QUOTE); if (!pj_stricmp2(&name, "icid-value")) { hdr->icid = value; } else { PJ_THROW(PJSIP_SYN_ERR_EXCEPTION); // LCOV_EXCL_LINE } for (;;) { pj_scan_skip_whitespace(scanner); // If we just parsed the last parameter we will have reached the end of the // header and have nothing more to do. if (pj_scan_is_eof(scanner) || (*scanner->curptr == '\r') || (*scanner->curptr == '\n')) { break; } // There's more content in the header so the next character must be the ";" // separator. if (*scanner->curptr == ';') { pj_scan_get_char(scanner); } else { PJ_THROW(PJSIP_SYN_ERR_EXCEPTION); // LCOV_EXCL_LINE } pjsip_parse_param_imp(scanner, pool, &name, &value, PJSIP_PARSE_REMOVE_QUOTE); if (!pj_stricmp2(&name, "orig-ioi")) { hdr->orig_ioi = value; } else if (!pj_stricmp2(&name, "term-ioi")) { hdr->term_ioi = value; } else if (!pj_stricmp2(&name, "icid-generated-at")) { hdr->icid_gen_addr = value; } else { pjsip_param *param = PJ_POOL_ALLOC_T(pool, pjsip_param); param->name = name; param->value = value; pj_list_insert_before(&hdr->other_param, param); } } // We're done parsing this header. pjsip_parse_end_hdr_imp(scanner); return (pjsip_hdr*)hdr; }
/* This is a recursive function! */ static pj_xml_node *xml_parse_node( pj_pool_t *pool, pj_scanner *scanner) { pj_xml_node *node; pj_str_t end_name; PJ_CHECK_STACK(); if (*scanner->curptr != '<') on_syntax_error(scanner); /* Handle Processing Instructino (PI) construct (i.e. "<?") */ if (*scanner->curptr == '<' && *(scanner->curptr+1) == '?') { pj_scan_advance_n(scanner, 2, PJ_FALSE); for (;;) { pj_str_t dummy; pj_scan_get_until_ch(scanner, '?', &dummy); if (*scanner->curptr=='?' && *(scanner->curptr+1)=='>') { pj_scan_advance_n(scanner, 2, PJ_TRUE); break; } else { pj_scan_advance_n(scanner, 1, PJ_FALSE); } } return xml_parse_node(pool, scanner); } /* Handle comments construct (i.e. "<!") */ if (pj_scan_strcmp(scanner, "<!", 2) == 0) { pj_scan_advance_n(scanner, 2, PJ_FALSE); for (;;) { pj_str_t dummy; pj_scan_get_until_ch(scanner, '>', &dummy); if (pj_scan_strcmp(scanner, ">", 1) == 0) { pj_scan_advance_n(scanner, 1, PJ_TRUE); break; } else { pj_scan_advance_n(scanner, 1, PJ_FALSE); } } return xml_parse_node(pool, scanner); } /* Alloc node. */ node = alloc_node(pool); /* Get '<' */ pj_scan_get_char(scanner); /* Get node name. */ pj_scan_get_until_chr( scanner, " />\t", &node->name); /* Get attributes. */ while (*scanner->curptr != '>' && *scanner->curptr != '/') { pj_xml_attr *attr = alloc_attr(pool); pj_scan_get_until_chr( scanner, "=> \t", &attr->name); if (*scanner->curptr == '=') { pj_scan_get_char( scanner ); pj_scan_get_quotes(scanner, "\"'", "\"'", 2, &attr->value); /* remove quote characters */ ++attr->value.ptr; attr->value.slen -= 2; } pj_list_push_back( &node->attr_head, attr ); } if (*scanner->curptr == '/') { pj_scan_get_char(scanner); if (pj_scan_get_char(scanner) != '>') on_syntax_error(scanner); return node; } /* Enclosing bracket. */ if (pj_scan_get_char(scanner) != '>') on_syntax_error(scanner); /* Sub nodes. */ while (*scanner->curptr == '<' && *(scanner->curptr+1) != '/') { pj_xml_node *sub_node = xml_parse_node(pool, scanner); pj_list_push_back( &node->node_head, sub_node ); } /* Content. */ if (!pj_scan_is_eof(scanner) && *scanner->curptr != '<') { pj_scan_get_until_ch(scanner, '<', &node->content); } /* Enclosing node. */ if (pj_scan_get_char(scanner) != '<' || pj_scan_get_char(scanner) != '/') on_syntax_error(scanner); pj_scan_get_until_chr(scanner, " \t>", &end_name); /* Compare name. */ if (pj_stricmp(&node->name, &end_name) != 0) on_syntax_error(scanner); /* Enclosing '>' */ if (pj_scan_get_char(scanner) != '>') on_syntax_error(scanner); return node; }
/* * 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; }
/** * This method is to parse and add the command attribute to command structure. **/ static pj_status_t add_cmd_node(pj_cli_t *cli, pj_cli_cmd_spec *group, pj_xml_node *xml_node, pj_cli_cmd_handler handler, pj_cli_cmd_spec **p_cmd, pj_cli_get_dyn_choice get_choice) { pj_xml_node *root = xml_node; pj_xml_attr *attr; pj_xml_node *sub_node; pj_cli_cmd_spec *cmd; pj_cli_arg_spec args[PJ_CLI_MAX_ARGS]; pj_str_t sc[PJ_CLI_MAX_SHORTCUTS]; pj_status_t status = PJ_SUCCESS; if (pj_stricmp2(&root->name, "CMD")) return PJ_EINVAL; /* Initialize the command spec */ cmd = PJ_POOL_ZALLOC_T(cli->pool, struct pj_cli_cmd_spec); /* Get the command attributes */ attr = root->attr_head.next; while (attr != &root->attr_head) { if (!pj_stricmp2(&attr->name, "name")) { pj_strltrim(&attr->value); if (!attr->value.slen || cmd_name_exists(cli, group, &attr->value)) { return PJ_CLI_EBADNAME; } pj_strdup(cli->pool, &cmd->name, &attr->value); } else if (!pj_stricmp2(&attr->name, "id")) { pj_bool_t is_valid = PJ_FALSE; if (attr->value.slen) { pj_cli_cmd_id cmd_id = pj_strtol(&attr->value); if (!pj_hash_get(cli->cmd_id_hash, &cmd_id, sizeof(pj_cli_cmd_id), NULL)) is_valid = PJ_TRUE; } if (!is_valid) return PJ_CLI_EBADID; cmd->id = (pj_cli_cmd_id)pj_strtol(&attr->value); } else if (!pj_stricmp2(&attr->name, "sc")) { pj_scanner scanner; pj_str_t str; PJ_USE_EXCEPTION; pj_scan_init(&scanner, attr->value.ptr, attr->value.slen, PJ_SCAN_AUTOSKIP_WS, &on_syntax_error); PJ_TRY { while (!pj_scan_is_eof(&scanner)) { pj_scan_get_until_ch(&scanner, ',', &str); pj_strrtrim(&str); if (!pj_scan_is_eof(&scanner)) pj_scan_advance_n(&scanner, 1, PJ_TRUE); if (!str.slen) continue; if (cmd->sc_cnt >= PJ_CLI_MAX_SHORTCUTS) { PJ_THROW(PJ_CLI_ETOOMANYARGS); } /* Check whether the shortcuts are already used */ if (cmd_name_exists(cli, group, &str)) { PJ_THROW(PJ_CLI_EBADNAME); } pj_strassign(&sc[cmd->sc_cnt++], &str); } } PJ_CATCH_ANY { pj_scan_fini(&scanner); return (PJ_GET_EXCEPTION()); } PJ_END; } else if (!pj_stricmp2(&attr->name, "desc")) {
/* * 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; }
int eof() const { return pj_scan_is_eof(&scanner_); }