📄 sip_parser.c
字号:
}
/* Register one handler for one header name. */
static pj_status_t int_register_parser( const char *name,
pjsip_parse_hdr_func *fptr )
{
unsigned pos;
handler_rec rec;
if (handler_count >= PJ_ARRAY_SIZE(handler)) {
pj_assert(!"Too many handlers!");
return PJ_ETOOMANY;
}
/* Initialize temporary handler. */
rec.handler = fptr;
rec.hname_len = strlen(name);
if (rec.hname_len >= sizeof(rec.hname)) {
pj_assert(!"Header name is too long!");
return PJ_ENAMETOOLONG;
}
/* Copy name. */
pj_memcpy(rec.hname, name, rec.hname_len);
rec.hname[rec.hname_len] = '\0';
/* Calculate hash value. */
rec.hname_hash = pj_hash_calc(0, rec.hname, rec.hname_len);
/* Get the pos to insert the new handler. */
for (pos=0; pos < handler_count; ++pos) {
int d;
d = compare_handler(&handler[pos], rec.hname, rec.hname_len,
rec.hname_hash);
if (d == 0) {
pj_assert(0);
return PJ_EEXISTS;
}
if (d > 0) {
break;
}
}
/* Shift handlers. */
if (pos != handler_count) {
pj_memmove( &handler[pos+1], &handler[pos],
(handler_count-pos)*sizeof(handler_rec));
}
/* Add new handler. */
pj_memcpy( &handler[pos], &rec, sizeof(handler_rec));
++handler_count;
return PJ_SUCCESS;
}
/* Register parser handler. If both header name and short name are valid,
* then two instances of handler will be registered.
*/
PJ_DEF(pj_status_t) pjsip_register_hdr_parser( const char *hname,
const char *hshortname,
pjsip_parse_hdr_func *fptr)
{
unsigned i, len;
char hname_lcase[PJSIP_MAX_HNAME_LEN+1];
pj_status_t status;
/* Check that name is not too long */
len = pj_ansi_strlen(hname);
if (len > PJSIP_MAX_HNAME_LEN) {
pj_assert(!"Header name is too long!");
return PJ_ENAMETOOLONG;
}
/* Register the normal Mixed-Case name */
status = int_register_parser(hname, fptr);
if (status != PJ_SUCCESS) {
return status;
}
/* Get the lower-case name */
for (i=0; i<len; ++i) {
hname_lcase[i] = (char)pj_tolower(hname[i]);
}
hname_lcase[len] = '\0';
/* Register the lower-case version of the name */
status = int_register_parser(hname_lcase, fptr);
if (status != PJ_SUCCESS) {
return status;
}
/* Register the shortname version of the name */
if (hshortname) {
status = int_register_parser(hshortname, fptr);
if (status != PJ_SUCCESS)
return status;
}
return PJ_SUCCESS;
}
/* Find handler to parse the header name. */
static pjsip_parse_hdr_func * find_handler_imp(pj_uint32_t hash,
const pj_str_t *hname)
{
handler_rec *first;
int comp;
unsigned n;
/* Binary search for the handler. */
comp = -1;
first = &handler[0];
n = handler_count;
for (; n > 0; ) {
unsigned half = n / 2;
handler_rec *mid = first + half;
comp = compare_handler(mid, hname->ptr, hname->slen, hash);
if (comp < 0) {
first = ++mid;
n -= half + 1;
} else if (comp==0) {
first = mid;
break;
} else {
n = half;
}
}
return comp==0 ? first->handler : NULL;
}
/* Find handler to parse the header name. */
static pjsip_parse_hdr_func* find_handler(const pj_str_t *hname)
{
pj_uint32_t hash;
char hname_copy[PJSIP_MAX_HNAME_LEN];
pj_str_t tmp;
pjsip_parse_hdr_func *handler;
if (hname->slen >= PJSIP_MAX_HNAME_LEN) {
/* Guaranteed not to be able to find handler. */
return NULL;
}
/* First, common case, try to find handler with exact name */
hash = pj_hash_calc(0, hname->ptr, hname->slen);
handler = find_handler_imp(hash, hname);
if (handler)
return handler;
/* If not found, try converting the header name to lowercase and
* search again.
*/
hash = pj_hash_calc_tolower(0, hname_copy, hname);
tmp.ptr = hname_copy;
tmp.slen = hname->slen;
return find_handler_imp(hash, &tmp);
}
/* Find URI handler. */
static pjsip_parse_uri_func* find_uri_handler(const pj_str_t *scheme)
{
unsigned i;
for (i=0; i<uri_handler_count; ++i) {
if (parser_stricmp(uri_handler[i].scheme, (*scheme))==0)
return uri_handler[i].parse;
}
return NULL;
}
/* Register URI parser. */
PJ_DEF(pj_status_t) pjsip_register_uri_parser( char *scheme,
pjsip_parse_uri_func *func)
{
if (uri_handler_count >= PJ_ARRAY_SIZE(uri_handler))
return PJ_ETOOMANY;
uri_handler[uri_handler_count].scheme = pj_str((char*)scheme);
uri_handler[uri_handler_count].parse = func;
++uri_handler_count;
return PJ_SUCCESS;
}
/* Public function to parse SIP message. */
PJ_DEF(pjsip_msg*) pjsip_parse_msg( pj_pool_t *pool,
char *buf, pj_size_t size,
pjsip_parser_err_report *err_list)
{
pjsip_msg *msg = NULL;
pj_scanner scanner;
pjsip_parse_ctx context;
pj_scan_init(&scanner, buf, size, PJ_SCAN_AUTOSKIP_WS_HEADER,
&on_syntax_error);
context.scanner = &scanner;
context.pool = pool;
context.rdata = NULL;
msg = int_parse_msg(&context, err_list);
pj_scan_fini(&scanner);
return msg;
}
/* Public function to parse as rdata.*/
PJ_DEF(pjsip_msg *) pjsip_parse_rdata( char *buf, pj_size_t size,
pjsip_rx_data *rdata )
{
pj_scanner scanner;
pjsip_parse_ctx context;
pj_scan_init(&scanner, buf, size, PJ_SCAN_AUTOSKIP_WS_HEADER,
&on_syntax_error);
context.scanner = &scanner;
context.pool = rdata->tp_info.pool;
context.rdata = rdata;
rdata->msg_info.msg = int_parse_msg(&context, &rdata->msg_info.parse_err);
pj_scan_fini(&scanner);
return rdata->msg_info.msg;
}
/* Determine if a message has been received. */
PJ_DEF(pj_bool_t) pjsip_find_msg( const char *buf, pj_size_t size,
pj_bool_t is_datagram, pj_size_t *msg_size)
{
#if PJ_HAS_TCP
const char *hdr_end;
const char *body_start;
const char *pos;
const char *line;
int content_length = -1;
*msg_size = size;
/* For datagram, the whole datagram IS the message. */
if (is_datagram) {
return PJ_SUCCESS;
}
/* Find the end of header area by finding an empty line. */
pos = pj_ansi_strstr(buf, "\n\r\n");
if (pos == NULL) {
return PJSIP_EPARTIALMSG;
}
hdr_end = pos+1;
body_start = pos+3;
/* Find "Content-Length" header the hard way. */
line = pj_ansi_strchr(buf, '\n');
while (line && line < hdr_end) {
++line;
if ( ((*line=='C' || *line=='c') &&
strnicmp_alnum(line, "Content-Length", 14) == 0) ||
((*line=='l' || *line=='L') &&
(*(line+1)==' ' || *(line+1)=='\t' || *(line+1)==':')))
{
/* Try to parse the header. */
pj_scanner scanner;
PJ_USE_EXCEPTION;
pj_scan_init(&scanner, (char*)line, hdr_end-line,
PJ_SCAN_AUTOSKIP_WS_HEADER, &on_syntax_error);
PJ_TRY {
pj_str_t str_clen;
/* Get "Content-Length" or "L" name */
if (*line=='C' || *line=='c')
pj_scan_advance_n(&scanner, 14, PJ_TRUE);
else if (*line=='l' || *line=='L')
pj_scan_advance_n(&scanner, 1, PJ_TRUE);
/* Get colon */
if (pj_scan_get_char(&scanner) != ':') {
PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
}
/* Get number */
pj_scan_get(&scanner, &pjsip_DIGIT_SPEC, &str_clen);
/* Get newline. */
pj_scan_get_newline(&scanner);
/* Found a valid Content-Length header. */
content_length = pj_strtoul(&str_clen);
}
PJ_CATCH_ANY {
content_length = -1;
}
PJ_END
pj_scan_fini(&scanner);
}
/* Found valid Content-Length? */
if (content_length != -1)
break;
/* Go to next line. */
line = pj_ansi_strchr(line, '\n');
}
/* Found Content-Length? */
if (content_length == -1) {
return PJSIP_EMISSINGHDR;
}
/* Enough packet received? */
*msg_size = (body_start - buf) + content_length;
return (*msg_size) <= size ? PJ_SUCCESS : PJSIP_EPARTIALMSG;
#else
PJ_UNUSED_ARG(buf);
PJ_UNUSED_ARG(is_datagram);
*msg_size = size;
return PJ_SUCCESS;
#endif
}
/* Public function to parse URI */
PJ_DEF(pjsip_uri*) pjsip_parse_uri( pj_pool_t *pool,
char *buf, pj_size_t size,
unsigned option)
{
pj_scanner scanner;
pjsip_uri *uri = NULL;
PJ_USE_EXCEPTION;
pj_scan_init(&scanner, buf, size, 0, &on_syntax_error);
PJ_TRY {
uri = int_parse_uri_or_name_addr(&scanner, pool, option);
}
PJ_CATCH_ANY {
uri = NULL;
}
PJ_END;
/* Must have exhausted all inputs. */
if (pj_scan_is_eof(&scanner) || IS_NEWLINE(*scanner.curptr)) {
/* Success. */
pj_scan_fini(&scanner);
return uri;
}
/* Still have some characters unparsed. */
pj_scan_fini(&scanner);
return NULL;
}
/* Generic function to print message body.
* This assumes that the 'data' member points to a contigous memory where the
* actual body is laid.
*/
static int generic_print_body (pjsip_msg_body *msg_body,
char *buf, pj_size_t size)
{
pjsip_msg_body *body = msg_body;
if (size < body->len)
return 0;
pj_memcpy (buf, body->data, body->len);
return body->len;
}
/* Internal function to parse SIP message */
static pjsip_msg *int_parse_msg( pjsip_parse_ctx *ctx,
pjsip_parser_err_report *err_list)
{
pj_bool_t parsing_headers;
pjsip_msg *msg = NULL;
pj_str_t hname;
pjsip_ctype_hdr *ctype_hdr = NULL;
pj_scanner *scanner = ctx->scanner;
pj_pool_t *pool = ctx->pool;
PJ_USE_EXCEPTION;
parsing_headers = PJ_FALSE;
PJ_TRY
{
if (parsing_headers)
goto parse_headers;
/* Skip leading newlines. */
while (IS_NEWLINE(*scanner->curptr)) {
pj_scan_get_newline(scanner);
}
/* Check if we still have valid packet.
* Sometimes endpoints just send blank (CRLF) packets just to keep
* NAT bindings open.
*/
if (pj_scan_is_eof(scanner))
return NULL;
/* Parse request or status line */
if (pj_scan_stricmp_alnum( scanner, PJSIP_VERSION, 7) == 0) {
msg = pjsip_msg_create(pool, PJSIP_RESPONSE_MSG);
int_parse_status_line( scanner, &msg->line.status );
} else {
msg = pjsip_msg_create(pool, PJSIP_REQUEST_MSG);
int_parse_req_line(scanner, pool, &msg->line.req );
}
parsing_headers = PJ_TRUE;
parse_headers:
/* Parse headers. */
do {
pjsip_parse_hdr_func * handler;
pjsip_hdr *hdr = NULL;
/* Init hname just in case parsing fails.
* Ref: PROTOS #2412
*/
hname.slen = 0;
/* Get hname. */
pj_scan_get( scanner, &pjsip_TOKEN_SPEC, &hname);
if (pj_scan_get_char( scanner ) != ':') {
PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
}
/* Find handler. */
handler = find_handler(&hname);
/* Call the handler if found.
* If no handler is found, then treat the header as generic
* hname/hvalue pair.
*/
if (handler) {
hdr = (*handler)(ctx);
/* Check if we've just parsed a Content-Type header.
* We will check for a message body if we've got Content-Type
* header.
*/
if (hdr->type == PJSIP_H_CONTENT_TYPE) {
ctype_hdr = (pjsip_ctype_hdr*)hdr;
}
} else {
hdr = parse_hdr_generic_string(ctx);
hdr->name = hdr->sname = hname;
}
/* Single parse of header line can produce multiple headers.
* For example, if one Contact: header contains Contact list
* separated by comma, then these Contacts will be split into
* different Contact headers.
* So here we must insert list instead of just insert one header.
*/
pj_list_insert_nodes_before(&msg->hdr, hdr);
/* Parse until EOF or an empty line is found. */
} while (!pj_scan_is_eof(scanner) && !IS_NEWLINE(*scanner->curptr));
parsing_headers = PJ_FALSE;
/* If empty line is found, eat it. */
if (!pj_scan_is_eof(scanner)) {
if (IS_NEWLINE(*scanner->curptr)) {
pj_scan_get_newline(scanner);
}
}
/* If we have Content-Type header, treat the rest of the message
* as body.
*/
if (ctype_hdr && scanner->curptr!=scanner->end) {
pjsip_msg_body *body = pj_pool_alloc(pool, sizeof(pjsip_msg_body));
body->content_type.type = ctype_hdr->media.type;
body->content_type.subtype = ctype_hdr->media.subtype;
body->content_type.param = ctype_hdr->media.param;
body->data = scanner->curptr;
body->len = scanner->end - scanner->curptr;
body->print_body = &generic_print_body;
body->clone_data = &pjsip_clone_text_data;
msg->body = body;
}
}
PJ_CATCH_ANY
{
/* Exception was thrown during parsing.
* Skip until newline, and parse next header.
*/
if (err_list) {
pjsip_parser_err_report *err_info;
err_info = pj_pool_alloc(pool, sizeof(*err_info));
err_info->except_code = PJ_GET_EXCEPTION();
err_info->line = scanner->line;
/* Scanner's column is zero based, so add 1 */
err_info->col = pj_scan_get_col(scanner) + 1;
if (parsing_headers)
err_info->hname = hname;
else if (msg && msg->type == PJSIP_REQUEST_MSG)
err_info->hname = pj_str("Request Line");
else if (msg && msg->type == PJSIP_RESPONSE_MSG)
err_info->hname = pj_str("Status Line");
else
err_info->hname.slen = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -