/* Blank lines have been deleted. * If a numbered line does not fit the * column width, it wraps. */ 9 #include <stdio.h> /* printf(), snprintf() */ 10 #include <stdlib.h> /* strtol(), exit() */ 11 #include <sys/types.h> 12 #include <sys/socket.h> /* socket(), setsockopt(), bind(), recvfrom(), sendto() */ 13 #include <errno.h> /* perror() */ 14 #include <netinet/in.h> /* IPPROTO_IP, sockaddr_in, htons(), htonl() */ 15 #include <arpa/inet.h> /* inet_addr() */ 16 #include <unistd.h> /* fork(), sleep() */ 17 #include <sys/utsname.h> /* uname() */ 18 #include <string.h> /* memset() */ 20 #define MAXLEN 1024 21 #define DELAY 2 22 #define TTL 1 25 int main(int argc, char* argv[]) 26 { 27 u_char no = 0; 28 u_int yes = 1; /* Used with SO_REUSEADDR. In Linux both u_int */ 29 /* and u_char are valid. */ 30 int send_s, recv_s; /* Sockets for sending and receiving. */ 31 u_char ttl; 32 struct sockaddr_in mcast_group; 33 struct ip_mreq mreq; 34 struct utsname name; 36 if ((argc<3) || (argc>4)) { 37 fprintf(stderr, "Usage: %s mcast_group port [ttl]\n", argv[0]); 38 exit(1); 39 } 41 memset(&mcast_group, 0, sizeof(mcast_group)); 42 mcast_group.sin_family = AF_INET; 43 mcast_group.sin_port = htons((unsigned short int)strtol(argv[2], NULL, 0)); 44 mcast_group.sin_addr.s_addr = inet_addr(argv[1]); 46 if ( (send_s=socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 47 perror ("send socket"); 48 exit(1); 49 } 51 /* If ttl supplied, set it */ 52 if (argc == 4) { 53 ttl = strtol(argv[3], NULL, 0); 54 } else { 55 ttl = TTL; 56 } 58 if (setsockopt(send_s, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, 59 sizeof(ttl)) < 0) { 60 perror ("ttl setsockopt"); 61 exit(1); 62 } 64 /* Disable Loop-back */ 65 if (setsockopt(send_s, IPPROTO_IP, IP_MULTICAST_LOOP, &no, 66 sizeof(no)) < 0) { 67 perror ("loop setsockopt"); 68 exit(1); 69 } 71 if ( (recv_s=socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 72 perror ("recv socket"); 73 exit(1); 74 } 76 if (setsockopt(recv_s, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) { 77 perror("reuseaddr setsockopt"); 78 exit(1); 79 } 81 if (bind(recv_s, (struct sockaddr*)&mcast_group,sizeof(mcast_group)) < 0){ 82 perror ("bind"); 83 exit(1); 84 } 86 /* Tell the kernel we want to join that multicast group. */ 87 mreq.imr_multiaddr = mcast_group.sin_addr; 88 mreq.imr_interface.s_addr = htonl(INADDR_ANY); 89 if (setsockopt(recv_s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) { 90 perror ("add_membership setsockopt"); 91 exit(1); 92 } 94 if (uname(&name) < 0) { 95 perror ("uname"); 96 exit(1); 97 } 99 switch (fork()) { 100 case -1: /* Error fork()ing */ 101 perror("fork"); 102 exit(1); 103 case 0: { /* Child -> receive. */ 104 int n; 105 int len; 106 struct sockaddr_in from; 107 char message [MAXLEN+1]; 109 for (;;) { 110 len=sizeof(from); 111 if ( (n=recvfrom(recv_s, message, MAXLEN, 0, 112 (struct sockaddr*)&from, &len)) < 0) { 113 perror ("recv"); 114 exit(1); 115 } 116 message[n] = 0; /* null-terminate string */ 117 printf("%s: Received message from %s.\n", name.nodename, 118 inet_ntoa(from.sin_addr)); 119 printf("\t%s", message); 120 } 121 /* Not reached. */ 122 } 123 default: { /* Parent -> send. */ 124 char message [MAXLEN]; 125 snprintf (message, sizeof(message), "Hi, I'm %s. " 126 "Merry Christmas!\t(TTL==%d)\n", name.nodename, ttl); 127 for (;;) { 128 if (sendto(send_s, message, strlen(message), 0, 129 (struct sockaddr*)&mcast_group, 130 sizeof(mcast_group)) < strlen(message)) { 131 perror("sendto"); 132 exit(1); 133 } 134 sleep(DELAY); 135 } 136 /* Not reached. */ 137 } 138 } 139 /* Not really reached. */ 140 }