/* mdpsniff.c  */
/*
 * This program can be used to monitor mdp multicast packets
 * and provide summary of log of group packet and types
 *
 * This code was written by Joe Macker,  1996
 */
#define MAIN
#include "protocol.h"
#if defined(sgi) || defined (ultrix) || defined (__alpha) || defined(hpux) || defined(__NetBSD__)
#include <sys/ioctl.h>
#else
#include <sys/sockio.h>
#include <sys/filio.h>
#endif
#include "mdpsniff.h"
#include <dirent.h>
#include <fcntl.h>
#include <memory.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <time.h>
#ifdef __NetBSD__
#include <stdlib.h>
#endif

#ifdef direct
#undef direct
#endif direct

static struct sockaddr_in addr;
static int len_addr;
int seed;

void closeall(int);
void resetalrm(), closealrm();
unsigned int recdata();
char *groupadd = NULL;
char *portnum = NULL;
int addr_len=4;
u_long k;
int	heard_nack_flag = FALSE;  /* set only if I heard a nack */
int	request_ack_flag = FALSE; /* set by initialize routine to request Packs */
struct infotype infoclient = {32000,1,15,0};

struct servetype serveFile[MAXFILES];	/* list of multicasted file - carries status */
unsigned long lasttime();		/* latest file date timestamp */
unsigned int stats = FALSE;
unsigned int num_passes = 1;		/* number of passes throught a directory  0-repeat */
char DEFAULT_PORT[] = "37793";
char DEFAULT_HOST[] = "224.2.158.99";

/******************************************************************************/
int main(argc, argv)
int argc;
char **argv;
{
    int dirsel;
    struct key *dir_ptr;
    int i;
    int deleteflag = FALSE;    
    debug=0;
    /* initialize the command line options */
    initialize(argc,argv);
 if (debug) printf("default setting in use multicast %s port %s\n",
	       group,portnum);
	           if ((portnum == NULL) || (group == NULL)) {
        portnum = DEFAULT_PORT;
        groupadd = DEFAULT_HOST;
	if (debug) printf("default setting in use multicast %s port %s\n",
	       groupadd,portnum);
	}
    /* Initializations receive port */
    
    sock=createsocket(portnum,groupadd);
    if (sock < 0) if (debug) printf("Improper port number or IP address assigned\n");
    
/*    fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) | O_NDELAY);*/
    signal(SIGTERM, closeall);  
    
    /* loop forever and receive packets*/
    while(1)
    {    recdata();
    }
}


/******************************************************************************/
/* shutdown everything - close all files */
void closeall(int nop)
{
    /* finished - send end of file marker */
    exit(0);
}


/******************************************************************************/
/* read the configuration file */
int initialize(argc, argv)
int argc;
char *argv[];
{
    
    int i=0;

    infoclient.lastid = -1;
    i = 1;
    while (i < argc) {
	if (*argv[i] == '-') {
	    switch (*(argv[i] + 1)) {
	    case 'd':
		i++;
		debug = atoi(argv[i]);
		break;
	    case 'p':
		/* take the port number */
		i++;
		portnum = argv[i];
		break;
	    case 's':
		/* stats */
		stats=TRUE;
		break;
	    case 'I':
	    case 'i':
		/* change the MULTICAST address */
		i++;
		groupadd = argv[i];
		break;		
	    case 'h':
	    default:	
		printf("snoopmdp [-d <level>] [-p <port>] [-i <ip>] [-s] [-h] \n");	
		exit(0);
	    }
	    i++;
	}
}
} /*end of initialize */


