/****************************************************************************
 *                                                                          *
 * The contents of this file are subject to the WebStone Public License     *
 * Version 1.0 (the "License"); you may not use this file except in         *
 * compliance with the License. You may obtain a copy of the License        *
 * at http://www.mindcraft.com/webstone/license10.html                      *
 *                                                                          *
 * Software distributed under the License is distributed on an "AS IS"      *
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See      *
 * the License for the specific language governing rights and limitations   *
 * under the License.                                                       *
 *                                                                          *
 * The Original Code is WebStone 2.5.                                       *
 *                                                                          *
 * The Initial Developer of the Original Code is Silicon Graphics, Inc.     *
 * and Mindcraft, Inc.. Portions created by Silicon Graphics. and           *
 * Mindcraft. are Copyright (C) 1995-1998 Silicon Graphics, Inc. and        *
 * Mindcraft, Inc. All Rights Reserved.                                     *
 *                                                                          *
 * Contributor(s): ______________________________________.                  *
 *                                                                          *
 * @(#) bench.c 2.4@(#)                                                     *
 ***************************************************************************/

#ifndef __BENCH_H__ 
#define __BENCH_H__


#include <stdio.h>
#include <stdarg.h>

#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif	/* HAVE_UNISTD_H */

#ifndef WIN32
#include <sys/time.h>
#endif /* WIN32 */

#define USECINSEC	    1000000
#define MSECINSEC	    1000
#define MAX_ACCEPT_SECS	    180	/* maximum time master will wait for listen() */

#define NCCARGS		    4096
#define MAXCLIENTS	    1024
#define MAXUSERNAME	    25
#define MAXPASSWD	    20
#define BUFSIZE		    4096

#define MAXTOTALPROCS	    MAXCLIENTS		/* overall max # of procs */
#define MAXPROCSPERNODE	    MAXCLIENTS		/* max # of procs/node */

/*
 * This is the number of times a webclient will try to connect to the
 * webmaster.  It will sleep CONNECT_TRY_DELAY_SEC between each attempt.
 * If you have a slow network between master and clients or slow client
 * systems then you might try increasing this.
 */
#define MAX_MASTER_CONNECT_TRIES 30
#define CONNECT_TRY_DELAY_SEC    1

#define CONTENT_LENGTH_STRING	"CONTENT-LENGTH:"
#define OKSTR		    "OK"
#define OKSTRLEN	    ((int)strlen(OKSTR))
#define GOSTR		    "GO"
#define GOSTRLEN	    ((int)strlen(GOSTR))
#define READYSTR	    "READY"
#define READYSTRLEN	    ((int)strlen(READYSTR))
#define ABORTSTR	    "ABORT"
#define ABORTSTRLEN	    ((int)strlen(ABORTSTR))
#define ENDTOKEN	   "EndOfFileList\n"
#define ENDTOKENSTRLEN	((int)strlen(ENDTOKEN))


#define MAXNUMOFFILES 1	    /* max # of files per page */
#define URL_SIZE	    1024
#define MAXNUMOFPAGES	    100


/*
 * SIZEOF_TIMEVALTEXT needs to be at least as long as the number of characters
 * in LONG_MAX.
 */
#define SIZEOF_TIMEVALTEXT  18


/*
 * SIZEOF_DOUBLETEXT needs to be at least as long as the number of characters
 * in DBL_MAX when it is printed without scientific notation.
 */
#define SIZEOF_DOUBLETEXT   400


#define SIZEOF_RQSTSTATSTEXT ((7 *  SIZEOF_TIMEVALTEXT) + \
			      (12 * SIZEOF_DOUBLETEXT) + 1)
#define SIZEOF_STATSTEXTBASE    (SIZEOF_RQSTSTATSTEXT + \
			     (3 * SIZEOF_TIMEVALTEXT) + \
			     (2 * SIZEOF_DOUBLETEXT) + 1)
#define SIZEOF_STATSTEXT   (SIZEOF_STATSTEXTBASE + MAXNUMOFPAGES * SIZEOF_DOUBLETEXT)
#define SIZEOF_PAGESTATSTEXT (SIZEOF_RQSTSTATSTEXT + \
			      (0 * SIZEOF_TIMEVALTEXT) + \
			      (3 * SIZEOF_DOUBLETEXT) + 1)

/*
 * The values of the debug variable are:
 *		DEBUG_OFF		-- No debugging output.
 *		DEBUG_TRACE		-- All D_TRACE() statements.  Intended for function
 *							entry and exit.  
 *		DEBUG_ALL		-- Enable all debugging output.  This can be quite 
 *							voluminous and severely impact performance.
 */
