/*--------------------------------------------------------------------
 * FILE:
 *     pglb.h
 *
 * Portions Copyright (c) 2003-2006  Atsushi Mitani
 *--------------------------------------------------------------------
 */
#ifndef PGLB_H
#define PGLB_H

#define PGLB_VERSION	"1.7.0rc7"

#include "../libpgc/libpgc.h"

/*
 * from pool.h
 */

/* 
 * define this if you do not want to issue RESET ALL at each new
 * connection.  Also you need to define this for 7.1 or prior
 * PostgreSQL since they do not support RESET ALL
 */
#undef NO_RESET_ALL

/* undef this if you have problems with non blocking accept() */
#define NONE_BLOCK

#define POOLMAXPATHLEN 8192

/* configuration file name */
#define POOL_CONF_FILE_NAME "pgpool.conf"

/* pid file directory */
#define DEFAULT_LOGDIR "/tmp"

/* Unix domain socket directory */
#define DEFAULT_SOCKET_DIR "/tmp"

/* pid file name */
#define PID_FILE_NAME "pgpool.pid"

/* strict mode comment in SQL */
#define STRICT_MODE_STR "/*STRICT*/"
#define STRICT_MODE(s) (strncasecmp((s), STRICT_MODE_STR, strlen(STRICT_MODE_STR)) == 0)

typedef enum {
    POOL_CONTINUE = 0,
	POOL_IDLE,
    POOL_END,
    POOL_ERROR,
    POOL_FATAL
} POOL_STATUS;

/* protocol major version numbers */
#define PROTO_MAJOR_V2	2
#define PROTO_MAJOR_V3	3

/*
 * startup packet definitions (v2) stolen from PostgreSQL
 */
#define SM_DATABASE		64
#define SM_USER			32
#define SM_OPTIONS		64
#define SM_UNUSED		64
#define SM_TTY			64

typedef struct PGR_StartupPacket_v2
{
	int			protoVersion;		/* Protocol version */
	char		database[SM_DATABASE];	/* Database name */
	char		user[SM_USER];	/* User name */
	char		options[SM_OPTIONS];	/* Optional additional args */
	char		unused[SM_UNUSED];		/* Unused */
	char		tty[SM_TTY];	/* Tty for debug output */
} PGR_StartupPacket_v2;

/* startup packet info */
typedef struct
{
	char *startup_packet;		/* raw startup packet without packet length (malloced area) */
	int len;					/* raw startup packet length */
	int major;	/* protocol major version */
	int minor;	/* protocol minor version */
	char *database;	/* database name in startup_packet (malloced area) */
	char *user;	/* user name in startup_packet (malloced area) */
} PGR_StartupPacket;

typedef struct CancelPacket
{
	int			protoVersion;		/* Protocol version */
	int			pid;	/* bcckend process id */
	int			key;	/* cancel key */
} CancelPacket;

/*
 * configuration paramters
 */
typedef struct {
    int	inetdomain;	/* should we make an INET domain socket too? */
    int	port;	/* port # to bind */
	char *socket_dir;		/* pgpool socket directory */
    char	*backend_host_name;	/* backend host name */
    int	backend_port;	/* backend port # */
    char	*secondary_backend_host_name;	/* secondary backend host name */
    int	secondary_backend_port;	/* secondary backend port # */
    int	num_init_children;	/* # of children initially pre-forked */
    int	child_life_time;	/* if idle for this seconds, child exits */
    int	connection_life_time;	/* if idle for this seconds, connection closes */
    int	max_pool;	/* max # of connection pool per child */
    char *logdir;		/* logging directory */
    char *backend_socket_dir;	/* Unix domain socket directory for the PostgreSQL server */
	int replication_mode;		/* replication mode */
	int replication_strict;	/* if non 0, wait for completion of the
                               query sent to master to avoid deadlock */
	/*
	 * if secondary does not respond in this milli seconds, abort this session.
	 * this is not compatible with replication_strict = 1. 0 means no timeout.
	 */
	int replication_timeout;

	int load_balance_mode;		/* load balance mode */

	/* followings do not exist in the configuration file */
    char	*current_backend_host_name;	/* current backend host name */
    int	current_backend_port;	/* current backend port # */
	int replication_enabled;		/* replication mode enabled */

	int replication_stop_on_mismatch;		/* if there's a data mismatch between master and secondary
											 * start degenration to stop replication mode
											 */
} POOL_CONFIG;

#define MAX_PASSWORD_SIZE		(1024)

typedef struct {
	int num;	/* number of entries */
	char **names;		/* parameter names */
	char **values;		/* values */
} ParamStatus;

