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

📄 sip_parser.c

📁 一个开源SIP协议栈
💻 C
📖 第 1 页 / 共 4 页
字号:
}

/* 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 + -