/* 
 * $Id: fcgi.h,v 1.10 1999/05/31 02:10:56 roberts Exp $
 */

#ifndef FCGI_H
#define FCGI_H

/* Apache header files */
#include "httpd.h"
#include "http_config.h"
#include "http_request.h"
#include "http_core.h"
#include "http_protocol.h"
#include "http_main.h"
#include "http_log.h"
#include "util_script.h"
#include "http_conf_globals.h"
#include "util_md5.h"

#if MODULE_MAGIC_NUMBER < 19980806
#error "This version of mod_fastcgi is incompatible with Apache versions 1.3.1 and earlier."
#error "Please upgrade, or try the last Apache 1.2 compatible release, mod_fastcgi 2.0.18 (no DSO support)."
#endif

#ifndef NO_WRITEV
#include <sys/uio.h>
#endif
#include <sys/un.h>

/* FastCGI header files */
#include "mod_fastcgi.h"
/* @@@ This should go away when fcgi_protocol is re-written */
#include "fcgi_protocol.h"

typedef struct {
    int size;               /* size of entire buffer */
    int length;             /* number of bytes in current buffer */
    char *begin;            /* begining of valid data */
    char *end;              /* end of valid data */
    char data[1];           /* buffer data */
} Buffer;

/*
 * ServerProcess holds data for each process associated with
 * a class.  It is embedded in fcgi_server below.
 */
typedef struct _FcgiProcessInfo {
    pid_t pid;                       /* pid of associated process */
    enum {STATE_STARTED,             /* currently running */
          STATE_NEEDS_STARTING,      /* needs to be started by PM */
          STATE_VICTIM,              /* SIGTERM was sent by PM */
          STATE_KILLED,              /* a wait() collected VICTIM */
          STATE_READY}               /* empty cell, init state */
          state;                     /* state of the process */
} ServerProcess;

/*
 * fcgi_server holds info for each AppClass specified in this
 * Web server's configuration.
 */
typedef struct _FastCgiServerInfo {
	int flush;
    const char *fs_path;            /* pathname of executable */
    const char **envp;              /* if NOT NULL, this is the env to send
                                     * to the fcgi app when starting a server
                                     * managed app. */
    u_int listenQueueDepth;         /* size of listen queue for IPC */
    u_int appConnectTimeout;        /* timeout (sec) for connect() requests */
    u_int numProcesses;             /* max allowed processes of this class,
                                     * or for dynamic apps, the number of
                                     * processes actually running */
    time_t restartTime;             /* most recent time when the process
                                     * manager started a process in this
                                     * class. */
    u_int initStartDelay;           /* min number of seconds to wait between
                                     * starting of AppClass processes at init */
    u_int restartDelay;             /* number of seconds to wait between
                                     * restarts after failure.  Can be zero. */
    int restartOnExit;              /* = TRUE = restart. else terminate/free */
    u_int numRestarts;              /* Total number of restarts */
    u_int numFailures;              /* num restarts due to exit failure */
    struct sockaddr *socket_addr;      /* Socket Address of FCGI app server class */
    int socket_addr_len;                /* Length of socket */
    enum {APP_CLASS_UNKNOWN,
          APP_CLASS_STANDARD,
          APP_CLASS_EXTERNAL,
          APP_CLASS_DYNAMIC}
         directive;                 /* AppClass or ExternalAppClass */
    const char *socket_path;           /* Name used to create a socket */
    const char *host;               /* Hostname for externally managed
                                     * FastCGI application processes */
    u_int port;                     /* Port number either for externally
                                     * managed FastCGI applications or for
                                     * server managed FastCGI applications,
                                     * where server became application mngr. */
    int listenFd;                   /* Listener socket of FCGI app server
                                     * class.  Passed to app server process
                                     * at process creation. */
    u_int processPriority;          /* If locally server managed process,
                                     * this is the priority to run the
                                     * processes in this class at. */
    struct _FcgiProcessInfo *procs; /* Pointer to array of
                                     * processes belonging to this class. */
    int keepConnection;             /* = 1 = maintain connection to app. */
    uid_t uid;                      /* uid this app should run as (suexec) */
    gid_t gid;                      /* gid this app should run as (suexec) */
    const char *username;           /* suexec user arg */
    const char *group;              /* suexec group arg, AND used in comm
                                     * between RH and PM */
    const char *user;               /* used in comm between RH and PM */
    /* Dynamic FastCGI apps configuration parameters */
    u_long totalConnTime;           /* microseconds spent by the web server
                                     * waiting while fastcgi app performs
                                     * request processing since the last
                                     * dynamicUpdateInterval */
    u_long smoothConnTime;          /* exponentially decayed values of the
                                     * connection times. */
    u_long totalQueueTime;          /* microseconds spent by the web server
                                     * waiting to connect to the fastcgi app
                                     * since the last dynamicUpdateInterval. */
    struct _FastCgiServerInfo *next;
} fcgi_server;


