Files
openairinterface5g/openair3/EXAMPLES/MULTICAST_2CHS/REFLECTOR/reflector-forwarding-v4.c
T
2013-06-25 09:05:02 +00:00

638 lines
19 KiB
C

/*******************************/
/* reflector-forwarding-v4m by */
/*******************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <strings.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/signal.h>
#include <sys/param.h>
#include <errno.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <syslog.h>
/* To get ifreq */
#include <arpa/inet.h>
#include <sys/socket.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <limits.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#define _PATH_PROCNET_IFINET6 "/proc/net/if_inet6"
#define MSGBUF_SIZE 32768
#define IFNAMSIZE 11
#define INLINE inline __attribute__((always_inline))
struct ipaddr_str
{
char buf[MAX(INET6_ADDRSTRLEN, INET_ADDRSTRLEN)];
};
int IP_VERSION;
static INLINE const char *ip4_to_string(struct ipaddr_str * const buf, const struct in_addr addr4) { return inet_ntop(AF_INET, &addr4, buf->buf, sizeof(buf->buf)); }
static INLINE const char *ip6_to_string(struct ipaddr_str * const buf, const struct in6_addr * const addr6) { return inet_ntop(AF_INET6, addr6, buf->buf, sizeof(buf->buf)); }
static INLINE const char *sockaddr4_to_string(struct ipaddr_str * const buf, const struct sockaddr * const addr) { const struct sockaddr_in * const addr4 = (const struct sockaddr_in *)addr; return ip4_to_string(buf, addr4->sin_addr); }
int programshutdown (void);
#define NUM_THREADS 200
struct thread_data{
int thread_id;
char interface1[11];
char multicast_addr1[41];
char interface2[11];
char multicast_addr2[41];
int ttl1;
int ttl2;
int port1;
int port2;
};
struct thread_data thread_data_array[NUM_THREADS];
/*******************************************************************
*From net-tools lib/interface.c
*
*******************************************************************/
int
get_ipv6_address(char *ifname, struct sockaddr_in6 *saddr6, int scope_in)
{
char addr6[40], devname[IFNAMSIZE];
char addr6p[8][5];
int plen, scope, dad_status, if_idx;
FILE *f;
struct sockaddr_in6 tmp_sockaddr6;
if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL)
{
while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
addr6p[0], addr6p[1], addr6p[2], addr6p[3],
addr6p[4], addr6p[5], addr6p[6], addr6p[7],
&if_idx, &plen, &scope, &dad_status, devname) != EOF)
{
if (!strcmp(devname, ifname))
{
sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
addr6p[0], addr6p[1], addr6p[2], addr6p[3],
addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
printf( "\t inet6 addr: %s\n", addr6);
printf("\t Scope: %d\n", scope);
if(scope == scope_in)
{
printf( "\tFound GLOBAL addr: %s:%s:%s:%s:%s:%s:%s:%s\n",
addr6p[0], addr6p[1], addr6p[2], addr6p[3],
addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
inet_pton(AF_INET6,addr6,&tmp_sockaddr6);
memcpy(&saddr6->sin6_addr, &tmp_sockaddr6, sizeof(struct in6_addr));
fclose(f);
return 1;
}
}
}
fclose(f);
}
return 0;
}
/*****************************************************/
/* Threaded routine */
/*****************************************************/
void *Reflector(void *threadarg)
{
int ioctl_s;
struct thread_data *my_data;
my_data = (struct thread_data *)threadarg;
struct in_addr multicastaddress_in; //IPv4 multicast address from command line
struct in_addr multicastaddress_out;
struct sockaddr_in6 tmp_saddr6;
struct ifreq ifr;
struct ipaddr_str buf;
int mcdataport4; //IPv4 multicast port 1
int mcdataport; //IPv4 multicast port 2
/*define variables*/
int mcdatarecvfd4; //multicast data receive socket side 1
int mcdatarecvfd; //multicast data receive socket side 2
int sendfd4; //local send socket IPv4 side 1
int sendfd; //local send socket IPv4 side 2
int ttl1; //time to live IPv4 side 1
int ttl2; //time to live IPv4 side 2
struct sockaddr_in mcdataaddr4; //reception IPv4 sockaddr
struct sockaddr_in mcdataaddr; //reception IPv44 sockaddr
char myhostnameipaddress4[20]; // IPv4 reflector's address string
char myhostnameipaddress[20]; // IPv44 reflector's address string
char addressstring4[20]; // IPv4 address string
char addressstring[20]; // IPv44 address string
struct sockaddr_in localsendaddr4; //IPv4 address of outgoing packets interface 1
struct sockaddr_in localsendaddr; //IPv4 address of outgoing packets interface 2
struct sockaddr_in sourceaddr4; //IPv4 address of incoming packets interface 1
struct sockaddr_in sourceaddr; //IPv4 address of incoming packets interface 2
struct ip_mreq mcdatareq4; //IPv4 join group structure
struct ip_mreq mcdatareq; //IPv44 join group structure
int mcdataaddrlen; //IPv4 multicast address length
unsigned int sourceaddrlen; //IPv4 source address length
char mcdatarecvbuf4[MSGBUF_SIZE]; //IPv4 multicast receive buffer
char mcdatarecvbuf[MSGBUF_SIZE]; //IPv44 multicast receive buffer
fd_set readfds; // file descriptors set
int maxfds; // max number of file descriptors
int nfds;
int nr; // number of bytes read with recvfrom
int ns; // number of bytes sent with sendto
int chksrc; // asserts if source address is not the reflector's one
int debugon=1;
int n2;
char inputbuf[32];
/* IPv4 multicast address */
if((inet_pton(AF_INET,my_data->multicast_addr1,&multicastaddress_in.s_addr))!=1){
printf("bad multicast IPv4 address format\n");
exit (1);
}
//printf("multicastaddress side 1 v4 =%s\n",my_data->multicast_addr1);
/* IPv4 multicast address */
if((inet_pton(AF_INET,my_data->multicast_addr2,&multicastaddress_out.s_addr))!=1){
printf("bad multicast IPv4 address format\n");
exit (1);
}
//printf("multicastaddress side 2 v4 =%s\n",my_data->multicast_addr2);
/* IPv4 multicast ports */
mcdataport4 = my_data->port1;
mcdataport = my_data->port2;
/* Time to live for IPv4 multicast */
ttl1 = my_data->ttl1;
/* Time to live for IPv4 multicast */
ttl2 = my_data->ttl2;
IP_VERSION=4;
if (IP_VERSION==4 )//
{
ioctl_s = socket(AF_INET, SOCK_DGRAM, 0);
if (ioctl_s < 0)
{
syslog(LOG_ERR, "ioctl socket: %m");
exit (0);
}
/* INTERFACE 1 */
memset(&ifr, 0, sizeof(struct ifreq));
strncpy(ifr.ifr_name, my_data->interface1, IFNAMSIZE);
/* Check interface address (IPv4) */
if(ioctl(ioctl_s, SIOCGIFADDR, &ifr) < 0)
{
printf( "\tCould not get address of interface 1 - removing it\n");
exit(0);
}
sockaddr4_to_string(&myhostnameipaddress4, &ifr.ifr_addr);
/* INTERFACE 2 */
memset(&ifr, 0, sizeof(struct ifreq));
strncpy(ifr.ifr_name, my_data->interface2, IFNAMSIZE);
/* Check interface address (IPv4) */
if(ioctl(ioctl_s, SIOCGIFADDR, &ifr) < 0)
{
printf( "\tCould not get address of interface 2 - removing it\n");
exit(0);
}
sockaddr4_to_string(&myhostnameipaddress, &ifr.ifr_addr);
}
else
{
/* Global address mode */
int ipv6_addrtype = 0; /* global */
/* Get IPV6 GLOBAL interface address */
memset(&ifr, 0, sizeof(struct ifreq));
strncpy(ifr.ifr_name, my_data->interface2, IFNAMSIZE);
if(get_ipv6_address(ifr.ifr_name, &tmp_saddr6, ipv6_addrtype ) <= 0)
{
printf( "\tCould not find site-local IPv6 address for %s\n", ifr.ifr_name);
}
memset(&ifr, 0, sizeof(struct ifreq));
strncpy(ifr.ifr_name, my_data->interface2, IFNAMSIZE);
// printf("\n Adding interface : %s \n", my_data->interface2);
/* Get IPV6 GLOBAL interface address */
if(get_ipv6_address(ifr.ifr_name, &tmp_saddr6, ipv6_addrtype ) <= 0)
{
printf( "\tCould not find site-local IPv6 address for %s\n", ifr.ifr_name);
}
}
/* Structures initialization */
/*enter the address/port data into the mcdataaddr structure for IPv4*/
bzero((char *) &mcdataaddr4, sizeof(mcdataaddr4));
mcdataaddr4.sin_family=AF_INET;
mcdataaddr4.sin_addr.s_addr = multicastaddress_in.s_addr;
mcdataaddr4.sin_port = htons(mcdataport4);
/*enter the address/port data into the mcdataaddr structure for IPv4*/
bzero((char *) &mcdataaddr, sizeof(mcdataaddr));
mcdataaddr.sin_family=AF_INET;
mcdataaddr.sin_addr.s_addr = multicastaddress_out.s_addr;
mcdataaddr.sin_port = htons(mcdataport);
/*enter the address/port data into the localsendaddr structure for IPv4*/
bzero((char *) &localsendaddr4, sizeof(localsendaddr4));
localsendaddr4.sin_family=AF_INET;
inet_pton(AF_INET, myhostnameipaddress4 , &localsendaddr4.sin_addr.s_addr);
localsendaddr4.sin_port = htons(0);
//LL
// inet_ntop(AF_INET, &localsendaddr4.sin_addr.s_addr,addressstring ,sizeof(addressstring));
// printf("threaded function local sender addr side 1=%s \t",addressstring);
/*enter the address/port data into the localsendaddr structure for IPv4*/
bzero((char *) &localsendaddr, sizeof(localsendaddr));
localsendaddr.sin_family=AF_INET;
inet_pton(AF_INET, myhostnameipaddress , &localsendaddr.sin_addr.s_addr);
localsendaddr.sin_port = htons(0);
//LL
// inet_ntop(AF_INET, &localsendaddr.sin_addr.s_addr,addressstring ,sizeof(addressstring));
// printf("threaded function local sender addr side 2=%s\n", addressstring);
/*enter the address/port data into the mcdatareq structure for IPv4*/
bzero((char *) &mcdatareq4, sizeof(mcdatareq4));
// mcdatareq4.imr_interface.s_addr=htonl(INADDR_ANY); < force to add a multicast route
inet_pton(AF_INET, myhostnameipaddress4 ,&mcdatareq4.imr_interface.s_addr );
mcdatareq4.imr_multiaddr.s_addr=multicastaddress_in.s_addr;
// inet_pton(AF_INET, myhostnameipaddress4 , &mcdatareq4.imr_interface.s_addr);
/*enter the address/port data into the mcdatareq structure for IPv4*/
bzero((char *) &mcdatareq, sizeof(mcdatareq));
inet_pton(AF_INET, myhostnameipaddress ,&mcdatareq.imr_interface.s_addr );
// mcdatareq.imr_interface.s_addr=htonl(INADDR_ANY);
mcdatareq.imr_multiaddr.s_addr=multicastaddress_out.s_addr;
/*get the sendfd socket linked to the first address of the current host */
if ((sendfd4 = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("can't open sendfd socket!");
exit (1);
}
if (bind(sendfd4, (struct sockaddr *) &localsendaddr4, \
sizeof(localsendaddr4)) < 0) {
perror("can't bind localsendaddr v4 to socket!");
exit(1);
}
/*get the sendfd socket linked to the first address of the current host*/
if ((sendfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("can't open sendfd socket!");
exit (1);
}
if (bind(sendfd, (struct sockaddr *) &localsendaddr, \
sizeof(localsendaddr)) < 0) {
perror("can't bind localsendaddr v4 side 2 to socket!");
exit(1);
}
if ((mcdatarecvfd4 = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("can't open mcdatarecvfd4 socket!");
exit(1);
}
/*allow multiple processes per host to read from IPv4 sockets side 2*/
if (setsockopt(mcdatarecvfd4, SOL_SOCKET, SO_REUSEADDR, &mcdataaddr4, sizeof(mcdataaddr4)) < 0) {
perror("SO_REUSEADDR setsockopt v4\n");
}
if (bind(mcdatarecvfd4, (struct sockaddr *) &mcdataaddr4, \
sizeof(mcdataaddr4)) < 0) {
inet_ntop(AF_INET, &mcdataaddr4.sin_addr.s_addr,addressstring ,sizeof(addressstring));
printf("with address of bind %s\n", addressstring);
perror("can't bind mcdataaddr v4 to socket!");
exit(1);
}
if (multicastaddress_out.s_addr!=multicastaddress_in.s_addr)
{
//multicast data receive socket side 2
/*get a mcdatarecvfd socket, bind to address for IPv4*/
if ((mcdatarecvfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("can't open mcdatarecvfd4 socket!");
exit(1);
}
/*allow multiple processes per host to read from IPv4 sockets side 2*/
if (setsockopt(mcdatarecvfd, SOL_SOCKET, SO_REUSEADDR, &mcdataaddr, sizeof(mcdataaddr)) < 0) {
perror("SO_REUSEADDR setsockopt v4\n");
}
if (bind(mcdatarecvfd, (struct sockaddr *) &mcdataaddr, \
sizeof(mcdataaddr)) < 0) {
perror("can't bind mcdataaddr v4 side 2 to socket!");
exit(1);
}
}
else
{
mcdatarecvfd= mcdatarecvfd4;
}
/*set socket options to join multicast group in IPv4*/
if (setsockopt(mcdatarecvfd4, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mcdatareq4,\
sizeof(mcdatareq4)) < 0) {
perror("can't set socket options to join multicast group data v4 side 1!");
exit(1);
}
/*set socket options to join multicast group in IPv4*/
if (setsockopt(mcdatarecvfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mcdatareq,\
sizeof(mcdatareq)) < 0) {
perror("can't set socket options to join multicast group data v4 side 2!");
exit(1);
}
/*now set multicast socket TTL option for IPv4*/
if (setsockopt(sendfd4, IPPROTO_IP, IP_MULTICAST_TTL, \
&ttl1, sizeof(ttl1)) < 0)
perror("can't set multicast ttl v4 socket option!");
/*now set multicast socket TTL option for IPv4*/
if (setsockopt(sendfd, IPPROTO_IP, IP_MULTICAST_TTL, \
&ttl2, sizeof(ttl2)) < 0)
perror("can't set multicast ttl v4 socket option!");
/*define the sizes of the address structures*/
mcdataaddrlen=sizeof(mcdataaddr4);
sourceaddrlen=sizeof(sourceaddr4);
/*start infinite while loop*/
/*and check for activity on sockets*/
/*set up the select sytem call parameters*/
/*zero out the readfds and writefds lists, then add*/
/*the file descriptors of interest*/
while(1) {
FD_ZERO(&readfds);
FD_SET(mcdatarecvfd4, &readfds);
FD_SET(mcdatarecvfd, &readfds);
if (debugon >= 1) {
FD_SET(0, &readfds);
}
maxfds = mcdatarecvfd4 + 5;
/*check for activity*/
nfds = select(maxfds, &readfds, NULL, NULL, NULL);
/*if specified on the command line, check for input on stdin*/
if (debugon >= 1) {
if (FD_ISSET(0, &readfds)) {
n2 = read(0,inputbuf, sizeof(inputbuf));
inputbuf[n2>0? n2-1: 0] = '\0';
if (!strcmp(inputbuf,"q")) {
programshutdown();
}
}
fflush(stdout);
}
/*1:receive from IPv4, send on IPv44 - data*/
if (FD_ISSET(mcdatarecvfd4, &readfds)) {
nr = recvfrom(mcdatarecvfd4, mcdatarecvbuf4, MSGBUF_SIZE, 0, (struct sockaddr *) \
&sourceaddr4, &sourceaddrlen);
if (debugon >= 2){
inet_ntop(AF_INET, &sourceaddr4.sin_addr.s_addr, addressstring4 , sizeof(addressstring4));
printf("\nreading from mcdatarecvfd4, got data from %s\n", addressstring4);
}
if (sourceaddr4.sin_addr.s_addr == localsendaddr4.sin_addr.s_addr){
chksrc = 0;
if (debugon >= 2)
printf("don't retransmit multicastv4 sourced from gateway machine\n");
} else {
chksrc = 1;
if (debugon >= 2)
printf("retransmit to multicast address\n");
}
if (chksrc) {
if (nr < 0)
printf ("mcdatarecvfd4:recvfrom over multicast v4 address error!(1)\n");
/*now send to IPv4*/
if (multicastaddress_out.s_addr != INADDR_ANY) {
if (debugon >= 2) {
inet_ntop(AF_INET, &mcdataaddr.sin_addr.s_addr,addressstring4 ,sizeof(addressstring4));
printf("sending to %s\n", addressstring4);
}
ns = sendto(sendfd, mcdatarecvbuf4, nr, 0, (struct sockaddr *)&mcdataaddr, \
sizeof(mcdataaddr));
} else {
if (debugon >= 2) printf("not resending to ORIGINATOR! or array entry = 0\n");
}
}
}
/*2:receive from IPv4 side 2, send on IPv44 side 1 - data*/
if (FD_ISSET(mcdatarecvfd, &readfds)) {
nr = recvfrom(mcdatarecvfd, mcdatarecvbuf, MSGBUF_SIZE, 0, (struct sockaddr *) \
&sourceaddr, &sourceaddrlen);
if (debugon >= 2){
inet_ntop(AF_INET, &sourceaddr.sin_addr.s_addr, addressstring , sizeof(addressstring));
printf("\nreading from mcdatarecvfd side 2, got data from %s\n", addressstring);
}
if (sourceaddr.sin_addr.s_addr == localsendaddr.sin_addr.s_addr){
chksrc = 0;
if (debugon >= 2)
printf("don't retransmit multicastv4 sourced from gateway machine\n");
} else {
chksrc = 1;
if (debugon >= 2)
printf("retransmit to multicast address side 1\n");
}
if (chksrc) {
if (nr < 0)
printf ("mcdatarecvfd:recvfrom over multicast v4 address error!(1)\n");
/*now send to IPv4*/
if (multicastaddress_in.s_addr != INADDR_ANY) {
if (debugon >= 2) {
inet_ntop(AF_INET, &mcdataaddr4.sin_addr.s_addr,addressstring ,sizeof(addressstring));
printf("sending to %s\n", addressstring);
}
ns = sendto(sendfd4, mcdatarecvbuf, nr, 0, (struct sockaddr *)&mcdataaddr4, \
sizeof(mcdataaddr4));
} else {
if (debugon >= 2) printf("not resending to ORIGINATOR! or array entry = 0\n");
}
}
}
} //end of while loop
}
/*****************************************************/
int
main (argc, argv)
int argc;
char **argv;
{
char interface1[11], interface2[11];
int ttl1; //time to live side1
int ttl2; //time to live side 2
struct couple
{
char multicast_addr1[41]; /* address multicast for the group side 1 */
char multicast_addr2[41]; /* address multicast for the group side 2 */
};
int nb_port_range;
int nb_multicast_couple;
int ip_version, ip_version2;
int displayon=0;
struct couple *multi_group;
int i,j, k, rc,port;
pthread_t threads[NUM_THREADS];
struct port_range
{
int port_begin;
int port_end;
};
struct port_range *prt_range;
if (argc < 12) {
fprintf (stderr, "Error in the syntax\n");
exit(1);
}
strcpy(interface1,argv[1]);
strcpy(interface2,argv[2]);
ip_version= atoi(argv[3]);
ip_version2=atoi(argv[4]);
/* Time to live for IPv4 multicast */
ttl1 = atoi(argv[5]);
/* Time to live for IPv4 multicast */
ttl2 = atoi(argv[6]);
nb_multicast_couple=atoi(argv[7]);
if (nb_multicast_couple !=0)
{
if ((multi_group=(struct couple *)malloc(nb_multicast_couple*sizeof(struct couple)))==NULL)
{
printf("Memory problem to allocate struct couple !\n") ;
exit (1);
}
for (i=0; i <nb_multicast_couple; i++)
{
strcpy(multi_group[i].multicast_addr1,argv[8+2*i]);
strcpy(multi_group[i].multicast_addr2,argv[8+2*i +1]);
}
}
else
{
exit(0);
}
nb_port_range=atoi(argv[8 + nb_multicast_couple*2]);
if (nb_port_range !=0)
{
if ((prt_range=(struct port_range *)malloc(nb_port_range*sizeof(struct port_range)))==NULL)
{
printf("Memory problem to allocate struct port !\n") ;
exit (1);
}
for (i=0; i <nb_port_range; i++)
{
prt_range[i].port_begin= atoi(argv[8+1 + nb_multicast_couple*2+2*i]);
prt_range[i].port_end = atoi(argv[8+1 + nb_multicast_couple*2+2*i +1]);
}
}
else
{
exit(0);
}
k=0;
printf( "Multicast state : for interface %s and interface %s for %d multicast group(s) on %d port range(s) \n", interface1, interface2, nb_multicast_couple, nb_port_range);
for (i=0; i <nb_multicast_couple; i++)
{
for(j=0; j <nb_port_range; j++)
{
for (port= prt_range[j].port_begin; port <=prt_range[j].port_end; port++)
{
strcpy (thread_data_array[k].interface1, interface1);
strcpy (thread_data_array[k].interface2, interface2);
thread_data_array[k].ttl1=ttl1;
thread_data_array[k].ttl2=ttl2;
strcpy (thread_data_array[k].multicast_addr1, multi_group[i].multicast_addr1);
strcpy (thread_data_array[k].multicast_addr2, multi_group[i].multicast_addr2);
thread_data_array[k].thread_id=k;
thread_data_array[k].port1=port;
thread_data_array[k].port2=port;
if (displayon >= 1) printf("Creating thread %d for group %d for port %d\n", k,i ,port);
rc=pthread_create(&threads[k], NULL, Reflector, (void *)&thread_data_array[k]);
if (rc)
{
printf("Error; return code from pthreade_create() is %d\n", rc);
exit(-1);
}
k=k+1;
if (k> NUM_THREADS)
{
printf("Number of created threads over the fixed limited!" );
exit(-1);
}
}
}
}
pthread_exit(NULL);
}
int programshutdown () {
exit (1);
}