#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <netdb.h>
#include <sys/socket.h>
#include <errno.h>
#include <stdarg.h>
#include <ctype.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <pthread.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <netinet/if_ether.h>
#include <net/if.h>
#include <linux/if_ether.h>
#include <linux/sockios.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "rtp.h"
// #include "./dbg_printf.h"
#define OUR_DEV
//#define HOME
typedef void * HANDLE;
#ifdef OUR_DEV
#define URL "192.168.1.95"
#define DEF_RTSP_URL "rtsp://192.168.1.95/264.264"
// #define DEF_RTSP_URL "rtsp://192.168.0.28/trackID1"
// #define DEF_RTSP_URL "rtsp://192.168.2.112/264.264"
#else
#define DEF_RTSP_URL "rtsp://192.168.0.29/"
#endif
#define RTSP_PORT 554
#define PRG_NAME "main"
#define UDP_RECV_PORT0 1023
#define UDP_RECV_PORT1 1024
#define max( a, b ) ( a > b ? a : b )
typedef enum RTSP_STAT
{
RTSP_NONE = 0,
RTSP_OPTION,
RTSP_DESCRIPT,
RTSP_SETUP,
RTSP_PLAY,
RTSP_GETPARM,
RTSP_KEEP,
RTSP_PAUSE,
RTSP_STOP
}RTPS_STAT_E;
typedef enum LINK_STAT
{
LINK_DISCONNECT = 0,
LINK_CONNECTING,
LINK_CONNECTED
}LINK_STAT_E;
typedef enum TRANSPORT
{
TRANS_UDP = 0,
TRANS_TCP,
TRANS_RAW
}TRANSPORT_E;
#define MAGIC_NUM 0x1a2b4c3d
#define RTSP_INVALID( obj ) ( obj->magic != MAGIC_NUM )
typedef struct tagRtspClient
{
unsigned int magic;
int fd; //rtsp web socket
TRANSPORT_E stream_type; // 码流方式
int recv_fd[2]; //
int recv_port[2]; // 监听端口
char rtsp_url[128]; // rtsp request url
char server_ip[128];
int server_port[2];
char session[20];
char authName[64];
char authPwd[64];
int support_cmd;
int bQuit;
int trackId;
time_t tou;
RTPS_STAT_E stat;
LINK_STAT_E link;
int CSeq;
unsigned char *recv_buf;
int maxBufSize;
HANDLE Filter;
HANDLE Vdec;
HANDLE rtp;
pthread_t threadID;
// struct list_head list;
}RtspClient, *PVHRtspClient;
#define SOCK_ERROR() do{\
if( len <= 0 )\
{\
fd = 0;\
printf("sock error, %s!\r\n", strerror(errno));\
break;\
}\
}while(0)
/* TCP and UDP API*/
int sock_listen( int port, const char *ipbind, int backlog )
{
struct sockaddr_in my_addr;
int fd, tmp = 1;
fd = socket(AF_INET,SOCK_STREAM,0);
if (fd < 0)
return -1;
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
memset(&my_addr, 0, sizeof(my_addr));
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons ((short)port);
if( ipbind != NULL ) {
inet_aton( ipbind, & my_addr.sin_addr );
} else {
my_addr.sin_addr.s_addr = htonl (INADDR_ANY);
}
if( 0 == bind (fd, (struct sockaddr *) &my_addr, sizeof (my_addr)) )
{
if( 0 == listen(fd, backlog) ) {
return fd;
}
}
close(fd);
return -1;
}
int sock_dataready( int fd, int tout )
{
fd_set rfd_set;
struct timeval tv, *ptv;
int nsel;
FD_ZERO( &rfd_set );
FD_SET( fd, &rfd_set );
if ( tout == -1 )
{
ptv = NULL;
}
else
{
tv.tv_sec = 0;
tv.tv_usec = tout * 1000;
ptv = &tv;
}
nsel = select( fd+1, &rfd_set, NULL, NULL, ptv );
if ( nsel > 0 && FD_ISSET( fd, &rfd_set ) )
return 1;
return 0;
}
int sock_udp_bind( int port )
{
struct sockaddr_in my_addr;
int tmp=0;
int udp_fd;
// signal init, to avoid app quit while pipe broken
// signal(SIGPIPE, SIG_IGN);
if ( (udp_fd = socket( AF_INET, SOCK_DGRAM, 0 )) >= 0 )
{
setsockopt( udp_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
memset(&my_addr, 0, sizeof(my_addr));
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons ((short)port);
my_addr.sin_addr.s_addr = htonl (INADDR_ANY); // get_ifadapter_ip("eth0",NULL);
if (bind ( udp_fd, (struct sockaddr *) &my_addr, sizeof (my_addr)) < 0)
{
close( udp_fd );
udp_fd = -EIO;
}
}
return udp_fd;
}
int sock_udp_send( const char *ip, int port, const void* msg, int len )
{
// SOCKADDR_IN udp_addr;
struct sockaddr_in udp_addr;
int sockfd, ret;
sockfd = socket( AF_INET, SOCK_DGRAM, 0 );
if( sockfd <= 0 ) return -1;
//setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
memset( & udp_addr, 0, sizeof(udp_addr) );
udp_addr.sin_family = AF_INET;
inet_aton( ip, &udp_addr.sin_addr );
udp_addr.sin_port = htons( (short)port );
ret = sendto( sockfd, msg, len, 0, (const struct sockaddr *) & udp_addr, sizeof(udp_addr) );
close( sockfd );
return ret;
}
static sock_read( int fd , char *buf, int maxBuf )
{
return read( fd, buf, maxBuf );
}
int sock_connect( const char *host, int port )
{
struct sockaddr_in destaddr;
struct hostent *hp;
int fd = 0;
memset( & destaddr, 0, sizeof(destaddr) );
destaddr.sin_family = AF_INET;
destaddr.sin_port = htons( (short)port );
if ((inet_aton(host, & destaddr.sin_addr)) == 0)
{
hp = gethostbyname(host);
if(! hp) return -EINVAL;
memcpy (& destaddr.sin_addr, hp->h_addr, sizeof(destaddr.sin_addr));
}
fd = socket(PF_INET, SOCK_STREAM, 0);
if (fd < 0) return -EIO;
if ( connect(fd, (struct sockaddr *)&destaddr, sizeof(destaddr)) < 0 )
{
close( fd );
return -EIO;
}
return fd;
}
static const char* to_b64 =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
/* encode 72 characters per line */
#define CHARS_PER_LINE 72
typedef unsigned char byte;
/* return value:
* >0: encoded string length, -1 buf too small
* Encoded string is terminated by '\0'.
*/
int str_b64enc(const char *src, char *buf, int bufsize )
{
int size = strlen( src );
int div = size / 3;
int rem = size % 3;
int chars = div*4 + rem + 1;
int newlines = (chars + CHARS_PER_LINE - 1) / CHARS_PER_LINE;
int outsize = chars + newlines;
const byte* data = (const byte *)src;
byte* enc = (byte *)buf;
if ( bufsize < outsize + 1 ) return -1;
chars = 0;
while (div > 0)
{
enc[0] = to_b64[ (data[0] >> 2) & 0x3f];
enc[1] = to_b64[((data[0] << 4) & 0x30) + ((data[1] >> 4) & 0xf)];
enc[2] = to_b64[((data[1] << 2) & 0x3c) + ((data[2] >> 6) & 0x3)];
enc[3] = to_b64[ data[2] & 0x3f];
data += 3;
enc += 4;
div--;
chars += 4;
if (chars == CHARS_PER_LINE)
{
chars = 0;
// *(enc++) = '\n'; /* keep the encoded string in single line */
}
}
switch (rem)
{
case 2:
enc[0] = to_b64[ (data[0] >> 2) & 0x3f];
enc[1] = to_b64[((data[0] << 4) & 0x30) + ((data[1] >> 4) & 0xf)];
enc[2] = to_b64[ (data[1] << 2) & 0x3c];
enc[3] = '=';
enc += 4;
chars += 4;
break;
case 1:
enc[0] = to_b64[ (data[0] >> 2) & 0x3f];
enc[1] = to_b64[ (data[0] << 4) & 0x30];
enc[2] = '=';
enc[3] = '=';
enc += 4;
chars += 4;
break;
}
*enc = '\0';
return strlen(buf); // exclude the tail '\0'
}
/*
* decode a base64 encoded string.
* return -1: bufsize too small, \
* 0: string content error,
* > 0: decoded string (null terminated).
*/
int str_b64dec(const char* string, char *buf, int bufsize)
{
register int length = string ? strlen(string) : 0;
register byte* data = (byte *)buf;
/* do a format verification first */
if (length > 0)
{
register int count = 0, rem = 0;
register const char* tmp = string;
while (length > 0)
{
register int skip = strspn(tmp, to_b64);
count += skip;
length -= skip;
tmp += skip;
if (length > 0)
{
register int i, vrfy = strcspn(tmp, to_b64);
for (i = 0; i < vrfy; i++)
{
if (isspace(tmp[i])) continue;
if (tmp[i] == '=')
{
/* we should check if we're close to the end of the string */
if ( (rem = count % 4) < 2 )
/* rem must be either 2 or 3, otherwise no '=' should be here */
return 0;
/* end-of-message recog