/* $Header: /home/cobweb3/surendar/networks/RCS/sendrecv.c,v 2.2 1993/09/02 23:13:18 surendar Exp $ */

/*
 * Module:	This module supports the basic send/recv operations used
 *		interncally to  communicate between the various layers
 * Author:	$Author: surendar $ 
 * 		Dept. of Computer Sciences 
 * 		Worcester Polytechnic Institute. 
 * Date:	$Date: 1993/09/02 23:13:18 $ 
 */

/* 
 * $Log: sendrecv.c,v $
 * Revision 2.2  1993/09/02  23:13:18  surendar
 * Latest Version
 *
 * Revision 2.1  1993/01/29  08:09:07  surendar
 * Assignment II release
 *
 * Revision 1.3  1993/01/20  06:16:49  surendar
 * Need to timeout even if we're only polling
 *
 * Revision 1.2  1993/01/14  19:07:36  surendar
 * Checked in for Assignment I
 * 
 */

#ifndef lint
static char rcs_ident[] = "$Header: /home/cobweb3/surendar/networks/RCS/sendrecv.c,v 2.2 1993/09/02 23:13:18 surendar Exp $";
#endif /* lint */

#include	<stdio.h>
#include	<sys/types.h>
#include	<sys/time.h>
#include	<sys/param.h>
#include	<sys/socket.h>
#include	<sys/un.h>
#include	<sys/stat.h>
#include	<fcntl.h>
#include	<errno.h>

#if HAVE_STRING_H
#include	<string.h>
#endif  /* HAVE_STRING_H */

#if HAVE_STDARG_H
#include	<stdarg.h>
#endif /* HAVE_STDARG_H */

#include	"defs.h"
#include	"extern.h"

extern long timer_reset;

/*
 * ====================================================================
 *
 * Function: \section{__send}
 *
 * Arguments: layer [ For error checking only ]
 * 	   fd    Descriptor to send data to.
 * 	   buf   Actual buffer to send
 * 	   len   Len of data in buf.
 * Return:  err_t 
 *
 * Description: This function is used for sending data across layers. Each
 * layer is a separate process and so data is sent through UNIX protocol
 * sockets. 
 *
 * ===================================================================
 */
err_t
    __send(layer_t layer, long fd, void *buf, size_t len)
{
    if (fd < 0)			/* fd not open yet? */
	fatal("Illegal fd");

    if (cur_layer != layer || buf == NULL || fd < 0) /* What is this?? */
	return(nerrno = E_Inappr);

    if (write(fd, &len, sizeof(len)) != sizeof(len)) /* First send the
							length of data  and
							then send the data
							as there is no way
							to send reliable
							End of Record */
	return(nerrno = Failure);

    if (write(fd, buf, len) != len) /* Send the actual data */
	return(nerrno = Failure);
    else
	return(Success);
}


/*
 * ====================================================================
 *
 * Function: \section{__recv}
 *
 * Arguments: layer - [ For debugging purposes only ]
 * 	   fd    - fid to recieve from
 * 	   data	 - Data is read into a allocated buffer. This buffer will be
 * 		 allocated using malloc() and the calling function should take 
 * 		 care to call free() when done with the data.	  
 * 	   len	 - Length of the data read in would be filled in,
 * 	   delay - (microseconds wait for a message)
 * Return:	   error status
 *
 * Description: This function reads in data from the layer above.
 *
 * ===================================================================
 *
 */
err_t
    __recv(layer_t layer, long fd, void **data, size_t *len, long delay)
{
    fd_set readfds;
    struct timeval timeout;
    int ret_value;
    
    if (fd < 0)			/* Not opened yet? */
	fatal("Illegal fd");
    
				/* Some error checking */
    if (cur_layer != layer || len == NULL || data == NULL || fd < 0) 
	return(nerrno = E_Inappr);
    
    if (cur_layer == Datalink && timer_reset == 1)
	return(timer_reset = 0, nerrno = E_Noack);
    
    /* Poll to see if any data left */
    FD_ZERO(&readfds);
    FD_SET(fd, &readfds);
    timeout.tv_sec = delay / 1000000; /* Isolate the seconds part */
    timeout.tv_usec = delay % 1000000; /* Isolate the micro seconds part */
    if ((ret_value = select(GETDTABLESIZE,
			    &readfds,
			    NULL,
			    NULL,
			    (delay < 0) ? NULL : &timeout)) == 0)
	{
	    char buf[132];

	    if (delay > 0)
		{
		    sprintf(buf, "Select timed out after %d", delay);
		    log(10, buf);
		}
	    return(nerrno = E_Nodata);
	}

    if (ret_value < 0)		/* Select failed, why? */
	/* return(Failure); */
	{
	    if (errno == EINTR && cur_layer == Datalink && timer_reset == 1)
		return(timer_reset = 0, nerrno = E_Noack);
	    fatal("Select failed");
	}
    
    /* Only if read a EOF */
    if ((ret_value = read(fd, len, sizeof(size_t))) < 0) /* Only if not EOF */
	/*return(E_Nodata);*/
	fatal("Read error");

    if (ret_value == 0)		/* EOF */
	{
	    log(10, "Read error of length");
	    exit(0);
	}
    
    if ((*data = (void *) malloc (*len)) == NULL)
	fatal("Dynamic memory exhausted");
    
    if (read(fd, *data, *len) != *len) /* Read in the actual length of data */
	/* return(E_Nodata); */
	fatal("Read error");

    return(Success);
}

