📄 sip_parser.c
字号:
/* $Id: sip_parser.c 1229 2007-04-29 18:13:20Z 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, unsigned option);static void int_parse_uri_param( pj_scanner *scanner, pj_pool_t *pool, pj_str_t *pname, pj_str_t *pvalue, unsigned option);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 + -