#include <sys/stat.h>
#include <sys/types.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>
#include <netinet/ip.h>
#include <netinet/ip6.h>
#include <net/ethernet.h>
#include <pcap.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
/*RTSP 端口*/
#define RTSP_TCP_PORT_RANGE 554
typedef enum {
RTSP_REQUEST,
RTSP_REPLY,
RTSP_NOT_FIRST_LINE
} rtsp_type_t;
static const char *rtsp_methods[] = {
"DESCRIBE",
"ANNOUNCE",
"GET_PARAMETER",
"OPTIONS",
"PAUSE",
"PLAY",
"RECORD",
"REDIRECT",
"SETUP",
"SET_PARAMETER",
"TEARDOWN"
};
/* 用于RTSP统计 */
struct rtsp_info_value_t {
char *request_method;
unsigned long int response_code;
};
/*
假定一个字节数组(假定包含一个以空值结尾的字符串)作为参数,
并返回字符串的长度-即该数组的大小,对于空终止符的值减去1。
*/
#define STRLEN_CONST(str) (sizeof (str) - 1)
static const char rtsp_content_type[] = "Content-Type:";
static const char rtsp_transport[] = "Transport:";
static const char rtsp_sps_server_port[] = "server_port=";
static const char rtsp_cps_server_port[] = "client_port=";
static const char rtsp_sps_dest_addr[] = "dest_addr=";
static const char rtsp_cps_src_addr[] = "src_addr=";
static const char rtsp_rtp_udp_default[] = "rtp/avp";
static const char rtsp_rtp_udp[] = "rtp/avp/udp";
static const char rtsp_rtp_tcp[] = "rtp/avp/tcp";
static const char rtsp_rdt_feature_level[] = "RDTFeatureLevel";
static const char rtsp_real_rdt[] = "x-real-rdt/";
static const char rtsp_real_tng[] = "x-pn-tng/"; /* synonym for x-real-rdt */
static const char rtsp_inter[] = "interleaved=";
static const char rtsp_content_length[] = "Content-Length:";
static void rtsp_create_conversation(u_char *line_begin, size_t line_len,rtsp_type_t rtsp_type_packet)
{
char buf[256];
char *tmp;
bool rtp_udp_transport = false;
bool rtp_tcp_transport = false;
bool rdt_transport = false;
//bool is_video = false; /* 是否需要显示视频 */
unsigned int c_data_port, c_mon_port;
unsigned int s_data_port, s_mon_port;
unsigned int ipv4_1, ipv4_2, ipv4_3, ipv4_4;
if (rtsp_type_packet != RTSP_REPLY) {
return;
}
/* 将行复制到buf */
if (line_len > sizeof(buf) - 1)
{
/* 避免溢出缓冲区。 */
line_len = sizeof(buf) - 1;
}
memcpy(buf, line_begin, line_len);
buf[line_len] = '\0';
printf("%s\n",buf);
/* Get past "Transport:" and spaces */
tmp = buf + STRLEN_CONST(rtsp_transport);
//printf("tmp %s\n",tmp);
while (*tmp && isspace(*tmp))
tmp++;
if ((tmp = strstr(buf, rtsp_cps_src_addr)))
{
tmp += strlen(rtsp_cps_src_addr);
//printf("tmp ====== %s\n",tmp);
if (sscanf(tmp, "\"%u.%u.%u.%u:%u\"", &ipv4_1, &ipv4_2, &ipv4_3, &ipv4_4, &c_data_port) == 5)
{
char *tmp2;
char *tmp3;
//printf("ipv4_1 %d\n",ipv4_1);
//printf("ipv4_2 %d\n",ipv4_2);
//printf("ipv4_3 %d\n",ipv4_3);
//printf("ipv4_4 %d\n",ipv4_4);
printf("c_data_port %d\n",c_data_port);
//Skip leading
tmp++;
tmp2=strstr(tmp,":");
tmp3=strndup(tmp,tmp2-tmp);
printf("src_addr %s\n",tmp3);
free(tmp3);
}
}
if ((tmp = strstr(buf, rtsp_sps_dest_addr)))
{
tmp += strlen(rtsp_sps_dest_addr);
if (sscanf(tmp, "\":%u\"", &s_data_port) == 1)
{
/* :9 mean ignore */
if (s_data_port == 9) {
s_data_port = 0;
}
printf("s_data_port %d\n",s_data_port);
}
}
if ((tmp = strstr(buf, rtsp_sps_server_port))) {
tmp += strlen(rtsp_sps_server_port);
if (sscanf(tmp, "%u", &s_mon_port) == 1) {
printf("s_mon_port %d\n",s_mon_port);
}
}
}
static bool is_rtsp_request_or_reply( unsigned char *line, int offset, rtsp_type_t *type)
{
unsigned int ii = 0;
char *data = reinterpret_cast<char *>(line);
int tokenlen;
char response_chars[4];
struct rtsp_info_value_t rtsp_info;
char *token, *next_token;
/*这是RTSP的回复 ? */
if ( strncasecmp("RTSP/", data, 5) == 0) {
/*
* Yes.
*/
*type = RTSP_REPLY;
/* 第一个标记是版本。 */
offset += 9;
memcpy(response_chars, data + offset, 3);
response_chars[3] = '\0';
rtsp_info.response_code = strtoul(response_chars, NULL, 10);
//printf("rtsp_info.response_code %d\n",rtsp_info.response_code);
return true;
}
/*
这是RTSP请求吗?
检查该行是否以RTSP请求方法之一开头。
*/
for (ii = 0; ii < sizeof rtsp_methods / sizeof rtsp_methods[0]; ii++) {
size_t len = strlen(rtsp_methods[ii]);
if (strncasecmp(rtsp_methods[ii], data, len) == 0 &&(isspace(data[len])))
{
*type = RTSP_REQUEST;
rtsp_info.request_method = strndupa(rtsp_methods[ii], len+1);
//printf("request_method: %s\n",rtsp_info.request_method);
return true;
}
}
/* 既不是请求也不是回应 */
*type = RTSP_NOT_FIRST_LINE;
return false;
}
/* 阅读回复消息的第一行 */
static void process_rtsp_reply(u_char *rtsp_data, int offset,rtsp_type_t rtsp_type_packet)
{
char *lineend = reinterpret_cast<char *>(rtsp_data + offset);
char *status = reinterpret_cast<char *>(rtsp_data );
char *status_start;
unsigned int status_i;
/* status code */
/* Skip protocol/version */
while (status < lineend && !isspace(*status))
status++;
/* Skip spaces */
while (status < lineend && isspace(*status))
status++;
/* Actual code number now */
status_start = status;
//printf("status_start %s\n",status_start);
status_i = 0;
while (status < lineend && isdigit(*status))
status_i = status_i * 10 + *status++ - '0';
//printf("status_i %d\n",status_i);
offset += strlen(lineend);
rtsp_create_conversation(rtsp_data,offset,rtsp_type_packet);
}
static void process_rtsp_request(u_char *rtsp_data, int offset,rtsp_type_t rtsp_type_packet)
{
char *lineend = reinterpret_cast<char *>(rtsp_data + offset);
// u_char *lineend = rtsp_data + offset;
unsigned int ii = 0;
char *url;
char *url_start;
char buf[256];
char *tmp;
int content_length = 0;
char content_type[256];
/* Request Methods */
for (ii = 0; ii < sizeof rtsp_methods / sizeof rtsp_methods[0]; ii++) {
size_t len = strlen(rtsp_methods[ii]);
if (strncasecmp(rtsp_methods[ii], lineend, len) == 0 &&(isspace(lineend[len])))
break;
}
//printf("process_rtsp_request 0x%.2X,0x%.2X,0x%.2X,0x%.2X\n",lineend[0],lineend[1],lineend[2],lineend[3]);
/* URL */
url = lineend;
/* Skip method name again */
while (url < lineend && !isspace(*url))
url++;
/* Skip spaces */
while (url < lineend && isspace(*url))
url++;
/* URL starts here */
url_start = url;
/* Scan to end of URL */
while (url < lineend && !isspace(*url))
url++;
printf("%s\n",url_start);
printf("111url %s\n",url);
if ((tmp = strstr(url_start, rtsp_content_type)))
{
tmp += strlen(rtsp_content_type);
if (sscanf(tmp, "%s", content_type) == 1)
{
//printf("content_type %s\n",content_type);
}
}
//Content-Length
if ((tmp = strstr(url_start, rtsp_content_length)))
{
tmp += strlen(rtsp_content_length);
if (sscanf(tmp, "%u", &content_length) == 1)
{
//printf("content_length %d\n",content_length);
}
}
}
void dissect_rtsp(u_char *rtsp_data)
{
int offset = 0;
rtsp_type_t rtsp_type_packet;
bool is_request_or_reply;
u_char *linep, *lineend;
u_char c;
//bool is_header = false;
is_request_or_reply = is_rtsp_request_or_reply(rtsp_data, offset, &rtsp_type_packet);
if (is_request_or_reply)
goto is_rtsp;
is_rtsp:
switch(rtsp_type_packet)
{
case RTSP_REQUEST:
process_rtsp_request(rtsp_data, offset,rtsp_type_packet);
break;
case RTSP_REPLY:
process_rtsp_reply(rtsp_data, offset,rtsp_type_packet);
break;
case RTSP_NOT_FIRST_LINE:
/* Drop through, it may well be a header line */
break;
default:
break;
}
}
static void dissect_rtsp_tcp(struct ip *pIp)
{
int iHeadLen = pIp->ip_hl*4;
int iPacketLen = ntohs(pIp->ip_len) - iHeadLen;
int offset = 0;
int nFragSeq = 0;
struct tcphdr *pTcpHdr = (struct tcphdr *)(((char *)pIp) + iHeadLen);
if (pIp->ip_p == IPPROTO_TCP && (ntohs(pTcpHdr->dest) == RTSP_TCP_PORT_RANGE)
|| (ntohs(pTcpHdr->source) == RTSP_TCP_PORT_RANGE) )/*仅处理TCP协议*/
{
int iPayloadLen = iPacketLen - pTcpHdr->doff*4;
//printf("TCP Payload Len %d\n",iPayloadLen);
u_char *RtspHdr = (u_char*)(pTcpHdr+1);
if (RtspHdr == NULL)
return;
u_char *RtspData = RtspHdr + 12; /*skip OPtions */
//printf("NtpHdr 0x%.2X,0x%.2X,0x%.2X,0x%.2X\n",RtspData[0],RtspData[1],RtspData[2],RtspData[3]);
dissect_rtsp(RtspData);
}
}
评论