/*
 * fcgi_request holds the state of a particular FastCGI request.
 */
typedef struct {
    int fd;                         /* connection to FastCGI server */
    int gotHeader;                  /* TRUE if reading content bytes */
    unsigned char packetType;       /* type of packet */
    int dataLen;                    /* length of data bytes */
    int paddingLen;                 /* record padding after content */
    fcgi_server *fs;                /* FastCGI server info */
    const char *fs_path;         /* fcgi_server path */
    Buffer *serverInputBuffer;   /* input buffer from FastCgi server */
    Buffer *serverOutputBuffer;  /* output buffer to FastCgi server */
    Buffer *clientInputBuffer;   /* client input buffer */
    Buffer *clientOutputBuffer;  /* client output buffer */
    table *authHeaders;			 /* headers received from an auth fs */
	int auth_compat;			 /* whether the auth request is spec compat */
	table *saved_subprocess_env; /* subprocess_env before auth handling */
#if defined(SIGPIPE) && MODULE_MAGIC_NUMBER < 19990320
    void (*apache_sigpipe_handler)(int);
#endif
    int expectingClientContent;     /* >0 => more content, <=0 => no more */
    array_header *header;
    char *fs_stderr;
    int parseHeader;                /* TRUE iff parsing response headers */
    request_rec *r;
    int readingEndRequestBody;
    FCGI_EndRequestBody endRequestBody;
    Buffer *erBufPtr;
    int exitStatus;
    int exitStatusSet;
    int requestId;
    int eofSent;
    int role;                       /* FastCGI Role: Authorizer or Responder */
    int dynamic;                    /* whether or not this is a dynamic app */
    struct timeval startTime;       /* dynamic app's connect() attempt start time */
    struct timeval queueTime;       /* dynamic app's connect() complete time */
    struct timeval completeTime;    /* dynamic app's connection close() time */
    int lockFd;                     /* dynamic app's lockfile file descriptor */
    int keepReadingFromFcgiApp;     /* still more to read from fcgi app? */
    const char *user;               /* user used to invoke app (suexec) */
    const char *group;              /* group used to invoke app (suexec) */
} fcgi_request;

/* Values of parseHeader field */
#define SCAN_CGI_READING_HEADERS 1
#define SCAN_CGI_FINISHED        0
#define SCAN_CGI_BAD_HEADER     -1
#define SCAN_CGI_INT_REDIRECT   -2
#define SCAN_CGI_SRV_REDIRECT   -3

/* Opcodes for Server->ProcMgr communication */
#define PLEASE_START 49        /* start dynamic application */
#define CONN_TIMEOUT 50        /* start another copy of application */
#define REQ_COMPLETE 51        /* do some data analysis */

/* Authorizer types, for auth directives handling */
#define FCGI_AUTH_TYPE_AUTHENTICATOR  0
#define FCGI_AUTH_TYPE_AUTHORIZER     1
#define FCGI_AUTH_TYPE_ACCESS_CHECKER 2

/* Bits for auth_options */
#define FCGI_AUTHORITATIVE 1
#define FCGI_COMPAT 2

typedef struct
{
	const char *authorizer;
	u_char authorizer_options;
	const char *authenticator;
	u_char authenticator_options;
	const char *access_checker;
	u_char access_checker_options;
} fcgi_dir_config;

#define	FCGI_LOG_EMERG    __FILE__,__LINE__,APLOG_EMERG		/* system is unusable */
#define	FCGI_LOG_ALERT    __FILE__,__LINE__,APLOG_ALERT		/* action must be taken immediately */
#define	FCGI_LOG_CRIT     __FILE__,__LINE__,APLOG_CRIT		/* critical conditions */
#define	FCGI_LOG_ERR      __FILE__,__LINE__,APLOG_ERR		/* error conditions */
#define	FCGI_LOG_WARNING  __FILE__,__LINE__,APLOG_WARNING	/* warning conditions */
#define	FCGI_LOG_NOTICE   __FILE__,__LINE__,APLOG_NOTICE	/* normal but significant condition */
#define	FCGI_LOG_INFO     __FILE__,__LINE__,APLOG_INFO		/* informational */
#define	FCGI_LOG_DEBUG    __FILE__,__LINE__,APLOG_DEBUG		/* debug-level messages */

#define	FCGI_LOG_EMERG_NOERRNO    __FILE__,__LINE__,APLOG_EMERG|APLOG_NOERRNO
#define	FCGI_LOG_ALERT_NOERRNO    __FILE__,__LINE__,APLOG_ALERT|APLOG_NOERRNO
#define	FCGI_LOG_CRIT_NOERRNO     __FILE__,__LINE__,APLOG_CRIT|APLOG_NOERRNO
#define	FCGI_LOG_ERR_NOERRNO      __FILE__,__LINE__,APLOG_ERR|APLOG_NOERRNO
#define	FCGI_LOG_WARNING_NOERRNO  __FILE__,__LINE__,APLOG_WARNING|APLOG_NOERRNO
#define	FCGI_LOG_NOTICE_NOERRNO   __FILE__,__LINE__,APLOG_NOTICE|APLOG_NOERRNO
#define	FCGI_LOG_INFO_NOERRNO     __FILE__,__LINE__,APLOG_INFO|APLOG_NOERRNO
#define	FCGI_LOG_DEBUG_NOERRNO    __FILE__,__LINE__,APLOG_DEBUG|APLOG_NOERRNO

#ifdef FCGI_DEBUG
#define FCGIDBG1(a)          ap_log_error(FCGI_LOG_DEBUG,fcgi_apache_main_server,a);
#define FCGIDBG2(a,b)        ap_log_error(FCGI_LOG_DEBUG,fcgi_apache_main_server,a,b);
#define FCGIDBG3(a,b,c)      ap_log_error(FCGI_LOG_DEBUG,fcgi_apache_main_server,a,b,c);
#define FCGIDBG4(a,b,c,d)    ap_log_error(FCGI_LOG_DEBUG,fcgi_apache_main_server,a,b,c,d);
#define FCGIDBG5(a,b,c,d,e)  ap_log_error(FCGI_LOG_DEBUG,fcgi_apache_main_server,a,b,c,d,e);
#else
#define FCGIDBG1(a)
#define FCGIDBG2(a,b)
#define FCGIDBG3(a,b,c)
#define FCGIDBG4(a,b,c,d)
#define FCGIDBG5(a,b,c,d,e)
#endif 

/* 
 * fcgi_config.c
 */
void *fcgi_config_create_dir_config(pool *p, char *dummy);
const char *fcgi_config_make_dir(pool *tp, char *path);
const char *fcgi_config_make_dynamic_dir_n_mbox(pool *p, int wax);
const char *fcgi_config_new_static_server(cmd_parms *cmd, void *dummy, const char *arg);
const char *fcgi_config_new_external_server(cmd_parms *cmd, void *dummy, const char *arg);
const char *fcgi_config_set_config(cmd_parms *cmd, void *dummy, const char *arg);
const char *fcgi_config_set_fcgi_uid_n_gid(int set);
const char *fcgi_config_new_auth_server(cmd_parms *cmd, fcgi_dir_config *dir_config, 
					const char *fs_path, const char *compat);
const char *fcgi_config_set_authoritative_slot(const cmd_parms *cmd, 
					       fcgi_dir_config *dir_config, int arg);
const char *fcgi_config_set_socket_dir(cmd_parms *cmd, void *dummy, char *arg);
const char *fcgi_config_set_suexec(cmd_parms *cmd, void *dummy, const char *arg);
void fcgi_config_reset_globals(void* dummy);

/*
 * fcgi_pm.c
 */
int fcgi_pm_main(void *dummy, child_info *info);

/*
 * fcgi_protocol.c
 */
void fcgi_protocol_queue_begin_request(fcgi_request *fr);
void fcgi_protocol_queue_client_buffer(fcgi_request *fr);
int fcgi_protocol_queue_env(request_rec *r, fcgi_request *fr, char ***envp);
int fcgi_protocol_dequeue(pool *p, fcgi_request *fr);

/* 
 * fcgi_buf.c 
 */
#define BufferLength(b)     ((b)->length)
#define BufferFree(b)       ((b)->size - (b)->length)
#define BufferSize(b)       ((b)->size)

void fcgi_buf_check(Buffer *bufPtr);
void fcgi_buf_reset(Buffer *bufPtr);
Buffer *fcgi_buf_new(pool *p, int size);
void BufferDelete(Buffer *bufPtr);
int fcgi_buf_add_fd(Buffer *bufPtr, int fd);
int fcgi_buf_get_to_fd(Buffer *bufPtr, int fd);
void fcgi_buf_get_block_info(Buffer *bufPtr, char **beginPtr, int *countPtr);
void fcgi_buf_toss(Buffer *bufPtr, int count);
void fcgi_buf_get_free_block_info(Buffer *bufPtr, char **endPtr, int *countPtr);
void fcgi_buf_add_update(Buffer *bufPtr, int count);
int fcgi_buf_add_block(Buffer *bufPtr, char *data, int datalen);
int fcgi_buf_add_string(Buffer *bufPtr, char *str);
int fcgi_buf_get_to_block(Buffer *bufPtr, char *data, int datalen);
void fcgi_buf_get_to_buf(Buffer *toPtr, Buffer *fromPtr, int len);
void fcgi_buf_get_to_array(Buffer *buf,array_header *arr, int len);

