/* This is the standard '#include' file for the cnet simulator.
   This file may change at any time to correct any problems which are detected.

   DO NOT COPY this file, simply #include it into your cnet protocol files.

   Last modified: Sat Jun 24 08:44:34 WST 2000
 */

#if	!defined(_CNET_H)
#define	_CNET_H

#define	CNET_VERSION		"cnet v1.6"


#include <stdio.h>

#define	MAX_NODENAME_LEN	32	/* len including terminating NULL */
#define	K			1024
#define	MAX_MESSAGE_SIZE	(8 * K)	/* largest msg (in bytes) that will be
					   generated by the Application Layer */

#define	LOOPBACK		0
#define	ALLNODES		(0xFFFFFFFF)

typedef unsigned long		CnetAddr;
typedef long			CnetData;
typedef enum			{ NT_HOST, NT_ROUTER }	CnetNodetype;

typedef	long			CnetTimer;
#define	NULLTIMER		(CnetTimer)0L



/* -------- these global variables should be considered READ-ONLY -------- */


typedef	struct {
    CnetNodetype  nodetype;	  /* Either a NT_HOST or a NT_ROUTER */
    int		  nodenumber;	  /* Ranging from 0.._NNODES-1 */
    CnetAddr	  address;	  /* Possibly different to the nodenumber */
    char	  *nodename;
    int		  nlinks;	  /* Ranging from 0(=LOOPBACK) .. nlinks */
    int		  minmessagesize; /* min size (in bytes) of msgs generated */
    int		  maxmessagesize; /* max size (in bytes) of msgs generated */
    int		  messagerate;	  /* rate of msg generation (in ms) */
    long	  time_in_ms;	  /* a monotonically increasing clock */
    struct {
	long	  sec;
	long	  msec;
    }		  time_of_day;	  /* a reflection of the wall-clock time */
} CnetNodeinfo;

extern	CnetNodeinfo	nodeinfo;
extern	int		NNODES;		/* only divulged with  cnet -N */


typedef struct {
    int         linkup;			/* Boolean: true if link not severed */
    int         bandwidth;		/* in bits per second */
    int         propagationdelay;	/* in ms */
    int         transmitbufsize;	/* in bytes */
    int         costperbyte;		/* in cents(?) */
    int         costperframe;		/* in cents(?) */
} CnetLinkinfo;

extern  CnetLinkinfo *linkinfo;	/* linkinfo[0]..linkinfo[nodeinfo.nlinks] */




/* ------ these enumerated values should be used (and not changed!) ----- */


typedef enum {
    EV_NULL = 0,	/* this event is never raised. */
    EV_REBOOT,		/* raised as reboot_node(EV_REBOOT, ... , ...) */
    EV_SHUTDOWN,	/* raised before cnet is (cleanly) terminated */

    EV_APPLICATIONREADY,/* raised when there is a msg ready for delivery */
    EV_PHYSICALREADY,	/* raised when a frame arrives at one of the links */
    EV_KEYBOARDREADY,	/* raised when a line entered from the keyboard */
    EV_LINKSTATE,	/* raised when a link changes state (up or down) */

    EV_DEBUG1,	EV_DEBUG2,	EV_DEBUG3,	EV_DEBUG4,	EV_DEBUG5,

    EV_TIMER1,	EV_TIMER2,	EV_TIMER3,	EV_TIMER4,	EV_TIMER5,
    EV_TIMER6,	EV_TIMER7,	EV_TIMER8,	EV_TIMER9,	EV_TIMER10
} CnetEvent;

typedef enum {
    ER_OK = 0,		/* No error */
    ER_BADARG,		/* Invalid argument passed to a function */
    ER_BADEVENT,	/* Invalid event passed to a function */
    ER_BADLINK,		/* Invalid link number passed to a function */
    ER_BADNODE,         /* Invalid node passed to a function */
    ER_BADSENDER,	/* Application Layer given msg from an unknown node */
    ER_BADSESSION,	/* Application Layer given msg from incorrect session */
    ER_BADSIZE,		/* Indicated length is of incorrect size */
    ER_BADTIMER,	/* Invalid CnetTimer passed to a function */
    ER_CORRUPTDATA,	/* Attempt to transfer corrupt data */
    ER_LINKDOWN,	/* Attempt to transmit on a link that is down */
    ER_NOTFORME,	/* Application Layer given a msg for another node */
    ER_NOTREADY,	/* Function called when service not available */
    ER_NOTSUPPORTED,	/* Invalid operation for this node type */
    ER_OUTOFSEQ,	/* Application Layer given msg out of sequence */
    ER_TOOBUSY		/* Function is too busy/congested to handle request */
} CnetError;


