/*
 * receiver - receive network data with error detection.
 *
 * Written by James Warhol  CSc 645  Spring 1995
 *
 * Compile with: cc -o receiver receiver.c chksum.c
 *
 */

#include <fcntl.h>			/* defines open flags */
#include <stdio.h>			/* standard file i/o definitions */
#include <strings.h>			/* string processing definitions */
#include "BUFDEF.h"			/* defines buffer parameters */

/* define chmod modes (which should be defined by include of sys/vnode.h,
   but does not work properly) */

#define VREAD	0400
#define VWRITE	0200

/* define variables */

message msgbuf;				/* message communication buffer */

int i;					/* scratch variable */
int ofn_id;				/* output file descriptor */

/* define function prototypes */

void crash(char line[]);		/* crash on error with message */
void initialize();			/* initialize receiver program */
int validate_packet();			/* verify message packet */

/* main program - receiver */

void main()
{

   int wc;				/* word count for read */

   initialize();			/* initialize receiver program */

   /* read packet of up to BUFSIZE bytes from standard input into message
      buffer; validate it. If packet is valid, write data bytes to the
      output file; if invalid packet, throw it away */

   do { 

      wc = read(0, &msgbuf, BUFSIZE);
      if (wc > 0) {
         if (validate_packet()) { /* if message is valid, write to file */
            i = write(ofn_id, &msgbuf.data, msgbuf.header.len);
            if (i < 0) crash("Unexpected write error in main function.\n");
         }
      }
      else if (wc < 0) 
         crash("Unexpected read error in main function.\n");

   } while (wc == BUFSIZE);

   /* close the output file and terminate receiver */

   if (close(ofn_id) != 0) crash("An error occurred while closing outfile.\n");
   exit(0);
}

/*
 * void crash(char line[]);
 *
 * crash sends the specified error message to standard error and then
 * terminates execution.
 *
 */

void crash(char line[])
{
   i = write(2, line, strlen(line));
   if (i < 0) crash("Unexpected write error in crash function.\n");
   exit(1);
}

/*
 * void initialize();
 *
 * initialize initializes processing for the receiver program.
 * Specifically, this means the output file is opened.
 *
 */

void initialize()
{

   /* open output file and check return status */

   ofn_id = open("outfile", O_WRONLY | O_CREAT | O_TRUNC, VREAD | VWRITE);
   if (ofn_id < 0)
         crash("An unexpected error occurred when opening the output file.\n"); 

   return;
}

/*
 * int validate_packet();
 *
 * validate_packet verifies that the received message packet is correct.
 * Specifically, the checksum is verified to be correct and the sender's
 * initials are confirmed to be as expected.
 *
 * validate_packet returns 1 if the message is valid, and 0 if invalid.
 *
 */

int validate_packet()
{

   short cksum_received;		/* checksum sent with current block */

   /* validate checksum received matches recalculated checksum */

   cksum_received =  msgbuf.header.cksum; /* save transmitted cksum */
   msgbuf.header.cksum = 0;		/* set to zero for recomputation */
   if (cksum_received != (short) in_cksum(&msgbuf, sizeof(msgbuf)))
      return 0; 	/* checksum does not match - return invalid status */

   /* verify that initials sent by sender are what were expected */

   if (msgbuf.header.initials[0] != 'j' ||
       msgbuf.header.initials[1] != 'r' ||
       msgbuf.header.initials[2] != 'w') 
      return 0; 	/* initials are not correct - return invalid status */

   /* packet has been shown to be valid - return valid status */

   return 1;

}

