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

📄 sip_parser.c

📁 一个开源SIP协议栈
💻 C
📖 第 1 页 / 共 4 页
字号:
/* $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 + -