#ifdef __cplusplus
#if __cplusplus
extern "C"{
#endif
#endif /* End of #ifdef __cplusplus */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
#include <time.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <net/if.h>
#include "list.h"
#include "rtsp.h"
#define MAX_VENC_THREAD 4
RTSP_client g_rtspClients[MAX_RTSP_CLIENT];
pthread_mutex_t g_mutex;
pthread_cond_t g_cond;
pthread_mutex_t g_sendmutex;
struct list_head RTPbuf_head = LIST_HEAD_INIT(RTPbuf_head);
int udpfd;
const char *get_stat(int err)
{
struct {
const char *token;
int code;
} status[] = {
{"Continue", 100},
{"OK", 200},
{"Created", 201},
{"Accepted", 202},
{"Non-Authoritative Information", 203},
{"No Content", 204},
{"Reset Content", 205},
{"Partial Content", 206},
{"Multiple Choices", 300},
{"Moved Permanently", 301},
{"Moved Temporarily", 302},
{"Bad Request", 400},
{"Unauthorized", 401},
{"Payment Required", 402},
{"Forbidden", 403},
{"Not Found", 404},
{"Method Not Allowed", 405},
{"Not Acceptable", 406},
{"Proxy Authentication Required", 407},
{"Request Time-out", 408},
{"Conflict", 409},
{"Gone", 410},
{"Length Required", 411},
{"Precondition Failed", 412},
{"Request Entity Too Large", 413},
{"Request-URI Too Large", 414},
{"Unsupported Media Type", 415},
{"Bad Extension", 420},
{"Invalid Parameter", 450},
{"Parameter Not Understood", 451},
{"Conference Not Found", 452},
{"Not Enough Bandwidth", 453},
{"Session Not Found", 454},
{"Method Not Valid In This State", 455},
{"Header Field Not Valid for Resource", 456},
{"Invalid Range", 457},
{"Parameter Is Read-Only", 458},
{"Unsupported transport", 461},
{"Internal Server Error", 500},
{"Not Implemented", 501},
{"Bad Gateway", 502},
{"Service Unavailable", 503},
{"Gateway Time-out", 504},
{"RTSP Version Not Supported", 505},
{"Option not supported", 551},
{"Extended Error:", 911},
{NULL, -1}
};
int i;
for (i = 0; status[i].code != err && status[i].code != -1; ++i);
return status[i].token;
}
int send_reply(int sock, int err, int cseq)
{
char buf[1024] = {0};
sprintf(buf, "RTSP/1.0 %d %s\r\nCSeq: %d\r\n\r\n", err, get_stat(err), cseq);
int ret = send(sock, buf, strlen(buf), 0);
if(ret <= 0)
{
return FALSE;
}
else
{
printf(">>>>>%s\n", buf);
return TRUE;
}
}
static char const* dateHeader()
{
static char buf[200];
time_t tt = time(NULL);
strftime(buf, sizeof buf, "Date: %a, %b %d %Y %H:%M:%S GMT\r\n", gmtime(&tt));
return buf;
}
static char* GetLocalIP(int sock)
{
struct ifreq stifreq;
struct sockaddr_in *sin;
char * LocalIP = malloc(20);
strcpy(stifreq.ifr_name,"eth0");
if (!(ioctl (sock, SIOCGIFADDR,&stifreq)))
{
sin = (struct sockaddr_in *)&stifreq.ifr_addr;
sin->sin_family = AF_INET;
strcpy(LocalIP,inet_ntoa(sin->sin_addr));
//inet_ntop(AF_INET, &sin->sin_addr,LocalIP, 16);
}
printf("--------------------------------------------%s\n",LocalIP);
return LocalIP;
}
int ParseRequestString(char const* reqStr,
unsigned reqStrSize,
char* resultCmdName,
unsigned resultCmdNameMaxSize,
char* resultURLPreSuffix,
unsigned resultURLPreSuffixMaxSize,
char* resultURLSuffix,
unsigned resultURLSuffixMaxSize,
char* resultCSeq,
unsigned resultCSeqMaxSize)
{
// This parser is currently rather dumb; it should be made smarter #####
// Read everything up to the first space as the command name:
int parseSucceeded = FALSE;
unsigned i;
for(i = 0; i < resultCmdNameMaxSize-1 && i < reqStrSize; ++i)
{
char c = reqStr[i];
// '\t'是制表符
if(c == ' ' || c == '\t')
{
parseSucceeded = TRUE;
break;
}
resultCmdName[i] = c; // 通过for循环把pRecvBuf中的内容复制到resultCmdName中;
}
resultCmdName[i] = '\0'; // 在每个命令命令后面都添加上'\0',当做字符串;
if(!parseSucceeded)
return FALSE;
// rtsp://192.168.1.10:554/stream_chn0.h264 RTSP/1.0
// Skip over the prefix of any "rtsp://" or "rtsp:/" URL that follows:
unsigned j = i + 1;
while(j < reqStrSize &&(reqStr[j] == ' ' || reqStr[j] == '\t'))
++j; // skip over any additional white space
for(j = i+1; j < reqStrSize-8; ++j)
{
if((reqStr[j] == 'r' || reqStr[j] == 'R')//rtsp: or RTSP/
&&(reqStr[j+1] == 't' || reqStr[j+1] == 'T')
&&(reqStr[j+2] == 's' || reqStr[j+2] == 'S')
&&(reqStr[j+3] == 'p' || reqStr[j+3] == 'P')
&& reqStr[j+4] == ':' && reqStr[j+5] == '/')
{
j += 6;
if(reqStr[j] == '/') // rtsp://
{
++j;
while(j < reqStrSize && reqStr[j] != '/' && reqStr[j] != ' ')
++j;
}
else
{
// This is a "rtsp:/" URL; back up to the "/":
--j;
}
i = j;
break;
}
}
// Look for the URL suffix(before the following "RTSP/"):
parseSucceeded = FALSE;
unsigned k;
for(k = i+1; k < reqStrSize-5; ++k)
{
if(reqStr[k] == 'R' && reqStr[k+1] == 'T' &&
reqStr[k+2] == 'S' && reqStr[k+3] == 'P' && reqStr[k+4] == '/')
{
while(--k >= i && reqStr[k] == ' ')
{} // go back over all spaces before "RTSP/"
unsigned k1 = k;
while(k1 > i && reqStr[k1] != '/' && reqStr[k1] != ' ')
--k1;
// the URL suffix comes from [k1+1,k]
// Copy "resultURLSuffix":
if(k - k1 + 1 > resultURLSuffixMaxSize)
return FALSE; // there's no room
unsigned n = 0, k2 = k1+1;
while(k2 <= k)
resultURLSuffix[n++] = reqStr[k2++];
resultURLSuffix[n] = '\0';
// Also look for the URL 'pre-suffix' before this:
unsigned k3 = --k1;
while(k3 > i && reqStr[k3] != '/' && reqStr[k3] != ' ')
--k3;
// the URL pre-suffix comes from [k3+1,k1]
// Copy "resultURLPreSuffix":
if(k1 - k3 + 1 > resultURLPreSuffixMaxSize)
return FALSE; // there's no room
n = 0; k2 = k3+1;
while(k2 <= k1)
resultURLPreSuffix[n++] = reqStr[k2++];
resultURLPreSuffix[n] = '\0';
i = k + 7; // to go past " RTSP/"
parseSucceeded = TRUE;
break;
}
}
if(!parseSucceeded)
return FALSE;
// Look for "CSeq:", skip whitespace,
// then read everything up to the next \r or \n as 'CSeq':
parseSucceeded = FALSE;
for(j = i; j < reqStrSize-5; ++j)
{
if(reqStr[j] == 'C' && reqStr[j+1] == 'S' && reqStr[j+2] == 'e' &&
reqStr[j+3] == 'q' && reqStr[j+4] == ':')
{
j += 5;
unsigned n;
while(j < reqStrSize &&(reqStr[j] == ' ' || reqStr[j] == '\t'))
++j;
for(n = 0; n < resultCSeqMaxSize - 1 && j < reqStrSize; ++n, ++j)
{
char c = reqStr[j];
if(c == '\r' || c == '\n')
{
parseSucceeded = TRUE;
break;
}
resultCSeq[n] = c;
}
resultCSeq[n] = '\0';
break;
}
}
if(!parseSucceeded)
return FALSE;
return TRUE;
}
int OptionAnswer(char *cseq, int sock)
{
if(sock != 0)
{
char buf[1024];
memset(buf,0,1024);
char *pTemp = buf;
pTemp += sprintf(pTemp,"RTSP/1.0 200 OK\r\nCSeq: %s\r\n%sPublic: %s\r\n\r\n",
cseq,dateHeader(),"OPTIONS,DESCRIBE,SETUP,PLAY,PAUSE,TEARDOWN");
int reg = send(sock, buf, strlen(buf), 0);
if(reg <= 0)
{
return FALSE;
}
else
{
printf(">>>>>%s\n", buf);
}
return TRUE;
}
return FALSE;
}
int DescribeAnswer(char *cseq,int s