/************************************************************************/
/*	
/*			gdb.h
/*	
/*	Includes for the global database facility (gdb)
/*
/*	Author: Noah Mendelsohn
/*	IBM T.J. Watson Research and Mit Project Athena
/*
/*	Revised:	8/21/87
/*
/*	$Source$
/*	$Author$
/*	$Header$
/*
/*	Copyright 1987 by the Massachusetts Institute of Technology.
/*	For copying and distribution information, see the file mit-copyright.h
/*	
/*	
/************************************************************************/

/*
 * Note: following include may safely be done redundantly, so it doesn't
 * matter if caller does it too.  We need it for fd_set.
 */
#include <sys/types.h>
#include <sys/time.h>

#ifndef TRUE
#define TRUE 1
#endif

#ifndef FALSE
#define FALSE 0
#endif

#ifndef max
#define max(a,b) ((a)>(b)?(a):(b))
#endif

#ifndef min
#define min(a,b) ((a)<(b)?(a):(b))
#endif

#ifndef NFDBITS
#define NFDBITS 32
#endif
#ifndef howmany
#define	howmany(x, y)	(((x)+((y)-1))/(y))
#endif
#ifndef FD_SET
#define FD_SET(n, p)    ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
#define FD_CLR(n, p)    ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
#define FD_ISSET(n, p)  ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
#define FD_ZERO(p)      bzero(p, sizeof(*(p)))
#endif 



	/*----------------------------------------------------------*/
	/*	
	/*			GDB_GIVEUP
	/*	
	/*	This macro is called with a string argument whenever a
	/*	fatal error is encounterd.  If you re-define this
	/*	macro, you can control the disposition of fatal gdb
	/*	errors.
	/*	
	/*	The gdb library must be recompiled for the change to
	/*	take effect.  That will have to be fixed sometime.
	/*	
	/*----------------------------------------------------------*/

#ifndef GDB_GIVEUP
#define GDB_GIVEUP(errormsg) g_givup(errormsg);
#endif  GDB_GIVEUP

	/*----------------------------------------------------------*/
	/*	
	/*	                GDB_ROUNDUP
	/*	
	/*	Round a number up to the next specified boundary.
	/*	
	/*----------------------------------------------------------*/

#define GDB_ROUNDUP(n,b) ((((n)+(b)-1)/(b))*(b))

extern int	gdb_Debug;			/* debugging flags are */
						/* stored here */
extern FILE *gdb_log;				/* file descriptor for */
						/* logging gdb output */


/*
 * 			connection failure indicator
 * 
 * This variable is used to communicate between gdb_move_data and
 * g_con_progress without passing an extra parameter through lots
 * of procedure calls.  When set to FALSE, it indicates that the 
 * connection currently being processed has encountered a fatal error
 * and should be severed.
 */
extern int gdb_conok;					
/************************************************************************/
/*	
/*			    USER IDENTIFICATION
/*	
/*	gdb_init puts the user's i.d. and hostname as strings here.
/*	
/************************************************************************/

extern char *gdb_uname;				/* user's string name */
extern char *gdb_host;				/* name of local host */
						/* goes here */



/************************************************************************/
/*	
/*	
/*			  TYPE MANAGEMENT
/*	
/*	Declarations used to control the definition and use of 'types'
/*	as supported by the global database system.  Most of the 
/*	declarations for 'System Defined Types' will not be of concern
/*	to typical users, with the exception of the type names like
/*	INTEGER_T which are defined below.
/*	
/*	In this implementation, user defined types are added
/*	dynamically during execution by calling the appropriate
/*	functions.  The define GDB_MAX_TYPES below sets the maximum
/*	total number of types, including both system and user defined,
/*	which the system can support for any one application.  When
/*	GDB_MAX_TYPES is changed, the libary must be re-built.  Space
/*	for a two dimensional array, with one word for each property
/*	of each possible type, is allocated statically in the library.
/*	
/************************************************************************/


/*
 * Maximum number of types we can support, including both system and
 * user defined.
 */

#define GDB_MAX_TYPES 50

typedef int FIELD_TYPE;				/* data needed to repre- */
						/* sent a system or user */
						/* defined data type */
						/* This is actualy just */
						/* a row index in the type */
						/* definition table */

	/*----------------------------------------------------------*/
	/*	
	/*		System defined types
	/*	
	/*	WARNING: Any changes to these type definitions must be
	/*	carefully matched with the initializations in the
	/*	gdb_i_stype routine in gdb_stype.c.  Mistakes in these
	/*	tables may be VERY difficult to debug.  Be careful!
	/*	
	/*----------------------------------------------------------*/

/*
 * Primitive types for ingres data
 */

#define INTEGER_T (0)
#define STRING_T (1)
#define REAL_T (2)
#define DATE_T (3)

/*
 * Structured types
 */

#define TUPLE_DESCRIPTOR_T (4)
#define TUPLE_T (5)
#define TUPLE_DATA_T (6)
#define RELATION_T (7)

/*
 * Number of system defined types
 * 
 * This will always be equal to one more than index of last system type
 */

#define SYSTEM_TYPE_COUNT 8

	/*----------------------------------------------------------*/
	/*	
	/*		Type descriptor tables
	/*	
	/*----------------------------------------------------------*/

/*
 * 			gdb_prop_union
 * 
 * Each entry in the type definition table is a union of this form,
 * which allows us to store a choice of an integer, a function 
 * pointer, or a pointer to a character string.
 */

union gdb_prop_union {
	int i;					/* when we want as an */
						/* integer */
	int (*f)();				/* as a function pointer */
	char *cp;				/* character pointer  */
};