/*
 * stream connection structure
 */
typedef struct {
	int fd;		/* fd for connection */
	FILE *write_fd;	/* stream write connection */

	char *hp;	/* pending data buffer head address */
	int po;		/* pending data offset */
	int bufsz;	/* pending data buffer size */
	int len;	/* pending data length */

	char *sbuf;	/* buffer for pool_read_string */
	int sbufsz;	/* its size in bytes */

	char *buf2;	/* buffer for pool_read2 */
	int bufsz2;	/* its size in bytes */

	int isbackend;		/* this connection is for backend if non 0 */
	int issecondary_backend;		/* this connection is for secondary backend if non 0 */

	char tstate;		/* transaction state (V3 only) */

	/*
	 * following are used to remember when re-use the authenticated connection
	 */
	int auth_kind;		/* 3: clear text password, 4: crypt password, 5: md5 password */
	int pwd_size;		/* password (sent back from frontend) size in host order */
	char password[MAX_PASSWORD_SIZE];		/* password (sent back from frontend) */
	char salt[4];		/* password salt */

	/*
	 * following are used to remember current session paramter status.
	 * re-used connection will need them (V3 only)
	 */
	ParamStatus params;

	int no_forward;		/* if non 0, do not write to frontend */

} POOL_CONNECTION;

/*
 * connection pool structure
 */
typedef struct {
	PGR_StartupPacket *sp;	/* startup packet info */
    int pid;	/* backend pid */
    int key;	/* cancel key */
    POOL_CONNECTION	*con;
	time_t closetime;	/* absolute time in second when the connection closed
						 * if 0, that means the connection is under use.
						 */
} POOL_CONNECTION_POOL_SLOT;

#define MAX_CONNECTION_SLOTS 2

typedef struct {
    int num;	/* number of slots */
    POOL_CONNECTION_POOL_SLOT	*slots[MAX_CONNECTION_SLOTS];
} POOL_CONNECTION_POOL;

#define MASTER_CONNECTION(p) ((p)->slots[0])
#define SECONDARY_CONNECTION(p) ((p)->slots[1])
#define MASTER(p) MASTER_CONNECTION(p)->con
#define SECONDARY(p) SECONDARY_CONNECTION(p)->con
#define MAJOR(p) MASTER_CONNECTION(p)->sp->major
#define TSTATE(p) MASTER(p)->tstate

#define Max(x, y)		((x) > (y) ? (x) : (y))
#define Min(x, y)		((x) < (y) ? (x) : (y))

/*
 * pglb
 */

typedef struct {
	int useFlag;
	int sock;
}SocketTbl;

typedef struct {
	int useFlag;
	char hostName[HOSTNAME_MAX_LENGTH];
	unsigned short port;
	short max_connect;
	int use_num;
	int rate;
	int rec_no;
	int retry_count;
}ClusterTbl;

typedef struct {
	long mtype;
	char mdata[1];
}MsgData;

typedef struct {
	int useFlag;
	int rec_no;
	pid_t pid;
}ChildTbl;

#define UNIX_DOMAIN_FD	(0)
#define INET_DOMAIN_FD	(1)
typedef struct {
	int unix_fd;
	int inet_fd;
}FrontSocket;

#define pool_config_inetdomain	(0)
#define pool_config_replication_mode	(0)
#define pool_config_replication_strict	(0)
#define pool_config_replication_timeout	(0)
#define pool_config_replication_enabled	(0)
#define pool_config_load_balance_mode	(0)
#define pool_config_replication_stop_on_mismatch	(0)
#define pool_config_port	(Recv_Port_Number)
#define pool_config_socket_dir	(Backend_Socket_Dir)
#define pool_config_backend_host_name	(CurrentCluster->hostName)
#define pool_config_backend_port	(CurrentCluster->port)
#define pool_config_secondary_backend_host_name	(CurrentCluster->hostName)
#define pool_config_secondary_backend_port	(CurrentCluster->port)
#define pool_config_num_init_children	(CurrentCluster->max_connect)
#define pool_config_child_life_time	(Connection_Life_Time)
#define pool_config_connection_life_time	(Connection_Life_Time)
#define pool_config_max_pool	(Max_Pool)
#define pool_config_logdir	"./"
#define pool_config_backend_socket_dir	(Backend_Socket_Dir)
#define pool_config_current_backend_host_name	(CurrentCluster->hostName)
#define pool_config_current_backend_port	(CurrentCluster->port)
#define REPLICATION (0)
#define IN_LOAD_BALANCE (0)

/*
 * for pglb
 */
