/*
NAME: mchat
SYNOPSIS: mchat
DESCRIPTION: The program creates a udp socket S bind it to port number
300DD and joins multicast ip address 225.0.0.DD.
The program uses select to:
read input from stdin and send it to S &
read chat data from S and send it to stdout
Example: mchat 22
*/
#include "multicast.h"
/* functions declarations */
int CreateMcastSocket();
void chat(int McastSock);
void sendMessage(int inSock,int outSock,int *FLAG);
void getMessage(int inSock, int outSock);
void map_mcast_address(char * session_numb);
char GroupIPaddress[MAX_LEN]; /* multicast group IP address */
int UDPport; /* port number */
u_char TimeToLive; /* ttl value */
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: mchat session_number\n");
printf("e.g.: mchat 22\n");
exit(1);
}
else
/* assign mcast group and port number for the session */
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", sys_errlist[errno]);
exit(-1);
}
/** allow multiple processes to bind to same multicast port on the same host */
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 loopback and
a value of 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/receiving
of messages to/from 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;
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 = 1;
wait.tv_usec = 0;
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)
{
#if defined(SUNOS4) || defined(IRIX5)
bcopy(&rfds,&rfds_copy,len);
#elif defined(SOLARIS2)
memcpy(&rfds_copy,&rfds,len);
#endif
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))
sendMessage(0,McastSock,&DONE);
if(FD_ISSET(McastSock,&rfds_copy))
getMessage(McastSock, 1);
}
}
}
/*
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;
#if defined(SUNOS4) || defined(IRIX5)
bzero(sendBuf,MAX_LEN);
#elif defined(SOLARIS2)
memset(sendBuf, '\0', MAX_LEN);
#endif
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 = UDPport;
dest.sin_addr.s_addr = inet_addr(GroupIPaddress);
if ( sendto(outSock, sendBuf,bytes,0,
(struct sockaddr *) &dest, sizeof(dest)) < 0 )
{
printf("error in sendto \n");
exit(-1);
}
}
}
/*
Get the multicast message sent by the group and print out to STDOUT
*/
void getMessage(int inSock, int outSock)
{
int bytes=0;
char recvBuf[MAX_LEN];
#if defined(SUNOS4) || defined(IRIX5)
bzero(recvBuf,MAX_LEN);
#elif defined(SOLARIS2)
memset(recvBuf,'\0',MAX_LEN);
#endif
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(outSock,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];
#if defined(SUNOS4) || defined(IRIX5)
bzero(GroupIPaddress,64);
#elif defined(SOLARIS2)
memset(GroupIPaddress,'\0',64);
#endif
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);
}