#define TYPE_PROPERTY_COUNT 8			/* number of properties */
						/* for each type*/

/*
 * Uses of the type properties.  Each type has a set of properties.
 * Some are integers, some are functions.  The defines below descrive
 * respectively the 0'th,1'st, 2'nd, etc. properties of EACH type.
 * 
 * Note:  TYPE_PROPERTY_COUNT (above) must be changed when new properties
 * are added.  For system defined types, bindings for the properties
 * are done in gdb_i_stype in the gdb_stype.c source file.
 */

#define LENGTH_PROPERTY 0			/* integer */
#define ALIGNMENT_PROPERTY 1			/* integer */
#define NULL_PROPERTY 2				/* function */
#define CODED_LENGTH_PROPERTY 3			/* function */
#define ENCODE_PROPERTY 4			/* function */
#define DECODE_PROPERTY 5			/* function */
#define FORMAT_PROPERTY 6			/* function */
#define NAME_PROPERTY 7				/* char pointer */

/*
 * 			gdb_type_def
 * 
 * Information to describe a single type
 */

typedef union gdb_prop_union gdb_type_def[TYPE_PROPERTY_COUNT];


/*
 * 			g_type_table
 * 
 * This is the table where the actual definitions for the types are
 * kept.
 */

extern gdb_type_def g_type_table[GDB_MAX_TYPES];
extern int gdb_n_types;				/* number of entries in */
						/* table */

	/*----------------------------------------------------------*/
	/*	
	/*	    Macros for accessing properties
	/*	
	/*----------------------------------------------------------*/

#define INT_PROPERTY(type, prop) (g_type_table[type][prop].i) 
#define STR_PROPERTY(type, prop) (g_type_table[type][prop].cp) 
#define FCN_PROPERTY(type, prop) (*g_type_table[type][prop].f) 


/************************************************************************/
/*	
/*			   STRUCTURED DATA
/*	
/*	Stuff needed to declare and manage TUPLES, TUPLE_DESCRIPTORS
/*	and RELATIONS.
/*	
/************************************************************************/

	/*----------------------------------------------------------*/
	/*	
	/*		   TUPLE_DESCRIPTOR
	/*	
	/*----------------------------------------------------------*/

#define GDB_DESC_ID 0x54504400			/* "TPD" */

struct tupld_var {				/* the variable length */
						/* stuff in a tuple */
						/* descriptor*/
	char *name;				/* string name of field */
	FIELD_TYPE type;			/* type of this field */
	int  offset;				/* byte offset of this field */
						/* relative to first byte of */
						/* data (not start of whole */
						/* tuple) */
	int length;				/* Length of the actual data */
						/* for this field. Note that */
						/* alignment requirements of */
						/* following field are NOT */
						/* included in this length */
};
struct tupl_desc {
	long id;				/* this should say TPD\0 */
	int ref_count;				/* when this goes to zero, */
						/* the descriptor may really */
						/* be reclaimed */
	int field_count;			/* number of fields in */
						/* the tuple*/
	int data_len;				/* length of the data in */
						/* the actual tuple */
	int str_len;				/* length of the strings */
						/* stored off the end of */
						/* this descriptor*/
	struct tupld_var var[1];		/* one of these for each */
						/* field, but the C compiler */
						/* won't accept the[] decl, */
						/* because it's afraid of */
						/* uncertain length*/
};

typedef struct tupl_desc *TUPLE_DESCRIPTOR;	/* use this to declare a */
						/* tuple descriptor anchor */

#define gdb_descriptor_length(num_flds) (sizeof(struct tupl_desc) + ((num_flds)-1) * sizeof(struct tupld_var))

	/*----------------------------------------------------------*/
	/*	
	/*			TUPLE
	/*	
	/*	tuple_dat is allocated by the create_tuple routine.
	/*	
	/*	TUPLE may be used in user code to declare a handle
	/*	on a tuple.
	/*	
	/*----------------------------------------------------------*/

#define GDB_TUP_ID 0x54555000

typedef struct tuple_dat *TUPLE;		/* handle on a tuple */

struct tuple_dat {
	TUPLE next, prev;			/* chain pointers when */
						/* tuples are linked, as in */
						/* a relation.  Convention is*/
						/* double linked, circular.*/
	long id;				/* should say TUP\0  */
	TUPLE_DESCRIPTOR desc;			/* pointer to the descriptor */
	char data[1];				/* data goes here, word */
						/* aligned.  Should be [] */
						/* if compiler would allow */
};


	/*----------------------------------------------------------*/
	/*	
	/*		      RELATION
	/*	
	/*	rel_dat is allocated by the create_relation
	/*	routine.
	/*	
	/*	RELATION may be used in user code to declare a handle
	/*	on a relation.
	/*	
	/*----------------------------------------------------------*/

#define GDB_REL_ID 0x52454c00

struct rel_dat {
	TUPLE first, last;			/* chain pointers to tuples */
						/* note that first->prev and */
						/* last->next are both == */
						/* &rel-dat.  Maintenance is */
						/* simplified by keeping */
						/* as the first fields in */
						/* both rel_dat and tuple_dat*/
						/* a minor non-portability */
	long id;				/* should contain REL\0  */
	TUPLE_DESCRIPTOR desc;			/* descriptor for the tuples */
						/* in this relation. Should */
						/* == that in each tuple */

};

typedef struct rel_dat *RELATION;		/* handle on a relation */

/************************************************************************/
/*	
/*		      transport LAYER DECLARATIONS
/*	
/*	Declares the state maintenance structures for full duplex 
/*	connections with asynchronous transmission capability.  Most
/*	users need only know that the type CONNECTION is defined, and
/*	that it may be treated as a pointer for most purposes (i.e. it
/*	is compact, and copying it does not actually copy the connection
/*	state.)
/*	
/************************************************************************/

#define GDB_PROTOCOL_VERSION 0x01		/* version of the gdb */
						/* protocols that we're */
						/* observing */
#define GDB_STREAM_BUFFER_SIZE 4096		/* amount to read in */
						/* one chunk from tcp stream*/
#define GDB_PORT htons(9425)			/* temporary until we use */
						/* services properly */
#define GDB_BIND_RETRY_COUNT 5			/* number of times to */
						/* retry a bind before */
						/* giving up.  Used when */
						/* accepting connections */
#define GDB_BIND_RETRY_INTERVAL 10		/* Number of seconds to wait */
						/* between attempts to bind */
						/* the listening socket */
#define GDB_MAX_CONNECTIONS 25			/* maximum number of */
						/* connections that */
						/* any one process can */
						/* control simultaneously */
/*
 * Circumvent bug in ACIS 4.2 socket support
 */
#ifdef ibm032
#define GDB_MAX_SOCK_WRITE 2047			/* rt can't do socket */
						/* writes longer than this */
						/* gives errno 40*/
#else
#define GDB_MAX_SOCK_WRITE 0x00ffffff
#endif

	/*----------------------------------------------------------*/
	/*	
	/*	     Declarations for HALF_CONNECTIONS
	/*	
	/*	Each full duplex connection has associated with it 
	/*	two simplex half-connections, each of which 
	/*	has its own queue of pending operations.  The
	/*	following describes the state of a half-connection.
	/*	
	/*----------------------------------------------------------*/

struct half_con_data {
       /*
        * these two must be first to match position in OPERATION
        */
	struct oper_data *op_q_first;		/* first item in q of pending*/
						/* operations for this */
						/* half-connection. (chained */
						/* circularly to half con, */
						/* NOT the con. */
	struct oper_data *op_q_last;		/* last item in q of pending*/
						/* operations for this */
						/* half-connection*/
	int status;				/* values are of type */
						/* OPSTATUS. tells whether */
						/* transmit/receive is */
						/* pending.*/
	long flags;				/* bit flags */
#define HCON_PROGRESS 0x00000001		/* used by selection */
						/* routines to detect */
						/* progress */
#define HCON_LISTEN   0x00000002		/* indicates that this is */
						/* a special half connection */
						/* used only for listenting */
						/* to incoming connection */
						/* requests */
#define HCON_UNUSED   0x00000004		/* on a one-way connection, */
						/* this flag marks an unused */
						/* half */
#define HCON_PENDING_LISTEN 0x00000008		/* a queued op on this half */
						/* connection is actually */
						/* trying to listen */
#define HCON_BUSY     0x00000010		/* we are currently making */
						/* progress on this half */
						/* connection.  Used to */
						/* detect re-entrance of */
						/* hcon_progress */
	int fd;					/* main half duplex file */
						/* descriptor for this h_conn*/
	int oob_fd;				/* file descriptor for */
						/* out of band signals*/
	char *next_byte;			/* next byte to send/recv */
	int remaining;				/* number of bytes remaining */
						/* to send/receive */
	char *stream_buffer;			/* points to a buffer */
						/* used to pre-read/write */
						/* the stream to avoid */
						/* window thrashing */
	int stream_buffer_length;		/* length of the stream */
						/* buffer */
	char *stream_buffer_next;		/* next byte to read in */
						/* stream buffer */
	int stream_buffer_remaining;		/* number of bytes currently */
						/* in use in stream buffer*/
	int *accepted_fdp;			/* used only for listening */
						/* connections.  latest */
						/* accepted fd is put where*/
						/* this points */
	int *accepted_len;			/* ptr to length of 'from' */
						/* data on accept  */

};

typedef struct half_con_data *HALF_CONNECTION;


	/*----------------------------------------------------------*/
	/*	
	/*	     Declarations for CONNECTIONS
	/*	
	/*----------------------------------------------------------*/

#define GDB_CON_ID 0x434f4e00 /*"CON"*/

struct con_data {
	long	id;				/* should contain CON\0  */
	int status;				/* See definitions below. */
						/* Do not confuse with */
						/* the status sub-fields of */
						/* in and out half-cons. */
	int version;				/* the version of the */
						/* protocol being observed */
						/* on this connection */
	int errno;				/* the real errno gets */
						/* copied here if it causes */
						/* the connection to die */
	int (*oob_fcn)();			/* pointer to function to */
						/* call when something */
						/* arrives on the out of */
						/* band channel */
	struct half_con_data in, out;		/* states of the inbound */
						/* and outbound half */
						/* sessions.*/
};

typedef struct con_data *CONNECTION;		/* the only externally */
						/* visible handle on a */
						/* connection*/

/*
 * Definitions of status fields.
 * 
 * WARNING: If you change any of the following, there are coordinated
 * changes to be made in gdb_debug.c
 */

#define CON_STOPPED 1				/* never started, terminated */
#define CON_UP 2				/* ready to use */
#define CON_STARTING 3				/* trying to start */
#define CON_STOPPING 4				/* trying to stop */

/*
 * The following are used as keywords when distinguishing input from output
 * half connections.
 */
#define CON_INPUT 1				/* this is an input half */
						/* session*/
#define CON_OUTPUT 2				/* this is an output half */
						/* session*/


	/*----------------------------------------------------------*/
	/*	
	/*			gdb_cons
	/*	
	/*	This is the array of connection control data 
	/*	structures for gdb.  Every connection has its 
	/*	structure stored here, but they are in no 
	/*	particular order.  Because the connection data
	/*	itself cannot be moved (due to possible dangling
	/*	pointers), there may be some unused connections 
	/*	in the middle of this array.  gdb_mcons is the
	/*	1 based number of the highest connection which is
	/*	actually in use at this time.  This is a considerable
	/*	optimization for the typical case where very few
	/*	are in use, and turnover is low.
	/*	
	/*	These are externs for globals defined in gdb_lib.h
	/*	and included by gdb.c.
	/*	
	/*----------------------------------------------------------*/

extern int  gdb_mcons;				/* one based number of the */
						/* highest connection */
						/* descriptor we're using */
						/* at the moment */

extern int  gdb_mfd;				/* number of the highest */
						/* file descriptor in use */
						/* for a connection */
extern struct con_data gdb_cons[GDB_MAX_CONNECTIONS];
						/* actual connection data */
						/* is stored here */

extern fd_set gdb_crfds, gdb_cwfds, gdb_cefds;	/* connection related file */
						/* descriptor maps to be */
						/* used in select */
fd_set last_crfds, last_cwfds, last_cefds;	/* these file desc. bit */
						/* masks are set up */
						/* for each select call */
						/* to include the user */
						/* supplied and the */
						/* connection related */
						/* fd's */

	/*----------------------------------------------------------*/
	/*	
	/*			OPERATIONS
	/*	
	/*----------------------------------------------------------*/

#define GDB_OP_ID 0x4f505200

struct oper_data {
	struct oper_data *next, *prev;		/* forward and back chain */
	long id;				/* should contain OPR\0  */
	int status;				/* current state of this */
						/* oaperation*/
	int flags;
#define OPF_MARKED_COMPLETE 0x00000001		/* operation was already */
						/* complete when opsel was */
						/* called*/
#define OPF_MARKED_CANCELLED 0x00000002		/* operation was already */
						/* cancelled when opsel was */
						/* called*/
	int result;				/* when the operation */
						/* completes, this field is */
						/* set to reflect its dispos-*/
						/* ition. Contents of this */
						/* field will depend on the */
						/* operation being performed */
	HALF_CONNECTION halfcon;		/* the half connection on */
						/* which this operation is */
						/* queued */
						/* May be meaningless if not */
						/* queued..*/
	char *arg;				/* pointer to user data */
	union fcn {
		int (*init)();			/* pointer to routine to */
						/* call to start this */
					
	/* operation*/
		int (*cont)();			/* pointer to function to */
						/* be called when this */
						/* logical operation */
						/* continues*/
	} fcn;

	int (*cancel)();			/* this routine gets called */
						/* to handle a cancel request*/
						/* this field is normally */
						/* set to NULL when the */
						/* operation is queued and */
						/* updated as required by */
						/* the init and cont funcs. */
};

typedef struct oper_data OPERATION_DATA;	/* an actual operation */
						/* descritor, creator is */
						/* responsible for making */
						/* sure that memory is not */
						/* freed while in use */
typedef OPERATION_DATA *OPERATION;		/* a handle on an operation */
						/* this is what most */
						/* applications will use */

	/*----------------------------------------------------------*/
	/*	
	/*	          STATES OF AN OPERATION
	/*	
	/*	These represent the state of an asynchronous, queued
	/*	operation.  For convenience of the application programmer,
	/*	some of these are folded together when queried through the
	/*	operation_status routine.  In particular, operation status
	/*	returns only one of:
	/*	
	/*	OP_NOT_RUNNING, OP_RUNNING, OP_COMPLETE,  or 
	/*	OP_CANCELLED.
	/*	
	/*	Any other status is reported as OP_RUNNING.  This is
	/*	done on the assumption that it makes correct coding
	/*	of applications less error-prone, as there are fewer
	/*	cases to check, and most of them would not be of 
	/*	interest anyway.
	/*	
	/*	Note that OP_CANCELLED may be generated by the system
	/*	even when no explicit request for cancellation has been
	/*	issued.  For example, this may occur when a connection
	/*	is severed unexpectedly.
	/*	
	/*	WARNING:  If you change any of the following, be sure
	/*	to make the equivalent changes to gdb_debug.c.
	/*	
	/*	We also define here certain standard values of OP_RESULT,
	/*	since some return conventions presume that op_status 
	/*	and op_result values are orthogonal.
	/*	
	/*----------------------------------------------------------*/

#define OP_SUCCESS     0			/* this value is actually */
						/* used only in result */
						/* fields, but it is */
						/* sometimes convenient to */
						/* have status and result */
						/* have orthogonal values */
#define OP_NOT_STARTED 1			/* this operation has been */
						/* initialized but is not on */
						/* any connection's queue */
#define OP_QUEUED 2				/* this operation is on */
						/* some connection's queue */
						/* but it has not yet */
						/* reached the head of the q */
#define OP_RUNNING 3				/* op is at head of q trying */
						/* to progress */
#define OP_COMPLETE 4				/* operation has run to */
						/* completion.  result field */
						/* is now valid */
#define OP_CANCELLING 5				/* we are in the process of */
						/* (trying to) cancel this */
						/* operation */
#define OP_CANCELLED 6				/* operation was prematurely */
						/* terminated.  result field */
						/* is NOT valid. */
#define OP_MARKED 7				/* used by op_select_all */
#define OP_REQUEUED 8				/* returned by an init or */
						/* continuation routine to */
						/* indicate that the */
						/* operation has requeued */
						/* itself */