#define MAX_DB_SERVER	(32)
#define PGLB_MAX_SOCKET_QUEUE (10000)
#define	CLUSTER_TBL_SHM_KEY	(1010)
#define PGLB_CONNECT_RETRY_TIME  (3)
#define DEFAULT_CONNECT_NUM	(32)
#define DEFAULT_PORT	(5432)
#define BUF_SIZE	(16384)
#define TBL_FREE	(0)
#define TBL_INIT	(1)
#define TBL_USE		(2)
#define TBL_STOP	(3)
#define TBL_ACCEPT	(10)
#define TBL_ERROR_NOTICE	(98)
#define TBL_ERROR	(99)
#define TBL_END	(-1)
#define STATUS_OK	(0)
#define STATUS_ERROR	(-1)
#ifdef	RECOVERY_PREPARE_REQ
#define ADD_DB		RECOVERY_PREPARE_REQ
#else
#define ADD_DB		(1)
#endif
#ifdef	RECOVERY_PGDATA_ANS
#define STOP_DB		RECOVERY_PGDATA_ANS
#else
#define STOP_DB		(3)
#endif
#ifdef	RECOVERY_FINISH
#define START_DB	RECOVERY_FINISH
#else
#define START_DB	(9)
#endif
#define DELETE_DB	(99)
#define QUERY_TERMINATE	(0x00)
#define RESPONSE_TERMINATE	(0x5a)
#define PGLB_CONF_FILE	"pglb.conf"
#define PGLB_PID_FILE	"pglb.pid"
#define PGLB_STATUS_FILE "pglb.sts"
#define PGLB_LOG_FILE "pglb.log"
#define CLUSTER_SERVER_TAG	"Cluster_Server_Info"
#define MAX_CONNECT_TAG	"Max_Connect"
#define RECOVERY_PORT_TAG	"Recovery_Port"
#define RECV_PORT_TAG	"Receive_Port"
#define MAX_CLUSTER_TAG	"Max_Cluster_Num"
#define USE_CONNECTION_POOL_TAG "Use_Connection_Pooling"
#define MAX_POOL_TAG	"Max_Pool_Each_Server"
#define BACKEND_SOCKET_DIR_TAG	"Backend_Socket_Dir"
#define CONNECTION_LIFE_TIME	"Connection_Life_Time"
#define NOT_USE_CONNECTION_POOL	(0)
#define USE_CONNECTION_POOL	(1)

#define PGR_SEND_RETRY_CNT (100)
#define PGR_SEND_WAIT_MSEC (500)
#define PGR_RECV_RETRY_CNT (100)
#define PGR_RECV_WAIT_MSEC (500)

extern int Recv_Port_Number;
extern int Recovery_Port_Number;
extern uint16_t LifeCheck_Port_Number;
extern int Use_Connection_Pool;
extern int Max_Pool;
extern int Connection_Life_Time;
extern int Msg_Id;
extern ClusterTbl * Cluster_Tbl;
extern int Max_DB_Server;
extern int MaxBackends;
extern char * Backend_Socket_Dir;
extern int ClusterShmid;
extern int ClusterSemid;
extern int ChildShmid;
extern int ClusterNum;
extern ChildTbl * Child_Tbl;
extern char * PGR_Data_Path;
extern char * PGR_Write_Path;
extern char * Backend_Socket_Dir;
extern FrontSocket Frontend_FD;
extern FILE * StatusFp;
extern char * ResolvedName;
extern char * PGRuserName;

/* for child.c */
extern POOL_CONNECTION * Frontend;
extern ClusterTbl * CurrentCluster;

extern char * Function;

extern POOL_CONNECTION_POOL *pool_connection_pool;	/* connection pool */

/* extern of main.c */
extern void PGRrecreate_child(int signal_args);
extern void PGRexit_subprocess(int sig);

/* extern of child.c */
extern int PGRpre_fork_children(ClusterTbl * ptr);
extern int PGRpre_fork_child(ClusterTbl * ptr);
extern int PGRdo_child( int use_pool);
extern int PGRcreate_child(ClusterTbl * cluster_p);
extern pid_t PGRscan_child_tbl(ClusterTbl * cluster_p);
extern void notice_backend_error(void);
extern void do_pooling_child(int sig);
extern int PGRset_status_to_child_tbl(pid_t pid, int status);
extern int PGRadd_child_tbl(ClusterTbl * cluster_p, pid_t pid, int status);
extern int PGRget_child_status(pid_t pid);
extern void PGRreturn_connection_full_error(void);
extern void PGRreturn_no_connection_error(void);
extern void PGRquit_children_on_cluster(int rec_no);

/* extern of cluster_table.c */
extern int PGRis_cluster_alive(void) ;
extern ClusterTbl * PGRscan_cluster(void);
extern void PGRset_key_of_cluster(ClusterTbl * ptr, RecoveryPacket * packet);
extern ClusterTbl * PGRadd_cluster_tbl (ClusterTbl * conf_data);
extern ClusterTbl * PGRset_status_on_cluster_tbl (int status, ClusterTbl * ptr);
extern ClusterTbl * PGRsearch_cluster_tbl(ClusterTbl * conf_data);

/* extern of load_balance.c */
extern int PGRload_balance(void);
extern int PGRload_balance_with_pool(void);
extern char PGRis_connection_full(ClusterTbl * ptr);
extern void PGRuse_connection(ClusterTbl * ptr);
extern void PGRrelease_connection(ClusterTbl * ptr);
extern void PGRchild_wait(int sig);

/* extern of recovery.c */
extern void PGRrecovery_main(int fork_wait_fime);

/* extern of socket.c */
extern int PGRcreate_unix_domain_socket(char * sock_dir, unsigned short port);
extern int PGRcreate_recv_socket(char * hostName , unsigned short portNumber);
extern int PGRcreate_acception(int fd, char * hostName , unsigned short portNumber);
extern void PGRclose_sock(int * sock);
extern int PGRread_byte(int sock,char * buf,int len, int flag);
extern int PGRcreate_cluster_socket( int * sock, ClusterTbl * ptr );

/* extern of pool_auth.c */
extern int pool_do_auth(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *cp);
extern int pool_do_reauth(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *cp);
extern int pool_read_message_length(POOL_CONNECTION_POOL *cp);
extern signed char pool_read_kind(POOL_CONNECTION_POOL *cp);

/* extern of pool_connection_pool.c */
extern int pool_init_cp(void);
extern POOL_CONNECTION_POOL *pool_get_cp(char *user, char *database, int protoMajor);
extern void pool_discard_cp(char *user, char *database, int protoMajor);
extern POOL_CONNECTION_POOL *pool_create_cp(void);
extern void pool_connection_pool_timer(POOL_CONNECTION_POOL *backend);
extern void pool_backend_timer_handler(int sig);
extern int connect_inet_domain_socket(int secondary_backend);
extern int connect_unix_domain_socket(int secondary_backend);
extern char PGRis_same_host(char * host1, char * host2);
extern void pool_finish(void);

/* extern of pool_process_query.c */
extern POOL_STATUS pool_process_query(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend, int connection_reuse);
extern POOL_STATUS ErrorResponse(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend);
extern void pool_enable_timeout(); 
extern void pool_disable_timeout();
extern int pool_check_fd(POOL_CONNECTION *cp, int notimeout);
extern void pool_send_frontend_exits(POOL_CONNECTION_POOL *backend);
extern POOL_STATUS SimpleForwardToFrontend(char kind, POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend);
extern POOL_STATUS SimpleForwardToBackend(char kind, POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend);
extern POOL_STATUS ParameterStatus(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend);
extern void pool_send_error_message(POOL_CONNECTION *frontend, int protoMajor, char *code, char *message, char *detail, char *hint, char *file, int line);

/* extern of pool_params.c */
extern int pool_init_params(ParamStatus *params);
extern void pool_discard_params(ParamStatus *params);
extern char *pool_find_name(ParamStatus *params, char *name, int *pos);
extern int pool_get_param(ParamStatus *params, int index, char **name, char **value);
extern int pool_add_param(ParamStatus *params, char *name, char *value);
extern void pool_param_debug_print(ParamStatus *params);

/* extern of pool_stream.c */
extern POOL_CONNECTION *pool_open(int fd);
extern void pool_close(POOL_CONNECTION *cp);
extern int pool_read(POOL_CONNECTION *cp, void *buf, int len);
extern char *pool_read2(POOL_CONNECTION *cp, int len);
extern int pool_write(POOL_CONNECTION *cp, void *buf, int len);
extern int pool_flush(POOL_CONNECTION *cp);
extern int pool_write_and_flush(POOL_CONNECTION *cp, void *buf, int len);
extern char *pool_read_string(POOL_CONNECTION *cp, int *len, int line);

/*
 * external prototype in show.c
 */
extern void show_error(const char * fmt,...);
extern void show_debug(const char * fmt,...);
extern void PGRwrite_log_file(FILE * fp, const char * fmt,...);

/*
 * external prototype in lifecheck.c
 */
extern int PGRlifecheck_main(int fork_wait_time);

#endif /* PGLB_H */
