📄 rc_ctl_data.c
字号:
/*
* 文 件 名: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 + -