#define DEBUG_OFF	0
#define DEBUG_TRACE	1
#define DEBUG_MORE	2
#define DEBUG_ALL	(DEBUG_TRACE | DEBUG_MORE)

#define DEBUGGING_ON	(debug == DEBUG_ALL)
#define TRACING_ON		(debug & DEBUG_TRACE)
#define DEBUGGING_ANY	(debug)

#define TRACE			TRACING_ON && d_printf
#define D_PRINTF		DEBUGGING_ON && d_printf
#define D_STRVAL(arg)	((arg) == NULL ? "(NULL)" : arg)


#ifdef USE_TIMEZONE
typedef struct rqst_timer {
    struct timeval		entertime;
    struct timezone		entertimezone;
    struct timeval		beforeconnect;
    struct timezone		beforeconnectzone;
    struct timeval		afterconnect;
    struct timezone		afterconnectzone;
    struct timeval		beforeheader;
    struct timezone		beforeheaderzone;
    struct timeval		afterheader;
    struct timezone		afterheaderzone;
    struct timeval		afterbody;
    struct timezone		afterbodyzone;
    struct timeval		exittime;
    struct timezone		exittimezone;
    long unsigned int	totalbytes;
    long unsigned int	bodybytes;
    int					valid;
    long unsigned int 	page_number;
} rqst_timer_t;
#else
typedef struct rqst_timer {
    struct timeval		entertime;
    struct timeval		beforeconnect;
    struct timeval		afterconnect;
    struct timeval		beforeheader;
    struct timeval		afterheader;
    struct timeval		afterbody;
    struct timeval		exittime;
    long unsigned int	totalbytes;
    long unsigned int	bodybytes;
    int					valid;
    long unsigned int 	page_number;
} rqst_timer_t;
#endif /* USE_TIMEZONE */

extern void rqtimer_init(rqst_timer_t *);

#ifdef USE_TIMEZONE
typedef struct rqst_stats {
	struct timeval		totalresponsetime;
	struct timezone		totalresponsetimezone;
	double				totalresponsetimesq;
	struct timeval		minresponsetime;
	struct timezone		minresponsetimezone;
	struct timeval		maxresponsetime;
	struct timezone		maxresponsetimezone;
	struct timeval		totalconnecttime;
	struct timezone		totalconnecttimezone;
	double				totalconnecttimesq;
	struct timeval		minconnecttime;
	struct timezone		minconnecttimezone;
	struct timeval		maxconnecttime;
	struct timezone		maxconnecttimezone;
	long unsigned int	totalconnects;
	long unsigned int	totalerrs;
	struct timeval		totalerrortime;
	struct timezone		totalerrortimezone;
	double				totalbytes;
	double				totalbytessq;
	double				minbytes;
	double				maxbytes;
	double				totalbody;
	double				totalbodysq;
	double				minbody;
	double				maxbody;
}	rqst_stats_t;
#else
typedef	struct rqst_stats	{
	struct timeval		totalresponsetime;
	double				totalresponsetimesq;
	struct timeval		minresponsetime;
	struct timeval		maxresponsetime;
	struct timeval		totalconnecttime;
	double				totalconnecttimesq;
	struct timeval		minconnecttime;
	struct timeval		maxconnecttime;
	long unsigned int	totalconnects;
	long unsigned int	totalerrs;
	struct timeval		totalerrortime;
	double				totalbytes;
	double				totalbytessq;
	double				minbytes;
	double				maxbytes;
	double				totalbody;
	double				totalbodysq;
	double				minbody;
	double				maxbody;
} rqst_stats_t;
#endif /* USE_TIMEZONE */

extern void rqstat_init(rqst_stats_t *);
extern void rqstat_sum(rqst_stats_t *, rqst_stats_t *);
extern void rqstat_print(rqst_stats_t *);
extern void rqstat_fprint(FILE *, rqst_stats_t *);
extern void rqstat_times(rqst_stats_t *, rqst_timer_t *);

#ifdef USE_TIMEZONE
typedef struct stats {
    rqst_stats_t		rs;
    struct timeval		starttime;			/* start of test run */
    struct timezone		starttimezone;
    struct timeval		endtime;			/* end of test run */
    struct timezone		endtimezone;
    struct timeval		datatime;
    struct timezone		datatimezone;
    long unsigned int	totalpages;
    unsigned int		total_num_of_files;
    unsigned int		page_numbers[MAXNUMOFPAGES];
} stats_t;
#else
typedef struct stats {
    rqst_stats_t		rs;
    struct timeval		starttime;			/* start of test run */
    struct timeval		endtime;			/* end of test run */
    struct timeval		datatime;
    long unsigned int	totalpages;
    unsigned int		total_num_of_files;
    unsigned int		page_numbers[MAXNUMOFPAGES];
} stats_t;
#endif /* USE_TIMEZONE */

