/*==============================================================*/
/* ENet/AppLink Inter Process Communication library header file	*/
/*								*/
/* AUTHOR:	Gabor Nagy					*/
/* DATE:	1996-Dec-24 23:46:00				*/
/*								*/
/* Copyright (C) 1995 by Gabor Nagy. All rights reserved.	*/
/*==============================================================*/
#ifndef _ENet_h
#define _ENet_h
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

#include <netinet/in.h>


#if defined (__cplusplus) && (!(defined (__CPLUSLIBS)))
extern "C" {
#endif

//#ifdef sgi
#define _BSD_SIGNALS
//#endif


// Define the Token type and Get/Put macros in one place,
// so it's easy to change it later (e.g. to 32 bits)
//
typedef short		EnToken;
#define EM_GetTokenI	EM_GetShortI
#define EM_PutTokenI	EM_PutShortI

#define EnM_PutTimeI(v, p) EM_PutIntI((v).Seconds, (p)), EM_PutIntI((v).Nanoseconds, (p))


typedef int	(*EnCallbackProc)(void*, int);



// This is an opaque structure, its content will depend on architecture
//
typedef struct
{
 unsigned int	Seconds;
 unsigned int	Nanoseconds;
} EnTime;


#define EnINBUFFER_INCREMENT	1024	// If the InBuffer of a connection is full when a new packet is received, increase the sice by this much

// Basic tokens 
//
enum
{
 EnTkNONE=0,
 EnTkTIME,			// Absolute time in microseconds (8 bytes)
 EnTkNEXT_FREE
};


// First port # we can use
//
#define EnFIRSTPORT		IPPORT_RESERVED


#define	EnMAX_NUM_OF_CONNECTIONS	    64
#define EnMIN_INBUFFER_SIZE		 16384
#define EnINBUFFER_SIZE_INCREMENT	 16384
#define EnMAXOUTBLOCKSIZE		524288

#define EnMSGBUFFERSIZE			 65536

#define	EnMAX_RELAYNUM			    16

#define EnMAIN_SHM_KEY			0x42434445
#define EnSHM_KEY			0x42434446
#define EnMAX_APPNUM			   32	// Maximum # of applications on one host that can use AppLink max # of port numbers
#define EnSHMS_OK			0	// Status flags for the main shared memory accessibility
#define EnSHMS_LOCKED			1
#define EnSHMS_LOCK_RQ			(1<<1)
#define EnSHMS_ALL			3


enum { EnDB_PRINT_ALL=0, EnDB_PRINT_SERVER_PORT_NUMBER };

#define	EnIPADDRESS_LENGTH		 6	// IPv6


// Host record
//
typedef struct
{
 int		RefCnt;
 char*		Name;
 int		IPAddressCount;				// There can be relays...	
 unsigned char	IPAddress[EnMAX_RELAYNUM][EnIPADDRESS_LENGTH];
 int		PortNumber;				// Preferred port number on which to contact this host
} EnHost;

#define EnCONTENTSHORT(p)	(*((short*)(&(p))))
#define EnCONTENTUSHORT(p)	(*((unsigned short*)(&(p))))
#define EnCONTENTLONG(p)	(*((long*)(&(p))))
#define EnCONTENTULONG(p)	(*((unsigned long*)(&(p))))

//--------------------------------------------------------
// How to poll to the server port in every n seconds
//--------------------------------------------------------
enum
{
 EnTmALARM_SIGNAL,	// With alarm signal
 EnLtXt_TIMER		// With Xt timer
};


#define EnONLINE		 0x100
#define EnNOT_ESTABLISHED	 0x200
#define EnSENDING		 0x400
#define EnRECEIVING		 0x800

#define EnCONNECTION_NOT_FOUND	(-1)
#define EnCONNECTION_BUSY	(-2)

#define EnBLKHDROFFS_TOTALLENGTH	 4
#define EnBLKHDROFFS_BLOCKTYPE		 8
#define EnBLOCKHEADERLENGTH		12

#define EnBLOCKRCVLENGTH		 8	// Length of 'handshake' message
#define EnNETNAMELEN			64	// Max length of host name
#define EnAPPNAMELEN			32	// Max length of application name


enum
{
 EnSTATUS_NONE=0,
 EnSTATUS_CONNECTION_OUT_ESTABLISHED,
 EnSTATUS_CONNECTION_IN_ESTABLISHED
};

typedef struct
{
 pid_t	ProcessID;
 int	ServerPort;
 char	AppName[EnAPPNAMELEN];
} EnAppLinkRec;


// Read status values
//
enum
{
 EnCLEAR=0,		// No data had been evaluated yet
 EnREADING_HEADER,	// Reading packet header
 EnEVALUATING_PACKET,
 EnREADING_PACKET
};


#define EnGARBAGE_ON_READ	-1


#define EnConnectionCore()\
 int		RefCnt;			/* Reference count										*/\
\
 EnHost*	Host;\
\
 unsigned int	ConnStatus;\
 unsigned int	PortNumber;\
\
 int		Socket;\
 int		NewBytesReceived;	/* Bytes just read										*/\
 int		InOffset;		/* ENet's packet reader will store the next incoming packet at this position			*/\
 unsigned char*	InBuffer;		/* On-demand-allocated receiving buffer								*/\
 unsigned int	InBufferSize;		/* Allocated size of InBuffer									*/\
\
/* This part is used mainly by the application's packet evaluator									*/\
\
 int		ReadStatus;\
 int		ReadPtr;		/* Next byte to read (evaluate_									*/\
 unsigned int	ReadPacketLength;\
 int		BytesToRead;		/* Bytes to read from the incoming packet (can be negative if we got a part of the next packet)	*/\
\
/* This part is used by the application's packet sender											*/\
\
 int		BytesToSend;		/* Bytes to send of the outgoing block								*/\
 int		BytesSent;		/* Bytes of the outgoing block actually received by the receiver				*/\
 int		OutOffset;		/* Bytes already sent of the outgoing block (current position in OutBuffer)			*/\
 unsigned char*	OutBuffer;\
\
 void*		UserData


typedef struct
{
// EnConnection fields
//
 EnConnectionCore();
} EnConnection;



typedef struct
{
// EnConnection fields
//
 EnConnectionCore();

// AppLink fields
//
 char		AppName[EnAPPNAMELEN];		// Name of the remote application
 uid_t		RAppProcID;			// Process id of the other application
 int		SharedMemoryID;
 void*		SharedMemoryAddress;
 unsigned long	SharedMemorySize;
} EnAppLinkConnection;


// Block types
//
enum
{
 EnBT_CONNECTION_REPLY0_FROM_CALLED=1,
 EnBT_CONNECTION_CONFIRM,
 EnBT_CONNECTION_CANCEL,
 EnBT_CONNECTION_ESTABLISHED,
 EnBT_CONNECTION_CANCELLED,
 EnBT_BLOCK_RECEIVED,
 EnBT_COME_IN,				// 'Come-in' message (usually broadcasted)
 EnBT_I_AM_HERE,			// Reply to 'Come-in' message
 EnBT_EXIT,				// Exit command to the remote application
 EnBT_CANNOT_EXIT,			// Replies to EXIT command
 EnBT_EXITED,
 EnBT_IMAGE,				// An incoming image
 EnBT_VIDEO_SETUP,			// Commands for EVideoDaemon
 EnBT_VIDEO_SEND_IMAGE,
 EnBT_VIDEOD_MESSAGE,			// Message from EVideoDaemon
 EnBT_3DMODEL,				// 3D system 'messages'
 EnBT_3DTRANSFORMATION
};

#define EnBT_CUSTOM	EnBT_EXIT	// The first 'Custom' message type

// VideoDaemon messages
//
enum
{
 EnVIDEO_COULD_NOT_CONNECT_TO_DAEMON=1
};


// Callback reasons
//
enum
{
 EnRSN_NETWORKING_INITIALIZED=1,
 EnRSN_CANNOT_CONNECT_TO_HOST,
 EnRSN_THERE_IS_ONLY_ME,
 EnRSN_CONNECTION_REQUEST_OUT,
 EnRSN_CONNECTION_OUT_SHALL_I_ACCEPT_IT,
 EnRSN_CONNECTION_OUT_CANCELLED,
 EnRSN_CONNECTION_OUT_ESTABLISHED,
 EnRSN_CONNECTION_IN_ESTABLISHED,
 EnRSN_CONNECTION_OUT_TERMINATED,
 EnRSN_CONNECTION_IN_TERMINATED,
 EnRSN_CANNOT_CONNECT,
 EnRSN_BLOCK_HEADER_RECEIVED,
 EnRSN_PART_OF_BLOCK_SENT,
 EnRSN_BLOCK_SENT,
 EnRSN_PART_OF_BLOCK_RECEIVED,
 EnRSN_BLOCK_RECEIVED,
 EnRSN_DO_YOU_NEED_THIS_BLOCK,
 EnRSN_LOCAL_LIST_CHANGED,
 EnRSN_REMOTE_LIST_CHANGED,
 EnRSN_APPLINK_CONNECTION_OUT_ESTABLISHED
};


// Callback replies from the application
//
enum
{
 EnREPLY_ACKNOWLEDGED=1,
 EnREPLY_ACCEPT_CONNECTION,
 EnREPLY_CANCEL_CONNECTION,
 EnREPLY_GET_THAT_BLOCK,
 EnREPLY_FORGET_IT,
 EnREPLY_ERROR
};


// Registered hosts
//
extern unsigned int	En_NumOfHosts;
extern EnHost**		En_Hosts;

extern char		En_MyHostName[EnNETNAMELEN];
extern unsigned char	En_MyIPAddress[EnIPADDRESS_LENGTH];

extern unsigned int	En_MaxInBufferSize;

extern int		En_BroadcastSocket;
extern EnConnection**	En_Connections;
extern unsigned int	En_NumOfConnections;

extern EBool		En_Verbose;


extern void		En_HostInit(EnHost* LHost);
extern EnHost*		En_HostAllocate();
extern void		En_HostFree(EnHost* LHost);
extern void		En_HostCopy(EnHost* LSHost, EnHost* LDHost);
extern EnHost*		En_HostRegister(EnHost* LHost);


extern unsigned char*	En_InitNetPacket(unsigned char* LBuffer, unsigned char** LContentStartRet);
extern int		En_CloseAndSendPacket(EnConnection* LConnection, unsigned char* LBuffer, unsigned char* LContentStart, unsigned char* LPtr);


extern EnConnection*	En_RegisterConnectionRequest(EnConnection* LConnectionTmplt, unsigned int LConnStatus);
extern void		En_ConnectionRemove(EnConnection* LConnection);
extern void		En_ConnectionFree(EnConnection* LConnection);

extern long		En_SendBlockToConn(EnConnection* LConnection, unsigned long LBlockNumber, unsigned long LBlocksRemained, unsigned char* LBuffer, unsigned long LLength, unsigned long LBlockType);
extern int		En_ConnStatus(EnConnection* LConnection);
extern long		En_SendBlock(EnConnection* LConnection, unsigned long LBlockNumber, unsigned long LBlocksRemained, unsigned char* LBuffer, unsigned long LLength, unsigned long LBlockType);
extern long		En_Broadcast(unsigned char* LBuffer, unsigned long LLength, unsigned long LBlockType);
extern int		En_ConnectToHost(EnHost* LHost, u_short LPortNumber);
extern int		En_Debug(int LOperation);

extern int		En_HostNameToIPAddress(EnHost* LHost);

extern int		En_Initialize(char* LNetName, char* LAppName, EnCallbackProc LAppFunction, u_short LServerPort);
extern void		En_Shutdown(void);

extern char*		En_ConnectionToString(EnConnection* LConnection, char* LStr);


#if defined (__cplusplus) && (!(defined (__CPLUSLIBS)))
}	// Close scope of 'extern "C"' declaration which encloses file.
#endif


#endif	// _ENet_h
