因为工作需要,需要对当前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广播包后直接返回对应的数据,没有做过多分析。
代码如下,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;
}