extern void stats_init(stats_t *);
extern stats_t * text_to_stats(char *);
extern char * stats_to_text(const stats_t *);


/* 
 * page_stats: structure to hold data for each "page" we are retrieving from
 *             the web server.
 * 	rs         -- Request statistics for this page
 *  totalpages -- The number of times this page was fetched from the web
 *                server.  At the end of the run this should be equal (or
 *                very close) to the page's "weight".
 *  page_valid -- temporary flag used to indicate that a page was successfully
 *                retrieved from the web server.
 */
typedef struct page_stats {
    rqst_stats_t		rs; 
    long unsigned int	totalpages;
    unsigned int		page_size;
    int					page_valid;
} page_stats_t;

extern void page_stats_init(page_stats_t *);
extern page_stats_t * text_to_page_stats(char *);
extern char * page_stats_to_text(const page_stats_t *);


/* 
 * This structure defines a page to be retrieved from the web server.
 *
 * load_num     -- the weight assigned to a URL in the "filelist" file.
 * num_of_files -- this is unused (it will always be set to 1) since we don't
 *                 currently support the ability to group several files on
 *                 one "page".
 * filename     -- this is the name of the file to be retrieved from the web
 *                 server.  
 * servername   -- if this line came from a "filelist" file and is of the 
 *                 form "http://server/file" then this will be the "server" 
 *                 Thus each line in the "filelist" file can hit a different
 *                 web server.  If, instead, the line was of the form
 *                 "/dir1/file.html" then this will be NULL and the web
 *                 server specified on the webclient command line will be 
 *                 used instead.
 * port_number  -- if this line came from a "filelist" file and is of the form
 *                 "http://server:port/file.html" then this will be the port
 *                 specified in that line.  If, the line was of the form 
 *                 "http://server/file.html" then this will default to 80.  
 *                 If the line was just "/file.html" then this will be set
 *                 to 0 and the port specified on the webclient command line 
 *                 will be used instead.
 * 
 */
typedef struct page_list {
    int 		load_num;
    int 		num_of_files;
    char		*(filename[MAXNUMOFFILES]);
    char		*(servername[MAXNUMOFFILES]);
    int			port_number[MAXNUMOFFILES];
}page_list_t;



/* shared variables */
extern THREAD FILE *debugfile;
extern int debug;

extern int	savefile;
extern int	timeexpired;
extern long int number_of_pages;

/* routines in bench.c */

extern void *mymalloc(size_t size);
extern int recvdata(SOCKET sock, char *ptr, int nbytes);
extern int senddata(SOCKET sock, char *ptr, int nbytes);
extern void rqstat_times(rqst_stats_t *rs, rqst_timer_t *rt);
/* note several others listed above */

/* routines in errexit.c */

void errexit(const char *, ...);
extern int returnerr(const char *, ...);
extern int d_printf(const char *, ...);
extern char *neterrstr(void);

/* routines in get.c */

#ifdef STONE_SSL
extern int  get(char *loc, NETPORT port, char *url, rqst_timer_t *timer,
		char* ssl_version, char* ssl_cipher);
#else
extern int  get(char *loc, NETPORT port, char *url, rqst_timer_t *timer);
#endif

/* routines in parse_file_list.c */

extern void parse_file_list (FILE *fp, page_list_t *page_list, 
		 long int *num_of_pages, long int *num_of_files);
extern long int load_percent(page_list_t *page_list, long int number_of_pages);

/* routines in statistics.c (formerly statistics.h) */

extern double	mean(const double, const int);
extern double	variance(const double, const double, const int);
extern double	stddev(const double, const double, const int);

/* routines in timefunc.c (formerly timefunc.h) */

extern double	timevaldouble(struct timeval *);
extern void	doubletimeval(const double, struct timeval *);

extern void	addtime(struct timeval *, struct timeval *);
extern void	compdifftime(struct timeval *, struct timeval *, struct timeval *);
extern void	mintime(struct timeval *, struct timeval *);
extern void	maxtime(struct timeval *, struct timeval *);
extern void	avgtime(struct timeval *, int, struct timeval *);
extern void	variancetime(struct timeval *, double, int, struct timeval *);
extern void	stddevtime(struct timeval *, double, int, struct timeval *);

extern void	sqtime(struct timeval *, struct timeval *);

extern double	thruputpersec(const double, struct timeval *);

/* routines in webclient.c */

extern SOCKET connectsock(char *host, NETPORT portnum, char *protocol);

#endif /* !__BENCH_H__ */
