return to first page linux journal archive
keywordscontents

Listing 1. Multicast Application

/* 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 }