/*
 * The Spread Toolkit.
 *     
 * The contents of this file are subject to the Spread Open-Source
 * License, Version 1.0 (the ``License''); you may not use
 * this file except in compliance with the License.  You may obtain a
 * copy of the License at:
 *
 * http://www.spread.org/license/
 *
 * or in the file ``license.txt'' found in this distribution.
 *
 * Software distributed under the License is distributed on an AS IS basis, 
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 
 * for the specific language governing rights and limitations under the 
 * License.
 *
 * The Creators of Spread are:
 *  Yair Amir, Michal Miskin-Amir, Jonathan Stanton.
 *
 *  Copyright (C) 1993-2002 Spread Concepts LLC <spread@spreadconcepts.com>
 *
 *  All Rights Reserved.
 *
 * Major Contributor(s):
 * ---------------
 *    Cristina Nita-Rotaru crisn@cnds.jhu.edu - group communication security.
 *    Theo Schlossnagle    jesus@omniti.com - Perl, skiplists, autoconf.
 *    Dan Schoenblum       dansch@cnds.jhu.edu - Java interface.
 *    John Schultz         jschultz@cnds.jhu.edu - contribution to process group membership.
 *
 */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sp.h"

#define	MAX_BYTES	100000

static	char	User[80];
static	char	Spread_name[80];
static	char	Private_group[MAX_GROUP_NAME];
static	mailbox	Mbox;
static	int	Num_bytes;
static	int	Num_messages;
static	int	Read_only, Write_only;

static	void	Usage( int argc, char *argv[] );
static  void    Print_help();

int main( int argc, char *argv[] )
{
	int		ret;
	int		service_type, num_groups;
	char		ret_groups[5][MAX_GROUP_NAME];
	char		sender[MAX_GROUP_NAME];
	char            mess[MAX_BYTES] ;
	char            recv_mess[MAX_BYTES] ;
	int16		dummy_mess_type;
	int		dummy_endian_mismatch;
	int		i;

	Usage( argc, argv );

	/* connecting to the relevant Spread daemon, no need for group info */
	printf("flooder: connecting to %s\n", Spread_name );
        ret = SP_connect( Spread_name, User, 0, 0, &Mbox, Private_group ) ;
        if(ret < 0) 
	{
		SP_error( ret );
                exit(1) ;
        }
	/* 
	 * Joining the process group.
	 *
	 * Note that this is not necessary in order to multicast the
	 * messages, but only to demonstrate end-to-end behaviour.
	 */
	if( Read_only )
	{
		printf("flooder: Only receiving messages\n");
		SP_join( Mbox, "flooder" );
	}else if( Write_only ) {
		printf("flooder: starting  multicast of %d messages, %d bytes each (self discarding).\n", Num_messages, Num_bytes);
	}else{
		SP_join( Mbox, "flooder" );
		printf("flooder: starting  multicast of %d messages, %d bytes each.\n", Num_messages, Num_bytes);
	}
	for( i=1; i <= Num_messages; i++ )
	{
		/* multicast a message unless Read_only */
		if( !Read_only )
		{
		    ret = SP_multicast( Mbox, RELIABLE_MESS, "flooder", 0, Num_bytes, mess );
		    if( ret != Num_bytes ) 
		    {
			if( ret < 0 )
			{
				SP_error( ret );
				exit(1);
			}
			printf("sent a different message %d -> %d\n", Num_bytes, ret );
		    }
		}

		/* receive a message (Read_only) or one of my messages */
		if( Read_only || ( i > 200 && !Write_only ) )
		{
		    do{
                        service_type = 0;

			ret = SP_receive( Mbox, &service_type, sender, 5, &num_groups, ret_groups, 
					  &dummy_mess_type, &dummy_endian_mismatch, sizeof(recv_mess), recv_mess );
                        if( ret < 0 ) 
                        {
                                if ( (ret == GROUPS_TOO_SHORT) || (ret == BUFFER_TOO_SHORT) ) {
                                        service_type = DROP_RECV;
                                        printf("\n========Buffers or Groups too Short=======\n");
                                        ret = SP_receive( Mbox, &service_type, sender, 5, &num_groups, ret_groups, 
                                                          &dummy_mess_type, &dummy_endian_mismatch, sizeof(recv_mess), recv_mess );
                                }
                        }
                        
			if( ret < 0 )
			{
				SP_error( ret );
				exit(1);
			}
		    } while( strcmp( sender, Private_group ) != 0  && !Read_only );
		}

		/* report some progress... */
		if( i%1000 == 0 ) printf("flooder: completed %6d messages of %d bytes\n",i, ret);
	}
	printf("flooder: completed multicast of %d messages, %d bytes each.\n", Num_messages, Num_bytes);

	return 0;
}

static  void    Usage(int argc, char *argv[])
{

	/* Setting defaults */
        sprintf( User, "flooder" );
        sprintf( Spread_name, "4803@localhost");
	Num_bytes    =  1000;
	Num_messages = 10000;
	Read_only    = 0;
	Write_only   = 0;

        while( --argc > 0 )
        {
                argv++;

                if( !strncmp( *argv, "-u", 2 ) )
                {
                        if (argc < 2) Print_help();
                        strcpy( User, argv[1] );
                        argc--; argv++;
                }else if( !strncmp( *argv, "-b", 2 ) ){
                        if (argc < 2) Print_help();
			sscanf(argv[1], "%d", &Num_bytes );
                        argc--; argv++;
                }else if( !strncmp( *argv, "-m", 2 ) ){
                        if (argc < 2) Print_help();
			sscanf(argv[1], "%d", &Num_messages );
                        argc--; argv++;
                }else if( !strncmp( *argv, "-s", 2 ) ){
                        if (argc < 2) Print_help();
                        strcpy( Spread_name, argv[1] ); 
                        argc--; argv++;
                }else if( !strncmp( *argv, "-ro", 3 ) ){
				Read_only  = 1;
				Write_only = 0;
                }else if( !strncmp( *argv, "-wo", 3 ) ){
				Write_only = 1;
				Read_only  = 0;
                }else{
                    Print_help();
                }
	}
}
static  void    Print_help()
{
    printf( "Usage: flooder\n%s\n%s\n%s\n%s\n%s\n%s\n",
            "\t[-u <user name>]     : unique (in this machine) user name",
            "\t[-m <num messages>]  : number of messages",
            "\t[-b <num bytes>]     : number of bytes per message 1-100,000",
            "\t[-s <spread name>]   : either port or port@machine",
            "\t[-ro]   		: read  only (no multicast)",
            "\t[-wo]   		: write only (no receive)");
    exit(1);
}
