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

📄 sip_parser.c

📁 一个开源SIP协议栈
💻 C
📖 第 1 页 / 共 4 页
字号:
	    pj_list_insert_before(err_list, err_info);
	}
	
	if (parsing_headers) {
	    if (!pj_scan_is_eof(scanner)) {
		/* Skip until next line.
		 * Watch for header continuation.
		 */
		do {
		    pj_scan_skip_line(scanner);
		} while (IS_SPACE(*scanner->curptr));
	    }

	    /* Restore flag. Flag may be set in int_parse_sip_url() */
	    scanner->skip_ws = PJ_SCAN_AUTOSKIP_WS_HEADER;

	    /* Continue parse next header, if any. */
	    if (!pj_scan_is_eof(scanner) && !IS_NEWLINE(*scanner->curptr)) {
		goto parse_headers;
	    }
	}

	msg = NULL;
    }
    PJ_END;

    return msg;
}


/* Parse parameter (pname ["=" pvalue]). */
static void parse_param_imp( pj_scanner *scanner, pj_pool_t *pool,
			     pj_str_t *pname, pj_str_t *pvalue,
			     const pj_cis_t *spec, const pj_cis_t *esc_spec,
			     unsigned option)
{
    /* pname */
    parser_get_and_unescape(scanner, pool, spec, esc_spec, pname);

    /* init pvalue */
    pvalue->ptr = NULL;
    pvalue->slen = 0;

    /* pvalue, if any */
    if (*scanner->curptr == '=') {
	pj_scan_get_char(scanner);
	if (!pj_scan_is_eof(scanner)) {
	    /* pvalue can be a quoted string. */
	    if (*scanner->curptr == '"') {
		pj_scan_get_quote( scanner, '"', '"', pvalue);
		if (option & PJSIP_PARSE_REMOVE_QUOTE) {
		    pvalue->ptr++;
		    pvalue->slen -= 2;
		}
	    } else if(pj_cis_match(spec, *scanner->curptr)) {
		parser_get_and_unescape(scanner, pool, spec, esc_spec, pvalue);
	    }
	}
    }
}

/* Parse parameter (pname ["=" pvalue]) using token. */
void pjsip_parse_param_imp(  pj_scanner *scanner, pj_pool_t *pool,
			     pj_str_t *pname, pj_str_t *pvalue,
			     unsigned option)
{
    parse_param_imp(scanner, pool, pname, pvalue, &pjsip_TOKEN_SPEC,
		    &pjsip_TOKEN_SPEC_ESC, option);
}


/* Parse parameter (pname ["=" pvalue]) using paramchar. */
void pjsip_parse_uri_param_imp(pj_scanner *scanner, pj_pool_t *pool,
			       pj_str_t *pname, pj_str_t *pvalue,
			       unsigned option)
{
    parse_param_imp(scanner, pool, pname, pvalue, &pjsip_PARAM_CHAR_SPEC,
		    &pjsip_PARAM_CHAR_SPEC_ESC, option);
}


/* Parse parameter (";" pname ["=" pvalue]) in header. */
static void int_parse_param( pj_scanner *scanner, pj_pool_t *pool,
			     pj_str_t *pname, pj_str_t *pvalue)
{
    /* Get ';' character */
    pj_scan_get_char(scanner);

    /* Get pname and optionally pvalue */
    pjsip_parse_param_imp(scanner, pool, pname, pvalue, 
			  PJSIP_PARSE_REMOVE_QUOTE);
}

/* Parse parameter (";" pname ["=" pvalue]) in URI. */
static void int_parse_uri_param( pj_scanner *scanner, pj_pool_t *pool,
				 pj_str_t *pname, pj_str_t *pvalue)
{
    /* Get ';' character */
    pj_scan_get_char(scanner);

    /* Get pname and optionally pvalue */
    pjsip_parse_uri_param_imp(scanner, pool, pname, pvalue, 
			      PJSIP_PARSE_REMOVE_QUOTE);
}