#define OP_PREEMPTED 9				/* returned by an init or */
						/* continuation routine to */
						/* indicate that the op has */
						/* preempted itself by */
						/* queueing a new operation */
						/* ahead of itself */

	/*----------------------------------------------------------*/
	/*	
	/*		     LIST_OF_OPERATIONS
	/*	
	/*----------------------------------------------------------*/

struct oper_list {
	int	count;				/* number of operations */
						/* in the list */
	OPERATION op[1];			/* really op[n], but */
						/* structs must have a */
						/* definite length */
};

typedef struct oper_list *LIST_OF_OPERATIONS;	/* handle on a list */

#define gdb_size_of_list_of_operations(n)					\
		(sizeof(struct oper_list) + (n-1)*sizeof(OPERATION))

	/*----------------------------------------------------------*/
	/*	
	/*			gdb_notime
	/*	
	/*	Pass this to select when doing a poll.
	/*	
	/*----------------------------------------------------------*/

extern struct timeval gdb_notime;


/************************************************************************/
/*	
/*		CHECKING ROUTINES IMPLEMENTED AS MACROS
/*	
/************************************************************************/

extern char g_errstr[150];			/* build emsgs here */

#define GDB_INIT_CHECK g_chk_init();		/* make sure gdb_init */
						/* was called */

#define GDB_CHECK_CON(con, where) if ((con)->id != GDB_CON_ID) \
	{ (void) sprintf(g_errstr, "Invalid connection descriptor passed to \"%s\"\n", where); \
	GDB_GIVEUP(g_errstr) }


#define GDB_CHECK_TUP(tup, where) if ((tup)->id != GDB_TUP_ID) \
	{ (void) sprintf(g_errstr, "Invalid tuple passed to \"%s\"\n", where); \
	GDB_GIVEUP(g_errstr) }


#define GDB_CHECK_TPD(tpd, where) if ((tpd)->id != GDB_DESC_ID) \
	{ (void) sprintf(g_errstr, "Invalid tuple descriptor passed to \"%s\"\n", where); \
	GDB_GIVEUP(g_errstr) }


#define GDB_CHECK_REL(rel, where) if ((rel)->id != GDB_REL_ID) \
	{ (void) sprintf(g_errstr, "Invalid relation passed to \"%s\"\n", where); \
	GDB_GIVEUP(g_errstr) }

#define GDB_CHECK_OP(op, where) if ((op)->id != GDB_OP_ID) \
	{ (void) sprintf(g_errstr, "Invalid operation passed to \"%s\"\n", where); \
	GDB_GIVEUP(g_errstr) }

#define GDB_CHECK_DB(db, where) if (db->id != GDB_DB_ID) \
	{ (void) sprintf(g_errstr, "Invalid database handle passed to \"%s\"\n", where); \
	GDB_GIVEUP(g_errstr) }




/************************************************************************/
/*	
/*		TRANSPORT ROUTINES IMPLEMENTED AS MACROS
/*	
/************************************************************************/

	/*----------------------------------------------------------*/
	/*	
	/*		   connection_status
	/*	
	/*	Returns the status of the indicated connection.
	/*	Possible return values are:
	/*	
	/*		CON_STOPPED	never started or terminated
	/*		CON_UP		currently usable
	/*		CON_STARTING    transient state on way up
	/*		CON_STOPPING    transient state on way down
	/*	
	/*----------------------------------------------------------*/

#define connection_status(con) ((con)->status)

	/*----------------------------------------------------------*/
	/*	
	/*		   connection_errno
	/*	
	/*	When a connection dies due to an error on a system
	/*	call, the corresponding errno is recorded in the 
	/*	connection descriptor.  This macro returns that value.
	/*	
	/*----------------------------------------------------------*/

#define connection_errno(con) ((con)->errno)



/************************************************************************/
/*	
/*		       SERVER/CLIENT MANAGEMENT
/*	
/*	Definitions used in starting and maintaining communication 
/*	between servers and clients (as opposed to peers.)
/*	
/************************************************************************/

#define GDB_MAX_SERVER_RETRIES 3		/* maximum number of times */
						/* clients will accept */
						/* forwarding requests from */
						/* a given server */


extern TUPLE_DESCRIPTOR gdb_tosrv;		/* descriptor for request */
						/* tuples sent to the */
						/* server during negotiation*/

extern TUPLE_DESCRIPTOR gdb_fmsrv;		/* descriptor for request */
						/* tuples sent from the */
						/* server during negotiation*/

#define GDB_MAX_SERVER_ID_SIZE 255		/* longest name of a server */
						/* that we can handle */
#define GDB_MAX_SERVER_PARMS_SIZE 1023		/* longest parm string we */
						/* can exchange between */
						/* server and client*/

	/*----------------------------------------------------------*/
	/*	
	/*	The following are values returned in the disposition
	/*	field of the response tuple to indicate what the
	/*	server has decided to do about the connection 
	/*	request.
	/*	
	/*----------------------------------------------------------*/

#define GDB_ACCEPTED 1
#define GDB_REFUSED  2
#define GDB_FORWARDED 3

	/*----------------------------------------------------------*/
	/*	
	/*	Global variables inherited by a child from a server
	/*	parent.
	/*	
	/*----------------------------------------------------------*/

extern TUPLE gdb_client_tuple;			/* request tuple sent from */
						/* the client */

extern char gdb_sockaddr_of_client[100];	/* this should really be */
						/* sockaddr_in, but I don't */
						/* want everyone to have */
						/* to include all those */
						/* big .h files */
extern int gdb_socklen;				/* length of above */