/******************************************************************************/
/* check for multicasted packets received - updates missingbufs */
unsigned int recdata()
{
    /* define received packet types */
    static struct bufdef 	buffer;
    static struct bufid  	*buffer_id;
    static struct bufcmd	*bufcmd_ptr;
    static struct bufmemberdef	*bufmemberdef_ptr;
    static struct servetype 	*fileptr;
    static struct bufstatdef 	*statptr;
    static struct bufmissdef 	*missptr;
    static unsigned long 	*data_ptr;
    static int lr;
    static int i;
    static int forme;
    static struct sockaddr_in srcaddr;
    int retflag = FALSE;
    int srcaddrlen = sizeof(srcaddr);
    memset((char *) &srcaddr, 0, sizeof(srcaddr));
    while ((lr = recvfrom(sock, (char *) &buffer,sizeof(buffer), 0,
			  (struct sockaddr *) &srcaddr,
			  &srcaddrlen)) > 0) {
/* Do time stamp */
    time_t currtime = time(NULL);
    char messtime[80];
    strcpy(messtime,ctime(&currtime));
    messtime[ strlen(messtime) - 6] = NULL;
    if (debug) printf("%s ",messtime);
/* end of time stamp */
	buffer.head.fid = (unsigned short)ntohs(buffer.head.fid);
	switch (buffer.head.type) {
	case BUF_TYPE_NEW_MEM:
	    bufmemberdef_ptr = (struct bufmemberdef *) &buffer;
	    bufmemberdef_ptr->myversion = ntohs(bufmemberdef_ptr->myversion);
	    if (debug) printf("Source %s ver %d New Member\n",inet_ntoa(srcaddr.sin_addr),bufmemberdef_ptr->myversion);
	    break;
	case BUF_TYPE_STAT:
	    statptr = (struct bufstatdef *)&buffer;
	    statptr->packet_recv = ntohs(statptr->packet_recv);
	    statptr->good = ntohs(statptr->good);
	    statptr->bad = ntohs(statptr->bad);
	    statptr->retries = ntohs(statptr->retries);
	    if (stats==TRUE && (!debug)) printf("%s ",messtime);
	    {
	    printf("Source %s id %d STAT flags %x \n  report=(rreq %u prec %u bad %u good %u)\n",
		       inet_ntoa(srcaddr.sin_addr), statptr->head.fid,
		       buffer.head.flags, statptr->retries, statptr->packet_recv,
		       statptr->bad, statptr->good);
	    }
	    break;
	case BUF_TYPE_MISS_REQ:
	case BUF_TYPE_MISS_ANS:
	    /* missing packet requests */
	    missptr = (struct bufmissdef *) &buffer;
	    heard_nack_flag = TRUE;	    

	    missptr->num_requests = (unsigned long) ntohl(missptr->num_requests);
	    /* set the transmit time interval - a crude test */
		if (debug) printf("Source %s id %u MISSING REPORT %d Entries flags %x\n",
		       inet_ntoa(srcaddr.sin_addr),
		       missptr->head.fid,
		       missptr->num_requests,
		       missptr->head.flags);
	    break;
	case BUF_TYPE_DATA:
	    /* data packet incoming */
	    buffer.bytepos = ntohl(buffer.bytepos);
	    if (debug) printf("Source %s id %d DATA pos %d\n",
				  inet_ntoa(srcaddr.sin_addr),
				  buffer.head.fid, buffer.bytepos);
	    break;
	case BUF_TYPE_ID:
	    /* id packet incoming */
	    buffer_id = (struct bufid *) &buffer;
	    if (debug) printf("Source %s id %d ID flags %x\n",
			      inet_ntoa(srcaddr.sin_addr), buffer.head.fid,buffer.head.flags);
	    if (debug > 2)
	    {
		    printf(" file:server  %s\n", &buffer_id->data[0]);
	       
	    }	       	      
	    break;
	case BUF_TYPE_BOMB:
	    if (debug) printf("Source %s BOMB\n",
		   inet_ntoa(srcaddr.sin_addr));
	    closeall(0);
	case BUF_TYPE_REQUEST:
	    buffer.bytepos = ntohl(buffer.bytepos);
	    if (debug) printf("Source %s REQUEST\n",
		   inet_ntoa(srcaddr.sin_addr));
	    break;
	case BUF_TYPE_CMD:
	    bufcmd_ptr = (struct bufcmd *) &buffer;
	    if (debug) 
	    {
	    printf("Source %s id %d ID flags %x\n",
		inet_ntoa(srcaddr.sin_addr), buffer.head.fid,buffer.head.flags);
	    lr -= BUFCMD_SIZE;
	    if (debug > 4) printf("lr = %d \n", lr);
	    if (lr > 0){
	    for (i = 0; i < (lr / 4); i++) {
		printf("%s \n", inet_ntoa((struct in_addr *)bufcmd_ptr->data[0]));
			}
		}
	    }
	    break;
	default:
	    if (debug) printf("rogue packet type %d\n", buffer.head.type);
	    break;
	}	
    }
    return retflag;
}



