/* ================================================ McastChat.c Kristin Kaeding Multicast and Multithreaded Chat LOGIN AS: McastChat IP must be multicast 224.0.0.0 THRU 239.255.255.255 Ctrl C to quit Enter BYE to logoff ================================================= */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "multicast.h" #define BUFSIZE 4096 int CreateMcastSocket(); void sendMessage(int s); void getMessage(int inSock); void map_mcast_address(char * session_numb); void *Tthread(void* arg); void *Lthread(void* arg); char *GroupIPaddress ="224.4.4.4"; /* multicast group IP address */ char *usrName = "kristin"; int UDPport; /* port number */ u_char LOOP=1, TimeToLive=3; /* ttl value */ int CMcastSock = -1; int SMcastSock = -1; thread_t thridT, thridL; thread_t thrid_main; struct sockaddr peer; int len = sizeof(peer); char *host; int hostlen = sizeof(host); int main(int argc,char *argv[]) { /* parse the command line to get the multicast group address */ switch (argc) { case 4: UDPport = atoi(argv[3]); GroupIPaddress= argv[2]; usrName= argv[1]; break; default: errexit("usage: McastChat \n"); } /*string user name default: kristin */ /*must be multicast default: 224.4.4.4 */ /*udp port number default: 3350 */ /* thr_setoncurrency(10);*/ thrid_main = thr_self(); printf("==================================\n"); printf("Welcome to McastChat\n"); printf("program by Kristin Kaeding\n"); printf("==================================\n"); printf("IP must be multicast\n"); printf("224.0.0.0 THRU 239.255.255.255\n"); printf("==================================\n"); printf("Ctrl C to quit\n"); printf("Enter BYE to logoff\n"); printf("==================================\n"); if ((CMcastSock = socket(PF_INET,SOCK_DGRAM, 0)) < 0) { printf("can't create socket: \n", sys_errlist[errno]); exit(-1); } printf("TALK socket created...\n"); SMcastSock = CreateMcastSocket(UDPport); /* OR SMcastSock = passiveUDP(UDPport); */ printf("LISTEN socket created...\n"); /* LISTEN THREAD: creates socket and calls receivemessage which writes to stdout and receives over mcast group */ thr_create(NULL, 0, &Lthread, (void*) SMcastSock, THR_DETACHED|THR_NEW_LWP, &thridL); thridL = thr_self(); /* TALK THREAD: creates socket and calls sendmessage which reads from stdin and sends over mcast */ thr_create(NULL, 0, &Tthread,(void*) CMcastSock, THR_DETACHED|THR_NEW_LWP, &thridT); thridT = thr_self(); /*waiting for both threads to terminate*/ /*thr_join(thrid_main, (thread_t *)&thridL ,NULL);*/ thr_join(thridT, NULL ,NULL); /*printf("Main Thread exiting...\n");*/ thr_exit((void *)0); } /*=================================== * Talk Thread using CMcastSock *==================================== */ void* Tthread(void* arg) { int CMcastSock; CMcastSock = (int)arg; printf("IN TALK THREAD\n"); setTTLvalue(CMcastSock,&TimeToLive); /* setting theTTL value */ setLoopback(CMcastSock,LOOP); /*0=disable,1=enable loopback; default is enable*/ sendMessage(CMcastSock); close(CMcastSock); thr_exit((void*)0); } /*=================================== * Listen Thread, Lthread using SMcastSock *==================================== */ void* Lthread (void* arg) { int SMcastSock; SMcastSock = (int)arg; printf("IN LISTEN THREAD\n"); joinGroup(SMcastSock, GroupIPaddress); getMessage(SMcastSock); leaveGroup(SMcastSock, GroupIPaddress); close(SMcastSock); thr_exit((void*)0); } /*=================================================================== This functions: allocates a socket for getting the group multicast messages ====================================================================*/ int CreateMcastSocket(int port) { int s,length,err; struct sockaddr_in groupHost; /* multicast group host info structure */ /* Get the multicast group host information */ groupHost.sin_family=AF_INET; groupHost.sin_port=htons(port); /* wildcard address: means it may receive any unicast or multicast pkts destined to this port */ groupHost.sin_addr.s_addr = htonl(INADDR_ANY); /*unicast ot mcast packets*/ /* OR (this is the only part missing in passiveUDP())==> groupHost.sin_addr.s_addr = htonl(inet_addr(GroupIPaddress1)); this way this server is restricted to listen for mcast packets ONLY*/ /* 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 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); } return s; } /* =================================================================== This function reads the input from STDIN and sends it to the group =====================================================================*/ void sendMessage(int sockfd) { int i, bytes=0; struct sockaddr_in dest; char sendBuf[BUFSIZE]; char stdinBuf[BUFSIZE]; char byeBuf[3] = "BYE"; char atBuf[1] = "@"; char format[2] = ": "; int n; /*char *lhost = "hawk";*/ char *hst; /* send the message to the group */ dest.sin_family = AF_INET; dest.sin_port = UDPport; dest.sin_addr.s_addr = inet_addr(GroupIPaddress); /* if((gethostname(&host,hostlen))< 0){ printf("error at gethostname\n"); exit(-1); } memcpy(&host,&lhost,sizeof(host)); */ hst = getenv("HOST"); printf("host is %s \n", hst); while(fgets(stdinBuf, sizeof(stdinBuf), stdin) != NULL) { n = strlen(stdinBuf); stdinBuf[n] = '\0'; if(strncmp("BYE",stdinBuf,3)==0){ sprintf(sendBuf,"%s@%s: %s",usrName,hst,byeBuf); dest.sin_addr.s_addr = inet_addr(GroupIPaddress); if ( sendto(sockfd, sendBuf,strlen(sendBuf),0,(struct sockaddr *) &dest, sizeof(dest)) < 0 ){ printf("error in sendto BYE \n"); exit(-1); } /*exit will kill all threads*/ exit(0); } sprintf(sendBuf,"%s@%s: %s",usrName,hst,stdinBuf); dest.sin_addr.s_addr = inet_addr(GroupIPaddress); if ( sendto(sockfd, sendBuf,strlen(sendBuf),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 INFO ON GETTING PEER NAME: int getpeername(int s, struct sockaddr *name, int *namelen); note: this is unsafe in multithreaded applications. Unsafe intefaces should be called only for the main thread STRUCTURE USED: struct sockaddr { u_char sa_len; u_short sa_family; char sa_data[14]; }; ====================================================================*/ void getMessage(int inSock) { int i,bytes=0; char recvBuf[MAX_LEN]; while(1){ /*==============GET PEER================================ if((getpeername(inSock, &peer, &len)) < 0) { printf("error in getpeername\n"); exit(-1); } =======================================================*/ memset(recvBuf,'\0',MAX_LEN); /*bytes = recv(inSock,recvBuf,MAX_LEN,0);*/ bytes = recvfrom( inSock, recvBuf,MAX_LEN,0, &peer, &len); 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); } } } }