blob: da3ce4ad2b47e28ba0bd446dcec9e8bf7dc78002 [file] [log] [blame]
//
// bjsocket.cpp
// TestTB
//
// Created by Terrin Eager on 10/24/12.
//
//
#define __APPLE_USE_RFC_2292
#include <unistd.h>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <ifaddrs.h>
#include <net/if.h>
#include "bjsocket.h"
#include "bjstring.h"
////////////////////////////
/// BJSocket
///////////////////////////
const BJ_UINT16 BonjourPort = 5353;
BJSocket::BJSocket()
{
socketHandle = 0;
buffer = NULL;
IPVersion = 0;
interfaceID = 0;
}
BJSocket::~BJSocket()
{
}
bool BJSocket::Init()
{
socketHandle = 0;
buffer = (BJ_UINT8*)malloc(MAX_FRAME_SIZE);
if (buffer == NULL)
return false;
//Setup msghdr;
memset(&socketMsghdr, '\0', sizeof(socketMsghdr));
socketMsghdr.msg_name = &peerAddr;
socketMsghdr.msg_namelen = sizeof(peerAddr);
socketMsghdr.msg_iov = socketIovec;
socketMsghdr.msg_iovlen = 1;
socketIovec[0].iov_base = (char *) buffer;
socketIovec[0].iov_len = MAX_FRAME_SIZE;
socketMsghdr.msg_control = socketCmsghdr;
socketMsghdr.msg_controllen = sizeof(socketCmsghdr);
return true;
}
bool BJSocket::CreateListenerIPv4(BJString interfaceName)
{
bool bResult = true;
const int onoptval = 1;
if (socketHandle)
Close();
Init();
if (interfaceName.GetLength() > 0)
interfaceID = if_nametoindex(interfaceName.GetBuffer());
socketHandle = socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP);
// socketHandle = socket(PF_INET,SOCK_DGRAM,IPPROTO_RAW);
if (-1 == setsockopt(socketHandle,SOL_SOCKET,SO_REUSEPORT,&onoptval,sizeof(onoptval)))
{
printf("setsockopt for SO_REUSEPORT failed");
Close();
return false;
}
JoinMulticastv4(interfaceName);
// set PktInfo to get dest address
if (-1 == setsockopt(socketHandle, IPPROTO_IP, IP_PKTINFO, &onoptval, sizeof(onoptval)))
{
printf("setsockopt for IP_PKTINFO failed");
Close();
return false;
}
// bind to socket
struct sockaddr_in sa;
memset(&sa,0,sizeof(sockaddr_in));
sa.sin_len = sizeof(sockaddr_in);
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = INADDR_ANY;
sa.sin_port = htons(BonjourPort);
if (-1 == bind(socketHandle,(struct sockaddr*)&sa,sizeof(sa)))
{
printf("error in bind: %s\n",strerror(errno));
Close();
return false;
}
IPVersion = 4;
return bResult;
}
bool BJSocket::CreateListenerIPv6(BJString interfaceName)
{
bool bResult = true;
const int onoptval=1;
if (socketHandle)
Close();
Init();
if (interfaceName.GetLength() > 0)
interfaceID = if_nametoindex(interfaceName.GetBuffer());
socketHandle = socket(PF_INET6,SOCK_DGRAM,IPPROTO_UDP);
if (-1 == setsockopt(socketHandle,SOL_SOCKET,SO_REUSEPORT,&onoptval,sizeof(onoptval)))
{
printf("setsockopt for SO_REUSEPORT failed");
Close();
return false;
}
JoinMulticastv6(interfaceName);
// set PktInfo to get dest address
if (-1 == setsockopt(socketHandle, IPPROTO_IPV6, IPV6_PKTINFO, &onoptval, sizeof(onoptval)))
{
printf("setsockopt for IP_PKTINFO failed");
Close();
return false;
}
// bind to socket
struct sockaddr_in6 sa6;
memset(&sa6,0,sizeof(sockaddr_in6));
sa6.sin6_len = sizeof(sockaddr_in6);
sa6.sin6_family = AF_INET6;
sa6.sin6_addr = in6addr_any;
sa6.sin6_port = htons(BonjourPort);
if (-1 == bind(socketHandle,(struct sockaddr*)&sa6,sizeof(sa6)))
{
printf("error in bind: %s\n",strerror(errno));
Close();
return false;
}
IPVersion = 6;
return bResult;
}
bool BJSocket::Close()
{
bool bResult = true;
if (socketHandle)
close(socketHandle);
socketHandle = 0;
return bResult;
}
int BJSocket::Read()
{
int nLength = (int) recvmsg(socketHandle, &socketMsghdr,0);
if (!CheckInterface())
return 0;
struct timeval tv;
gettimeofday(&tv, NULL);
m_CurrentFrame.Set(buffer-14-40-8,nLength,tv.tv_sec*1000000ll + tv.tv_usec);
return nLength;
}
BJIPAddr* BJSocket::GetSrcAddr()
{
sourceAddr.Set(&peerAddr);
return &sourceAddr;
}
BJIPAddr* BJSocket::GetDestAddr()
{
struct cmsghdr *cmsg;
for(cmsg = CMSG_FIRSTHDR(&socketMsghdr); cmsg != NULL; cmsg = CMSG_NXTHDR(&socketMsghdr, cmsg))
{
if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO)
{
struct in_pktinfo* pPktInfo = (struct in_pktinfo*)CMSG_DATA(cmsg);
destAddr.Set(&pPktInfo->ipi_addr);
}
if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO)
{
struct in6_pktinfo* pPktInfo = (struct in6_pktinfo*)CMSG_DATA(cmsg);
destAddr.Set(&pPktInfo->ipi6_addr);
}
}
return &destAddr;
}
bool BJSocket::CheckInterface()
{
if (interfaceID ==0)
return true;
struct cmsghdr *cmsg;
bool bFound = false;
for(cmsg = CMSG_FIRSTHDR(&socketMsghdr); cmsg != NULL; cmsg = CMSG_NXTHDR(&socketMsghdr, cmsg))
{
if ((cmsg->cmsg_level == IPPROTO_IP) && cmsg->cmsg_type == IP_PKTINFO)
{
bFound = true;
struct in_pktinfo* pPktInfo = (struct in_pktinfo*)CMSG_DATA(cmsg);
if (pPktInfo->ipi_ifindex == interfaceID)
return true;
else
{
if (pPktInfo->ipi_ifindex != 4)
{
sourceAddr.Set(&peerAddr);
printf("address:%d %s \n",pPktInfo->ipi_ifindex,sourceAddr.GetString());
}
}
}
if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO)
{
bFound = true;
struct in6_pktinfo* pPktInfo = (struct in6_pktinfo*)CMSG_DATA(cmsg);
if (pPktInfo->ipi6_ifindex == interfaceID)
return true;
}
}
if (!bFound)
printf("PKTINFO not found \n");
return false;
}
bool BJSocket::IsMulticastPacket()
{
return GetDestAddr()->IsBonjourMulticast();
}
int BJSocket::GetSockectHandle()
{
return socketHandle;
}
BJ_UINT8* BJSocket::GetBuffer()
{
return buffer;
}
void BJSocket::JoinMulticastv4(BJString interfaceName)
{
if (interfaceName.GetLength() == 0)
{
// join Multicast group
struct ip_mreq imr;
imr.imr_multiaddr.s_addr = inet_addr( "224.0.0.251");
imr.imr_interface.s_addr = INADDR_ANY;
if (-1 == setsockopt(socketHandle, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr)))
{
printf("setsockopt for IP_ADD_MEMBERSHIP failed");
}
return;
}
struct ifaddrs *ifa, *orig;
getifaddrs(&ifa);
orig = ifa;
for ( ; ifa; ifa = ifa->ifa_next)
{
if (interfaceName == ifa->ifa_name && ifa->ifa_addr->sa_family == AF_INET)
{
struct sockaddr_in *ifa_addr = (struct sockaddr_in *)ifa->ifa_addr;
struct ip_mreq imr;
imr.imr_multiaddr.s_addr = inet_addr( "224.0.0.251");
imr.imr_interface.s_addr = ifa_addr->sin_addr.s_addr;
if (-1 == setsockopt(socketHandle, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr)))
{
printf("setsockopt for IP_ADD_MEMBERSHIP failed");
}
}
}
freeifaddrs(orig);
}
void BJSocket::JoinMulticastv6(BJString interfaceName)
{
if (interfaceName.GetLength() == 0)
return;
// join Multicast group
struct in6_addr BonjourMultiaddr = {{{ 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xFB }}};
struct ipv6_mreq i6mr;
memset(&i6mr,0,sizeof(i6mr));
memcpy(&i6mr.ipv6mr_multiaddr, &BonjourMultiaddr, sizeof(BonjourMultiaddr));
if (interfaceName.GetLength() > 0)
i6mr.ipv6mr_interface = interfaceID;
else
i6mr.ipv6mr_interface = __IPV6_ADDR_SCOPE_SITELOCAL;
int err = setsockopt(socketHandle, IPPROTO_IPV6, IPV6_JOIN_GROUP, &i6mr, sizeof(i6mr));
if (err < 0 && (errno != EADDRINUSE))
{
printf("setsockopt for IPV6_JOIN_GROUP failed %d",errno);
}
}
////////////////////////////////////////
// BJSelect
///////////////////////////////////////
BJSelect::BJSelect()
{
FD_ZERO(&socketSet);
maxSocket = 0;
}
bool BJSelect::Add(BJSocket& s)
{
int sock = s.GetSockectHandle();
FD_SET(sock, &socketSet);
if (sock > maxSocket)
maxSocket = sock;
return true;
}
int BJSelect::Wait(int sec)
{
struct timeval tv;
memset(&tv, 0, sizeof(tv));
tv.tv_sec = sec;
int result = select(maxSocket+1, &socketSet, NULL, NULL, &tv);
return result;
}
bool BJSelect::IsReady(BJSocket& Socket)
{
int bIsSet = FD_ISSET(Socket.GetSockectHandle(), &socketSet);
return (bIsSet != 0);
}