/*
 * fcgi_util.c
 */

/* Set a shared read lock, wait until you have it.  */
#define fcgi_wait_for_shared_read_lock(fd) fcgi_util_lock_fd((fd), F_SETLKW, F_RDLCK, 0, SEEK_SET, 0)

/* Set an exclusive write lock, no wait, failure->errno==EACCES.  */
#define fcgi_get_exclusive_write_lock_no_wait(fd) fcgi_util_lock_fd(fd, F_SETLK, F_WRLCK, 0, SEEK_SET, 0)

/* Set a shared write lock, wait until you have it.  */
#define fcgi_wait_for_shared_write_lock(fd) fcgi_util_lock_fd(fd, F_SETLKW, F_WRLCK, 0, SEEK_SET, 0)

/* Remove a shared or exclusive lock, no wait, failure->errno=EACCES.  */
#define fcgi_unlock(fd) fcgi_util_lock_fd(fd, F_SETLK, F_UNLCK, 0, SEEK_SET, 0)

char *fcgi_util_socket_hash_filename(pool *p, const char *path,
	const char *user, const char *group);
const char *fcgi_util_socket_make_path_absolute(pool * const p, 
  	const char *const file, const int dynamic);
const char *fcgi_util_socket_get_lock_filename(pool *p, const char *socket_path);
const char *fcgi_util_socket_make_domain_addr(pool *p, struct sockaddr_un **socket_addr,
  	int *socket_addr_len, const char *socket_path);
const char *fcgi_util_socket_make_inet_addr(pool *p, struct sockaddr_in **socket_addr,
  	int *socket_addr_len, const char *host, int port);
const char *fcgi_util_check_access(pool *tp, 
    const char * const path, const struct stat *statBuf, 
    const int mode, const uid_t uid, const gid_t gid);
fcgi_server *fcgi_util_fs_get_by_id(const char *ePath, uid_t uid, gid_t gid);
fcgi_server *fcgi_util_fs_get(const char *ePath, const char *user, const char *group);
const char *fcgi_util_fs_is_path_ok(pool * const p, const char * const fs_path, 
	struct stat *finfo, const uid_t uid, const gid_t gid);
fcgi_server *fcgi_util_fs_new(pool *p);
void fcgi_util_fs_add(fcgi_server *s);
const char *fcgi_util_fs_set_uid_n_gid(pool *p, fcgi_server *s, uid_t uid, gid_t gid);
ServerProcess *fcgi_util_fs_create_procs(pool *p, int num);
int fcgi_util_lock_fd(int fd, int cmd, int type, off_t offset, int whence, off_t len);



/*
 * Globals
 */

extern pool *fcgi_config_pool;

extern server_rec *fcgi_apache_main_server;

extern const char *fcgi_suexec;           /* suexec_bin path */
extern uid_t fcgi_user_id;                       /* the run uid of Apache & PM */
extern gid_t fcgi_group_id;                      /* the run gid of Apache & PM */

extern fcgi_server *fcgi_servers;

extern char *fcgi_socket_dir;             /* default FastCgiIpcDir */

extern pid_t fcgi_pm_pid;

extern char *fcgi_dynamic_dir;            /* directory for the dynamic
                                           * fastcgi apps' sockets */
extern char *fcgi_dynamic_mbox;           /* file through which the fcgi */

extern u_int dynamicMaxProcs;
extern u_int dynamicMinProcs;
extern u_int dynamicMaxClassProcs;
extern u_int dynamicKillInterval;
extern u_int dynamicUpdateInterval;
extern float dynamicGain;
extern u_int dynamicThreshhold1;
extern u_int dynamicThreshholdN;
extern u_int dynamicPleaseStartDelay;
extern u_int dynamicAppConnectTimeout;
extern const char **dynamicEnvp;
extern u_int dynamicProcessSlack;
extern int dynamicAutoRestart;
extern int dynamicAutoUpdate;
extern u_int dynamicListenQueueDepth;
extern u_int dynamicInitStartDelay;
extern u_int dynamicRestartDelay;

extern module MODULE_VAR_EXPORT fastcgi_module;

#endif	/* FCGI_H */