/* Parse header parameter. */
static void int_parse_hparam( pj_scanner *scanner, pj_pool_t *pool,
			      pj_str_t *hname, pj_str_t *hvalue )
{
    /* Get '?' or '&' character. */
    pj_scan_get_char(scanner);

    /* hname */
    parser_get_and_unescape(scanner, pool, &pjsip_HDR_CHAR_SPEC, 
			    &pjsip_HDR_CHAR_SPEC_ESC, hname);

    /* Init hvalue */
    hvalue->ptr = NULL;
    hvalue->slen = 0;

    /* pvalue, if any */
    if (*scanner->curptr == '=') {
	pj_scan_get_char(scanner);
	if (!pj_scan_is_eof(scanner) && 
	    pj_cis_match(&pjsip_HDR_CHAR_SPEC, *scanner->curptr))
	{
	    parser_get_and_unescape(scanner, pool, &pjsip_HDR_CHAR_SPEC,
				    &pjsip_HDR_CHAR_SPEC_ESC, hvalue);
	}
    }
}

/* Parse host:port in URI. */
static void int_parse_uri_host_port( pj_scanner *scanner, 
				     pj_str_t *host, int *p_port)
{
    pj_scan_get( scanner, &pjsip_HOST_SPEC, host);
    /* RFC3261 section 19.1.2: host don't need to be unescaped */
    if (*scanner->curptr == ':') {
	pj_str_t port;
	pj_scan_get_char(scanner);
	pj_scan_get(scanner, &pjsip_DIGIT_SPEC, &port);
	*p_port = pj_strtoul(&port);
    } else {
	*p_port = 0;
    }
}

/* Determine if the next token in an URI is a user specification. */
static int int_is_next_user(pj_scanner *scanner)
{
    pj_str_t dummy;
    int is_user;

    /* Find character '@'. If this character exist, then the token
     * must be a username.
     */
    if (pj_scan_peek( scanner, &pjsip_PROBE_USER_HOST_SPEC, &dummy) == '@')
	is_user = 1;
    else
	is_user = 0;

    return is_user;
}

/* Parse user:pass tokens in an URI. */
static void int_parse_user_pass( pj_scanner *scanner, pj_pool_t *pool,
				 pj_str_t *user, pj_str_t *pass)
{
    parser_get_and_unescape(scanner, pool, &pjsip_USER_SPEC, 
			    &pjsip_USER_SPEC_ESC, user);

    if ( *scanner->curptr == ':') {
	pj_scan_get_char( scanner );
	parser_get_and_unescape(scanner, pool, &pjsip_PASSWD_SPEC,
				&pjsip_PASSWD_SPEC_ESC, pass);
    } else {
	pass->ptr = NULL;
	pass->slen = 0;
    }

    /* Get the '@' */
    pj_scan_get_char( scanner );
}

/* Parse all types of URI. */
static pjsip_uri *int_parse_uri_or_name_addr( pj_scanner *scanner, pj_pool_t *pool,
					      unsigned opt)
{
    pjsip_uri *uri;
    int is_name_addr = 0;

    /* Exhaust any whitespaces. */
    pj_scan_skip_whitespace(scanner);

    if (*scanner->curptr=='"' || *scanner->curptr=='<') {
	uri = (pjsip_uri*)int_parse_name_addr( scanner, pool );
	is_name_addr = 1;
    } else {
	pj_str_t scheme;
	int next_ch;

	next_ch = pj_scan_peek( scanner, &pjsip_DISPLAY_SPEC, &scheme);

	if (next_ch==':') {
	    pjsip_parse_uri_func *func = find_uri_handler(&scheme);

	    if (func == NULL) {
		/* Unsupported URI scheme */
		PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
	    }

	    uri = (*func)( scanner, pool, 
			  (opt & PJSIP_PARSE_URI_IN_FROM_TO_HDR)== 0);


	} else {
	    uri = (pjsip_uri*)int_parse_name_addr( scanner, pool );
	    is_name_addr = 1;
	}
    }

    /* Should we return the URI object as name address? */
    if (opt & PJSIP_PARSE_URI_AS_NAMEADDR) {
	if (is_name_addr == 0) {
	    pjsip_name_addr *name_addr;

	    name_addr = pjsip_name_addr_create(pool);
	    name_addr->uri = uri;

	    uri = (pjsip_uri*)name_addr;
	}
    }

    return uri;
}

