/*mboneuctomcgw program*/ /*version 3*/ /*MBONE UNICAST/MUTLICAST Gateway program.*/ /*This program provides a gateway service*/ /*between a unicast mbone session and a */ /*multicast mbone session.*/ /*This version of the program supports will*/ /*will provide two-way unicast/multicast gateway*/ /*services for a multiple unicast participant over*/ /*a single multicast group*/ /*This requires reading from the unicast socket*/ /*and sending over the multicast socket and */ /*visa-versa.*/ /*The address and port number for the mbone data /*is specified on the command line (with an even port number)*/ /*The program also performs the gateway service for the RTCP*/ /*data which is on the odd numbered port one higher*/ /*than the data*/ /*The select system call is used in order handle socket*/ /*operations asynchronously*/ /*August 19, 1999 -- TWL*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define MSGBUFSIZE 8192 #ifndef MAXHOSTNAMELEN #define MAXHOSTNAMELEN 64 #endif #define MAXUNICASTMEMBERS 32 /*#define TIMEOUTSECS 300 */ #define TIMEOUTSECS 60 #define ACLFILE "bridge.acl" typedef struct uctable{ struct in_addr addr; // address of unicast host int flag; // activity flag; }uctable_t; /* * access list type */ typedef struct acl{ u_long mask; u_long addr; struct acl *next; }acl_t; acl_t *list=NULL; int ucdatatotalbytesrecv = 0; int ucdatatotalbytessent = 0; int ucdatarecvfromcalls = 0; int ucdatasendtocalls = 0; int mcdatatotalbytesrecv = 0; int mcdatatotalbytessent = 0; int mcdatarecvfromcalls = 0; int mcdatasendtocalls = 0; int ucrtcptotalbytesrecv = 0; int ucrtcptotalbytessent = 0; int ucrtcprecvfromcalls = 0; int ucrtcpsendtocalls = 0; int mcrtcptotalbytesrecv = 0; int mcrtcptotalbytessent = 0; int mcrtcprecvfromcalls = 0; int mcrtcpsendtocalls = 0; int maxunicastmem = 0; /* number of current unicast members */ int programshutdown () { printf ("\n"); /*print out debug information*/ printf("number of uc data bytes received = %d\n", ucdatatotalbytesrecv); printf("number of uc data recvfromcalls = %d\n", ucdatarecvfromcalls); printf("number of mc data bytes sent = %d\n", mcdatatotalbytessent); printf("number of mc data sendtocalls = %d\n", mcdatasendtocalls); printf("--------------------------------\n"); printf("number of uc rtcp bytes received = %d\n", ucrtcptotalbytesrecv); printf("number of uc rtcp recvfromcalls = %d\n", ucrtcprecvfromcalls); printf("number of mc rtcp bytes sent = %d\n", mcrtcptotalbytessent); printf("number of mc rtcp sendtocalls = %d\n", mcrtcpsendtocalls); printf("--------------------------------\n"); printf("number of mc data bytes received = %d\n", mcdatatotalbytesrecv); printf("number of mc data recvfromcalls = %d\n", mcdatarecvfromcalls); printf("number of uc data bytes sent = %d\n", ucdatatotalbytessent); printf("number of uc data sendtocalls = %d\n", ucdatasendtocalls); printf("--------------------------------\n"); printf("number of mc rtcp bytes received = %d\n", mcrtcptotalbytesrecv); printf("number of mc rtcp recvfromcalls = %d\n", mcrtcprecvfromcalls); printf("number of uc rtcp bytes sent = %d\n", ucrtcptotalbytessent); printf("number of uc rtcp sendtocalls = %d\n", ucrtcpsendtocalls); exit(0); } int findentrymatch(uctable_t array[MAXUNICASTMEMBERS], struct in_addr *address) { int stopcond = 0; int index; index = maxunicastmem +1; /*figure out if address is in array*/ for (stopcond=0; stopconds_addr) { index = stopcond; stopcond = maxunicastmem +1; } }//end of for return (index); } int printmembers(uctable_t array[MAXUNICASTMEMBERS]) { int stopcond = 0; for (stopcond=0; stopcondnext){ if( (a & p->mask) == p->addr ){ return 1; } } return 0; } void set_acl(char *file){ FILE *in; char line[160],*a=NULL,*m=NULL; acl_t *new; char *s; int skip; in = fopen(file,"r"); if( ! in ){ printf("No %s file found, no ACL set\n",file); return; } printf("ACL is:\n"); while( fgets(line,160,in) ){ a=NULL; m=NULL; skip=0; for(s=line;*s;s++){ /* remove comments */ if( *s == '#' ){ *s='\0'; break; } if( *s == ' ' || *s == '\t' ){ *s='\0'; skip=0; }else{ if( ! a ){ a = s; skip=1; }else{ if( ! m && (skip == 0 )){ m=s; } } } } if( a && m ){ /* found a line with 2 strings */ printf("%s\t%s\n",a,m); new = (acl_t *) malloc(sizeof(acl_t)); if( ! new ){ perror("malloc failed\n"); exit(1); } new->addr=inet_addr(a); if( new->addr == -1 ){ printf("bad address in acl file %s\n",a); exit(1); } new->mask=inet_addr(m); if( new->mask == -1 ){ printf("bad mask in acl file %s\n",m); exit(1); } /* * There are no deny rules only permit so its fine to * build list in reverse order */ new->next=list; list=new; } } fclose(in); } main (argc, argv) int argc; char **argv; { /*define variables*/ int ucdatarecvfd; //unicast data receive socket int mcdatarecvfd; //multicast data receive socket int ucrtcprecvfd; //unicast rtcp receive socket int mcrtcprecvfd; //multicast rtcp receive socket int sendfd; //local send socket u_char ttl; struct sockaddr_in ucdatarecvaddr; struct sockaddr_in ucdatasendaddr; struct sockaddr_in mcdataaddr; struct sockaddr_in ucrtcprecvaddr; struct sockaddr_in ucrtcpsendaddr; struct sockaddr_in mcrtcpaddr; struct sockaddr_in localsendaddr; struct sockaddr_in sourceaddr; struct ip_mreq mcdatareq; int ucdatarecvaddrlen; int mcdataaddrlen; int ucrtcprecvaddrlen; int mcrtcpaddrlen; int sourceaddrlen; char ucdatarecvbuf[MSGBUFSIZE]; char mcdatarecvbuf[MSGBUFSIZE]; char ucrtcprecvbuf[MSGBUFSIZE]; char mcrtcprecvbuf[MSGBUFSIZE]; int mcdataport; int ucdataport; int mcrtcpport; int ucrtcpport; u_long multicastaddress; u_long remoteunicastaddress; int stopcond = 0; int arrayindex = 0; fd_set readfds; int maxfds; int nfds; int nr; int ns; int chksrc; char myhostname[MAXHOSTNAMELEN]; char *myhostnameipaddress; struct hostent *host; int debugon = 0; char addressreadbuf[16]; uctable_t ucmemarray[MAXUNICASTMEMBERS]; int group_member=0; /* are we a member of the multicast group */ int foundindex; int activityflag = 0; int deleteflag = 0; int n2; int timeoutsecs = TIMEOUTSECS; char input; char inputbuf[32]; int timerstatus; struct itimerval timerval, chktimerval; struct timeval tv; /*check command line arguments*/ if (argc < 5) { fprintf (stderr, "Usages: mboneuctomcgw [unicast port] [multicast addrss] [multicast port] [ttl]\n"); fprintf(stderr,"Access list defined in %s file\nas address netmask pairs\n",ACLFILE); exit(1); } /*set signal to catch SIGINT (cntl C) and do special shutdown processing*/ /*not required, since now reading stdin via select call*/ //if (signal(SIGINT, SIG_IGN) != SIG_IGN) // signal(SIGINT, programshutdown); /*set signal to catch SIGUSR1 and do special output processing*/ /*does not work yet*/ //if (signal(SIGUSR1, SIG_IGN) != SIG_IGN) // signal(SIGUSR1, write(1,"got usr1!",strlen("got usr1!"))); /*now read in the command line arguments*/ /*check if port specified on command line is even or odd*/ /*adjust port values so that the data port is the even one*/ /*and the rtcp port is the odd port one higher than the data port*/ if (atoi(argv[1]) % 2 == 0) { ucdataport = atoi(argv[1]); ucrtcpport = atoi(argv[1]) + 1; } else { ucdataport = atoi(argv[1]) - 1; ucrtcpport = atoi(argv[1]); } multicastaddress = inet_addr(argv[2]); if( multicastaddress == -1 ){ printf("Bad multicast address\n"); exit(1); } if (atoi(argv[3]) % 2 == 0) { mcdataport = atoi(argv[3]); mcrtcpport = atoi(argv[3]) + 1; } else { mcdataport = atoi(argv[3]) - 1; mcrtcpport = atoi(argv[3]); } ttl = atoi(argv[4]); if (argv[5] != NULL) { if (!strcmp(argv[5],"d")) { printf("command line operation is on\n"); debugon = 1; } if (!strcmp(argv[5],"d2")) { printf("debug level 2 is on\n"); debugon = 2; } if (!strcmp(argv[5],"d3")) { printf("debug level 3 is on\n"); debugon = 3; } if (!strcmp(argv[5],"d4")) { printf("debug level 4 is on\n"); debugon = 4; } } printf("ucdataport=%d ",ucdataport); printf("ucrtcpport=%d\n",ucrtcpport); printf("multicastaddress=%s ",argv[2]); printf("mcdataport=%d ",mcdataport); printf("mcrtcpport=%d\n",mcrtcpport); //printf("multicastaddress=%d\n",multicastaddress); /*enter the address/port data into the ucdatarecvaddr structure*/ bzero((char *) &ucdatarecvaddr, sizeof(ucdatarecvaddr)); ucdatarecvaddr.sin_family = AF_INET; ucdatarecvaddr.sin_addr.s_addr = htonl(INADDR_ANY); ucdatarecvaddr.sin_port = htons(ucdataport); /*enter the address/port data into the ucdatasendaddr structure*/ bzero((char *) &ucdatasendaddr, sizeof(ucdatasendaddr)); ucdatasendaddr.sin_family = AF_INET; ucdatasendaddr.sin_addr.s_addr = remoteunicastaddress; ucdatasendaddr.sin_port = htons(ucdataport); /*enter the address/port data into the ucdatarecvaddr structure*/ bzero((char *) &ucdatarecvaddr, sizeof(ucdatarecvaddr)); ucdatarecvaddr.sin_family = AF_INET; ucdatarecvaddr.sin_addr.s_addr = htonl(INADDR_ANY); ucdatarecvaddr.sin_port = htons(ucdataport); /*enter the address/port data into the ucdatasendaddr structure*/ bzero((char *) &ucdatasendaddr, sizeof(ucdatasendaddr)); ucdatasendaddr.sin_family = AF_INET; ucdatasendaddr.sin_addr.s_addr = remoteunicastaddress; ucdatasendaddr.sin_port = htons(ucdataport); /*enter the address/port data into the ucrtcprecvaddr structure*/ bzero((char *) &ucrtcprecvaddr, sizeof(ucrtcprecvaddr)); ucrtcprecvaddr.sin_family = AF_INET; ucrtcprecvaddr.sin_addr.s_addr = htonl(INADDR_ANY); ucrtcprecvaddr.sin_port = htons(ucrtcpport); /*enter the address/port data into the ucrtcpsendaddr structure*/ bzero((char *) &ucrtcpsendaddr, sizeof(ucrtcpsendaddr)); ucrtcpsendaddr.sin_family = AF_INET; ucrtcpsendaddr.sin_addr.s_addr = remoteunicastaddress; ucrtcpsendaddr.sin_port = htons(ucrtcpport); /*enter the address/port data into the mcdataaddr structure*/ bzero((char *) &mcdataaddr, sizeof(mcdataaddr)); mcdataaddr.sin_family=AF_INET; mcdataaddr.sin_addr.s_addr = multicastaddress; mcdataaddr.sin_port = htons(mcdataport); /*enter the address/port data into the mcrtcpaddr structure*/ bzero((char *) &mcrtcpaddr, sizeof(mcrtcpaddr)); mcrtcpaddr.sin_family=AF_INET; mcrtcpaddr.sin_addr.s_addr = multicastaddress; mcrtcpaddr.sin_port = htons(mcrtcpport); /*figure out the hostname and get a local ip address*/ if (gethostname(myhostname, MAXHOSTNAMELEN) < 0){ perror("gethostname error"); exit(1); } printf("myhostname=%s\n", myhostname); if((host = gethostbyname(myhostname)) == NULL){ perror("gethostbyname failure!"); exit(1); } myhostnameipaddress = (char *) inet_ntoa(*((struct in_addr *)host->h_addr_list[0])); printf("myhostipaddress=%s\n\n", myhostnameipaddress); /*enter the address/port data into the localsendaddr structure*/ bzero((char *) &localsendaddr, sizeof(localsendaddr)); localsendaddr.sin_family=AF_INET; //localsendaddr.sin_addr.s_addr = htonl(INADDR_ANY); localsendaddr.sin_addr.s_addr = inet_addr(myhostnameipaddress); localsendaddr.sin_port = htons(0); //printf("localsendaddr=%s\n",inet_ntoa(localsendaddr.sin_addr)); /*enter the address/port data into the mcdatareq structure*/ bzero((char *) &mcdatareq, sizeof(mcdatareq)); mcdatareq.imr_multiaddr.s_addr=multicastaddress; mcdatareq.imr_interface.s_addr=htonl(INADDR_ANY); /*get the ucdatarecvfd socket, bind to address*/ if ((ucdatarecvfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { perror("can't open ucdatarecvfd socket!"); exit (1); } if (bind(ucdatarecvfd, (struct sockaddr *) &ucdatarecvaddr, \ sizeof(ucdatarecvaddr)) < 0) { perror("can't bind ucdatarecvaddr to socket!"); exit(1); } /*get the sendfd socket*/ 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 to socket!"); exit(1); } /*get the ucrtcprecvfd socket, bind to address*/ if ((ucrtcprecvfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { perror("can't open ucrtcprecvfd socket!"); exit (1); } if (bind(ucrtcprecvfd, (struct sockaddr *) &ucrtcprecvaddr, \ sizeof(ucrtcprecvaddr)) < 0) { perror("can't bind ucrtcprecvaddr to socket!"); exit(1); } /*get a mcdatarecvfd socket, bind to address */ if ((mcdatarecvfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { perror("can't open mcdatarecvfd socket!"); exit(1); } if (bind(mcdatarecvfd, (struct sockaddr *) &mcdataaddr, \ sizeof(mcdataaddr)) < 0) { perror("can't bind mcdataaddr to socket!"); exit(1); } /*get a mcrtcprecvfd socket, bind to address */ if ((mcrtcprecvfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { perror("can't open mcrtcprecvfd socket!"); exit(1); } if (bind(mcrtcprecvfd, (struct sockaddr *) &mcrtcpaddr, \ sizeof(mcrtcpaddr)) < 0) { perror("can't bind mcrtcpaddr to socket!"); exit(1); } /*now set multicast socket TTL option*/ /*setsocketopt (int filedescriptor, int level, in optname),*/ /*charpointer optvalue, intpointer optlen)*/ if (setsockopt(sendfd, IPPROTO_IP, IP_MULTICAST_TTL, \ &ttl, sizeof(ttl)) < 0){ perror("can't set multicast ttl socket option!"); } /*define the sizes of the address structures*/ ucdatarecvaddrlen=sizeof(ucdatarecvaddr); mcdataaddrlen=sizeof(mcdataaddr); ucrtcprecvaddrlen=sizeof(ucrtcprecvaddr); mcrtcpaddrlen=sizeof(mcrtcpaddr); sourceaddrlen=sizeof(sourceaddr); set_acl(ACLFILE); /*zero out ucmemarray*/ zeroarray(ucmemarray); /*set up timer timeout values, call setitimer*/ /*set interval to 0, will not restart timer as part of timeout processing*/ timerval.it_interval.tv_sec = 0; timerval.it_interval.tv_usec = 0; timerval.it_value.tv_sec = timeoutsecs; timerval.it_value.tv_usec = 0; /*ignore SIGALRM*/ signal(SIGALRM,SIG_IGN); timerstatus = setitimer(ITIMER_REAL, &timerval, (struct itimerval *)0); /*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*/ /* maxfds should be one more than largest fd */ maxfds = 0; if(ucdatarecvfd>maxfds) maxfds = ucdatarecvfd; if(mcdatarecvfd>maxfds) maxfds = mcdatarecvfd; if(ucrtcprecvfd>maxfds) maxfds = ucrtcprecvfd; if(mcrtcprecvfd>maxfds) maxfds = mcrtcprecvfd; maxfds++; while(1) { FD_ZERO(&readfds); FD_SET(ucdatarecvfd, &readfds); FD_SET(mcdatarecvfd, &readfds); FD_SET(ucrtcprecvfd, &readfds); FD_SET(mcrtcprecvfd, &readfds); if (debugon >= 1) { FD_SET(0, &readfds); } /*check for activity and processor accordingly*/ /* * We add a timeout when ther are active unicast sessions so that we * can detect when the last client leaves. Without this we would * need a multicast packet to come in and trigger clearup. * some OS will change the timerval struct so make a new one each time. */ if( maxunicastmem > 0 ){ tv.tv_sec = timeoutsecs; tv.tv_usec = 0; nfds = select(maxfds, &readfds, NULL, NULL, &tv); }else{ 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)); //printf("inputbuf=%s\n",inputbuf); inputbuf[n2>0? n2-1: 0] = '\0'; //input = inputbuf[0]; //printf("stdin input!=%d\n",input); if (!strcmp(inputbuf,"p")) { printf("current unicast members:\n"); printmembers(ucmemarray); } if (!strcmp(inputbuf,"q")) { programshutdown(); } //fflush(stdin); //fflush(stdout); } fflush(stdout); } /*1:receive from unicast, send on multicast and other unicast participants - data*/ if (FD_ISSET(ucdatarecvfd, &readfds)) { //printf("\nready to receive data on ucdatarecvfd!\n"); nr = recvfrom(ucdatarecvfd, ucdatarecvbuf, MSGBUFSIZE, 0, (struct sockaddr *) \ &sourceaddr, &sourceaddrlen); if (debugon >= 2) printf("\nreading from ucdatarecvfd, got data from %s\n", inet_ntoa(sourceaddr.sin_addr)); ucdatarecvfromcalls = ucdatarecvfromcalls + 1; ucdatatotalbytesrecv = ucdatatotalbytesrecv + nr; if (nr < 0){ perror("ucdatarecvfd:recvfrom over unicast address error!(1)\n"); }else{ /*send to all unicast (execpt the one it came from)*/ /*first figure out if sourceaddress is in ucmemarray*/ /*if sourceaddress if local host address, do not update the ucmemarray*/ if (sourceaddr.sin_addr.s_addr != localsendaddr.sin_addr.s_addr) { foundindex = findentrymatch(ucmemarray, &sourceaddr.sin_addr); //printf("sourceaddr=%d\n",sourceaddr.sin_addr.s_addr); //printf("foundindex=%d\n",foundindex); if (foundindex < maxunicastmem) { //printf("found address at ucmemarray[%d]\n",foundindex); /*update activity flag*/ ucmemarray[foundindex].flag = 1; } else { if (debugon >= 2) printf("did not find address in ucmemarray\n"); /*add entry to array*/ if ((maxunicastmem < MAXUNICASTMEMBERS) && is_auth(sourceaddr.sin_addr.s_addr)) { ucmemarray[maxunicastmem].addr.s_addr = sourceaddr.sin_addr.s_addr; ucmemarray[maxunicastmem].flag = 1; maxunicastmem++; printf("\nadding an entry, unicast members are now:\n"); printmembers(ucmemarray); if( ! group_member ){ printf("joining multicast group\n"); /*set socket options to join multicast group*/ /*setsockopt (int filedescriptor, int level, int optname,*/ /* charpointer optvalue, intpointer optlen)*/ if (setsockopt(mcdatarecvfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mcdatareq,\ sizeof(mcdatareq)) < 0) { perror("can't set socket options to join multicast group!"); exit(1); } if (setsockopt(mcrtcprecvfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mcdatareq,\ sizeof(mcdatareq)) < 0) { perror("can't set socket options to join multicast group!"); exit(1); } group_member=1; }else{ printf("already in multicast group\n"); } } else { if(debugon >= 1 ){ printf("Not auth or too many unicast members, can't add another!\n"); } goto skip1; } }//end of else } //end of updating ucmemarray values /*now step thru array and send to all unicast members, except current source*/ for (stopcond=0; stopcond= 2) printf("sending to %s\n", inet_ntoa(ucmemarray[stopcond].addr)); ns = sendto(sendfd, ucdatarecvbuf, nr, 0, (struct sockaddr *)&ucdatasendaddr, \ sizeof(ucdatasendaddr)); } else { if (debugon >= 4) printf("not resending to ORIGINATOR! or array entry = 0\n"); } }//end of for (stopcond=0;.... /*sent to the multicast group*/ if (debugon >= 2) printf("sending to %s\n", inet_ntoa(mcdataaddr.sin_addr)); ns = sendto(sendfd, ucdatarecvbuf, nr, 0, (struct sockaddr *)&mcdataaddr, \ sizeof(mcdataaddr)); mcdatasendtocalls = mcdatasendtocalls + 1; mcdatatotalbytessent = mcdatatotalbytessent + ns; //printf("mcdatatotalbytessent=%d\n", mcdatatotalbytessent); if (ns < 0) perror("sendfd:sendto over multicast address error!(2)\n"); } } skip1: /*2:receive from unicast, send on multicast and other unicast participants - rtcp*/ if (FD_ISSET(ucrtcprecvfd, &readfds)) { //printf("ready to receive data on ucrtcprecvfd!\n"); nr = recvfrom(ucrtcprecvfd, ucrtcprecvbuf, MSGBUFSIZE, 0, (struct sockaddr *) \ &sourceaddr, &sourceaddrlen); if (debugon >= 2) printf("\nreading from ucrtcprecvfd, got data from %s\n", inet_ntoa(sourceaddr.sin_addr)); ucrtcprecvfromcalls = ucrtcprecvfromcalls + 1; ucrtcptotalbytesrecv = ucrtcptotalbytesrecv + nr; //printf("ucrtcptotalbytesrecv=%d\n", ucrtcptotalbytesrecv); if (nr < 0){ perror("ucrtcprecvfd:recvfrom over unicast address error!(3)\n"); }else{ /*send to all unicast (execpt the one it came from)*/ /*first figure out if sourceaddress is in ucmemarray*/ /*if sourceaddress if local host address, do not update the ucmemarray*/ if (sourceaddr.sin_addr.s_addr != localsendaddr.sin_addr.s_addr) { foundindex = findentrymatch(ucmemarray, &sourceaddr.sin_addr); //printf("sourceaddr=%d\n",sourceaddr.sin_addr.s_addr); //printf("foundindex=%d\n",foundindex); if (foundindex < maxunicastmem) { //printf("found address at ucmemarray[%d]\n",foundindex); /*update activity flag*/ ucmemarray[foundindex].flag = 1; } else { if (debugon >= 2) printf("did not find address in ucmemarray\n"); /*add entry to array*/ if ((maxunicastmem < MAXUNICASTMEMBERS) && is_auth(sourceaddr.sin_addr.s_addr)) { ucmemarray[maxunicastmem].addr.s_addr = sourceaddr.sin_addr.s_addr; ucmemarray[maxunicastmem].flag = 1; maxunicastmem++; printf("\nadding an entry, unicast members are now:\n"); printmembers(ucmemarray); if( ! group_member ){ printf("joining multicast group\n"); /*set socket options to join multicast group*/ /*setsockopt (int filedescriptor, int level, int optname,*/ /* charpointer optvalue, intpointer optlen)*/ if (setsockopt(mcdatarecvfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mcdatareq,\ sizeof(mcdatareq)) < 0) { perror("can't set socket options to join multicast group!"); exit(1); } if (setsockopt(mcrtcprecvfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mcdatareq,\ sizeof(mcdatareq)) < 0) { perror("can't set socket options to join multicast group!"); exit(1); } group_member=1; }else{ printf("already in multicast group\n"); } } else { if( debugon >= 1 ){ printf("too many unicast members, can't add another!\n"); } goto skip2; } }//end of else } //end of updating ucmemarray values /*now step thru array and send to all unicast members, except current source*/ for (stopcond=0; stopcond= 2) printf("sending to %s\n", inet_ntoa(ucmemarray[stopcond].addr)); ns = sendto(sendfd, ucrtcprecvbuf, nr, 0, (struct sockaddr *)&ucrtcpsendaddr, \ sizeof(ucrtcpsendaddr)); } else { if (debugon >= 4) printf("not resending to ORIGINATOR! or array entry = 0\n"); } }//end of for (stopcond=0;.... /*sent to the multicast group*/ if (debugon >= 2) printf("sending to %s\n", inet_ntoa(mcrtcpaddr.sin_addr)); ns = sendto(sendfd, ucrtcprecvbuf, nr, 0, (struct sockaddr *)&mcrtcpaddr, \ sizeof(mcrtcpaddr)); mcrtcpsendtocalls = mcrtcpsendtocalls + 1; mcrtcptotalbytessent = mcrtcptotalbytessent + ns; //printf("mcrtcptotalbytessent=%d\n", mcrtcptotalbytessent); if (ns < 0) printf("sendfd:sendto over multicast address error!(4)\n"); } } skip2: /*3:receive from multicast, send on unicast to all unicast participants - data*/ if (FD_ISSET(mcdatarecvfd, &readfds)) { //printf("ready to receive data on mcdatarecvfd!\n"); nr = recvfrom(mcdatarecvfd, mcdatarecvbuf, MSGBUFSIZE, 0, (struct sockaddr *) \ &sourceaddr, &sourceaddrlen); if (debugon >= 2) { printf("\nreading from mcdatarecvfd, got data from=%s\n",inet_ntoa(sourceaddr.sin_addr)); printf("localsendaddr=%s\n",inet_ntoa(localsendaddr.sin_addr)); } if (sourceaddr.sin_addr.s_addr == localsendaddr.sin_addr.s_addr){ chksrc = 0; if (debugon >= 2) printf("don't retransmit multicast sourced from gateway machine\n"); } else { chksrc = 1; if (debugon >= 2) printf("retransmit to unicast addresses\n"); } //printf("chksrc=%d\n", chksrc); if (chksrc != 0 ) { mcdatarecvfromcalls = mcdatarecvfromcalls + 1; mcdatatotalbytesrecv = mcdatatotalbytesrecv + nr; //printf("mcdatatotalbytesrecv=%d\n", mcdatatotalbytesrecv); if (nr < 0) printf ("mcdatarecvfd:recvfrom over multicast address error!(5)\n"); /*now step thru array and send to all unicast members*/ for (stopcond=0; stopcond= 2) printf("sending to %s\n", inet_ntoa(ucmemarray[stopcond].addr)); ns = sendto(sendfd, mcdatarecvbuf, nr, 0, (struct sockaddr *)&ucdatasendaddr, \ sizeof(ucdatasendaddr)); ucdatasendtocalls = ucdatasendtocalls + 1; ucdatatotalbytessent = ucrtcptotalbytessent + 1; }//end of for (stopcond=0;.... }//end of if (chksrc == 0) } /*4:receive from multicast, send on unicast - rtcp*/ if (FD_ISSET(mcrtcprecvfd, &readfds)) { //printf("ready to receive data on mcrtcprecvfd!\n"); nr = recvfrom(mcrtcprecvfd, mcrtcprecvbuf, MSGBUFSIZE, 0, (struct sockaddr *) \ &sourceaddr, &sourceaddrlen); if (debugon >= 2) { printf("\nreading from mcrtcprecvfd, got data from=%s\n",inet_ntoa(sourceaddr.sin_addr)); printf("localsendaddr=%s\n",inet_ntoa(localsendaddr.sin_addr)); } if (sourceaddr.sin_addr.s_addr == localsendaddr.sin_addr.s_addr){ chksrc = 0; if (debugon >= 2) printf("don't retransmit\n"); } else { chksrc = 1; if (debugon >= 2) printf("retransmit to unicast address\n"); } //printf("chksrc=%d\n", chksrc); if (chksrc != 0 ) { mcrtcprecvfromcalls = mcrtcprecvfromcalls + 1; mcrtcptotalbytesrecv = mcrtcptotalbytesrecv + nr; //printf("mcrtcptotalbytesrecv=%d\n", mcrtcptotalbytesrecv); if (nr < 0){ printf ("mcrtcprecvfd:recvfrom over multicast address error!(6)\n"); }else{ /*now step thru array and send to all unicast members*/ for (stopcond=0; stopcond= 2) printf("sending to %s\n", inet_ntoa(ucmemarray[stopcond].addr)); ns = sendto(sendfd, mcrtcprecvbuf, nr, 0, (struct sockaddr *)&ucrtcpsendaddr, \ sizeof(ucrtcpsendaddr)); ucrtcpsendtocalls = ucrtcpsendtocalls + 1; ucrtcptotalbytessent = ucrtcptotalbytessent + 1; }//end of for (stopcond=0;.... } }//end of if (chksrc == 0) } /*5:check for unicast members in array, that may have timed out*/ /*first see i timer has expired*/ getitimer(ITIMER_REAL, &chktimerval); timerstatus = chktimerval.it_value.tv_sec; if (timerstatus == 0) { printf("\ntime to check to see if any unicast members are inactive\n"); timeoutchk(ucmemarray); /*reset timer*/ timerval.it_value.tv_sec = timeoutsecs;; timerstatus = setitimer(ITIMER_REAL, &timerval, (struct itimerval *)0); getitimer(ITIMER_REAL, &chktimerval); timerstatus = chktimerval.it_value.tv_sec; printf("just reset the timer to %d sec\n",timerstatus); printf("current unicast members are now:\n"); printmembers(ucmemarray); if( maxunicastmem == 0 && group_member ){ printf("leaving multicast group\n"); if (setsockopt(mcdatarecvfd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mcdatareq,\ sizeof(mcdatareq)) < 0) { perror("can't set socket options to leave multicast group!"); exit(1); } if (setsockopt(mcrtcprecvfd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mcdatareq,\ sizeof(mcdatareq)) < 0) { perror("can't set socket options to leave multicast group!"); exit(1); } group_member=0; } } } //end of while loop } //end of main