/*

 * u_mctest.c            (c) Bob Quinn           2/4/97
 *
 * Released to the public domain
 *
 * Description:
 *  Tries out BSD-compatible Multicast APIs, and sends multicast 
 *  messages in response to multicast messages received.  
 */

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "declarations.h"

#define BUFSIZE   1024
#define TTL_VALUE 2
//#define TEST_ADDR "234.5.6.7"
//#define TEST_PORT 3456
#define LOOPMAX   10000

int main()
{
  struct sockaddr_in stLocal, stTo, stFrom;
  char achIn[BUFSIZE];
  char achOut[] = "Message number:              ";
  int s, i;
  struct ip_mreq stMreq;
  int iTmp, iRet;


  /* get a datagram socket */
  s = socket(AF_INET, 
     SOCK_DGRAM, 
     0);
  if (s == -1) {
    perror("socket() failed\n");
    exit(1);
  }

  /* avoid EADDRINUSE error on bind() */ 
  iTmp = 1;
  iRet = setsockopt(s, 
     SOL_SOCKET, 
     SO_REUSEADDR, 
     (char *)&iTmp, 
     sizeof(iTmp));
  if (iRet == -1) {

     perror("setsockopt1() failed\n");
  }

  /* name the socket */
  stLocal.sin_family = 	 AF_INET;
  stLocal.sin_addr.s_addr = htonl(INADDR_ANY);
  stLocal.sin_port = 	 htons(TEST_PORT);
  iRet = bind(s, (struct sockaddr*) &stLocal, sizeof(stLocal));
  if (iRet == -1) {
      perror("bind() failed\n");
  }

  /* join the multicast group. */
  stMreq.imr_multiaddr.s_addr = inet_addr(TEST_ADDR);
  stMreq.imr_interface.s_addr = INADDR_ANY;
  iRet = setsockopt(s, 
     IPPROTO_IP, 
     IP_ADD_MEMBERSHIP, 
     (char *)&stMreq, 
     sizeof(stMreq));
  if (iRet == -1) {
      perror("setsockopt2() failed\n");
  } 

  /* set TTL to traverse up to multiple routers */
  /*
  iTmp = TTL_VALUE;
  iRet = setsockopt(s, 
     IPPROTO_IP, 
     IP_MULTICAST_TTL, 
     (char *)&iTmp, 
     sizeof(iTmp));
  if (iRet == -1) {
      perror("setsockopt3() failed\n");
  }
  */
  /* disable loopback */
  /*
  iTmp = 0;
  iRet = setsockopt(s, 
     IPPROTO_IP, 
     IP_MULTICAST_LOOP, 
     (char *)&iTmp, 
     sizeof(iTmp));
  if (iRet == -1) {
      perror("setsockopt4() failed\n");
  }
  */
  /* assign our destination address */
  stTo.sin_family =      AF_INET;
  stTo.sin_addr.s_addr = inet_addr(TEST_ADDR);
  stTo.sin_port =        htons(TEST_PORT);
  #ifdef DEBUG_MCRECV
    printf ("Now sending to (and receiving from) multicast group: %s\n", TEST_ADDR);
  #endif  

  for (i=0;i<LOOPMAX;i++) {
    int addr_size = sizeof(struct sockaddr_in);
    static iCounter = 1;

    /* send to the multicast address */
    sprintf(&achOut[16], "%d", iCounter++);
    iRet = sendto(s,
      achOut,
      sizeof(achOut),
      0,
      (struct sockaddr*)&stTo, 
      addr_size);
    if (iRet < 0) {
      perror("sendto() failed\n");
      exit(1);
    }

    iRet = recvfrom(s, 
      achIn, 
      BUFSIZE, 
      0,
      (struct sockaddr*)&stFrom, 
      &addr_size);
    if (iRet < 0) {
      perror("recvfrom() failed\n");
      exit(1);
    }
    #ifdef WARN_MCRECV
      printf("From host:%s port:%d, %s\n", inet_ntoa(stFrom.sin_addr), ntohs(stFrom.sin_port), achIn);
    #endif  
  } /* end for(;;) */

} /* end main() */ 
