📄 sip_parser.c
字号:
/* $Id: sip_parser.c 1083 2007-03-19 12:55: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 <pjsip/sip_parser.h>
#include <pjsip/sip_uri.h>
#include <pjsip/sip_msg.h>
#include <pjsip/sip_auth_parser.h>
#include <pjsip/sip_errno.h>
#include <pjsip/sip_transport.h> /* rdata structure */
#include <pjlib-util/scanner.h>
#include <pjlib-util/string.h>
#include <pj/except.h>
#include <pj/log.h>
#include <pj/hash.h>
#include <pj/os.h>
#include <pj/pool.h>
#include <pj/string.h>
#include <pj/ctype.h>
#include <pj/assert.h>
#define ALNUM
#define RESERVED ";/?:@&=+$,"
#define MARK "-_.!~*'()"
#define UNRESERVED ALNUM MARK
#define ESCAPED "%"
#define USER_UNRESERVED "&=+$,;?/"
#define PASS "&=+$,"
#define TOKEN "-.!%*_`'~+" /* '=' was removed for parsing
* param */
#define HOST "_-."
#define HEX_DIGIT "abcdefABCDEF"
#define PARAM_CHAR "[]/:&+$" UNRESERVED ESCAPED
#define HNV_UNRESERVED "[]/?:+$"
#define HDR_CHAR HNV_UNRESERVED UNRESERVED ESCAPED
#define PJSIP_VERSION "SIP/2.0"
#define UNREACHED(expr)
#define IS_NEWLINE(c) ((c)=='\r' || (c)=='\n')
#define IS_SPACE(c) ((c)==' ' || (c)=='\t')
/*
* Header parser records.
*/
typedef struct handler_rec
{
char hname[PJSIP_MAX_HNAME_LEN+1];
pj_size_t hname_len;
pj_uint32_t hname_hash;
pjsip_parse_hdr_func *handler;
} handler_rec;
static handler_rec handler[PJSIP_MAX_HEADER_TYPES];
static unsigned handler_count;
static int parser_is_initialized;
/*
* URI parser records.
*/
typedef struct uri_parser_rec
{
pj_str_t scheme;
pjsip_parse_uri_func *parse;
} uri_parser_rec;
static uri_parser_rec uri_handler[PJSIP_MAX_URI_TYPES];
static unsigned uri_handler_count;
/*
* Global vars (also extern).
*/
int PJSIP_SYN_ERR_EXCEPTION;
const pj_str_t pjsip_USER_STR = { "user", 4};
const pj_str_t pjsip_METHOD_STR = { "method", 6};
const pj_str_t pjsip_TRANSPORT_STR = { "transport", 9};
const pj_str_t pjsip_MADDR_STR = { "maddr", 5 };
const pj_str_t pjsip_LR_STR = { "lr", 2 };
const pj_str_t pjsip_SIP_STR = { "sip", 3 };
const pj_str_t pjsip_SIPS_STR = { "sips", 4 };
const pj_str_t pjsip_TEL_STR = { "tel", 3 };
const pj_str_t pjsip_BRANCH_STR = { "branch", 6 };
const pj_str_t pjsip_TTL_STR = { "ttl", 3 };
const pj_str_t pjsip_RECEIVED_STR = { "received", 8 };
const pj_str_t pjsip_Q_STR = { "q", 1 };
const pj_str_t pjsip_EXPIRES_STR = { "expires", 7 };
const pj_str_t pjsip_TAG_STR = { "tag", 3 };
const pj_str_t pjsip_RPORT_STR = { "rport", 5};
/* Character Input Specification buffer. */
static pj_cis_buf_t cis_buf;
/* Character Input Specifications. */
pj_cis_t pjsip_HOST_SPEC, /* For scanning host part. */
pjsip_DIGIT_SPEC, /* Decimal digits */
pjsip_ALPHA_SPEC, /* Alpha (A-Z, a-z) */
pjsip_ALNUM_SPEC, /* Decimal + Alpha. */
pjsip_TOKEN_SPEC, /* Token. */
pjsip_TOKEN_SPEC_ESC, /* Token without '%' character */
pjsip_HEX_SPEC, /* Hexadecimal digits. */
pjsip_PARAM_CHAR_SPEC, /* For scanning pname (or pvalue when
* it's not quoted.) */
pjsip_PARAM_CHAR_SPEC_ESC, /* The variant without escaped char */
pjsip_HDR_CHAR_SPEC, /* Chars in hname or hvalue */
pjsip_HDR_CHAR_SPEC_ESC, /* Variant without escaped char */
pjsip_PROBE_USER_HOST_SPEC, /* Hostname characters. */
pjsip_PASSWD_SPEC, /* Password. */
pjsip_PASSWD_SPEC_ESC, /* Variant without escaped char */
pjsip_USER_SPEC, /* User */
pjsip_USER_SPEC_ESC, /* Variant without escaped char */
pjsip_NOT_COMMA_OR_NEWLINE, /* Array separator. */
pjsip_NOT_NEWLINE, /* For eating up header.*/
pjsip_DISPLAY_SPEC; /* Used when searching for display name
* in URL. */
/*
* Forward decl.
*/
static pjsip_msg * int_parse_msg( pjsip_parse_ctx *ctx,
pjsip_parser_err_report *err_list);
static void int_parse_param( pj_scanner *scanner,
pj_pool_t *pool,
pj_str_t *pname,
pj_str_t *pvalue);
static void int_parse_uri_param( pj_scanner *scanner,
pj_pool_t *pool,
pj_str_t *pname,
pj_str_t *pvalue);
static void int_parse_hparam( pj_scanner *scanner,
pj_pool_t *pool,
pj_str_t *hname,
pj_str_t *hvalue );
static void int_parse_req_line( pj_scanner *scanner,
pj_pool_t *pool,
pjsip_request_line *req_line);
static int int_is_next_user( pj_scanner *scanner);
static void int_parse_status_line( pj_scanner *scanner,
pjsip_status_line *line);
static void int_parse_user_pass( pj_scanner *scanner,
pj_pool_t *pool,
pj_str_t *user,
pj_str_t *pass);
static void int_parse_uri_host_port( pj_scanner *scanner,
pj_str_t *p_host,
int *p_port);
static pjsip_uri * int_parse_uri_or_name_addr( pj_scanner *scanner,
pj_pool_t *pool,
unsigned option);
static void* int_parse_sip_url( pj_scanner *scanner,
pj_pool_t *pool,
pj_bool_t parse_params);
static pjsip_name_addr *
int_parse_name_addr( pj_scanner *scanner,
pj_pool_t *pool );
static void parse_hdr_end( pj_scanner *scanner );
static pjsip_hdr* parse_hdr_accept( pjsip_parse_ctx *ctx );
static pjsip_hdr* parse_hdr_allow( pjsip_parse_ctx *ctx );
static pjsip_hdr* parse_hdr_call_id( pjsip_parse_ctx *ctx);
static pjsip_hdr* parse_hdr_contact( pjsip_parse_ctx *ctx);
static pjsip_hdr* parse_hdr_content_len( pjsip_parse_ctx *ctx );
static pjsip_hdr* parse_hdr_content_type( pjsip_parse_ctx *ctx );
static pjsip_hdr* parse_hdr_cseq( pjsip_parse_ctx *ctx );
static pjsip_hdr* parse_hdr_expires( pjsip_parse_ctx *ctx );
static pjsip_hdr* parse_hdr_from( pjsip_parse_ctx *ctx );
static pjsip_hdr* parse_hdr_max_forwards( pjsip_parse_ctx *ctx);
static pjsip_hdr* parse_hdr_min_expires( pjsip_parse_ctx *ctx );
static pjsip_hdr* parse_hdr_rr( pjsip_parse_ctx *ctx );
static pjsip_hdr* parse_hdr_route( pjsip_parse_ctx *ctx );
static pjsip_hdr* parse_hdr_require( pjsip_parse_ctx *ctx );
static pjsip_hdr* parse_hdr_retry_after( pjsip_parse_ctx *ctx );
static pjsip_hdr* parse_hdr_supported( pjsip_parse_ctx *ctx );
static pjsip_hdr* parse_hdr_to( pjsip_parse_ctx *ctx );
static pjsip_hdr* parse_hdr_unsupported( pjsip_parse_ctx *ctx );
static pjsip_hdr* parse_hdr_via( pjsip_parse_ctx *ctx );
static pjsip_hdr* parse_hdr_generic_string( pjsip_parse_ctx *ctx);
/* Convert non NULL terminated string to integer. */
static unsigned long pj_strtoul_mindigit(const pj_str_t *str,
unsigned mindig)
{
unsigned long value;
unsigned i;
value = 0;
for (i=0; i<(unsigned)str->slen; ++i) {
value = value * 10 + (str->ptr[i] - '0');
}
for (; i<mindig; ++i) {
value = value * 10;
}
return value;
}
/* Case insensitive comparison */
#define parser_stricmp(s1, s2) (s1.slen!=s2.slen || pj_stricmp_alnum(&s1, &s2))
/* Get a token and unescape */
PJ_INLINE(void) parser_get_and_unescape(pj_scanner *scanner, pj_pool_t *pool,
const pj_cis_t *spec,
const pj_cis_t *unesc_spec,
pj_str_t *token)
{
#if defined(PJSIP_UNESCAPE_IN_PLACE) && PJSIP_UNESCAPE_IN_PLACE!=0
PJ_UNUSED_ARG(pool);
PJ_UNUSED_ARG(spec);
pj_scan_get_unescape(scanner, unesc_spec, token);
#else
PJ_UNUSED_ARG(unesc_spec);
pj_scan_get(scanner, spec, token);
*token = pj_str_unescape(pool, token);
#endif
}
/* Syntax error handler for parser. */
static void on_syntax_error(pj_scanner *scanner)
{
PJ_UNUSED_ARG(scanner);
PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
}
/* Concatenate unrecognized params into single string. */
void pjsip_concat_param_imp( pj_str_t *param, pj_pool_t *pool,
const pj_str_t *pname, const pj_str_t *pvalue,
int sepchar)
{
char *new_param, *p;
int len;
len = param->slen + pname->slen + pvalue->slen + 3;
p = new_param = pj_pool_alloc(pool, len);
if (param->slen) {
int old_len = param->slen;
pj_memcpy(p, param->ptr, old_len);
p += old_len;
}
*p++ = (char)sepchar;
pj_memcpy(p, pname->ptr, pname->slen);
p += pname->slen;
if (pvalue->slen) {
*p++ = '=';
pj_memcpy(p, pvalue->ptr, pvalue->slen);
p += pvalue->slen;
}
*p = '\0';
param->ptr = new_param;
param->slen = p - new_param;
}
/* Concatenate unrecognized params into single string. */
static void concat_param( pj_str_t *param, pj_pool_t *pool,
const pj_str_t *pname, const pj_str_t *pvalue )
{
pjsip_concat_param_imp(param, pool, pname, pvalue, ';');
}
/* Initialize static properties of the parser. */
static pj_status_t init_parser()
{
pj_status_t status;
/*
* Syntax error exception number.
*/
status = pj_exception_id_alloc("PJSIP syntax error",
&PJSIP_SYN_ERR_EXCEPTION);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
/*
* Init character input spec (cis)
*/
pj_cis_buf_init(&cis_buf);
status = pj_cis_init(&cis_buf, &pjsip_DIGIT_SPEC);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
pj_cis_add_num(&pjsip_DIGIT_SPEC);
status = pj_cis_init(&cis_buf, &pjsip_ALPHA_SPEC);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
pj_cis_add_alpha( &pjsip_ALPHA_SPEC );
status = pj_cis_init(&cis_buf, &pjsip_ALNUM_SPEC);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
pj_cis_add_alpha( &pjsip_ALNUM_SPEC );
pj_cis_add_num( &pjsip_ALNUM_SPEC );
status = pj_cis_init(&cis_buf, &pjsip_NOT_NEWLINE);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
pj_cis_add_str(&pjsip_NOT_NEWLINE, "\r\n");
pj_cis_invert(&pjsip_NOT_NEWLINE);
status = pj_cis_init(&cis_buf, &pjsip_NOT_COMMA_OR_NEWLINE);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
pj_cis_add_str( &pjsip_NOT_COMMA_OR_NEWLINE, ",\r\n");
pj_cis_invert(&pjsip_NOT_COMMA_OR_NEWLINE);
status = pj_cis_dup(&pjsip_TOKEN_SPEC, &pjsip_ALNUM_SPEC);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
pj_cis_add_str( &pjsip_TOKEN_SPEC, TOKEN);
status = pj_cis_dup(&pjsip_TOKEN_SPEC_ESC, &pjsip_TOKEN_SPEC);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
pj_cis_del_str(&pjsip_TOKEN_SPEC_ESC, "%");
status = pj_cis_dup(&pjsip_HOST_SPEC, &pjsip_ALNUM_SPEC);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
pj_cis_add_str( &pjsip_HOST_SPEC, HOST);
status = pj_cis_dup(&pjsip_HEX_SPEC, &pjsip_DIGIT_SPEC);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
pj_cis_add_str( &pjsip_HEX_SPEC, HEX_DIGIT);
status = pj_cis_dup(&pjsip_PARAM_CHAR_SPEC, &pjsip_ALNUM_SPEC);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
pj_cis_add_str(&pjsip_PARAM_CHAR_SPEC, PARAM_CHAR);
status = pj_cis_dup(&pjsip_PARAM_CHAR_SPEC_ESC, &pjsip_PARAM_CHAR_SPEC);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
pj_cis_del_str(&pjsip_PARAM_CHAR_SPEC_ESC, ESCAPED);
status = pj_cis_dup(&pjsip_HDR_CHAR_SPEC, &pjsip_ALNUM_SPEC);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
pj_cis_add_str(&pjsip_HDR_CHAR_SPEC, HDR_CHAR);
status = pj_cis_dup(&pjsip_HDR_CHAR_SPEC_ESC, &pjsip_HDR_CHAR_SPEC);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
pj_cis_del_str(&pjsip_HDR_CHAR_SPEC_ESC, ESCAPED);
status = pj_cis_dup(&pjsip_USER_SPEC, &pjsip_ALNUM_SPEC);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
pj_cis_add_str( &pjsip_USER_SPEC, UNRESERVED ESCAPED USER_UNRESERVED );
status = pj_cis_dup(&pjsip_USER_SPEC_ESC, &pjsip_USER_SPEC);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
pj_cis_del_str( &pjsip_USER_SPEC_ESC, ESCAPED);
status = pj_cis_dup(&pjsip_PASSWD_SPEC, &pjsip_ALNUM_SPEC);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
pj_cis_add_str( &pjsip_PASSWD_SPEC, UNRESERVED ESCAPED PASS);
status = pj_cis_dup(&pjsip_PASSWD_SPEC_ESC, &pjsip_PASSWD_SPEC);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
pj_cis_del_str( &pjsip_PASSWD_SPEC_ESC, ESCAPED);
status = pj_cis_init(&cis_buf, &pjsip_PROBE_USER_HOST_SPEC);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
pj_cis_add_str( &pjsip_PROBE_USER_HOST_SPEC, "@ \n>");
pj_cis_invert( &pjsip_PROBE_USER_HOST_SPEC );
status = pj_cis_init(&cis_buf, &pjsip_DISPLAY_SPEC);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
pj_cis_add_str( &pjsip_DISPLAY_SPEC, ":\r\n<");
pj_cis_invert(&pjsip_DISPLAY_SPEC);
/*
* Register URI parsers.
*/
status = pjsip_register_uri_parser("sip", &int_parse_sip_url);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
status = pjsip_register_uri_parser("sips", &int_parse_sip_url);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
/*
* Register header parsers.
*/
status = pjsip_register_hdr_parser( "Accept", NULL, &parse_hdr_accept);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
status = pjsip_register_hdr_parser( "Allow", NULL, &parse_hdr_allow);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
status = pjsip_register_hdr_parser( "Call-ID", "i", &parse_hdr_call_id);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
status = pjsip_register_hdr_parser( "Contact", "m", &parse_hdr_contact);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
status = pjsip_register_hdr_parser( "Content-Length", "l",
&parse_hdr_content_len);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
status = pjsip_register_hdr_parser( "Content-Type", "c",
&parse_hdr_content_type);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
status = pjsip_register_hdr_parser( "CSeq", NULL, &parse_hdr_cseq);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
status = pjsip_register_hdr_parser( "Expires", NULL, &parse_hdr_expires);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
status = pjsip_register_hdr_parser( "From", "f", &parse_hdr_from);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
status = pjsip_register_hdr_parser( "Max-Forwards", NULL,
&parse_hdr_max_forwards);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
status = pjsip_register_hdr_parser( "Min-Expires", NULL,
&parse_hdr_min_expires);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
status = pjsip_register_hdr_parser( "Record-Route", NULL, &parse_hdr_rr);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
status = pjsip_register_hdr_parser( "Route", NULL, &parse_hdr_route);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
status = pjsip_register_hdr_parser( "Require", NULL, &parse_hdr_require);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
status = pjsip_register_hdr_parser( "Retry-After", NULL,
&parse_hdr_retry_after);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
status = pjsip_register_hdr_parser( "Supported", "k",
&parse_hdr_supported);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
status = pjsip_register_hdr_parser( "To", "t", &parse_hdr_to);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
status = pjsip_register_hdr_parser( "Unsupported", NULL,
&parse_hdr_unsupported);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
status = pjsip_register_hdr_parser( "Via", "v", &parse_hdr_via);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
/*
* Register auth parser.
*/
status = pjsip_auth_init_parser();
return status;
}
void init_sip_parser(void)
{
pj_enter_critical_section();
if (++parser_is_initialized == 1) {
init_parser();
}
pj_leave_critical_section();
}
void deinit_sip_parser(void)
{
pj_enter_critical_section();
if (--parser_is_initialized == 0) {
/* Clear header handlers */
pj_bzero(handler, sizeof(handler));
handler_count = 0;
/* Clear URI handlers */
pj_bzero(uri_handler, sizeof(uri_handler));
uri_handler_count = 0;
}
pj_leave_critical_section();
}
/* Compare the handler record with header name, and return:
* - 0 if handler match.
* - <0 if handler is 'less' than the header name.
* - >0 if handler is 'greater' than header name.
*/
PJ_INLINE(int) compare_handler( const handler_rec *r1,
const char *name,
pj_size_t name_len,
pj_uint32_t hash )
{
PJ_UNUSED_ARG(name_len);
/* Compare hashed value. */
if (r1->hname_hash < hash)
return -1;
if (r1->hname_hash > hash)
return 1;
/* Compare length. */
/*
if (r1->hname_len < name_len)
return -1;
if (r1->hname_len > name_len)
return 1;
*/
/* Equal length and equal hash. compare the strings. */
return pj_memcmp(r1->hname, name, name_len);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -