OpenVMS Source Code Demos

NSR_COUNTER

//===============================================================================================================================
// title  : nsr_count.c
// author : Neil Rieck
// started: 2013-11-28
// purpose: our current very cool graphical page counter (written my Muhammad A Muquit between 1995 and 1999 when web-servers
//	    were powerful machines serving up mostly static pages to underpowered PCs running Pentium-2 and Pentium-3 CPUs)
//	    seems to eat up more server resources than I am now comfortable with. This replacement counter attempts to shift the
//	    "compute burden" from our server to the client. This is just an experiment.
// target : Apache/2.0.63 (OpenVMS)
// notes  : the compiled size of count.exe on OpenVMS is 342k while this program (nsr_count_100.c) is only 4k
//	    (adding bells-n-whistles may make it a little larger)
//
// ver who when   what
// --- --- ------ ---------------------------------------------------------------------------------------------------------------
// 100 NSR 131128 1. started this experimental hack
//     NSR 131129 2. added support for processing query_string data ("df=" etc.)
//     NSR 131202 3. added support for parameter "st="
// 101 NSR 131203 1. now use the file-i/o logic found in wwwcount (for compatability + portability reasons)
//===============================================================================================================================
#include <stdio.h>								// standard i/o
#include <stdlib.h>								// standard library
#include <string.h>								// string routines
//
#ifdef __VMS
#include <fcntl.h>
#include <unixio.h>								// open() etc.
#endif
//
#define DATA_DIR	"wwwcount_etc:[data]"					// counter files live here on OpenVMS
#define MAX_PARAM_SIZE	30							//
//
char		query_string[128];						//
char		temp[128];							//
char		p_df[MAX_PARAM_SIZE];						// parameter "df=" (Data File)
char		p_st[MAX_PARAM_SIZE];						// parameter "st=" (STarting count)
char		count_fs[120];							// counter filename specification
char		file_buffer[80];						// for reading from the counter file
char		msg_buffer[80];							//
long long	start_value;							//
long long	count_value;							//
long		junk1;								//
long		junk2;								//
long		junk3;								//
long		dollar_found;							//
long		pipe1;								//
long		pipe2;								//
long		fd;								// not a pointer with open/lock/close etc.
char		*tmpPtr;							//
//=================================================================
//	this function works like BASIC's seg$() function like so:
//		s1$ = seg$(s2$,1,9)
//=====================================================================
void strseg(char *s1, char *s2, long const p1, long const p2){
    long t0, t1, t2;								//
    t0 = 0;									//
    t1 = p1;									// starting char
    t2 = p2;									// ending char
    while (t1<=t2){								//
	s1[t0] = s2[t1];							// copy char-by-char
	t0++;									//
	t1++;									//
    }
    s1[t0] = '\0';								// terminate string 1
}
//
//	the big kahoona
//
void main(){
	//
	//	initializations
	//
	temp[0]		= '\0';							// workbench
	p_df[0]		= '\0';							// parameter "df=" (Data File)
	p_st[0]		= '\0';							// parameter "st=" (STarting count)
	file_buffer[0]	= '\0';							//
	msg_buffer[0]	= '\0';							//
	dollar_found	= 0;							//
	start_value	= 0;							//
	count_value	= 0;							//

	//
	//	prep to send back a plain-text HTTP response
	//	(error messages will also be returned in this stream)
	//
	printf("Status: 200\n");						// this is for Apache (it will be changed)
	printf("Content-type: text/plain\n");					// tell client browser that this is plain text
	printf("Cache-Control: no-cache, no-store\n");				// this client browser not to cache this data
	printf("\n");								// end of HTTP header
	//
	//	read query string (do not allow hackers to use a buffer overflow exploit)
	//
	//	note: this is data following the question mark as seen in this example
	//	http://kawc09.on.bell.ca/scripts/count?df=icsis_20010101.DAT|dd=d|reload=T
	//
	tmpPtr = getenv("query_string");					// this is set by Apache
	if (tmpPtr==NULL){							//
	    fprintf(stderr,"-e-error, could not locate QUERY_STRING\n");	// write to Apache log
	    fprintf(stdout,"-e-error, could not locate QUERY_STRING\n");	// write to client
	    return;								//
	}
	if (strlen(tmpPtr)>=(sizeof(query_string)-3)){				//
	    fprintf(stderr,"-e-error, QUERY_STRING is too large (hacking?)\n");	// write to Apache log
	    fprintf(stdout,"-e-error, QUERY_STRING is too large (hacking?)\n");	// write to client
	    return;								//
	}
	sprintf(query_string, "%c%s%c",'|',tmpPtr,'|');				// tack pipes on each end for easier processing
	//
	//	okay, scan query string looking for our parameters (we only care about "df=" and "st=")
	//
	junk1 = strlen(query_string);						//
	pipe1 = 0;								// there is always one pipe at position #0
	pipe2 = 0;								// init to same as pipe1
	//
	get_more_params:							//
	for (junk2=pipe1+1; junk2<junk1; junk2++){				// scan query_string starting with pos-1
	    if (query_string[junk2]=='|'){					// if this is a pipe
		pipe2 = junk2;							// remember this position
		//
		junk3 = pipe2 - pipe1 - 1;					// compute the resultant data length
		if ((junk3 > 0) && (junk3 < MAX_PARAM_SIZE)){			// if not null, and we have room to store it
		    strseg(temp,query_string,pipe1+1,pipe2-1);			// copy data found between the pipes
//		    fprintf(stderr,"-i-param %s\n",temp);			// debug to the Apache error log
		    if (strncasecmp(temp,"DF=",3)==0){				//
			strseg(p_df,temp,3,strlen(temp));			//
			sprintf(count_fs,"%s%s",DATA_DIR,p_df);			//
//			fprintf(stderr,"-i-fs: %s\n",count_fs);			// debug to the Apache error log
		    }
		    if (strncasecmp(temp,"ST=",3)==0){				//
			strseg(p_st,temp,3,strlen(temp));			//
			if (strlen(p_st)<=13){					// if <= characters for 9 trillion
			    start_value = atoll(p_st);				//
			    if (start_value<0)					//
				start_value = 1;				//
			}else{							//
			    start_value = 0;					//
			}
//			fprintf(stderr,"-i-st: %d\n",start_value);		// debug to the Apache error log
		    }								//
		}								//
		pipe1 = pipe2;							// prep for next chunk
	    }									//
	}									//
	no_more_params:;
	//
	//	okay, lets read the counter file
	//	note: for compatability reasons, this open/read code is the same as "wwwcount2_6/src/rwdata.c"
	//
#ifdef SYS_WIN32
	fd = sopen(count_fs,_O_RDWR|_O_CREAT,_SH_DENYWR,_S_IREAD|_S_IWRITE);
#else
#ifdef __VMS
	fd = open(count_fs,O_RDWR|O_CREAT,0644,"shr=put","ctx=rec");		// VMS, OpenVMS
#else
	fd = open(count_fs,O_RDWR|O_CREAT,0644);				// UNIX, Linux, etc.
#endif
#endif
	if (fd<0){								//
		printf("-e-oops, file open error: %d",fd);			//
		return;								//
	}									//
#ifdef SYS_UNIX
        SetLock(fd);								//
#endif
	lseek(fd,0L,0);								// rewind
	//
	junk1 = read(fd,file_buffer,80);					// read the file (unix style)
	if (junk1<=0){								// oops, nothing here (must be a new file)
	    if (start_value>0){							//
		count_value=start_value;					//
	    }else{								//
		count_value=0;							//
	    }									//
	    sprintf(file_buffer,"%lld",count_value);				// write this data to the disk buffer
	    junk1 = strlen(file_buffer);					// find the string count before continuing
	}									//
	//
	//	wwwcount2_6 places a dollar sign after the ascii data string. Do not display it.
	//
	for (junk2=0; junk2<junk1; junk2++){					//
	    if (file_buffer[junk2]=='$'){					// if we detected the optional dollar sign
		dollar_found = 1;						// then remember this fact
		msg_buffer[junk2] = '\0';					// and also zap it
		exit;								//
	    }else{								//
		msg_buffer[junk2] = file_buffer[junk2];				// copy char-by-char
	    }									//
	}									//
	count_value = atoll(msg_buffer);					//
	count_value++;
	if (dollar_found==1){
	    sprintf(file_buffer,"%lld%c",count_value,'$');
	}else{
	    sprintf(file_buffer,"%lld",count_value);
	}
	sprintf(msg_buffer,"%lld",count_value);
	junk1 = strlen(msg_buffer);						//
	while (junk1<6){							//
		printf("0");							// need some zero padding
		junk1++;							//
	}									//
	printf("%s",msg_buffer);						// this goes back to the client
	//
	//	write changes back to disk
	//
	lseek(fd,0L,0);								// rewind
	junk3 = write(fd,file_buffer,strlen(file_buffer));			//
	(void) close(fd);
	//
#ifdef SYS_UNIX
	UnsetLock(fd);
#endif
}