/* Parse URI. */
static pjsip_uri *int_parse_uri(pj_scanner *scanner, pj_pool_t *pool, 
				pj_bool_t parse_params)
{
    /* Bug:
     * This function should not call back int_parse_name_addr() because
     * it is called by that function. This would cause stack overflow
     * with PROTOS test #1223.
    if (*scanner->curptr=='"' || *scanner->curptr=='<') {
	return (pjsip_uri*)int_parse_name_addr( scanner, pool );
    } else {
    */
	pj_str_t scheme;
	int colon;
	pjsip_parse_uri_func *func;

	/* Get scheme. */
	colon = pj_scan_peek(scanner, &pjsip_TOKEN_SPEC, &scheme);
	if (colon != ':') {
	    PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
	}

	func = find_uri_handler(&scheme);
	if (func)  {
	    return (pjsip_uri*)(*func)(scanner, pool, parse_params);

	} else {
	    /* Unsupported URI scheme */
	    PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
	    UNREACHED({ return NULL; /* Not reached. */ })
	}

    /*
    }
    */
}

/* Parse "sip:" and "sips:" URI. 
 * This actually returns (pjsip_sip_uri*) type,
 */
static void* int_parse_sip_url( pj_scanner *scanner, 
				pj_pool_t *pool,
				pj_bool_t parse_params)
{
    pj_str_t scheme;
    pjsip_sip_uri *url = NULL;
    int colon;
    int skip_ws = scanner->skip_ws;
    scanner->skip_ws = 0;

    pj_scan_get(scanner, &pjsip_TOKEN_SPEC, &scheme);
    colon = pj_scan_get_char(scanner);
    if (colon != ':') {
	PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
    }

    if (parser_stricmp(scheme, pjsip_SIP_STR)==0) {
	url = pjsip_sip_uri_create(pool, 0);

    } else if (parser_stricmp(scheme, pjsip_SIPS_STR)==0) {
	url = pjsip_sip_uri_create(pool, 1);

    } else {
	PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
	/* should not reach here */
	UNREACHED({
	    pj_assert(0);
	    return 0;
	})
    }

    if (int_is_next_user(scanner)) {
	int_parse_user_pass(scanner, pool, &url->user, &url->passwd);
    }

    /* Get host:port */
    int_parse_uri_host_port(scanner, &url->host, &url->port);

    /* Get URL parameters. */
    if (parse_params) {
      while (*scanner->curptr == ';' ) {
	pj_str_t pname, pvalue;

	int_parse_uri_param( scanner, pool, &pname, &pvalue);

	if (!parser_stricmp(pname, pjsip_USER_STR) && pvalue.slen) {
	    url->user_param = pvalue;

	} else if (!parser_stricmp(pname, pjsip_METHOD_STR) && pvalue.slen) {
	    url->method_param = pvalue;

	} else if (!parser_stricmp(pname,pjsip_TRANSPORT_STR) && pvalue.slen) {
	    url->transport_param = pvalue;

	} else if (!parser_stricmp(pname, pjsip_TTL_STR) && pvalue.slen) {
	    url->ttl_param = pj_strtoul(&pvalue);

	} else if (!parser_stricmp(pname, pjsip_MADDR_STR) && pvalue.slen) {
	    url->maddr_param = pvalue;

	} else if (!parser_stricmp(pname, pjsip_LR_STR)) {
	    url->lr_param = 1;

	} else {
	    pjsip_param *p = pj_pool_alloc(pool, sizeof(pjsip_param));
	    p->name = pname;
	    p->value = pvalue;
	    pj_list_insert_before(&url->other_param, p);
	}
      }
    }

    /* Get header params. */
    if (parse_params && *scanner->curptr == '?') {
      do {
	pjsip_param *param;
	param = pj_pool_alloc(pool, sizeof(pjsip_param));
	int_parse_hparam(scanner, pool, &param->name, &param->value);
	pj_list_insert_before(&url->header_param, param);
      } while (*scanner->curptr == '&');
    }

    scanner->skip_ws = skip_ws;
    pj_scan_skip_whitespace(scanner);
    return url;
}

