/*************************************************************************************** * * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. * * By downloading, copying, installing or using the software you agree to this license. * If you do not agree to this license, do not download, install, * copy or use the software. * * Copyright (C) 2014-2024, Happytimesoft Corporation, all rights reserved. * * Redistribution and use in binary forms, with or without modification, are permitted. * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. * ****************************************************************************************/ #include "sys_inc.h" #include "word_analyse.h" #include "rtsp_parse.h" #include "http_cln.h" /**************************************************************************/ const RREQMTV rtsp_req_mtvs[] = { {RTSP_MT_DESCRIBE, "DESCRIBE", 8}, {RTSP_MT_ANNOUNCE, "ANNOUNCE", 8}, {RTSP_MT_OPTIONS, "OPTIONS", 7}, {RTSP_MT_PAUSE, "PAUSE", 5}, {RTSP_MT_PLAY, "PLAY", 4}, {RTSP_MT_RECORD, "RECORD", 6}, {RTSP_MT_REDIRECT, "REDIRECT", 8}, {RTSP_MT_SETUP, "SETUP", 5}, {RTSP_MT_SET_PARAMETER, "SET_PARAMETER",13}, {RTSP_MT_GET_PARAMETER, "GET_PARAMETER",13}, {RTSP_MT_TEARDOWN, "TEARDOWN", 8} }; /**************************************************************************/ BOOL rtsp_is_rtsp_msg(char * msg_buf) { uint32 i; for (i=0; i < sizeof(rtsp_req_mtvs)/sizeof(RREQMTV); i++) { if (memcmp(msg_buf, rtsp_req_mtvs[i].msg_str, rtsp_req_mtvs[i].msg_len) == 0) { return TRUE; } } if (memcmp(msg_buf, "RTSP/1.0", strlen("RTSP/1.0")) == 0) { return TRUE; } return FALSE; } void rtsp_headl_parse(char * pline, int llen, HRTSP_MSG * p_msg) { char word_buf[256]; int word_len; int next_word_offset; BOOL bHaveNextWord; bHaveNextWord = GetLineWord(pline, 0, llen, word_buf, sizeof(word_buf), &next_word_offset, WORD_TYPE_STRING); word_len = (int)strlen(word_buf); if (word_len > 0 && word_len < 31) { memcpy(p_msg->first_line.header, pline, word_len); p_msg->first_line.header[word_len] = '\0'; while (pline[next_word_offset] == ' ') { next_word_offset++; } p_msg->first_line.value_string = pline+next_word_offset; p_msg->first_line.value_string[llen-next_word_offset] = '\0'; if (strcasecmp(word_buf, "RTSP/1.0") == 0) { if (bHaveNextWord) { word_len = sizeof(word_buf); bHaveNextWord = GetLineWord(pline, next_word_offset, llen, word_buf, sizeof(word_buf), &next_word_offset, WORD_TYPE_NUM); word_len = (int)strlen(word_buf); if (word_len > 0) { p_msg->msg_type = 1; p_msg->msg_sub_type = atoi(word_buf); } } } else { uint32 i; p_msg->msg_type = 0; for (i=0; i < sizeof(rtsp_req_mtvs)/sizeof(RREQMTV); i++) { if (strcasecmp(word_buf, (char *)(rtsp_req_mtvs[i].msg_str)) == 0) { p_msg->msg_sub_type = rtsp_req_mtvs[i].msg_type; break; } } } } } int rtsp_line_parse(char * p_buf, int max_len, char sep_char, PPSN_CTX * p_ctx) { char word_buf[256]; BOOL bHaveNextLine = TRUE; int line_len = 0; int parse_len = 0; char * ptr = p_buf; do { if (GetSipLine(ptr, max_len, &line_len, &bHaveNextLine) == FALSE) { return -1; } if (line_len <= 2) { return(parse_len + line_len); } int next_word_offset = 0; GetLineWord(ptr, 0, line_len-2, word_buf, sizeof(word_buf), &next_word_offset, WORD_TYPE_STRING); char nchar = *(ptr + next_word_offset); if (nchar != sep_char) // SIP is ':',SDP is '=' { return -1; } next_word_offset++; while (ptr[next_word_offset] == ' ') { next_word_offset++; } HDRV * pHdrV = hdrv_buf_get_idle(); if (pHdrV == NULL) { log_print(HT_LOG_ERR, "%s, hdrv_buf_get_idle return NULL!!!\r\n", __FUNCTION__); return -1; } strncpy(pHdrV->header, word_buf, 31); pHdrV->value_string = ptr+next_word_offset; pps_ctx_ul_add(p_ctx, pHdrV); ptr += line_len; max_len -= line_len; parse_len += line_len; while (*ptr == '\r' || *ptr == '\n') { ptr++; parse_len++; } } while (bHaveNextLine); return parse_len; } int rtsp_ctx_parse(HRTSP_MSG * p_msg) { int flag = 0; RTSPCTXT w_ctx_type; HDRV * pHdrV = (HDRV *)pps_lookup_start(&(p_msg->rtsp_ctx)); while (pHdrV != NULL) { if (strcasecmp(pHdrV->header, "Content-Length") == 0) { p_msg->ctx_len = atol(pHdrV->value_string); flag++; } else if (strcasecmp(pHdrV->header, "Content-Type") == 0) { char type_word[64]; int next_tmp; GetLineWord(pHdrV->value_string, 0, (int)strlen(pHdrV->value_string), type_word, sizeof(type_word), &next_tmp, WORD_TYPE_STRING); if (strcasecmp(type_word, "application/sdp") == 0) { w_ctx_type = RTSP_CTX_SDP; } else { w_ctx_type = RTSP_CTX_NULL; } p_msg->ctx_type = w_ctx_type; flag++; } pHdrV = (HDRV *)pps_lookup_next(&(p_msg->rtsp_ctx), pHdrV); } pps_lookup_end(&(p_msg->rtsp_ctx)); if (p_msg->ctx_type && p_msg->ctx_len) { return 1; } return 0; } int rtsp_msg_parse(char * msg_buf, int msg_buf_len, HRTSP_MSG * msg) { int line_len = 0; BOOL bHaveNextLine; char * p_buf = msg_buf; msg->msg_type = (uint32) -1; if (GetSipLine(p_buf, msg_buf_len, &line_len, &bHaveNextLine) == FALSE) { return -1; } if (line_len > 0) { rtsp_headl_parse(p_buf, line_len-2, msg); } if (msg->msg_type == (uint32) -1) { return -1; } p_buf += line_len; msg->rtsp_len = rtsp_line_parse(p_buf, msg_buf_len-line_len, ':', &(msg->rtsp_ctx)); if (msg->rtsp_len <= 0) { return -1; } p_buf += msg->rtsp_len; if (rtsp_ctx_parse(msg) == 1 && msg->ctx_len > 0) { msg->sdp_len = rtsp_line_parse(p_buf, msg->ctx_len, '=', &(msg->sdp_ctx)); if (msg->sdp_len < 0) { return -1; } } return (line_len + msg->rtsp_len + msg->sdp_len); } int rtsp_msg_parse_part1(char * p_buf, int buf_len, HRTSP_MSG * msg) { int line_len = 0; BOOL bHaveNextLine; msg->msg_type = (uint32) -1; if (GetSipLine(p_buf, buf_len, &line_len, &bHaveNextLine) == FALSE) { return -1; } if (line_len > 0) { rtsp_headl_parse(p_buf, line_len-2, msg); } if (msg->msg_type == (uint32) -1) { return -1; } p_buf += line_len; msg->rtsp_len = rtsp_line_parse(p_buf, buf_len-line_len, ':', &(msg->rtsp_ctx)); if (msg->rtsp_len <= 0) { return -1; } rtsp_ctx_parse(msg); return (line_len + msg->rtsp_len); } int rtsp_msg_parse_part2(char * p_buf, int buf_len, HRTSP_MSG * msg) { msg->sdp_len = rtsp_line_parse(p_buf, buf_len, '=', &(msg->sdp_ctx)); if (msg->sdp_len < 0) { msg->sdp_len = rtsp_line_parse(p_buf, buf_len, ':', &(msg->sdp_ctx)); if (msg->sdp_len < 0) { return -1; } } return msg->sdp_len; } HDRV * rtsp_find_headline(HRTSP_MSG * msg, const char * head) { if (msg == NULL || head == NULL) { return NULL; } HDRV * line = (HDRV *)pps_lookup_start(&(msg->rtsp_ctx)); while (line != NULL) { if (strcasecmp(line->header, head) == 0) { return line; } line = (HDRV *)pps_lookup_next(&(msg->rtsp_ctx), line); } pps_lookup_end(&(msg->rtsp_ctx)); return NULL; } HDRV * rtsp_find_headline_next(HRTSP_MSG * msg, const char * head, HDRV * hrv) { HDRV * line; if (msg == NULL || head == NULL) { return NULL; } line = (HDRV *)pps_lookup_start(&(msg->rtsp_ctx)); while (line != NULL) { if (line == hrv) { line = (HDRV *)pps_lookup_next(&(msg->rtsp_ctx), line); break; } line = (HDRV *)pps_lookup_next(&(msg->rtsp_ctx), line); } while (line != NULL) { if (strcasecmp(line->header, head) == 0) { pps_lookup_end(&(msg->rtsp_ctx)); return line; } line = (HDRV *)pps_lookup_next(&(msg->rtsp_ctx), line); } pps_lookup_end(&(msg->rtsp_ctx)); return NULL; } BOOL rtsp_get_headline_string(HRTSP_MSG * rx_msg, const char * head, char * p_value, int size) { HDRV * rx_head = rtsp_find_headline(rx_msg, head); if (rx_head == NULL || p_value == NULL) { return FALSE; } if (rx_head->value_string == NULL) { return FALSE; } p_value[0] = '\0'; int len = (int)strlen(rx_head->value_string); if (len >= size) { log_print(HT_LOG_ERR, "%s, %s, value_string(%s) len(%d) > size(%d)\r\n", __FUNCTION__, head, rx_head->value_string, len, size); return FALSE; } strcpy(p_value, rx_head->value_string); return TRUE; } BOOL rtsp_get_headline_uri(HRTSP_MSG * rx_msg, char * p_uri, int size) { char * p_ptr = rx_msg->first_line.value_string; if (p_ptr == NULL) { return FALSE; } char * p_end = p_ptr; while (*p_end != ' ') { p_end++; } int len = (int)(p_end - p_ptr); if (len >= size) { return FALSE; } memcpy(p_uri, p_ptr, len); p_uri[len] = '\0'; return TRUE; } HDRV * rtsp_find_sdp_headline(HRTSP_MSG * msg, const char * head) { if (msg == NULL || head == NULL) { return NULL; } HDRV * line = (HDRV *)pps_lookup_start(&(msg->sdp_ctx)); while (line != NULL) { if (strcasecmp(line->header, head) == 0) { return line; } line = (HDRV *)pps_lookup_next(&(msg->sdp_ctx), line); } pps_lookup_end(&(msg->sdp_ctx)); return NULL; } BOOL rtsp_msg_with_sdp(HRTSP_MSG * msg) { if (msg == NULL) { return FALSE; } if (msg->sdp_ctx.node_num == 0) { return FALSE; } return TRUE; } BOOL rtsp_get_msg_session(HRTSP_MSG * rx_msg, char *session_buf, int len) { session_buf[0] = '\0'; HDRV * rx_id = rtsp_find_headline(rx_msg, "Session"); if (rx_id == NULL || len <= 0) { return FALSE; } int next_word_offset; GetLineWord(rx_id->value_string, 0, (int)strlen(rx_id->value_string), session_buf, len, &next_word_offset, WORD_TYPE_STRING); return TRUE; } BOOL rtsp_match_msg_session(HRTSP_MSG * rx_msg, HRTSP_MSG * tx_msg) { HDRV * rx_id = rtsp_find_headline(rx_msg, "Session"); HDRV * tx_id = rtsp_find_headline(tx_msg, "Session"); if (rx_id == NULL || tx_id == NULL) { return FALSE; } char rx_word_buf[256]; char tx_word_buf[256]; int next_word_offset; GetLineWord(rx_id->value_string, 0, (int)strlen(rx_id->value_string), rx_word_buf, sizeof(rx_word_buf), &next_word_offset, WORD_TYPE_STRING); GetLineWord(tx_id->value_string, 0, (int)strlen(tx_id->value_string), tx_word_buf, sizeof(tx_word_buf), &next_word_offset, WORD_TYPE_STRING); if (strcmp(rx_word_buf, tx_word_buf) != 0) { return FALSE; } return TRUE; } BOOL rtsp_match_msg_cseq(HRTSP_MSG * rx_msg, HRTSP_MSG * tx_msg) { HDRV * rx_cseq = rtsp_find_headline(rx_msg, "CSeq"); HDRV * tx_cseq = rtsp_find_headline(tx_msg, "CSeq"); if (rx_cseq == NULL || tx_cseq == NULL) { return FALSE; } char rx_word_buf[256]; char tx_word_buf[256]; int next_offset; GetLineWord(rx_cseq->value_string, 0, (int)strlen(rx_cseq->value_string), rx_word_buf, sizeof(rx_word_buf), &next_offset, WORD_TYPE_NUM); GetLineWord(tx_cseq->value_string, 0, (int)strlen(tx_cseq->value_string), tx_word_buf, sizeof(tx_word_buf), &next_offset, WORD_TYPE_NUM); if (strcmp(rx_word_buf, tx_word_buf) != 0) { return FALSE; } GetLineWord(rx_cseq->value_string, next_offset, (int)strlen(rx_cseq->value_string), rx_word_buf, sizeof(rx_word_buf), &next_offset, WORD_TYPE_STRING); GetLineWord(tx_cseq->value_string, next_offset, (int)strlen(tx_cseq->value_string), tx_word_buf, sizeof(tx_word_buf), &next_offset, WORD_TYPE_STRING); if (strcasecmp(rx_word_buf, tx_word_buf) != 0) { return FALSE; } return TRUE; } BOOL rtsp_get_msg_cseq(HRTSP_MSG * rx_msg, char *cseq_buf, int len) { HDRV * rx_cseq = rtsp_find_headline(rx_msg, "CSeq"); if ((rx_cseq == NULL) || len <= 0) { return FALSE; } int next_offset; GetLineWord(rx_cseq->value_string, 0, (int)strlen(rx_cseq->value_string), cseq_buf, len, &next_offset, WORD_TYPE_NUM); return TRUE; } BOOL rtsp_get_user_agent_info(HRTSP_MSG * rx_msg, char * agent_buf, int max_len) { if (agent_buf == NULL || max_len <= 0) { return FALSE; } agent_buf[0] = '\0'; HDRV * rx_line = rtsp_find_headline(rx_msg, "User-Agent"); if (rx_line == NULL) { return FALSE; } strncpy(agent_buf, rx_line->value_string, max_len); return TRUE; } BOOL rtsp_get_session_info(HRTSP_MSG * rx_msg, char * session_buf, int max_len, int * timeout) { if (session_buf == NULL || max_len <= 0) { return FALSE; } HDRV * rx_line = rtsp_find_headline(rx_msg, "Session"); if (rx_line == NULL) { return FALSE; } session_buf[0] = '\0'; if (rx_line->value_string) { char * p = strchr(rx_line->value_string, ';'); if (!p) { strncpy(session_buf, rx_line->value_string, max_len); } else { *p = '\0'; strncpy(session_buf, rx_line->value_string, max_len); *p = ';'; } if (timeout) { char value_string[256] = {'\0'}; strncpy(value_string, rx_line->value_string, sizeof(value_string)-1); lowercase(value_string); p = strstr(value_string, "timeout="); if (p) { p += strlen("timeout="); *timeout = atoi(p); if (*timeout <= 0) { *timeout = 60; } else if (*timeout < 10) { *timeout = 10; } } } } return TRUE; } BOOL rtsp_get_rtp_info(HRTSP_MSG * rx_msg, char * v_ctl, uint32 * p_v_ts, char * a_ctl, uint32 * p_a_ts) { HDRV * rx_line = rtsp_find_headline(rx_msg, "RTP-Info"); if (rx_line == NULL) { return FALSE; } if (NULL == rx_line->value_string) { return FALSE; } // set default value -1 *p_v_ts = -1; *p_a_ts = -1; if (v_ctl && v_ctl[0] != '\0') { int ctl_len; char * p = strchr(v_ctl, '?'); if (p) { char ctl[128] = {'\0'}; strncpy(ctl, v_ctl, p-v_ctl); p = strstr(rx_line->value_string, ctl); ctl_len = strlen(ctl); } else { p = strstr(rx_line->value_string, v_ctl); ctl_len = strlen(v_ctl); } if (p) { p += ctl_len; int i = 0, j = 0; char * p_buff = NULL; char * p_semicolon = strchr(p, ','); char * p_rtptime = strstr(p, "rtptime="); char rtptime[32] = {'\0'}; if (p_rtptime) { if (p_semicolon) { if (p_rtptime < p_semicolon) { p_buff = p_rtptime+strlen("rtptime="); } } else { p_buff = p_rtptime+strlen("rtptime="); } while (p_buff && p_buff[i] != '\0') { if (p_buff[i] == ',' || p_buff[i] == ';') { break; } else if (j < 31) { rtptime[j++] = p_buff[i]; } i++; } *p_v_ts = (uint32)strtoul(rtptime, NULL, 10); } } } if (a_ctl && a_ctl[0] != '\0') { int ctl_len; char * p = strchr(a_ctl, '?'); if (p) { char ctl[128] = {'\0'}; strncpy(ctl, a_ctl, p-a_ctl); p = strstr(rx_line->value_string, ctl); ctl_len = strlen(ctl); } else { p = strstr(rx_line->value_string, a_ctl); ctl_len = strlen(a_ctl); } if (p) { p += ctl_len; int i = 0, j = 0; char * p_buff = NULL; char * p_semicolon = strchr(p, ','); char * p_rtptime = strstr(p, "rtptime="); char rtptime[32] = {'\0'}; if (p_rtptime) { if (p_semicolon) { if (p_rtptime < p_semicolon) { p_buff = p_rtptime+strlen("rtptime="); } } else { p_buff = p_rtptime+strlen("rtptime="); } while (p_buff && p_buff[i] != '\0') { if (p_buff[i] == ',' || p_buff[i] == ';') { break; } else if (j < 31) { rtptime[j++] = p_buff[i]; } i++; } *p_a_ts = (uint32)strtoul(rtptime, NULL, 10); } } } return TRUE; } BOOL rtsp_get_tcp_transport_info(HRTSP_MSG * rx_msg, uint16 * interleaved) { BOOL ret = FALSE; HDRV * rx_line = rtsp_find_headline(rx_msg, "Transport"); if (rx_line == NULL) { return FALSE; } if (rx_line->value_string) { char buff[32] = {'\0'}; if (GetNameValuePair(rx_line->value_string, (int)strlen(rx_line->value_string), "interleaved", buff, sizeof(buff)-1)) { if (interleaved) { *interleaved = atoi(buff); } ret = TRUE; } } return ret; } BOOL rtsp_get_udp_transport_info(HRTSP_MSG * rx_msg, uint16 * client_port, uint16 * server_port) { BOOL ret = FALSE; HDRV * rx_line = rtsp_find_headline(rx_msg, "Transport"); if (rx_line == NULL) { return FALSE; } if (rx_line->value_string) { char buff[32] = {'\0'}; if (GetNameValuePair(rx_line->value_string, (int)strlen(rx_line->value_string), "client_port", buff, sizeof(buff)-1)) { if (client_port) { *client_port = atoi(buff); } ret = TRUE; } if (GetNameValuePair(rx_line->value_string, (int)strlen(rx_line->value_string), "server_port", buff, sizeof(buff)-1)) { if (server_port) { *server_port = atoi(buff); } ret = TRUE; } } return ret; } BOOL rtsp_get_mc_transport_info(HRTSP_MSG * rx_msg, char * destination, uint16 * port) { BOOL ret = FALSE; HDRV * rx_line = rtsp_find_headline(rx_msg, "Transport"); if (rx_line == NULL) { return FALSE; } if (rx_line->value_string) { char buff[32] = {'\0'}; if (GetNameValuePair(rx_line->value_string, (int)strlen(rx_line->value_string), "destination", buff, sizeof(buff)-1)) { if (destination) { strcpy(destination, buff); } ret = TRUE; } if (GetNameValuePair(rx_line->value_string, (int)strlen(rx_line->value_string), "port", buff, sizeof(buff)-1)) { if (port) { *port = atoi(buff); } ret = TRUE; } } return ret; } BOOL rtsp_is_line_exist(HRTSP_MSG * rx_msg, const char * head, const char * value) { char buf[256]; char lovalue[256] = {'\0'}; if (!rtsp_get_headline_string(rx_msg, head, buf, sizeof(buf))) { return FALSE; } strncpy(lovalue, value, sizeof(lovalue)-1); lowercase(buf); lowercase(lovalue); if (!strstr(buf, lovalue)) { return FALSE; } return TRUE; } BOOL rtsp_get_cbase_info(HRTSP_MSG * rx_msg, char * cbase_buf, int max_len) { if (cbase_buf == NULL || max_len <= 0) { return FALSE; } cbase_buf[0] = '\0'; HDRV * rx_line = rtsp_find_headline(rx_msg, "Content-Base"); if (rx_line == NULL) { return FALSE; } strncpy(cbase_buf, rx_line->value_string, max_len); return TRUE; } void rtsp_add_tx_msg_line(HRTSP_MSG * tx_msg, const char * msg_hdr, const char * msg_fmt, ...) { int slen; va_list argptr; if (tx_msg == NULL || tx_msg->msg_buf == NULL) { return; } HDRV *pHdrV = hdrv_buf_get_idle(); if (pHdrV == NULL) { log_print(HT_LOG_ERR, "%s, hdrv_buf_get_idle return NULL!!!\r\n", __FUNCTION__); return; } pHdrV->value_string = tx_msg->msg_buf + tx_msg->buf_offset; strncpy(pHdrV->header, msg_hdr, 31); va_start(argptr, msg_fmt); #if __LINUX_OS__ slen = vsnprintf(pHdrV->value_string, 1600-tx_msg->buf_offset, msg_fmt, argptr); #else slen = vsprintf(pHdrV->value_string, msg_fmt, argptr); #endif va_end(argptr); if (slen < 0) { log_print(HT_LOG_ERR, "%s, vsnprintf return %d !!!\r\n", __FUNCTION__, slen); hdrv_buf_free(pHdrV); return; } pHdrV->value_string[slen] = '\0'; tx_msg->buf_offset += slen + 1; pps_ctx_ul_add(&(tx_msg->rtsp_ctx), pHdrV); } void rtsp_add_tx_msg_sdp_line(HRTSP_MSG * tx_msg, const char * msg_hdr, const char * msg_fmt, ...) { int slen; va_list argptr; if (tx_msg == NULL || tx_msg->msg_buf == NULL) { return; } HDRV *pHdrV = hdrv_buf_get_idle(); if (pHdrV == NULL) { log_print(HT_LOG_ERR, "%s, hdrv_buf_get_idle return NULL!!!\r\n", __FUNCTION__); return; } pHdrV->value_string = tx_msg->msg_buf + tx_msg->buf_offset; strncpy(pHdrV->header, msg_hdr, 31); va_start(argptr, msg_fmt); #if __LINUX_OS__ slen = vsnprintf(pHdrV->value_string, 1600-tx_msg->buf_offset, msg_fmt, argptr); #else slen = vsprintf(pHdrV->value_string, msg_fmt, argptr); #endif va_end(argptr); if (slen < 0) { log_print(HT_LOG_ERR, "%s, vsnprintf return %d !!!\r\n", __FUNCTION__, slen); hdrv_buf_free(pHdrV); return; } pHdrV->value_string[slen] = '\0'; tx_msg->buf_offset += slen + 1; pps_ctx_ul_add(&(tx_msg->sdp_ctx), pHdrV); } void rtsp_add_tx_msg_fline(HRTSP_MSG * tx_msg, const char * msg_hdr, const char * msg_fmt, ...) { int slen; va_list argptr; if (tx_msg == NULL || tx_msg->msg_buf == NULL) { return; } strncpy(tx_msg->first_line.header, msg_hdr, sizeof(tx_msg->first_line.header)-1); tx_msg->first_line.value_string = tx_msg->msg_buf + tx_msg->buf_offset; va_start(argptr, msg_fmt); #if __LINUX_OS__ slen = vsnprintf(tx_msg->first_line.value_string, 1600-tx_msg->buf_offset, msg_fmt, argptr); #else slen = vsprintf(tx_msg->first_line.value_string, msg_fmt, argptr); #endif va_end(argptr); if (slen < 0) { log_print(HT_LOG_ERR, "%s, vsnprintf return %d !!!\r\n", __FUNCTION__, slen); return; } tx_msg->first_line.value_string[slen] = '\0'; tx_msg->buf_offset += slen + 1; } void rtsp_copy_msg_line(HRTSP_MSG * src_msg, HRTSP_MSG * dst_msg, char * msg_hdr) { HDRV * src_line = rtsp_find_headline(src_msg, msg_hdr); if (src_line == NULL) { return; } HDRV * dst_line = hdrv_buf_get_idle(); if (dst_line == NULL) { return; } strcpy(dst_line->header, src_line->header); dst_line->value_string = dst_msg->msg_buf + dst_msg->buf_offset; if (dst_line->value_string == NULL) { hdrv_buf_free(dst_line); return; } strcpy(dst_line->value_string, src_line->value_string); dst_msg->buf_offset += (int)strlen(src_line->value_string) + 1; pps_ctx_ul_add(&(dst_msg->rtsp_ctx), dst_line); } void rtsp_free_msg(HRTSP_MSG * msg) { if (msg == NULL) { return; } rtsp_free_msg_content(msg); rtsp_free_msg_buf(msg); } void rtsp_free_msg_content(HRTSP_MSG * msg) { if (msg == NULL) { return; } hdrv_ctx_free(&(msg->rtsp_ctx)); hdrv_ctx_free(&(msg->sdp_ctx)); net_buf_free(msg->msg_buf); } BOOL rtsp_get_remote_media_ip(HRTSP_MSG * rx_msg, uint32 * media_ip) { HDRV * pHdr = rtsp_find_sdp_headline(rx_msg, "c"); if ((pHdr != NULL) && (pHdr->value_string != NULL) && (strlen(pHdr->value_string) > 0)) { char tmp_buf[128]; int next_offset; GetLineWord(pHdr->value_string, 0, (int)strlen(pHdr->value_string), tmp_buf, sizeof(tmp_buf), &next_offset, WORD_TYPE_STRING); if (strcasecmp(tmp_buf, "IN") != 0) { return FALSE; } GetLineWord(pHdr->value_string, next_offset, (int)strlen(pHdr->value_string), tmp_buf, sizeof(tmp_buf), &next_offset, WORD_TYPE_STRING); if (strcasecmp(tmp_buf, "IP4") != 0) { return FALSE; } GetLineWord(pHdr->value_string, next_offset, (int)strlen(pHdr->value_string), tmp_buf, sizeof(tmp_buf), &next_offset, WORD_TYPE_STRING); log_print(HT_LOG_DBG, "%s, media_ip=%s\r\n", __FUNCTION__, tmp_buf); if (is_ip_address(tmp_buf)) { *media_ip = inet_addr(tmp_buf); return TRUE; } } return FALSE; } HDRV * rtsp_find_mdesc_point(HRTSP_MSG * rx_msg, HDRV * pStartHdr, const char * cap_name, int * next_offset, const char * attr) { char media_type[16]; HDRV * pHdr = pStartHdr; HDRV * pHdr1 = NULL; for (; pHdr != NULL; pHdr = (HDRV *)pps_lookup_next(&(rx_msg->sdp_ctx),pHdr)) { if (strcasecmp(pHdr->header, "m") != 0) { continue; } GetLineWord(pHdr->value_string, 0, (int)strlen(pHdr->value_string), media_type, sizeof(media_type), next_offset, WORD_TYPE_STRING); if (strcasecmp(media_type, cap_name) != 0) { continue; } if (NULL == attr) { return pHdr; } pHdr1 = (HDRV *)pps_lookup_next(&(rx_msg->sdp_ctx), pHdr); for (; pHdr1 != NULL; pHdr1 = (HDRV *)pps_lookup_next(&(rx_msg->sdp_ctx), pHdr1)) { if (strcasecmp(pHdr1->header, "m") == 0) { break; } if (pHdr1->value_string && (pHdr1->header[0] == 'a') && (memcmp(pHdr1->value_string, attr, strlen(attr)) == 0)) { return pHdr; } } } return NULL; } BOOL rtsp_get_remote_cap(HRTSP_MSG * rx_msg, const char * cap_name, int * cap_count, uint8 * cap_array, uint16 * rtp_port, const char * attr) { int next_offset = 0; char media_port[16],tmp_buf[64]; *cap_count = 0; HDRV * pHdr = (HDRV *)pps_lookup_start(&(rx_msg->sdp_ctx)); pHdr = rtsp_find_mdesc_point(rx_msg, pHdr, cap_name, &next_offset, attr); if (pHdr == NULL) { pps_lookup_end(&(rx_msg->sdp_ctx)); return FALSE; } GetLineWord(pHdr->value_string, next_offset, (int)strlen(pHdr->value_string), media_port, sizeof(media_port), &next_offset, WORD_TYPE_NUM); GetLineWord(pHdr->value_string, next_offset, (int)strlen(pHdr->value_string), tmp_buf, sizeof(tmp_buf), &next_offset, WORD_TYPE_STRING); if (strcasecmp(tmp_buf, "RTP/AVP") != 0) { pps_lookup_end(&(rx_msg->sdp_ctx)); return FALSE; } int count = 0; BOOL cap_next_flag = TRUE; do { cap_next_flag = GetLineWord(pHdr->value_string, next_offset, (int)strlen(pHdr->value_string), tmp_buf, sizeof(tmp_buf), &next_offset, WORD_TYPE_NUM); if (tmp_buf[0] != '\0') { if (count >= MAX_AVN) { pps_lookup_end(&(rx_msg->sdp_ctx)); return FALSE; } cap_array[count++] = (uint8)atol(tmp_buf); *cap_count = count; } } while (cap_next_flag); if (count > 0) { if (rtp_port) { *rtp_port = (uint16)atol(media_port); } pps_lookup_end(&(rx_msg->sdp_ctx)); return TRUE; } pps_lookup_end(&(rx_msg->sdp_ctx)); return FALSE; } BOOL rtsp_get_digest_info(HRTSP_MSG * rx_msg, HD_AUTH_INFO * p_auth) { int len; int next_offset; char word_buf[128]; HDRV * chap_id = NULL; char * p; p_auth->auth_response[0] = '\0'; RETRY: if (chap_id) { chap_id = rtsp_find_headline_next(rx_msg, "WWW-Authenticate", chap_id); } else { chap_id = rtsp_find_headline(rx_msg, "WWW-Authenticate"); } if (chap_id == NULL) { return FALSE; } GetLineWord(chap_id->value_string, 0, (int)strlen(chap_id->value_string), word_buf, sizeof(word_buf), &next_offset, WORD_TYPE_STRING); if (strcasecmp(word_buf, "digest") != 0) { goto RETRY; } p = chap_id->value_string + next_offset; len = (int)strlen(chap_id->value_string) - next_offset; if (!http_get_digest_params(p, len, p_auth)) { goto RETRY; } if (p_auth->auth_algorithm[0] != '\0' && strncasecmp(p_auth->auth_algorithm, "MD5", 3) && strncasecmp(p_auth->auth_algorithm, "SHA-256", 7)) { goto RETRY; } return TRUE; } BOOL rtsp_get_auth_digest_info(HRTSP_MSG * rx_msg, HD_AUTH_INFO * p_auth) { int len; int next_offset; char word_buf[128]; char * p; HDRV * res_line = rtsp_find_headline(rx_msg, "Authorization"); if (res_line == NULL) { return FALSE; } GetLineWord(res_line->value_string, 0, (int)strlen(res_line->value_string), word_buf, sizeof(word_buf), &next_offset, WORD_TYPE_STRING); if (strcasecmp(word_buf, "digest") != 0) { return FALSE; } p = res_line->value_string + next_offset; len = (int)strlen(res_line->value_string) - next_offset; if (!GetNameValuePair(p, len, "username", p_auth->auth_name, sizeof(p_auth->auth_name))) { return FALSE; } if (!GetNameValuePair(p, len, "realm", p_auth->auth_realm, sizeof(p_auth->auth_realm))) { return FALSE; } if (!GetNameValuePair(p, len, "nonce", p_auth->auth_nonce, sizeof(p_auth->auth_nonce))) { return FALSE; } if (!GetNameValuePair(p, len, "uri", p_auth->auth_uri, sizeof(p_auth->auth_uri))) { return FALSE; } if (!GetNameValuePair(p, len, "response", p_auth->auth_response, sizeof(p_auth->auth_response))) { return FALSE; } if (!GetNameValuePair(p, len, "algorithm", p_auth->auth_algorithm, sizeof(p_auth->auth_algorithm))) { p_auth->auth_algorithm[0] = '\0'; } if (GetNameValuePair(p, len, "qop", p_auth->auth_qop, sizeof(p_auth->auth_qop))) { char * stop_string; if (!GetNameValuePair(p, len, "cnonce", p_auth->auth_cnonce, sizeof(p_auth->auth_cnonce))) { p_auth->auth_cnonce[0] = '\0'; } if (!GetNameValuePair(p, len, "nc", p_auth->auth_ncstr, sizeof(p_auth->auth_ncstr))) { p_auth->auth_ncstr[0] = '\0'; } p_auth->auth_nc = strtol(p_auth->auth_ncstr, &stop_string, 16); if (strlen(stop_string) > 0) { return FALSE; } } else { p_auth->auth_qop[0] = '\0'; p_auth->auth_cnonce[0] = '\0'; p_auth->auth_ncstr[0] = '\0'; p_auth->auth_nc = 0; } return TRUE; } BOOL rtsp_get_remote_cap_desc(HRTSP_MSG * rx_msg, const char * cap_name, char cap_desc[][MAX_AVDESCLEN], const char * attr) { int next_offset = 0; int index = 0; HDRV * pHdr = (HDRV *)pps_lookup_start(&(rx_msg->sdp_ctx)); pHdr = rtsp_find_mdesc_point(rx_msg, pHdr, cap_name, &next_offset, attr); if (pHdr == NULL) { pps_lookup_end(&(rx_msg->sdp_ctx)); return FALSE; } for (index=0; indexsdp_ctx), pHdr); while (pHdr != NULL) { if (strcasecmp(pHdr->header, "m") == 0) { break; } if (index >= MAX_AVN) { break; } snprintf(cap_desc[index], MAX_AVDESCLEN, "%s=%s", pHdr->header, pHdr->value_string); index++; pHdr = (HDRV *)pps_lookup_next(&(rx_msg->sdp_ctx), pHdr); } pps_lookup_end(&(rx_msg->sdp_ctx)); return (index != 0); } BOOL rtsp_find_sdp_control(HRTSP_MSG * rx_msg, char * ctl_buf, const char * tname, int max_len, const char *attr) { if (rx_msg == NULL || ctl_buf == NULL) { return FALSE; } int next_offset = 0; int mlen = (int)strlen("control:"); ctl_buf[0] = '\0'; HDRV * pHdr = (HDRV *)pps_lookup_start(&(rx_msg->sdp_ctx)); pHdr = rtsp_find_mdesc_point(rx_msg, pHdr, tname, &next_offset, attr); if (pHdr == NULL) { pps_lookup_end(&(rx_msg->sdp_ctx)); return FALSE; } pHdr = (HDRV *)pps_lookup_next(&(rx_msg->sdp_ctx), pHdr); while (pHdr != NULL) { if (strcasecmp(pHdr->header, "m") == 0) { break; } if (pHdr->value_string && pHdr->header[0] == 'a' && memcmp(pHdr->value_string, "control:", mlen) == 0) { int rlen = (int)strlen(pHdr->value_string) - mlen; if (rlen > max_len) { rlen = max_len; } int offset = 0; while (pHdr->value_string[offset+mlen] == ' ') { offset++; } strcpy(ctl_buf, pHdr->value_string+offset+mlen); pps_lookup_end(&(rx_msg->sdp_ctx)); return TRUE; } pHdr = (HDRV *)pps_lookup_next(&(rx_msg->sdp_ctx), pHdr); } pps_lookup_end(&(rx_msg->sdp_ctx)); return FALSE; } // a=range:npt=0-20.735 BOOL rtsp_get_sdp_range(HRTSP_MSG * rx_msg, int * p_start, int * p_end) { if (rx_msg == NULL) { return FALSE; } *p_start = 0; *p_end = 0; int mlen = (int)strlen("range:"); HDRV * pHdr = (HDRV *)pps_lookup_start(&(rx_msg->sdp_ctx)); pHdr = (HDRV *)pps_lookup_next(&(rx_msg->sdp_ctx), pHdr); while (pHdr != NULL) { if (strcasecmp(pHdr->header, "m") == 0) { break; } if (pHdr->value_string && pHdr->header[0] == 'a' && memcmp(pHdr->value_string, "range:", mlen) == 0) { int i = 0; int offset = 0; int rlen = (int)strlen(pHdr->value_string) - mlen; char start_buf[32] = {'\0'}, end_buf[32] = {'\0'}; char * p_buff = start_buf; // skip space while (pHdr->value_string[offset+mlen] == ' ') { offset++; } if (rlen < offset + 4) { pps_lookup_end(&(rx_msg->sdp_ctx)); return FALSE; } if (pHdr->value_string[offset+mlen] != 'n' && pHdr->value_string[offset+mlen+1] == 'p' && pHdr->value_string[offset+mlen+2] == 't') { pps_lookup_end(&(rx_msg->sdp_ctx)); return FALSE; } offset += 3; // skip "npt" // skip space while (pHdr->value_string[offset+mlen] == ' ') { offset++; } if (pHdr->value_string[offset+mlen] != '=') { pps_lookup_end(&(rx_msg->sdp_ctx)); return FALSE; } offset++; // skip '=' while (pHdr->value_string[offset+mlen] != '\0') { if (pHdr->value_string[offset+mlen] == '-') { i = 0; p_buff = end_buf; } else if (pHdr->value_string[offset+mlen] != ' ') { p_buff[i++] = pHdr->value_string[offset+mlen]; if (i >= 32) { pps_lookup_end(&(rx_msg->sdp_ctx)); return FALSE; } } offset++; } *p_start = (int)(atof(start_buf) * 1000); // convert to millisecond *p_end = (int)(atof(end_buf) * 1000); break; } pHdr = (HDRV *)pps_lookup_next(&(rx_msg->sdp_ctx), pHdr); } pps_lookup_end(&(rx_msg->sdp_ctx)); return TRUE; } BOOL rtsp_is_support_mcast(HRTSP_MSG * rx_msg) { BOOL ret = FALSE; HDRV * pHdr = (HDRV *)pps_lookup_start(&(rx_msg->sdp_ctx)); while (pHdr != NULL) { if (strcasecmp(pHdr->header, "m") == 0) { break; } if (strcasecmp(pHdr->header, "a") == 0) { if (strstr(pHdr->value_string, "type:broadcast")) { ret = TRUE; break; } } pHdr = (HDRV *)pps_lookup_next(&(rx_msg->sdp_ctx), pHdr); } pps_lookup_end(&(rx_msg->sdp_ctx)); return ret; } BOOL rtsp_get_scale_info(HRTSP_MSG * rx_msg, int * p_scale) { if (rx_msg == NULL || p_scale == NULL) { return FALSE; } HDRV * rx_line = rtsp_find_headline(rx_msg, "Scale"); if (rx_line == NULL) { return FALSE; } char * ptr = rx_line->value_string; while (*ptr == ' ' || *ptr == '\t') { ptr++; } double scale = strtod(ptr, NULL); if (scale == 0) { return FALSE; } *p_scale = (int)(scale * 100); return TRUE; } BOOL rtsp_get_rate_control(HRTSP_MSG * rx_msg, int * p_ratectrl) { if (rx_msg == NULL || p_ratectrl == NULL) { return FALSE; } HDRV * rx_line = rtsp_find_headline(rx_msg, "Rate-Control"); if (rx_line == NULL) { return FALSE; } char * ptr = rx_line->value_string; while (*ptr == ' ' || *ptr == '\t') { ptr++; } int ratectrl = 1; if (strcasecmp(ptr, "no") == 0) { ratectrl = 0; } *p_ratectrl = ratectrl; return TRUE; } BOOL rtsp_get_immediate(HRTSP_MSG * rx_msg, int * p_imme) { if (rx_msg == NULL || p_imme == NULL) { return FALSE; } HDRV * rx_line = rtsp_find_headline(rx_msg, "Immediate"); if (rx_line == NULL) { return FALSE; } char * ptr = rx_line->value_string; while (*ptr == ' ' || *ptr == '\t') { ptr++; } int imme = 0; if (strcasecmp(ptr, "yes") == 0) { imme = 1; } *p_imme = imme; return TRUE; } BOOL rtsp_get_frame_info(HRTSP_MSG * rx_msg, int * p_frame, int * p_interval) { if (rx_msg == NULL || p_frame == NULL) { return FALSE; } HDRV * rx_line = rtsp_find_headline(rx_msg, "Frames"); if (rx_line == NULL) { return FALSE; } char * ptr = rx_line->value_string; while (*ptr == ' ' || *ptr == '\t') { ptr++; } int frame = 0; // all frames if (strncasecmp(ptr, "intra", 5) == 0) { frame = 2; // I-frame ptr += 5; while (*ptr == ' ' || *ptr == '\t') { ptr++; } if (*ptr == '/') { ptr++; if (p_interval) { *p_interval = atoi(ptr); } } } else if (strcasecmp(ptr, "predicted") == 0) { frame = 1; // I-frame and P-frame } *p_frame = frame; return TRUE; } /*****************************************************************/ static PPSN_CTX * rtsp_msg_buf_fl = NULL; static int rtsp_msg_buf_init_count = 0; /*****************************************************************/ BOOL rtsp_msg_buf_init(int num) { rtsp_msg_buf_init_count++; if (rtsp_msg_buf_fl) { return TRUE; } rtsp_msg_buf_fl = pps_ctx_fl_init(num, sizeof(HRTSP_MSG), TRUE); if (rtsp_msg_buf_fl == NULL) { return FALSE; } return TRUE; } void rtsp_msg_buf_deinit() { rtsp_msg_buf_init_count--; if (rtsp_msg_buf_init_count == 0) { if (rtsp_msg_buf_fl) { pps_fl_free(rtsp_msg_buf_fl); rtsp_msg_buf_fl = NULL; } } if (rtsp_msg_buf_init_count < 0)rtsp_msg_buf_init_count = 0; } HRTSP_MSG * rtsp_get_msg_buf() { HRTSP_MSG * tx_msg = (HRTSP_MSG *)pps_fl_pop(rtsp_msg_buf_fl); if (tx_msg == NULL) { return NULL; } memset(tx_msg, 0, sizeof(HRTSP_MSG)); tx_msg->msg_buf = net_buf_get_idle(); if (tx_msg->msg_buf == NULL) { rtsp_free_msg_buf(tx_msg); return NULL; } rtsp_msg_ctx_init(tx_msg); return tx_msg; } void rtsp_msg_ctx_init(HRTSP_MSG * msg) { pps_ctx_ul_init_nm(hdrv_buf_fl, &(msg->rtsp_ctx)); pps_ctx_ul_init_nm(hdrv_buf_fl, &(msg->sdp_ctx)); } void rtsp_free_msg_buf(HRTSP_MSG * msg) { pps_fl_push(rtsp_msg_buf_fl, msg); } uint32 rtsp_idle_msg_buf_num() { return rtsp_msg_buf_fl->node_num; } BOOL rtsp_parse_buf_init(int nums) { BOOL ret = rtsp_msg_buf_init(nums); return ret; } void rtsp_parse_buf_deinit() { rtsp_msg_buf_deinit(); }