/************************************************************************/
/*	
/*			DATABASE MANAGEMENT
/*	
/*	This layer of GDB provides access to the services of a relational
/*	database from anywhere in a GDB network.
/*	
/************************************************************************/

	/*----------------------------------------------------------*/
	/*	
	/*			GDB_DB_SERVICE
	/*	
	/*	The name of the default service, as found in /etc/services,
	/*	for GDB database servers.
	/*	
	/*----------------------------------------------------------*/

#define GDB_DB_SERVICE "#9420"

	/*----------------------------------------------------------*/
	/*	
	/*			GDB_HESIOD_NAMETYPE
	/*	
	/*	When Hesiod is used to resolve a database name, this
	/*	is the NameType specified.
	/*	
	/*----------------------------------------------------------*/

#define GDB_HESIOD_NAMETYPE "service"

	/*----------------------------------------------------------*/
	/*	
	/*			DATABASE
	/*	
	/*	Describes a client's active connection to a database.
	/*	
	/*----------------------------------------------------------*/

#define GDB_DB_ID 0x44420000			/* eye catcher */

struct db_struct {
	long id;				/* eye catcher */
	CONNECTION connection;			/* the GDB connection */
						/* used to get at this */
						/* database */
	int status;				/* status of this */
						/* database connection */
#define DB_OPEN 1				/* database opened */
						/* successfully */
#define DB_CLOSED 2				/* not open */
	char *name;				/* pointer to string name */
						/* of the database, for */
						/* debugging */
	char *server;				/* pointer to the i.d. */
						/* of the server, for */
						/* debugging */
};

typedef struct db_struct *DATABASE;

	/*----------------------------------------------------------*/
	/*	
	/*	Return codes from DB operations
	/*	
	/*----------------------------------------------------------*/

#define DB_NO_SUCH_OP 3

	/*----------------------------------------------------------*/
	/*	
	/*	Parameters which limit sizes of things
	/*	
	/*----------------------------------------------------------*/

#define GDB_MAX_QUERY_SIZE 2048			/* length of the longest */
						/* substituted query */
						/* string we can make */
#define GDB_MAX_QUERY_FIELDS 100		/* maximum number of fields */
						/* we can retrieve in one */
						/* query */
#define GDB_SIZE_OF_INGRES_TEXT 2001		/* number of chars in */
						/* largest ingres text */
						/* field */
#define GDB_MAX_RETRIEVED_TEXT_FIELDS 60	/* maximum number of text */
						/* type fields we can */
						/* retrieve in a single */
						/* query.  we hold this */
						/* down because stack space */
						/* is taken for max size of */
						/* each during query. */

	/*----------------------------------------------------------*/
	/*	
	/*	Return codes from database operations
	/*	
	/*----------------------------------------------------------*/

#define DB_PARSE_FAIL (-3)			/* couldn't parse */
						/* the request string*/


/************************************************************************/
/*	
/*			DATABASE OPERATIONS IMPLEMENTED
/*			        AS MACROS
/*	
/************************************************************************/

	/*----------------------------------------------------------*/
	/*	
	/*			DB_STATUS
	/*	
	/*----------------------------------------------------------*/

#define DB_STATUS(dbhandle) ((dbhandle)->status)




/************************************************************************/
/*	
/*			STRING MANAGEMENT
/*	
/*	To allow dynamic manipulation of strings in gdb without
/*	excessive memory re-allocation, we define a string as a
/*	counted byte space.  Though this space will frequently be used
/*	to store a standard null terminated string, that is not
/*	required.
/*	
/*	Current representation for a string is a pointer followed by
/*	an integer length.  A null pointer indicates a null string, in
/*	which case the length is arbitrary.  Any other pointer is to
/*	memory which was allocated by db_alloc in which must be free'd
/*	eventually with db_free.
/*	
/************************************************************************/

typedef struct str_dat {
	char *ptr;				/* pointer to the data */
	int length;				/* length of the allocated */
						/* memory (not necessarily */
						/* length of null-term'd */
						/* string stored there) */
} STRING;

	/*----------------------------------------------------------*/
	/*	
	/*	Macros for manipulating strings.  These return
	/*	the actual data from the string and the size of
	/*	the data space respectively.  To get the length of
	/*	the null terminated string which might be stored 
	/*	there, use strlen(STRING_DATA(string)).
	/*	
	/*----------------------------------------------------------*/


#define STRING_DATA(str) ((str).ptr)
#define MAX_STRING_SIZE(str) ((str).length)


/************************************************************************/
/*	
/*			MEMORY ALLOCATION
/*	
/*	db_alloc and db_free are the externally visible names of
/*	the memory allocation services.  These actually call the 
/*	routines pointed to by the vectors gdb_amv and gdb_fmv, which
/*	default to the supplied routines gdb_am and gdb_fm.  Users
/*	may supply their own memory allocation by storing over the
/*	vectors.  This may be done prior to calling gdb_init to 
/*	insure that all dynamic memory is controlled by the user.
/*	
/************************************************************************/

#define db_alloc (*gdb_amv)
#define db_free  (*gdb_fmv)

extern char *gdb_am();
extern int  gdb_fm();

extern char *((*gdb_amv)());
extern int  (*gdb_fmv)();


/************************************************************************/
/*	
/*	      STRUCTURED DATA ROUTINES IMPLEMENTED AS MACROS
/*	
/************************************************************************/

	/*----------------------------------------------------------*/
	/*	
	/*	             ADD_TUPLE_TO_RELATION
	/*	
	/*----------------------------------------------------------*/