/* Parse nameaddr. */
static pjsip_name_addr *int_parse_name_addr( pj_scanner *scanner, 
					     pj_pool_t *pool )
{
    int has_bracket;
    pjsip_name_addr *name_addr;

    name_addr = pjsip_name_addr_create(pool);

    if (*scanner->curptr == '"') {
	pj_scan_get_quote( scanner, '"', '"', &name_addr->display);
	/* Trim the leading and ending quote */
	name_addr->display.ptr++;
	name_addr->display.slen -= 2;

    } else if (*scanner->curptr != '<') {
	int next;
	pj_str_t dummy;

	/* This can be either the start of display name,
	 * the start of URL ("sip:", "sips:", "tel:", etc.), or '<' char.
	 * We're only interested in display name, because SIP URL
	 * will be parser later.
	 */
	next = pj_scan_peek(scanner, &pjsip_DISPLAY_SPEC, &dummy);
	if (next == '<') {
	    /* Ok, this is what we're looking for, a display name. */
	    pj_scan_get_until_ch( scanner, '<', &name_addr->display);
	    pj_strtrim(&name_addr->display);
	}
    }

    /* Manually skip whitespace. */
    pj_scan_skip_whitespace(scanner);

    /* Get the SIP-URL */
    has_bracket = (*scanner->curptr == '<');
    if (has_bracket)
	pj_scan_get_char(scanner);
    name_addr->uri = int_parse_uri( scanner, pool, PJ_TRUE );
    if (has_bracket) {
	if (pj_scan_get_char(scanner) != '>')
	    PJ_THROW( PJSIP_SYN_ERR_EXCEPTION);
    }

    return name_addr;
}


/* Parse SIP request line. */
static void int_parse_req_line( pj_scanner *scanner, pj_pool_t *pool,
				pjsip_request_line *req_line)
{
    pj_str_t token;

    pj_scan_get( scanner, &pjsip_TOKEN_SPEC, &token);
    pjsip_method_init_np( &req_line->method, &token);

    req_line->uri = int_parse_uri(scanner, pool, PJ_TRUE);
    if (pj_scan_stricmp_alnum( scanner, PJSIP_VERSION, 7) != 0)
	PJ_THROW( PJSIP_SYN_ERR_EXCEPTION);
    pj_scan_advance_n (scanner, 7, 1);
    pj_scan_get_newline( scanner );
}

/* Parse status line. */
static void int_parse_status_line( pj_scanner *scanner, 
				   pjsip_status_line *status_line)
{
    pj_str_t token;

    if (pj_scan_stricmp_alnum(scanner, PJSIP_VERSION, 7) != 0)
	PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
    pj_scan_advance_n( scanner, 7, 1);

    pj_scan_get( scanner, &pjsip_DIGIT_SPEC, &token);
    status_line->code = pj_strtoul(&token);
    pj_scan_get( scanner, &pjsip_NOT_NEWLINE, &status_line->reason);
    pj_scan_get_newline( scanner );
}


/*
 * Public API to parse SIP status line.
 */
PJ_DEF(pj_status_t) pjsip_parse_status_line( char *buf, pj_size_t size,
					     pjsip_status_line *status_line)
{
    pj_scanner scanner;
    PJ_USE_EXCEPTION;

    pj_bzero(status_line, sizeof(*status_line));
    pj_scan_init(&scanner, buf, size, 0, &on_syntax_error);

    PJ_TRY {
	int_parse_status_line(&scanner, status_line);
    } 
    PJ_CATCH_ANY {
	/* Tolerate the error if it is caused only by missing newline */
	if (status_line->code == 0 && status_line->reason.slen == 0) {
	    pj_scan_fini(&scanner);
	    return PJSIP_EINVALIDMSG;
	}
    }
    PJ_END;

    pj_scan_fini(&scanner);
    return PJ_SUCCESS;
}


/* Parse ending of header. */
static void parse_hdr_end( pj_scanner *scanner )
{
    if (pj_scan_is_eof(scanner)) {
	;   /* Do nothing. */
    } else if (*scanner->curptr == '&') {
	pj_scan_get_char(scanner);
    } else {
	pj_scan_get_newline(scanner);
    }
}

/* Parse ending of header. */
void pjsip_parse_end_hdr_imp( pj_scanner *scanner )
{
    parse_hdr_end(scanner);
}

/* Parse generic array header. */
static void parse_generic_array_hdr( pjsip_generic_array_hdr *hdr,
				     pj_scanner *scanner)
{
    /* Some header fields allow empty elements in the value:
     *   Accept, Allow, Supported
     */
    if (*scanner->curptr == '\r' || *scanner->curptr == '\n') {
	goto end;
    }

    pj_scan_get( scanner, &pjsip_NOT_COMMA_OR_NEWLINE, &hdr->values[0]);
    hdr->count++;

    while (*scanner->curptr == ',') {
	pj_scan_get_char(scanner);
	pj_scan_get( scanner, &pjsip_NOT_COMMA_OR_NEWLINE, 
		     &hdr->values[hdr->count]);
	hdr->count++;
    }

end:
    parse_hdr_end(scanner);
}

⌨️ 快捷键说明

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