📄 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; pj_list_insert_before(err_list, err_info); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -