⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rc_ctl_data.c

📁 epoll机制的收发程序 只能在2.6内核上使用
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
 * 文 件 名:rc_ctl_data.c
 * 功    能:数据解析部分的函数
 * 作    者:马云龙
 * E_mail : mayunlong21@163.com
 * 开始时间:2007-4-24 9:38
 * 结束时间:2007-4-27 13:13
 * 修改时间:
 */
#include	<stdio.h>
#include	<stdlib.h>
#include	<unistd.h>
#include	<string.h>
#include	<fcntl.h>
#include	<dirent.h>
#include	<errno.h>
#include	<sys/socket.h>
#include	<netinet/in.h>
#include	<arpa/inet.h>     
#include	<sys/time.h>
#include	<time.h>
#include	<signal.h>
#include	<sys/types.h>
#include	<pthread.h>

#include	"rc_pub_define.h"
#include	"rc_pub_type.h"
#include	"rc_pub_path.h"
#include	"rc_pub_packet.h"
#include	"rc_pub_file.h"
#include	"rc_pub_net.h"
#include	"rc_pub_fifo.h"
#include	"rc_pub_time.h"
#include	"rc_pub_log.h"

#include	"rc_ctl_define.h"
#include	"rc_ctl_mysql.h"
#include	"rc_ctl_data.h"
#include	"rc_ctl_table.h"
#include	"rc_ctl_fifo.h"

extern struct_msg_con		*head_con;//链接信息的结构体头指针
extern struct_task_net_w	*task_w_cam;//网络写摄像机任务队列头指针
extern int					port_video;
extern char					ip_video[16];
extern unsigned char		space_delay;//链接间隔

extern pthread_mutex_t		mutex_r_cam;//读摄像机任务队列的互斥锁
extern pthread_mutex_t		mutex_w_cam;//写摄像机任务队列的互斥锁
extern pthread_cond_t		cond_r_cam;//读摄像机任务线程要使用的条件变量
extern pthread_cond_t		cond_w_cam;//写摄像机任务线程要使用的条件变量

extern pthread_mutex_t		mutex_con_t;//摄像机链接链表的互斥锁

extern pthread_mutex_t		mutex_r_atx;//读控件任务队列的互斥锁
extern pthread_mutex_t		mutex_w_atx;//写控件任务队列的互斥锁
extern pthread_cond_t		cond_r_atx;//读控件任务线程要使用的条件变量
extern pthread_cond_t		cond_w_atx;//写控件任务线程要使用的条件变量
extern struct_task_net_r	*task_r_atx;//网络读控件任务队列头指针
extern struct_task_net_w	*task_w_atx;//网络写控件任务队列头指针



int rc_reques_delay_cam(struct_msg_con *ctlinfo);

int rc_reques_data_all_cam(struct_msg_con *ctlinfo);
int rc_deal_web_net(unsigned char *data, int len_d, const unsigned char *serial, struct_lab_mysql *mysql_lab);
int rc_deal_act_net(unsigned char *data, int len_d, struct_msg_con *ctlinfo);
int rc_get_info_ser(unsigned char *ip, unsigned short int *port);
int rc_snd_req_cam(const unsigned char *serial, const unsigned char *ip, unsigned short int port);
int rc_return2ctl_cam(struct_msg_con *ctlinfo, int state, struct sockaddr_in *camsocket, const unsigned char *serip, unsigned short int serport);
int rc_snd_alarm(unsigned short int id, struct_msg_con *ctlinfo);

/*
 * 功  能:向指定的进程发送一个信号
 * 参  数:pid:进程的id
 *         signal:信号值
 *         val:要传递的数值
 * 返回值:成功返回0,否则返回-1
 */
int rc_snd_signal(pid_t pid, int signal, int val)
{
	int					res;
	union sigval		msg;
	
	msg.sival_int = val;
	
	res = sigqueue(pid, signal, msg);
	if(res < 0)
		return -1;
	
	return 0;
}

/*
 * 功  能:解析并处理信息包的数据
 * 参  数:data:从网络接收到的数据
 *         len_d:从网络接收到的数据长度
 *         info_cli:链接相关的信息
 * 返回值:成功返回值大于或者等于0,否则返回值小于0
 * 说  明:如果是与摄像机的链接则创建一个线程用来读管道
 */
int rc_deal_packet_msg(unsigned char *data, int len_d, struct_msg_con *info_cli)
{
	int							total;
	int							res;
	int							type;//包类型
	int							len;
	int							len_s;//序列号的长度
	int							len_sun;//子包的长度
	unsigned char				*tmp_d;
	unsigned short int			id;//id
	unsigned char				type_msg;//信息类型
	
	len_s = strlen(info_cli->serial);
	if(len_s != LEN_SERIAL_CHECK)
		return -1;
	
	tmp_d = data;
	total = 0;
	while(1)
	{
		len_sun = 0;
		memcpy(&len_sun, tmp_d, LEN_LEN_PACKET_CON);
		if(len_sun <= 0)
			break;
		tmp_d += LEN_LEN_PACKET_CON;
		
		type = tmp_d[0];
		tmp_d += LEN_TYPE_PACKET_CON;
		len = len_sun - LEN_TYPE_PACKET_CON;
		
		memcpy(&id, tmp_d, LEN_TYPE_UINT16);
		type_msg = tmp_d[LEN_TYPE_UINT16];
		switch(type)
		{
		case TYPE_P_M_USER://用户信息
			break;
		case TYPE_P_M_FORMAT://格式变化
			break;
		case TYPE_P_M_AREA://检测区域
			break;
		case TYPE_P_M_IO://IO命名
			break;
		case TYPE_P_M_ALARM://主动报警
			res = rc_snd_alarm(id, info_cli);
	//		printf("\t\t ++++++ %s %d res : %d ; id : %u ++++++\n", __FILE__, __LINE__, res, id);
			break;
		default:
			break;
		}
		if((type >= TYPE_P_M_USER) && (type <= TYPE_P_M_ALARM))
			total++;
		tmp_d += len;
	}
	return total;
}

/*
 * 功  能:解析并处理网络部分的数据
 * 参  数:data:从网络接收到的数据
 *         len_d:从网络接收到的数据长度
 *         info_cli:链接相关的信息
 * 返回值:成功返回值大于或者等于0,否则返回值小于0
 * 说  明:如果是与摄像机的链接则创建一个线程用来读管道
 */
int rc_deal_data_net(unsigned char *data, int len_d, struct_msg_con *info_cli)
{
	int							res = 0;
	int							offset;
	int							location;
#ifdef		MYSQL_SAVE_USED_YES
	int							res1 = 0;
#endif
	int							type;//包类型
	int							len;
	int							len_s;//序列号的长度
	int							len_sun;//子包的长度
	unsigned int				len_f;//总的包长度
	unsigned char				*tmp_d;
	unsigned char				version[32];
	
	tmp_d = data;
	len_f = 0;
	memcpy(&len_f, tmp_d, LEN_LEN_PACKET_FATHER);
	tmp_d += LEN_LEN_PACKET_FATHER;
	location = LEN_LEN_PACKET_FATHER;
	
	type = tmp_d[0];
	tmp_d += LEN_TYPE_PACKET_FATHER;
	location += LEN_TYPE_PACKET_FATHER;
	
	switch(type)
	{
	case TYPE_P_F_CTL_CON://连接控制
		break;
	case TYPE_P_F_MSG://信息包
		res = rc_deal_packet_msg(tmp_d, len_f, info_cli);
		if(res < 0)
			return -1;
		return 0;
		break;
	case TYPE_P_F_NODEFINE://无定义
	case TYPE_P_F_AUDIO://声音包
	case TYPE_P_F_VIDEO://视频包
	case TYPE_P_F_TRANSMIT://转发协议
	default:
		return -1;
		break;
	}
	
	/* 下面的是处理链接控制部分的代码 */
	
	
	len_s = strlen(info_cli->serial);
	
	while(1)
	{
		len_sun = 0;
		memcpy(&len_sun, tmp_d, LEN_LEN_PACKET_CON);
		if(len_sun <= 0)
			break;
		tmp_d += LEN_LEN_PACKET_CON;
		location += LEN_LEN_PACKET_CON;
		
		type = tmp_d[0];
		tmp_d += LEN_TYPE_PACKET_CON;
		location += LEN_TYPE_PACKET_CON;
		
		len = len_sun - LEN_TYPE_PACKET_CON;
		switch(type)
		{
		case TYPE_P_C_HEART_ALARM_CLIENT://报警客户端的心跳包类型 7
			res = rc_check_heart(tmp_d);
			if(res < 0)//心跳包不正确
			{
				return -1;
			}
	//		printf("\t\t ====== %s %d ip : %s ; sockfd : %d ; serial : %s ======\n", __FILE__, __LINE__, inet_ntoa(info_cli->address.sin_addr),info_cli->sockfd ,tmp_d);
			if(len_s == LEN_SERIAL_CHECK)
			{
				break;
			}
			
			/* 提取序列号 */
			offset = 0;
			bzero(info_cli->serial, sizeof(info_cli->serial));
			memcpy(info_cli->serial, tmp_d, LEN_SERIAL_CHECK);
#ifdef		MYSQL_USED_YES
			res = rc_check_alarmclient(info_cli->serial);
#else
			res = 1;
#endif
	//		printf("\t\t ====== %s %d res : %d ======\n", __FILE__, __LINE__, res);
			if(res < 0)
				return -1;
			offset += LEN_SERIAL_CHECK;
			info_cli->type = TYPE_CONNECT_ALARM_CLIENT;
			break;
		case TYPE_P_C_HEART_ALARM_HOST://报警主机的心跳包类型 6
		case TYPE_P_C_HEART://摄像机的心跳包类型
			res = rc_check_heart(tmp_d);
			if(res < 0)//心跳包不正确
			{
				return -1;
			}
			printf("\t\t ====== %s %d ip : %s Heart Packet! ======\n", __FILE__, __LINE__, inet_ntoa(info_cli->address.sin_addr));
			if(len_s == LEN_SERIAL_CHECK)
			{
				break;
			}
			
			/* 提取序列号 */
			offset = 0;
			bzero(info_cli->serial, sizeof(info_cli->serial));
			memcpy(info_cli->serial, tmp_d, LEN_SERIAL_CHECK);
			offset += LEN_SERIAL_CHECK;
			
			bzero(&(info_cli->local), sizeof(struct_cam_local));
			
			/* 提取内网ip */
			memcpy(&(info_cli->local.ip.s_addr), tmp_d + offset, LEN_TYPE_UINT32);
			offset += LEN_TYPE_UINT32;
			
			/* 提取子网掩码 */
			memcpy(&(info_cli->local.submask.s_addr), tmp_d + offset, LEN_TYPE_UINT32);
			offset += LEN_TYPE_UINT32;
			
			/* 提取内网的web端口 */
			memcpy(&(info_cli->local.port_web), tmp_d + offset, LEN_TYPE_UINT16);
			offset += LEN_TYPE_UINT16;
			
			/* 从数据库中获得摄像机的外网映射端口 */
#ifdef		MYSQL_USED_YES
			info_cli->local.port_nat = rc_get_port_nat(info_cli->serial);
#else
			info_cli->local.port_nat = 1127;
#endif
			
			/* 提取版本号 */
			bzero(version, sizeof(version));
			memcpy(version, tmp_d + offset, LEN_VERSION);
			
			if(type == TYPE_P_C_HEART)
			{
#ifdef		MYSQL_USED_YES
				res = rc_select_cam_mysql(info_cli->serial, &(info_cli->mysql));
#endif
				info_cli->type = TYPE_CONNECT_CAM;
			}
			else if(type == TYPE_P_C_HEART_ALARM_HOST)
			{
#ifdef		MYSQL_USED_YES
				res = rc_check_alarmhost(info_cli->serial);
#endif
				info_cli->type = TYPE_CONNECT_ALARM_HOST;
			}
			
#ifndef		MYSQL_USED_YES
			res = 1;
#endif
			if(res <= 0)//还没有添加摄像机
			{
				rc_reques_delay_cam(info_cli);
#ifdef		DEBUG_MYL
				printf("========= %s %d No Such camera(%s)! =========\n", __FILE__, __LINE__, info_cli->serial);
#endif
				return -1;
			}
#ifdef		DEBUG_MYL
			printf("\t %s %d serial : %s(ip : %s ; port : %u)\n", __FILE__, __LINE__, info_cli->serial, inet_ntoa(info_cli->address.sin_addr), info_cli->address.sin_port);
#endif
			
#ifdef		MYSQL_SAVE_USED_YES
{
			res = rc_select_serial_mysql(info_cli->serial, &(info_cli->mysql));
			if(res <= 0)
			{
				/* 摄像机信息列表不存在,添加并请求摄像机发送所有数据 */
				res1 = rc_add_ar003_sql(info_cli->serial, version, &(info_cli->mysql), info_cli->logintime);
				if(res1 < 0)//添加摄像机列表出错
				{
#ifdef		DEBUG_MYL
					printf("========= %s %d Add camera error! =========\n", __FILE__, __LINE__);
#endif
					return -1;
				}
				
				res1 = rc_reques_data_all_cam(info_cli);
				if(res1 < 0)//发送请求数据出错
				{
#ifdef		DEBUG_MYL
					printf("====== %s %d Request all data error! ======\n", __FILE__, __LINE__);
#endif
					return -1;
				}
			}
			
			/* 修改摄像机在线状态为在线 */
			res = rc_change_state_cam(&(info_cli->mysql), info_cli->logintime);
			rc_add_log(__FILE__, __FUNCTION__, __LINE__, KEY_LOG_NET, "camera %s(IP : %s) connect ok", info_cli->serial, inet_ntoa(info_cli->address.sin_addr));
}
#endif
			break;
		case TYPE_P_C_EVENT://事件包类型
			break;
		case TYPE_P_C_WEB://网页相关包类型
#ifdef		MYSQL_SAVE_USED_YES
			if((len_s != LEN_SERIAL_CHECK) || (info_cli->type != TYPE_CONNECT_CAM))
				break;//序列号和链接类型不正确
			res = rc_deal_web_net(tmp_d, len, info_cli->serial, &(info_cli->mysql));
#endif
			break;
		case TYPE_P_C_LINK_ASK://链接请求包类型
			rc_add_log(__FILE__, __FUNCTION__, __LINE__, KEY_LOG_NET, "ActiveX %s connect", inet_ntoa(info_cli->address.sin_addr));
			res = rc_deal_act_net(tmp_d, len, info_cli);
			info_cli->type = TYPE_CONNECT_CTL;
			break;
		case TYPE_P_C_RETURN://返回结果包类型
#ifdef		MYSQL_SAVE_USED_YES
			if(len_s != LEN_SERIAL_CHECK)//序列号不正确
				break;
	//		res = rc_deal_return(info_cli->task, info_cli->serial, tmp_d, len, mysql_lab);
#endif
			break;
		default:
			break;
		}
		tmp_d += len;
		location += len;
		if(location >= len_d)
			break;
	}

	return 0;
}

/*
 * 功  能:根据报警的相关信息生成一个xml文档的内容
 * 参  数:msg:要报警的信息
 *         ip:摄像机的外网ip
 *         port:摄像机的外网映射端口
 *         buf:xml的信息缓冲区
 *         size:xml缓冲区大小
 * 返回值:成功返回xml信息的长度,否则返回-1
 */
int rc_xml_alarm(struct_msg_alarm msg, const char *ip, unsigned short int port, char *buf, int size)
{
	int			len;
	char		tmp[256];
	
	
	bzero(buf, size);
	len = 0;
	
	bzero(tmp, sizeof(tmp));
	sprintf(tmp, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n");
	len += strlen(tmp);
	if(len > size)
		return -1;
	strcat(buf, tmp);
	
	bzero(tmp, sizeof(tmp));
	sprintf(tmp, "<alarm>\r\n");
	len += strlen(tmp);
	if(len > size)
		return -1;
	strcat(buf, tmp);
	
	bzero(tmp, sizeof(tmp));
	sprintf(tmp, "<type>%s</type>\r\n", msg.type);
	len += strlen(tmp);
	if(len > size)
		return -1;
	strcat(buf, tmp);
	
	bzero(tmp, sizeof(tmp));
	sprintf(tmp, "<username>%s</username>\r\n", msg.name_user);
	len += strlen(tmp);
	if(len > size)
		return -1;
	strcat(buf, tmp);
	
	bzero(tmp, sizeof(tmp));
	sprintf(tmp, "<telephone>%s</telephone>\r\n", msg.tel);
	len += strlen(tmp);
	if(len > size)
		return -1;
	strcat(buf, tmp);
	
	bzero(tmp, sizeof(tmp));
	sprintf(tmp, "<mobile>%s</mobile>\r\n", msg.mob);
	len += strlen(tmp);
	if(len > size)
		return -1;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -