Multicasting

·      Receiving Multicast Messages

·      Sending Multicast Message

·      Multicast Control

·      Multicast Examples

·      Displaying Destination Address

·      Binding Options

 

 

 


·      Receiving Multicast Message

For a process to recieve multicast messages it needs to perform the following steps:

ü Create a UDP socket sd

sd = socket (PF_INET,SOCK_DGRAM, 0);

 

ü Bind it to a UDPPort, e.g., 10123.


#define SA      struct  sockaddr;

 

 struct   sockaddr_in   LocalAddress;

 LocalAddress.sin_family = AF_INET;
 LocalAddress.sin_port = htons( UDPPort);
 LocalAddresst.sin_addr.s_addr  =  htonl (INADDR_ANY);

 bind (sd,  (SA *) &LocalAddress, sizeof(LocalAddress));

ü All processes must bind to the same port  UDPPort  in order to receive the multicast messages.

Thus all processes on the same host must execute the following statement before bind.

reusePort (sd);

 

ü Join a multicast IP address MulticatIPAddress ,  e.g., 224.0.0.1

 

joinGroup (sd, MulticastIPAddress);

 

ü Use recv or recvfrom to read the messages, e.g.,

 

nbytes = recv (sd, recvBuf, sizeof(recvBuf), 0);

 

 


Sendinging Multicast Message

For a process to send multicast messages it needs to perform the following. You may use the same UDP socket  sd  for  both sending as well as receiving multicast messages or you can use  a 2nd  udp socket  for sending, it does not have to join any multicast group.

   struct  sockaddr_in    MulticatGroupAddress;

   MulticatGroupAddress.sin_family = AF_INET;
   MulticatGroupAddress.sin_port =  UDPport;
   MulticatGroupAddress.sin_addr.s_addr = inet_addr (MulticatIPAddress);

sendto (sd, sendBuf, Len,0,  (SA *) &MulticastGroupAddress, sizeof(MulticastGroupAddress)) ;

 

 


Control Utility:

 

Join Group:

To join a udp socket sd to multicast IP address in the range: 224.0.0.0 through 239.255.255.255 use:

joinGroup (sd, “224.0.0.1”);

 

Time-to-live:

To control how far a messages can go, e.g., 2 means at most 2 routers away.
 

u_char   TimeToLive;
TimeToLive = 2;

setTTLvalue (sd,  &TimeToLive);


Loop-back:

To allow the process to get a copy of its own transmission we use:

u_char loop;
loop = 1;    // 0 to turn it off

setLoopback (sd,  &loop);

Reuse-port:

To allow multiple multicast processes to run on the same host:

       reusePort (sd);

 

Display Distination Address:

To display destination address of a received packet:

       displayDaddr (sd);

 

 

  

 


Multicast Examples

 

ü Group Chat

Usage: mcastChat <mcastIPAddress>  <port>

        E.g: % mcastChat  224.0.0.22  10022

The program creates one socket used for both sending  and receiving.

It binds the socket to INADDR_ANY (see binding options below)

 

 

 

ü Textbook Example   (chapter 21)

 

      Usage: sendrecv  <maddr>   <port>

        E.g: % sendrecv  224.0.0.33    10123 
  

The program creates two sockets, one for sending and the other for receiving.

Note that the main program uses the wrapper function:

http://www.cs.odu.edu/~cs779/stevens2nd/lib/udp_client.c

To bind the receive socket to the mcast address (see binding options below)

 

 

 


Displaying Destination Address

 

msghdr structure:

 

Description: msgHeader

 

êExample: DisplayDistAddr.c

 

struct msghdr   mhdr;
struct iovec    iov;
char            data[8192];
char            cdata[sizeof(struct sockaddr_in) + sizeof(struct cmsghdr)];
struct cmsghdr *cmsg;
struct sockaddr_in from;
socklen_t       fromlen = sizeof(struct sockaddr_in);
struct in_addr  ip_addr;
struct cmsghdr *cmptr;
char            str[32];


int
main(int argc, char **argv)
{

 
int             echo_s;
   struct sockaddr_in laddr;
   int             ret;
   int             loop;

   if (argc < 2) {
         printf("usage: udpServerDaddr <group IP> <local_port>\n");
         exit(0);
   }
  echo_s = socket(AF_INET, SOCK_DGRAM, 0);
 
reusePort(echo_s);

  bzero(&laddr, sizeof(laddr));
  laddr.sin_family = AF_INET;
  laddr.sin_port = htons(atoi(argv[2]));
  if (
bind(echo_s, (struct sockaddr *) & laddr, sizeof(laddr)) < 0) {
       perror("bind error");
       exit(1);
  }
 
displayDaddr(echo_s);

 
joinGroup(echo_s, argv[1]);

  loop = 0;
 
setLoopback(echo_s, loop);


  while (1) {

     /*  using recvmsg &  sendmsg */
        printf("\n.... Using recvMSG & sendMSG ....\n");
      
init_mhdr();


       if ((ret =
recvmsg(echo_s, &mhdr, MSG_WAITALL)) < 0) {
            perror("recvmsg()");
       }
       printf("received:");
       fflush(stdout);
       write(1, data, ret);
      
display_addr();

       iov.iov_len = ret;
       if (
sendmsg(echo_s, &mhdr, MSG_DONTWAIT) < 0) {
            perror("sendmsg()");
            exit(-1);
       }
       
/*  using recvfrom & sendto */
        printf("\n.... Using recvFROM & sendTO ....\n");
       if ((ret =
recvfrom(echo_s, data, sizeof(data), 0,
            (SA *) & from, &fromlen)) < 0) {
            perror("recvfrom");
       }
       printf("received:");
       fflush(stdout);
       write(1, data, ret);
       printf("udp message sent  from: %s:%d\n",
             inet_ntop(AF_INET, &from.sin_addr, str, sizeof(str)),
            ntohs(from.sin_port));

       if (
sendto(echo_s, data, ret, 0, (SA *) & from, fromlen) < 0) {
            printf("error in sendto\n");
            exit(-1);
       }
  }
}
void
init_mhdr()
{
  bzero(cdata, sizeof(cdata));
  bzero(&mhdr, sizeof(mhdr));
  mhdr.msg_name = &from;
  mhdr.msg_namelen = fromlen;
  mhdr.msg_iov = &iov;
  mhdr.msg_iovlen = 1;
  mhdr.msg_control = cdata;
  mhdr.msg_controllen = sizeof(cdata);
  iov.iov_base = data;
  iov.iov_len = sizeof(data);
  cmsg = (struct cmsghdr *) cdata;
}

void
display_addr()
{
  for (cmptr = CMSG_FIRSTHDR(&mhdr); cmptr != NULL;
       cmptr = CMSG_NXTHDR(&mhdr, cmptr)) {
       if (cmptr->cmsg_level == IPPROTO_IP &&
           cmptr->cmsg_type == IP_RECVDSTADDR) {
            memcpy(&ip_addr, CMSG_DATA(cmptr), sizeof(struct in_addr));
            printf("udp message sent  to: %s\n",
                    inet_ntop(AF_INET, &ip_addr, str, sizeof(str)));
            printf("udp message sent  from: %s:%d\n",
                    inet_ntop(AF_INET, &from.sin_addr, str,
                      sizeof(str)), ntohs(from.sin_port));
       }
  }
}

 

 

To test:

 

·       Server:

%  cd   ~/mcastChat

%  DisplayDistAddr   224.0.0.1  10123

 

·       Client:

%  cd   ~/mcastChat
%  mcastChat    224.0.0.1   10123

 

 

Notice

 

If both programs runs at the same host and DisplayDistAddr starts first,

then a message typed by mcastChat will be echoed back to the same port.

Only one process gets it (the one that starts first, DisplayDistAddr) and that will

cause infinite message circulation.

 

 

 

 


 Binding  Options:

 

BindChoice.c

 

 

main (int argc, char *argv[])

{

 

  struct sockaddr_in LocalHost;

  int UDPsocket;

 

 

  if (argc != 4)

    {

      printf ("Usage: BindChoice <multicast ip> <port> <-l|-u|-m|-a>\n");

      printf ("e.g.: BindChoice 224.0.0.1 10123 -a\n");

      exit (1);

    }

 

  bzero(&LocalHost, sizeof(LocalHost));

 

  if (strcmp (argv[3], "-a") == 0)

    {

      printf ("Using INADDR_ANY\n");

      LocalHost.sin_addr.s_addr = htonl (INADDR_ANY);

    }

  else if (strcmp (argv[3], "-m") == 0)

    {

      printf ("Using MCAST ADDR: %s\n", argv[1]);

      LocalHost.sin_addr.s_addr = inet_addr (argv[1]);

    }

  else if (strcmp (argv[3], "-l") == 0)

    {

      printf ("Using LOCAL ADDR: %s\n", "127.0.0.1");

      LocalHost.sin_addr.s_addr = inet_addr ("127.0.0.1");

    }

  else if (strcmp (argv[3], "-u") == 0)

    {

      getIPaddress ();

      printf ("Using UNICAST ADDR: %s\n", UnicastIPaddress);

      LocalHost.sin_addr.s_addr = inet_addr (UnicastIPaddress);

    }

 

  MulticastIPAddress = argv[1];

  UDPport = htons (atoi (argv[2]));

 

  LocalHost.sin_family = AF_INET;

  LocalHost.sin_port = UDPport;

 

 

  if ((UDPsocket = socket (AF_INET, SOCK_DGRAM, 0)) < 0)

    {

      printf ("can't create UDP socket: \n");

      exit (-1);

    }

  reusePort (UDPsocket);

 

  if (bind (UDPsocket, (SA *) & LocalHost, sizeof (LocalHost)) < 0)

    {

      printf ("error in bind\n");

      exit (-1);

    }

  TimeToLive = 2;

  setTTLvalue (UDPsocket, &TimeToLive);

 

  loop = 1;               /* enable loopback */

  setLoopback (UDPsocket, loop);

 

  joinGroup (UDPsocket, argv[1]);

 

  if (fork () == 0)

    sendMessage (0, UDPsocket);

  getMessage (UDPsocket, 1);

}

 

……

 

Option :

-a  : Binding to INADDR_ANY  receives both multicast and unicast messages.

-m : Binding to MCAST ADDR  receives only multicast messages.

-l   :  Binding to LOCAL ADDR receives only unicast messages from local host

-u  : Binding to UNICAST ADDR receives only unicast messages from other hosts.

 

 

Example Usage:

 

·       Server: (run at antraes,128.82.4.98)

%  cd   ~/mcastChat

%  BindChoice   224.0.0.1  10123 -a

 

·       Clients: (run at antraes,128.82.4.98)

%  cd   ~/mcastChat
%  mcastChat    224.0.0.1   10123

 

%  cd   ~/SocketProgramming/c
%  UDPClient1  127.0.0.1    10123

 

%  UDPClient1  128.82.4.98  10123

 

 

& Try other options and different hosts