// mcast-chat is a proram that read from the STDIN and send to multicast group // to Compile: gcc -g mcast-chat.c multicast.c -o mcast-chat #include "multicast.h" #include /* functions declarations */ int CreateMcastSocket(); void chat(int McastSock); void sendMessage(int inSock, int outSock, int *FLAG); void getMessage(int inSock); void map_mcast_address(char * session_numb); char GroupIPaddress[MAX_LEN];/* multicast group IP address */ int UDPport; /* port number */ u_char TimeToLive; /* ttl value */ struct in_addr localInterface; main(int argc,char *argv[]) { int McastSock; int session_num; /* parse the command line to get the multicast group address */ if (argc != 2) { printf("Usage: chat session_number\n"); exit(1); } else /* just to map an integer to a random ip multicast + port ! */ map_mcast_address(argv[1]); McastSock = CreateMcastSocket(); joinGroup(McastSock, GroupIPaddress); chat(McastSock); leaveGroup(McastSock, GroupIPaddress); close(McastSock); } /* This functions: allocates a socket for getting the group multicast messages */ int CreateMcastSocket() { int s,length,err; u_char loop; /* variable used to enable/disable loopback */ struct sockaddr_in groupHost; /* multicast group host info structure */ /* Get the multicast group host information */ groupHost.sin_family=AF_INET; groupHost.sin_port=htons(UDPport); groupHost.sin_addr.s_addr = htonl(INADDR_ANY); /* Allocate a UDP socket and set the multicast options */ if ((s = socket(PF_INET,SOCK_DGRAM, 0)) < 0) { printf("can't create socket: \n", strerror(errno)); exit(-1); } /* allow multipule processes to bind to same multicast port */ reusePort(s); /* bind the UDP socket to the mcast address to recv messages from the group */ if((bind(s,(struct sockaddr *) &groupHost, sizeof(groupHost))== -1)) { printf("error in bind\n"); exit(2); } /* allow multicast datagrams to be transmitted to any site anywhere value to ttl set according to the value put in "TimeToLive" variable */ setTTLvalue(s,&TimeToLive); /* disable or enable loopback according to value stored in the "loop" variable loopback. a value of 0 means disabling and 1 means enabling loopback by default, loopback is enabled */ loop = 1;/*enable loopback*/ setLoopback(s,loop); return s; } /* This functions takes care of the actual sending and recieving of messages with the group. It takes input from the STDINPUT and sends the message to the group and it reads messages sent by the group from the socket and displays them to the STDOUTPUT */ void chat(int McastSock) { fd_set rfds,rfds_copy; struct timeval wait; int DONE=FALSE,McastOutSock; int len; int nb=0; /* set the bits corresponding to STDIN and the socket to be monitored */ FD_ZERO(&rfds); FD_ZERO(&rfds_copy); FD_SET(0,&rfds); FD_SET(McastSock,&rfds); len = McastSock +1; /* set the monitoring frequency to 1 second */ wait.tv_sec = 0; wait.tv_usec = 5000; if ((McastOutSock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { perror("socket"); exit(1); } printf("type in message to be sent to the group followed by ENTER\n"); printf("hit CTRL-D to quit from the group \n"); /* monitor the socket and STDIN to get/send messages from/to the group */ while(!DONE) { /* bzero(GroupIPaddress,64); memset(GroupIPaddress,'\0',64);*/ memcpy(&rfds_copy, &rfds, sizeof(rfds_copy)); nb = select(len,&rfds_copy,(fd_set *) 0,(fd_set *) 0,&wait); if (nb<0) { printf("error in select \n"); exit(-1); } else if (nb > 0) { if(FD_ISSET(0,&rfds_copy)) {printf("Sending .... \n"); sendMessage(0,McastOutSock,&DONE); } if(FD_ISSET(McastSock,&rfds_copy)) {printf("Receiving ....\n"); getMessage(McastSock);} } } } /* This function reads the input from STDIN and sends it to the group */ void sendMessage(int inSock,int outSock,int *flag) { char sendBuf[MAX_LEN]; int bytes=0; struct sockaddr_in dest; /* bzero(GroupIPaddress,64); memset(GroupIPaddress,'\0',64);*/ /* inSock in STDIN in this case because it is 0 */ bytes = read(inSock,sendBuf,MAX_LEN); if (bytes < 0) { printf("error in reading from STDIN \n"); exit(-1); } else if(bytes == 0) *flag = TRUE; else /* send the message to the group */ { dest.sin_family = AF_INET; dest.sin_port = htons(UDPport); dest.sin_addr.s_addr = inet_addr(GroupIPaddress); // Setting the local interface -- new added requirement localInterface.s_addr = INADDR_ANY; if(setsockopt(outSock, IPPROTO_IP, IP_MULTICAST_IF, (char *)&localInterface, sizeof(localInterface)) < 0) { perror("Setting local interface error"); exit(1); } //printf("Outsock=%d, msg=%s\n; bytes=%d", outSock,sendBuf,bytes); if ( sendto(outSock,sendBuf,bytes,0,(struct sockaddr *) &dest, sizeof(dest)) < 0 ) { printf("error in sendto %s\n", strerror(errno)); exit(-1); } } } /* Get the multicast message sent by the group and print out to STDOUT */ void getMessage(int inSock) { int bytes=0; char recvBuf[MAX_LEN]; bytes = recv(inSock,recvBuf,MAX_LEN,0); if (bytes < 0) { printf("error in reading from multicast socket\n"); exit(-1); } else if(bytes == 0) printf("zero bytes read\n"); else /* print the message to STDOUT */ { if (write(1,recvBuf,bytes) < 0) { printf("error in write to STDOUT \n"); exit(-1); } } } /* This function maps the session number to the multicast address */ void map_mcast_address(char * session_numb) { char s[20]; bzero(GroupIPaddress,64); /*memset(GroupIPaddress,'\0',64);*/ strcpy(GroupIPaddress,MULTICAST_ADDRESS_BASE); strcat(GroupIPaddress,session_numb); UDPport = MULTICAST_PORT_BASE + atoi(session_numb); TimeToLive = DEFAULT_MULTICAST_TTL_VALUE; /* diagnostic message */ fprintf(stderr,"process joining multicast group %s:%d \n", GroupIPaddress, UDPport); }