Files
ANSCORE/MediaClient/rtsp/rtsp_parse.cpp

1840 lines
38 KiB
C++

/***************************************************************************************
*
* 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; index<MAX_AVN; index++)
{
cap_desc[index][0] = '\0';
}
index = 0;
pHdr = (HDRV *)pps_lookup_next(&(rx_msg->sdp_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();
}