基于IPv6的Onvif 搜索功能实现

文章目录

  • 1 简单介绍
  • 2 代码
  • 3 效果

1 简单介绍

因为工作需要,需要对当前Onvif增加IPv6支持。于是便先把onvif discovery 部分独立出来先进行测试,看能否在IPv6下搜索发现。

关于IPv4和IPv6这里就不再介绍,相比较于IPv4 Onvif代码,IPv6 Onvif discovrey部分在创建Socket时候讲相关地址设置为IPv6, 广播地址由IPv4的 “239.255.255.250”改为IPv6的本地链路地址“ff02::c”,其它地方则与IPv4相同。

需要注意一点,运行ODT的PC和设备需要有IPv6地址。

代码是简化的代码,只是收到ODT广播包后直接返回对应的数据,没有做过多分析。

2 代码

代码如下,Linux下直接使用gcc编译即可。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include 
#include 
#include 
#include 		/* offsetof */

#define PORT 3702
#define LOCALADDR "fe80::20c:29ff:fed0:12a8"

#define SEDBUF " "\
""\
" "\
"uuid:ce8d3259-bd5d-ab7f-01c5-146b9c65d83c"\
"uuid:%s"\
"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous"\
"http://schemas.xmlsoap.org/ws/2005/04/discovery/ProbeMatches"\
""\
""\
""\
""\
"urn:uuid:ce8d3259-bd5d-ab7f-01c5-146b9c65d83c"\
""\
"dn:NetworkVideoTransmitter tds:Device"\
"onvif://www.onvif.org/Profile/Streaming onvif://www.onvif.org/location/country/china onvif://www.onvif.org/type/video_encoder onvif://www.onvif.org/type/audio_encoder "\
"http://[%s]:2000/onvif/device_service"\
"1"\
""\
""\
""\
""

int onvif_init6()
{
    int opt = 1;
    int loop = 0;
    int addr_len;
    int len = 65535;
    int fd;
    struct sockaddr_in6 addr;
    struct ipv6_mreq mcast;

	fd = socket(AF_INET6, SOCK_DGRAM, 0);
	if (fd <= 0)
	{
		printf("socket SOCK_DGRAM error!\n");
		return 0;
	}

	addr_len = sizeof(addr);

	addr.sin6_family = AF_INET6;
	addr.sin6_addr = in6addr_any;
	addr.sin6_port = htons(PORT);

	if (bind(fd,(struct sockaddr *)&addr,sizeof(addr)) == -1)
	{
		printf("Bind udp socket fail,error = %s\r\n", strerror(errno));
		close(fd);
		return 0;
	}
	
	if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char*)&len, sizeof(int)))
	{
		printf("setsockopt SO_SNDBUF error!\n");
	}

	if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char*)&len, sizeof(int)))
	{
		printf("setsockopt SO_RCVBUF error!\n");
	}

	/* reuse socket addr */
    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&opt, sizeof(opt)))
    {
        printf("setsockopt SO_REUSEADDR error!\n");
    }

    //setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, (char*)&loop, sizeof(loop));
    memset( &mcast, 0, sizeof(struct ipv6_mreq ) );
    inet_pton(AF_INET6,"ff02::c",&mcast.ipv6mr_multiaddr);
    
    mcast.ipv6mr_interface =  htonl(INADDR_ANY);

	if (setsockopt(fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char*)&mcast, sizeof(mcast)) < 0)
	{
		printf("setsockopt IP_ADD_MEMBERSHIP error!%s\n", strerror(errno));
		return 0;
	}

	return fd;
}


int onvif_probe_rx(int fd)
{
    fd_set fdr;
    struct timeval tv;
	struct sockaddr_in6 addr;
    struct sockaddr_in6 addrSnd;
    int addr_len = sizeof(struct sockaddr_in6);
    int rlen,sret;
	char rbuf[1024*10] = {'\0'};
	char sbuf[1024*10] = {'\0'};
	char* tmpBuf = NULL;
	char* tmpBuf2 = NULL;
    char UUID[64] = {0};
    char srcIp[INET6_ADDRSTRLEN] = {0};
    
	FD_ZERO(&fdr);
	FD_SET(fd, &fdr);
    
	tv.tv_sec = 0;
	tv.tv_usec = 100 * 1000;
	sret = select((int)(fd+1), &fdr,NULL,NULL,&tv);
	if (sret == 0)
	{
		return 0;
	}
	else if (sret < 0)
	{
		printf("onvif_probe_rx::select err[%s]\r\n", strerror(errno));
		return -1;
	}
    
    rlen = recvfrom(fd, rbuf, sizeof(rbuf), 0, (struct sockaddr *)&addr, (socklen_t*)&addr_len);
	if (rlen < 0)
	{
		printf("onvif_probe_rx::recvfrom err[%s]\r\n", strerror(errno));
		return -1;
	}
    
    inet_ntop(AF_INET6, &addr.sin6_addr, srcIp, INET6_ADDRSTRLEN);
    printf("------->recv from ip:%s, port:%d, buf:%s\n", srcIp, ntohs(addr.sin6_port), rbuf);
    
    //分析
    if (strstr(rbuf,"Probe") != NULL && (strstr(rbuf,"http://schemas.xmlsoap.org/ws/2005/04/discovery" )!= NULL))
    {
        if (((tmpBuf = strstr(rbuf, "sendbuf is %s\n", sbuf);
        
    }
    
    return 0;
}

int main()
{
    int fd = onvif_init6();
    if (fd <= 0)
    {
        printf("Create Socket error!\n");
    }
    
    while(1)
    {
        onvif_probe_rx(fd);
        usleep(100000);
    }
    
    return 0;
}

3 效果

在Linux下运行程序,然后再PC上运行ODT,选择对应网卡,便可以搜索到Onvif了,效果如下:
基于IPv6的Onvif 搜索功能实现_第1张图片

你可能感兴趣的:(IPv6)