#define ADD_TUPLE_TO_RELATION(relation, tuple) 			\
	{							\
                (tuple)->prev    = (relation)->last;            \
		(tuple)->next    = (TUPLE)(relation);      	\
		(relation)->last = tuple;			\
		(tuple)->prev->next = tuple;                    \
        }

	/*----------------------------------------------------------*/
	/*	
	/*	             ADD_TUPLE_AFTER_TUPLE
	/*	
	/*----------------------------------------------------------*/

#define ADD_TUPLE_AFTER_TUPLE(relation, tuple, prev_tuple)	\
	{								\
                (tuple)->prev    = (prev_tuple)->next->prev;            \
		(tuple)->next    = (prev_tuple)->next; 			\
		(tuple)->next->prev = tuple;				\
		(prev_tuple)->next = tuple;                    		\
        }

	/*----------------------------------------------------------*/
	/*	
	/*	          REMOVE_TUPLE_FROM_RELATION
	/*	
	/*----------------------------------------------------------*/

#define REMOVE_TUPLE_FROM_RELATION(relation, tuple) 			\
	{								\
		(tuple)->prev->next = (tuple)->next;			\
		(tuple)->next->prev = (tuple)->prev;			\
        }


	/*----------------------------------------------------------*/
	/*	
	/*	           DESCRIPTOR_FROM_TUPLE
	/*	
	/*----------------------------------------------------------*/

#define DESCRIPTOR_FROM_TUPLE(tuple) ((tuple)->desc)

	/*----------------------------------------------------------*/
	/*	
	/*	           DESCRIPTOR_FROM_RELATION
	/*	
	/*----------------------------------------------------------*/

#define DESCRIPTOR_FROM_RELATION(relation) ((relation)->desc)

	/*----------------------------------------------------------*/
	/*	
	/*		   REFERENCE_TUPLE_DESCRIPTOR
	/*	
	/*	Bumps the reference count for a tuple descriptor.
	/*	Intended only for internal use of GDB.
	/*	
	/*----------------------------------------------------------*/

#define REFERENCE_TUPLE_DESCRIPTOR(tpd) (++((tpd)->ref_count))

	/*----------------------------------------------------------*/
	/*	
	/*		   UNREFERENCE_TUPLE_DESCRIPTOR
	/*	
	/*	Decrements the reference count for a tuple descriptor.
	/*	Intended only for internal use of GDB.  Warning: it
	/*	is the user's responsibility to use delete_tuple_descriptor
	/*	instead of this macro in any situation in which the
	/*	reference count might go to zero.
	/*	
	/*----------------------------------------------------------*/

#define UNREFERENCE_TUPLE_DESCRIPTOR(tpd) (--((tpd)->ref_count))

	/*----------------------------------------------------------*/
	/*	
	/*	                 FIELD_FROM_TUPLE
	/*	
	/*----------------------------------------------------------*/

#define FIELD_FROM_TUPLE(tuple, field_index)				\
	(((tuple)->data) + (((tuple)->desc)->var[field_index].offset))

	/*----------------------------------------------------------*/
	/*	
	/*	                FIELD_OFFSET_IN_TUPLE
	/*	
	/*----------------------------------------------------------*/

#define FIELD_OFFSET_IN_TUPLE(tuple_descriptor, field_index)		\
	((tuple_descriptor)->var[field_index].offset)

	/*----------------------------------------------------------*/
	/*	
	/*	                FIELD_TYPE_IN_TUPLE
	/*	
	/*----------------------------------------------------------*/

#define FIELD_TYPE_IN_TUPLE(tuple_descriptor, field_index)		\
	((tuple_descriptor)->var[field_index].type)

	/*----------------------------------------------------------*/
	/*	
	/*	              FIRST_TUPLE_IN_RELATION
	/*	
	/*----------------------------------------------------------*/

#define FIRST_TUPLE_IN_RELATION(relation)				\
	(((relation)->first) == (TUPLE)relation ? NULL : (relation)-> first)

	/*----------------------------------------------------------*/
	/*	
	/*			NEXT_TUPLE_IN_RELATION
	/*	
	/*----------------------------------------------------------*/

#define NEXT_TUPLE_IN_RELATION(relation, prev)				\
	(((prev)->next) == (TUPLE)relation ? NULL : prev->next )

	/*----------------------------------------------------------*/
	/*	
	/*			PREV_TUPLE_IN_RELATION
	/*	
	/*----------------------------------------------------------*/

#define PREV_TUPLE_IN_RELATION(relation, next)				\
	(((next)->prev) == (TUPLE) relation ? NULL : next->prev)




/************************************************************************/
/*	
/*	TRANSPORT and OPERATION SERVICES IMPLEMENTED AS MACROS
/*	
/************************************************************************/

	/*----------------------------------------------------------*/
	/*	
	/*	             OPERATION_FROM_DATA
	/*	
	/*	Given OPERATION_DATA, return the corresponding handle
	/*	of type OPERATION.  Currently, OPERATION is just
	/*	implemented as a pointer to OPERATION_DATA.
	/*	
	/*----------------------------------------------------------*/

#define OPERATION_FROM_DATA(op_data)					\
	((OPERATION)&(op_data))

	/*----------------------------------------------------------*/
	/*	
	/*		       OP_STATUS
	/*	
	/*	Return the status of a given operation.  Note that
	/*	status describes an operations progress through 
	/*	execution.  It has the same values for all operations.
	/*	Result describes the final outcome of an operation.
	/*	It's values depend on the particular operation which
	/*	was attempted.  
	/*	
	/*----------------------------------------------------------*/

#define OP_STATUS(operation) ((operation)->status)

	/*----------------------------------------------------------*/
	/*	
	/*			OP_DONE
	/*	
	/*	True iff the operation is either OP_COMPLETE or
	/*	OP_CANCELLED.
	/*	
	/*----------------------------------------------------------*/

#define OP_DONE(op) ((op)->status == OP_COMPLETE || (op)->status == OP_CANCELLED)

	/*----------------------------------------------------------*/
	/*	
	/*		       OP_RESULT
	/*	
	/*	Return the result of a given operation.  Note that
	/*	status describes an operations progress through 
	/*	execution.  It has the same values for all operations.
	/*	Result describes the final outcome of an operation.
	/*	It's values depend on the particular operation which
	/*	was attempted. The special result value -1 is used 
	/*	to indicate an invalid value for result.  Generally,
	/*	-1 is returned when result is accidently queried at
	/*	a time when OP_STATUS != OPERATION_COMPLETE.
	/*	
	/*----------------------------------------------------------*/

#define OP_RESULT(operation) ((operation)->result)


/************************************************************************/
/*	
/*			Debugging Interfaces
/*	
/************************************************************************/

	/*----------------------------------------------------------*/
	/*	
	/*	The following operation codes my be passed to 
	/*	gdb_debug to set special debugging modes of operation.
	/*	
	/*	Note that most of these are toggles
	/*	
	/*----------------------------------------------------------*/

#define GDB_LOG 	0x00000001		/* turn on tracing to */
						/* log file */
#define GDB_NOFORK 	0x00000002		/* don't fork forking */
						/* servers */
#define GDB_NOPROTOCHK  0x00000004		/* don't verify protocol */
						/* levels (not strictly */
						/* a debug flag)*/


/************************************************************************/
/*	
/*	Things which have to be at the end because they require
/*	the various types to be defined first.
/*	
/************************************************************************/


#ifdef DUMB_7_CHAR_LOADER
	/*----------------------------------------------------------*/
	/*	
	/*	          Long Names for Routines
	/*	
	/*	External names in Unix must generally be unique
	/*	within the first 7 characters or so, at least for
	/*	some versions of ld.  To account for this without
	/*	making all our routine names terribly short and
	/*	cryptic, we use the following defines.
	/*	
	/*----------------------------------------------------------*/

#define string_alloc 			gdb_sta
#define string_free 			gdb_stf

#define create_tuple_descriptor 	gdb_ctd
#define delete_tuple_descriptor 	gdb_dtd
#define field_index			gdb_fi
#define create_tuple 			gdb_ctup
#define delete_tuple			gdb_dtup
#define initialize_tuple		gdb_itup
#define null_tuple_strings		gdb_ntps

#define create_relation			gdb_crel
#define delete_relation			gdb_drel
#define tuples_in_relation              gdb_trel


/*
 * Transport layer
 */
#define create_operation		gdb_crop
#define delete_operation		gdb_dop
#define initialize_operation	        gdb_inop
#define reset_operation			gdb_rsop
#define cancel_operation		gdb_cnop

#define create_list_of_operations	gdb_clop
#define delete_list_of_operations	gdb_dlop

#define op_select			gdb_opsel
#define op_select_any			gdb_opsel
#define op_select_all			gdb_aopsel
#define con_select			gdb_cnsel

#define gdb_receive_data 		gdb_rcdat        
#define gdb_send_data 			gdb_sndat        
#define gdb_start_listening		gdb_stl
#define start_accepting_client		gdb_stac


#define gdb_listen			gdb_lis

/*
 * Connection management
 */
#define start_peer_connection		gdb_spconn
#define sever_connection		gdb_svconn
#define start_server_connection		gdb_stsrv
#define create_listening_connection	gdb_clc
#define start_replying_to_client	gdb_strtc
#define create_forking_server		gdb_cfs


/*
 * Asynchronous operations
 */
#define start_sending_object 		gdb_snobj
#define start_receiving_object 		gdb_rcobj
#define preempt_and_start_receiving_object 		gdb_prcobj

#define queue_operation			gdb_qop

#define requeue_operation		g_req_op

#define complete_operation		gdb_cmpo
/*
 * Synchronous operations
 */
#define send_object			gdb_sobj
#define receive_object			gdb_robj
/*
 * Database operations
 */
#define access_db 			gdb_adb
#define start_accessing_db 		gdb_sadb
#define perform_db_operation		gdb_pdbo
#define db_query			gdb_dbq
#define start_performing_db_operation	gdb_spdb
#define   start_db_query			gdb_sdbq
#else
#define op_select_any  op_select
#endif DUMB_7_CHAR_LOADER

extern char *string_alloc();
extern int   string_free();
extern TUPLE_DESCRIPTOR create_tuple_descriptor();
extern int  delete_tuple_descriptor();
extern int  field_index();
extern TUPLE create_tuple();
extern int   delete_tuple();
extern int   initialize_tuple();
extern int   null_tuple_strings();
extern RELATION create_relation();
extern int delete_relation();
extern OPERATION create_operation();
extern LIST_OF_OPERATIONS create_list_of_operations();
extern OPERATION g_op_newhead();
extern CONNECTION start_peer_connection();
extern CONNECTION sever_connection();
extern CONNECTION start_server_connection();
extern CONNECTION create_listening_connection();
extern CONNECTION create_forking_server();
extern int start_sending_object();
extern int start_receiving_object();
extern int preempt_and_start_receiving_object();
extern int queue_operation();
extern int requeue_operation();
extern int complete_operation();
extern int send_object();
extern int receive_object();


	/*----------------------------------------------------------*/
	/*	
	/*	Other routines requiring extern to avoid forward
	/*	reference to non integer type functions.
	/*	
	/*----------------------------------------------------------*/

extern CONNECTION g_make_con();
