#include <stdio.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>

int       SEND = 0, RECEPT = 0, TTL=1;
short int PORT = 31416;
in_addr_t ADDRMULTICAST;
int       len = 16;
int perreur(char *s)
{
  perror( s );
  exit( 1 );
}
//mark=args
int args(int argc, char* argv[])
{
  char *optliste = "a:p:rs:t:h";
  int   opt;
  while ( ( opt = getopt(argc, argv, optliste )) >=0 ) {
	    switch ( opt ){
	    case 'a' : ADDRMULTICAST  = inet_addr(optarg); break;
	    case 's' : SEND   = atoi(optarg);              break;
            case 'r' : RECEPT = 1;                         break; 
	    case 't' : TTL =    atoi(optarg);              break;
	    case 'p' : PORT   = atoi(optarg);              break;
	    case 'h' : printf("\nusage %s : %s", argv[0], optliste);
	    default  : return 0;
	    }
	  }
return 1;
}
//mark=emission
//kwds=setsockopt
void  emission( int sock )
{  char bfr[ 1024 ]="\nhello !";
  int  nb;
  struct sockaddr_in adr;
  unsigned char LOOP = 1; 
  memset( & adr, 0, sizeof( struct sockaddr_in) );  
  adr.sin_family       = AF_INET;
  adr.sin_addr.s_addr  = ADDRMULTICAST;
  adr.sin_port         = htons(PORT); 
  if ( setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, &TTL, sizeof(TTL)) < 0 )
    perreur("ttl");;
  // le groupe recoit aussi en local :
  if ( setsockopt( sock , IPPROTO_IP, IP_MULTICAST_LOOP, &LOOP, sizeof(LOOP)) < -1 )
        perreur("loop");

   while ( SEND-- ) {
      nb = sendto(sock, bfr, 1024, 0, (struct sockaddr *)&adr, len);
      if ( nb <= 0 ) {
	if ( nb ) perror("send");
	break;
      }
      sleep(1);
  }
}
//mark=reception
//kwds=setsockopt
void  reception( int sock )                                                
{ char bfr[ 1024 ];
  int  nb;
  int reuse = 1;
  unsigned int len;
  struct ip_mreq rm;
  struct sockaddr_in adr;
  
  // plusieurs processus entre par sock :
  if ( setsockopt( sock , SOL_SOCKET, SO_REUSEADDR, (int *)&reuse, sizeof(reuse)) < 0 )
   perreur("reusing problem");
   memset( & rm, 0, sizeof( struct ip_mreq) ); 
  rm.imr_multiaddr.s_addr = ADDRMULTICAST;
  rm.imr_interface.s_addr = htonl( INADDR_ANY);
  if ( setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, & rm, sizeof( struct ip_mreq )) < 0 )
    perreur("opt");

  memset( & adr, 0, sizeof( struct sockaddr_in) );  
  adr.sin_family       = AF_INET;
  adr.sin_addr.s_addr  = htonl(INADDR_ANY);
  adr.sin_port         = htons(PORT);
  //  
  if ( bind(sock,  (struct sockaddr*) & adr, len ) < 0 )
    perreur("bind");
  // joindre le groupe :
 
  len = sizeof( adr );
  while ( 1 ) {
    //nb = recv(sock, bfr, 1024, 0 );
      nb = recvfrom(sock, bfr, 1024, 0, (struct sockaddr *)& adr, &len);

      if ( nb > 0 ) printf("%s", bfr);
      else printf("\nerreur!");
      fflush(stdout);
  }
}
//mark=main
//kwds=reception, emission
int  main( int argc, char* argv[] )                                         
{ 
  int sock;
  
  ADDRMULTICAST = inet_addr( "224.1.2.3"); // adresse par defaut
 
  if ( (sock = socket(PF_INET, SOCK_DGRAM, 0 )) < 0  )
    perreur("socket");

  if ( ! args( argc, argv ) ) exit( 1 ); 

  if ( RECEPT ) reception( sock );
  if ( SEND   )  emission( sock ); 
  
  close(sock);
  return 0;
}
// cut