#define	N_CNET_DEBUGS	 5
#define	N_CNET_ERRORS	16
#define	N_CNET_EVENTS	22
#define	N_CNET_TIMERS	10

extern	CnetError	cnet_errno;
extern	char		*cnet_evname[], *cnet_errname[], *cnet_errstr[];


/* -------- Functions for communicating with the network and timers ----- */


extern	int CNET_set_handler(CnetEvent ev, void (*handler)(), CnetData data);

	/* Register handler as the void ``returning'' function to be invoked
	   when the event ev occurs. When the handler is invoked, it will
	   be passed the event, a timer and the user-specified data. */

extern	int CNET_get_handler(CnetEvent ev, void (**handler)(), CnetData *data);

	/* Obtains the address of the void ``returning'' function which will
	   be invoked when the indicated event occurs, together with the
	   user-specified data value that will be passed to the handler. */

extern	int CNET_read_application(CnetAddr *destaddr, char *msg, int *len);

	/* On invocation, len will point to an integer indicating the maximum
	   number of bytes that may be copied into msg.  On return, len will
	   point to an integer now indicating the number of bytes copied into
	   msg.  The address of the required destination node is copied
	   into destaddr. */

extern	int CNET_write_physical(int link, char *frame, int *len);

	/* Passes a number of bytes, pointed to by frame ``down to'' the
	   physical layer which will attempt to deliver them on the indicated
	   link (wire).  Each node has a fixed number of links, the first
	   available link is number 1, the second is number 2, and so on.
	   As a special case, a node may reliably transmit a frame to itself
	   by requesting the loopback link, number 0.  On invocation, len will
	   point to an integer indicating the number of bytes to be taken from
	   frame. On return, len will point to an integer now indicating the
	   number of bytes accepted by the physical layer. */

extern	int CNET_write_physical_reliable(int link, char *frame, int *len);

	/* CNET_write_physical_reliable() performs an identical function to
	   CNET_write_physical() but will never introduce any corruption or
	   loss (thus providing a reliable datalink layer). */

extern	int CNET_write_direct(CnetAddr destaddr, char *frame, int *len);

	/* CNET_write_direct() performs identically to
	   CNET_write_physical_reliable() although the address of the required
	   destination node must be specified (providing a reliable network
	   layer).  All directly written frames arrive on link 1 in the
	   destination.  */

extern	int CNET_read_physical(int *link, char *frame, int *len);

	/* Accepts the specified maximum number of bytes from the physical
	   layer, placing them in the address pointed to by frame.
	   On invocation, len will point to an integer indicating the maximum
	   number of bytes that may be copied into frame.  On return, len will
	   point to an integer now indicating the number of bytes taken from
	   the physical layer and link will point to an integer indicating on
	   which link they were received. */

extern	int CNET_write_application(char *msg, int *len);

	/* Passes a number of bytes, pointed to by msg, ``up to'' the
	   application layer. On invocation, len must point to an integer
	   indicating the number of bytes to be taken from msg.
	   On return, len will point to an integer now indicating the number
	   of bytes accepted by the application layer. */

extern	int CNET_enable_application(CnetAddr destaddr);

	/* Permits the application layer to generate messages for the node
	   with the indicated address. Initially, msg generation for all nodes
	   is disabled and must be enabled to begin the generation of msgs.
	   If destaddr == ALLNODES, message generation will be enabled
	   for all nodes.  */

extern	int CNET_disable_application(CnetAddr destaddr);

	/* Prevents the application layer from generating new messages for the
	   node with the indicated address. This function should be called
	   when a harried node runs out of buffer space, or perhaps while
	   routing information is being gathered.  If destaddr == ALLNODES,
	   message generation will be disabled for all nodes.  */

extern	CnetTimer CNET_start_timer(CnetEvent ev, long ms, CnetData data);

	/* Requests that a new timer be created which will expire in the
	   indicated number of milliseconds.  When the timer expires, the
	   handler for the indicated event, EV_TIMER1..EV_TIMER10, will be
	   called together with the user-specified data value.
	   A unique timer is returned to distinguish this newly created
	   timer from all others. This timer may later be used in
	   subsequent calls to CNET_stop_timer() or CNET_timer_data(). */

extern	int CNET_stop_timer(CnetTimer timer);

	/* Requests that the indicated timer be cancelled. */

extern	int CNET_timer_data(CnetTimer timer, CnetData *data);

	/* Allows the CnetData value for the indicated CnetTimer value
	   to be recovered. The timer is not cancelled. */

extern	int CNET_read_keyboard(char *line, int *len);

	/* Requests the specified maximum number of bytes from the keyboard
	   buffer and places them in the address pointed to by line.
	   On invocation, len will point to an integer indicating the maximum
	   number of bytes that may be copied into line. On return, line
	   will be NULL-byte terminated (and not include a newline) and the
	   integer pointed to by len will contain strlen(line)+1. */

extern	int CNET_set_time_of_day(long newsec, long newmsec);

	/* Changes the node's notion of the wall-clock time of day.
	   time_of_day.sec is the number of seconds since Jan. 1, 1970,
	   and may be used in a call to ctime(3c).
	   As nodeinfo should be considered a read-only structure, this is
	   the only method to set time_of_day.sec and time_of_day.msec . */

extern	int CNET_set_debug_string(CnetEvent ev, char *str);

	/* Changes the string on the required debug button, indicated by the
	   event EV_DEBUG1..EV_DEBUG5, to the indicated string.
	   Passing the NULL or empty string will remove the button. */

extern	void	CNET_exit(char *file,char *fn,int line);

	/* Calling this function will exit (all of) cnet, and display the
	   invoking node's name, source file, function, and line where it
	   was called, together with the latest cnet_errno value. */

extern	void	CNET_perror(char *msg);

extern	unsigned short	checksum_ccitt(unsigned char *addr, int nbytes);
extern	unsigned short	checksum_crc16(unsigned char *addr, int nbytes);
extern	unsigned long	checksum_crc32(unsigned char *addr, int nbytes);
extern		 int	checksum_internet(unsigned short *addr, int nbytes);


/* --- Next, constants and declarations for debugging and event tracing --- */

#define	TE_NOEVENTS		(0)
#define	TE_ALLEVENTS		(1)
#define	TE_REBOOT		(1<<(int)EV_REBOOT)
#define	TE_SHUTDOWN		(1<<(int)EV_SHUTDOWN)
#define	TE_APPLICATIONREADY	(1<<(int)EV_APPLICATIONREADY)
#define	TE_PHYSICALREADY	(1<<(int)EV_PHYSICALREADY)
#define	TE_KEYBOARDREADY	(1<<(int)EV_KEYBOARDREADY)
#define	TE_LINKSTATE		(1<<(int)EV_LINKSTATE)
#define	TE_DEBUG1		(1<<(int)EV_DEBUG1)
#define	TE_DEBUG2		(1<<(int)EV_DEBUG2)
#define	TE_DEBUG3		(1<<(int)EV_DEBUG3)
#define	TE_DEBUG4		(1<<(int)EV_DEBUG4)
#define	TE_DEBUG5		(1<<(int)EV_DEBUG5)
#define	TE_TIMER1		(1<<(int)EV_TIMER1)
#define	TE_TIMER2		(1<<(int)EV_TIMER2)
#define	TE_TIMER3		(1<<(int)EV_TIMER3)
#define	TE_TIMER4		(1<<(int)EV_TIMER4)
#define	TE_TIMER5		(1<<(int)EV_TIMER5)
#define	TE_TIMER6		(1<<(int)EV_TIMER6)
#define	TE_TIMER7		(1<<(int)EV_TIMER7)
#define	TE_TIMER8		(1<<(int)EV_TIMER8)
#define	TE_TIMER9		(1<<(int)EV_TIMER9)
#define	TE_TIMER10		(1<<(int)EV_TIMER10)

extern	int	CNET_trace(const char *, ...);
extern	int	CNET_trace_name(void *addr, const char *name);
extern	int	CNET_set_trace(int);
extern	int	CNET_get_trace(void);


/* ---------------------- Some helpful macros ------------------------- */

#if	defined(__GNUC__)
#define CHECK(call)	if((call) != 0) { \
			    CNET_exit(__FILE__, __FUNCTION__, __LINE__);}
#else
#define CHECK(call)	if((call) != 0) { \
			    CNET_exit(__FILE__, (char *)NULL, __LINE__);}
#endif

#define	IS_DEBUG(ev)	((int)EV_DEBUG1<=(int)ev && (int)ev<=(int)EV_DEBUG5)
#define	IS_TIMER(ev)	((int)EV_TIMER1<=(int)ev && (int)ev<=(int)EV_TIMER10)


/* ----------------- Finally, the STDIO window definitions ------------ */


#if	defined(putchar)
#undef	putchar
#endif

/* These functions are supported: */
extern	int	putchar(int ch);
extern	int	puts(const char *str);
extern	int	printf(const char *, ...);
extern	int	fprintf(FILE *, const char *, ...);
extern	void	CNET_clear(void);

/* The following functions are no longer supported: */
extern	int	CNET_set_cursor(int  row, int  col);
extern	int	CNET_get_cursor(int *row, int *col);
extern	void	CNET_clear_to_eoln(void);
extern	void	CNET_clear_to_eos(void);

#endif
