From 99aa8c60282c7b8072eb35eb9ac815702f5bf586 Mon Sep 17 00:00:00 2001 From: "William R. Otte" Date: Tue, 4 Mar 2008 14:51:23 +0000 Subject: undoing accidental deletion --- ACE/apps/JAWS/clients/WebSTONE/src/webmaster.c | 1420 ++++++++++++++++++++++++ 1 file changed, 1420 insertions(+) create mode 100644 ACE/apps/JAWS/clients/WebSTONE/src/webmaster.c (limited to 'ACE/apps/JAWS/clients/WebSTONE/src/webmaster.c') diff --git a/ACE/apps/JAWS/clients/WebSTONE/src/webmaster.c b/ACE/apps/JAWS/clients/WebSTONE/src/webmaster.c new file mode 100644 index 00000000000..1bfbcc06b9d --- /dev/null +++ b/ACE/apps/JAWS/clients/WebSTONE/src/webmaster.c @@ -0,0 +1,1420 @@ +/* $Id$ */ +/************************************************************************** + * * + * Copyright (C) 1995 Silicon Graphics, Inc. * + * * + * These coded instructions, statements, and computer programs were * + * developed by SGI for public use. If any changes are made to this code* + * please try to get the changes back to the author. Feel free to make * + * modifications and changes to the code and release it. * + * * + **************************************************************************/ + +/* FUZZ: disable check_for_math_include */ +/* FUZZ: disable check_for_improper_main_declaration */ + +#include +#include +#include +#include +#include +#include + +#ifndef WIN32 +#include +#endif /* WIN32 */ + +#include + +#ifndef WIN32 +#include +#include +#include +#include +#include +#include +#include +#else +#define FD_SETSIZE 1024 /* max size for select() - keep before + * and same size as MAXCLIENTS */ +#include +#include +#include +#include +#endif /* WIN32 */ + +#include "sysdep.h" +#include "bench.h" + +/* command line options/data */ +int savefile = 0; +int debug = 0; +int norexec = 0; +int haveproxyserver = 0; +char proxyserver[MAXHOSTNAMELEN]; +char network_mask_str[30] = "255.255.255.0"; +unsigned network_mask = 0; +int servaddrin_config = 0; +int dumpall = 0; +int testtime = 0; +int havewebserver = 0; +int numloops = 0; +NETPORT portnum = 0; +int redirect = 0; +int record_all_transactions = 0; +int uil_filelist_f = 0; +int verbose = 0; +char webserver[MAXHOSTNAMELEN]; +char configfile[MAXPATHLEN]; +char uil_filelist[NCCARGS]; + +char filelist[256][MAXPATHLEN]; +fd_set zerofdset; + +/* other key data */ +long int number_of_pages = 0; +int totalnumclients = 0; +int num_rexecs = 0; +SOCKET socknum[MAXCLIENTS]; +SOCKET sockIO[MAXTOTALPROCS]; +SOCKET sockErr[MAXTOTALPROCS]; +THREAD FILE *debugfile = stderr; +struct hostent *master_phe; /* IP addresses for webmaster */ +struct timeval sumedh_start, sumedh_end; + +void HostEntCpy(struct hostent *dest, struct hostent *src); + +static void +usage(const char *progname) +{ + + fprintf(stderr, "Usage: %s [-a] [-d] -f config_file [-l numloops]\n", + progname); + fprintf(stderr, " [-p port_num] [-r] [-s] [-t run_time] \n"); + fprintf(stderr, "\n"); + fprintf(stderr, "-w webserver URL [URL ...]\n\n"); + fprintf(stderr, "-a print timing information for all clients\n"); + fprintf(stderr, "-d turn on debug statements\n"); + fprintf(stderr, "-f config_file\tfile specifying clients\n"); + fprintf(stderr, "-l number of iterations to retrieve uils\n"); + fprintf(stderr, "-p port number of web server if not 80\n"); + fprintf(stderr, "-r redirect stdout of clients to /tmp/webstone.xxx\n"); + fprintf(stderr, "-s save client gets to /tmp/webstone.data.*\n"); + fprintf(stderr, "-t run_time\tduration of test in minutes\n"); + fprintf(stderr, "-w webserver\tname of webserver host to contact\n"); + fprintf(stderr, "-u URL file\tfilelist of URLs\n"); + fprintf(stderr, "-v verbose mode\n"); + fprintf(stderr, "-P servername\tuse proxy server for transactions\n"); + fprintf(stderr, "-W webserver addresses are in the config file\n"); + fprintf(stderr, "-R record all transactions\n"); + errexit("\n"); +} + +static SOCKET +passivesock(const NETPORT portnum, const char *protocol, const int qlen) +{ + struct protoent *ppe; /* pointer to protocol info entry */ + struct sockaddr_in sin; /* Internet endpoint address */ + SOCKET s; /* socket descriptor */ + int type; /* socket type */ + + D_PRINTF( "Beginning passivesock with errno %d\n",errno ); + + D_PRINTF( "Zeroing address structure\n" ); + memset((char *)&sin, 0, sizeof(sin)); + + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = INADDR_ANY; + + /* NOT USED: Map service name to portnumber */ + D_PRINTF( "Mapping portnum errno %d\n",errno ); + sin.sin_port = htons(portnum); + + /* Map protocol name to number */ + D_PRINTF( "Mapping protocol name errno %d\n",errno ); + if ((ppe = getprotobyname(protocol)) == 0) + { + errexit("Can't get \"%s\" protocol entry\n", protocol); + } + errno = 0; + + /* use protocol to choose socket type */ + D_PRINTF( "Changing socket type, errno %d\n",errno ); + if (strcmp(protocol, "udp") == 0) + { + type = SOCK_DGRAM; + D_PRINTF( "Choosing SOCK_DGRAM\n" ); + } + else + { + type = SOCK_STREAM; + D_PRINTF( "Choosing SOCK_STREAM, errno %d\n",errno ); + } + + /* allocate a socket */ + s = socket(PF_INET, type, ppe->p_proto); + if (BADSOCKET(s)) + { + D_PRINTF( "Socket PF_INET %d %d returned %d with %s\n", + type, ppe->p_proto, s, neterrstr() ); + errexit("Can't create socket: %s\n", neterrstr()); + } + D_PRINTF( "Socket %d created with errno %d\n",s,errno ); + + /* Bind the socket */ + if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) + { + errexit("Can't bind to port %d: %s\n", portnum, neterrstr()); + } + D_PRINTF( "Bind succeeded\n" ); + + /* If it's a stream, listen for connections */ + /* NOTE: ON NT, the listen() backlog parm is silently limited to 5 conns */ + if ((type == SOCK_STREAM) && BADSOCKET(listen(s, qlen))) + { + errexit("Can't listen on port %s: %s\n", portnum, neterrstr()); + } + D_PRINTF( "Listen succeeded\n" ); + + /* all done, return socket descriptor */ + return(s); +} + + +/* abort clients -- called by SIGINT handler */ +static void abort_clients(void) +{ + /* Not supposed to have fprintf in a signal handler, but... */ + fprintf(stdout, "Webmaster received SIGINT. Terminating.\n"); + /* exit will close all open connections */ + exit(2); +} + +/* signal handler for SIGINT */ +static void sig_int(int sig) { + + abort_clients(); +} + +#ifdef WIN32 + +/* echo stdout/stderr from clients */ +void echo_client(void *stream) +{ + SOCKET *sockarr; + FILE *outfile; + int which_stream = (int) stream; + char buf[BUFSIZ]; + int i, len, rv; + fd_set readfds; + + /* This code which handles the timeout may need + to be ifdef'ed for WIN32 */ + struct timeval timeout; + + timeout.tv_sec = (long)5; + timeout.tv_usec = (long)0; + + if (which_stream) { + sockarr = sockIO; + outfile = stdout; + } else { + sockarr = sockErr; + outfile = stderr; + } + + D_PRINTF( "echo_client running\n" ); + signal( SIGINT, SIG_DFL); /* restore default behavior + for SIGINT */ + + while (1) { + FD_ZERO(&readfds); + for (i = 0; i < num_rexecs; i++) + if (sockarr[i] != BADSOCKET_VALUE) + FD_SET(sockarr[i], &readfds); + rv = select(num_rexecs, &readfds, 0, 0, &timeout); + if ( rv == 0) + continue; + if (rv < 0 && WSAGetLastError() == WSANOTINITIALISED) + return; + if (rv < 0) + errexit("Error in echo_client(): select() returns %d: %s\n", rv, neterrstr()); + + /* loop over the sockets that are ready with data */ + for (i = 0; i < num_rexecs; i++) { + if (sockarr[i] != BADSOCKET_VALUE && FD_ISSET(sockarr[i], &readfds)) { + len = NETREAD(sockarr[i], buf, sizeof(buf)); + if (len <= 0) { + /* mark connection closed */ + sockarr[i] = BADSOCKET_VALUE; + if (len < 0 && WSAGetLastError() == WSANOTINITIALISED) + return; + if (len < 0) + fprintf(stderr, "Error in echo_client() after NETREAD(): %s\n", neterrstr()); + continue; + } + + /* copy to stdout or stderr */ + fwrite(buf, sizeof(char), len, outfile); + } + } + } + D_PRINTF( "Exiting echo_client\n" ); +} + +#else +static int +echo_client(char *hostname, const int fd) +{ + /* + * WRITE TEXT FROM FILE DESCRIPTOR INTO STDOUT + */ + char buf[BUFSIZ]; + int cc; + D_PRINTF( "echo_client running\n" ); + + while (getppid() != 1) + { + cc = NETREAD(fd, buf, sizeof(buf)); + if (cc > 0) + { + write(STDOUT_FILENO, buf, cc); + } + } + D_PRINTF( "Exiting echo_client\n" ); + NETCLOSE(fd); +} +#endif /* WIN32 */ + +/* Picks the appropriate webmaster IP address based on the address of the client. + * This is significant only for hosts with multiple interfaces + * + * return value is a string with the IP address or hostname (or NULL) + */ +char *pick_webmaster_IP_address(char *client_hostname, struct hostent *master_phe, + unsigned netmask) { +static char buf[20]; +unsigned char addr[4]; +int client_addr; +int i; + + if (client_hostname[0] >= '0' && client_hostname[0] <= '9') { + /* we have an IP address */ + client_addr = inet_addr(client_hostname); + if (client_addr == INADDR_NONE) + return 0; + } else { + /* we have a hostname, use the webserver hostname */ + return master_phe->h_name; + } + + for (i = 0; master_phe->h_addr_list[i] != 0; i++) { + if ((*(int *)(master_phe->h_addr_list[i]) & netmask) == + (client_addr & netmask)) + goto gotit; + } + i = 0; /* give up */ + +gotit: + memcpy((char *)addr, master_phe->h_addr_list[i], sizeof(addr)); /* Internet specific */ + sprintf(buf, "%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]); + return buf; +} + +/* + Command line parsing +*/ + +void ParseCmdLine(int argc, char **argv ) +{ +char getoptch; +int currarg; +extern char *optarg; +extern int optind; + + /* + * PARSE THE COMMAND LINE OPTIONS + */ + while((getoptch = getopt(argc,argv,"P:f:t:l:p:u:R:w:n:M:adrsvWX")) != (const char)EOF) + { + switch(getoptch) + { + case 'M': + strcpy(network_mask_str, optarg); + break; + case 'P': + haveproxyserver = 1; + strcpy(proxyserver, optarg); + break; + case 'R': + record_all_transactions = 1; + break; + case 'X': + norexec = 1; + break; + case 'W': + servaddrin_config = 1; + break; + case 'a': + dumpall = 1; + break; + case 'd': + debug = 1; + break; + case 'f': + strcpy(configfile, optarg); + break; + case 'l': + numloops = atoi(optarg); + break; + case 'p': + portnum = atoi(optarg); + break; + case 'r': + redirect = 1; + break; + case 's': + savefile = 1; + break; + case 't': + testtime = atoi(optarg); + break; + case 'u': + uil_filelist_f = 1; + strcpy(uil_filelist, optarg); + break; + case 'v': + verbose = 1; + break; + case 'w': + havewebserver = 1; + strcpy(webserver, optarg); + break; + default: + usage(argv[0]); + } /* end switch */ + } /* end while */ + + if (numloops && testtime) + errexit("Can't have both -l and -t\n"); + + if(!havewebserver && !servaddrin_config) + { + /* + * THE SERVERS NAME MUST BE SPECIFIED + */ + + fprintf(stderr,"No WWW Server specified\n"); + usage(argv[0]); + } + + if (havewebserver && servaddrin_config) + { + /* + * CAN'T HAVE BOTH -w and -W + */ + fprintf(stderr, "Can't have both -w and -W options\n"); + usage(argv[0]); + } + + network_mask = inet_addr(network_mask_str); + if (network_mask == INADDR_NONE) { + fprintf(stderr, "Invalid network mask (-M %s)\n", network_mask_str); + usage(argv[0]); + } + + if(strlen(configfile) == 0) + { + /* + * THE MASTER MUST HAVE A CONFIGURATION FILE TO READ. + */ + fprintf(stderr,"No Configuration file specified\n"); + usage(argv[0]); + } + /* IF WE DO NOT HAVE A FILE LIST THEN THERE ARE UIL'S AT THE END OF THE + * COMMAND LINE SO GRAB THEM. + */ + if (uil_filelist_f == 0) + { + currarg = optind; + number_of_pages = 0; + while(currarg != argc) + { + /* + * GET THE UILS TO RETRIEVE. + */ + + sscanf(argv[currarg],"%s",filelist[number_of_pages]); + number_of_pages++; + currarg++; + } + } + else + { + /* have filelist; take a stab at the number of valid URLs */ + D_PRINTF( "About to parse filelist %s\n", uil_filelist ); + number_of_pages = count_file_list(uil_filelist); + } + if (number_of_pages == 0) + { + /* + * AT LEAST ONE FILE MUST BE SPECIFIED + */ + fprintf(stderr,"No URL resources specified\n"); + usage(argv[0]); + } +} + +/* + This function sets up the socket we will use to synchronize with the + clients. + Returns the socket number if successful, doesn't return if it fails +*/ + +SOCKET SetupSyncSocket( serveraddr ) +struct sockaddr_in *serveraddr; +{ + int sock,len; + + /* + * SET UP THE SOCKET WE ARE GOING TO USE TO SYNCHRONIZE WITH THE CLIENTS. + */ + D_PRINTF( "About to call sock %d %d\n", portnum, MAXCLIENTS ); + + sock = passivesock(0, "tcp", MAXCLIENTS); + + if (BADSOCKET(sock)) + { + errexit("Couldn't open socket %d: %s\n", sock, neterrstr()); + } + D_PRINTF( "The passivesock call succeeded\n" ); + + D_PRINTF( "calling getsockname\n" ); + + len = sizeof(struct sockaddr); + if(getsockname(sock, (struct sockaddr *)serveraddr, &len) < 0) + { + errexit("Could not get socket informaton\n"); + } + + return( sock ); +} + +/* + Function which generates a commandline for the webclients +*/ +void MakeCmdLine( commandline) +char *commandline; +{ + char tmpcommandline[NCCARGS]; + char hostname[MAXHOSTNAMELEN]; + char *webclient_path, *temp; + int cnt; + struct hostent *master_phe_tmp; /* temp. variable added by - Rajesh Shah*/ + + /* + * BUILD THE PORTIONS OF THE cmdline FOR EACH CLIENT THAT WE CAN BUILD NOW. + * WE WILL FILL IN THE NUMBER OF CLIENTS LATER WITH AN sprintf. + */ + D_PRINTF( "Calling gethostname\n" ); + + if(gethostname(hostname,MAXHOSTNAMELEN) != 0) + { + errexit("Could not retrieve local host name"); + } else { + /* convert hostname to address (to avoid DNS problems for webclients) */ + /* The following lines are add to copy the system + buffer (output of gethostbyname()) into user area. + This is because, there are very good chances that later + on system buffer might be overwritten by some calls and + still if your pointer is pointing to same addr. nothing + but only trouble and trouble! Infact this is what + happening when I tried to run webstone benchmark for more + then one clients. It used to over write the webmaster name + with the first client name and so remaining on client(s) + the webclient process(es) were invoked with wrong webmaster + name! This behaviour is observed Solaris 2.4 this bug + can be hit in any OS. - Rajesh Shah 5/18/96 */ + + /* master_phe = gethostbyname(hostname); */ + master_phe_tmp = gethostbyname(hostname); + master_phe = (struct hostent *)malloc(sizeof(struct hostent)); + HostEntCpy(master_phe, master_phe_tmp); + } + + /* set up executable pathname */ +#ifndef WIN32 + temp = getenv("TMPDIR"); + + if ( temp && *temp ) { + webclient_path = (char *)mymalloc( strlen(temp) + strlen("/webclient") + + 1); + strcpy(webclient_path, temp); + strcat(webclient_path, "/webclient"); + + } else +#else + temp = temp; +#endif /* WIN32 */ + webclient_path = PROGPATH; + + + D_PRINTF( "Path to webclient is: %s\n", webclient_path ); + + sprintf(commandline,"%s", webclient_path); + + if(haveproxyserver) + { + sprintf(tmpcommandline, " -P %s", proxyserver); + strcat(commandline, tmpcommandline); + } + if (debug) + { + strcat(commandline," -d"); + } + if (numloops != 0) + { + sprintf(tmpcommandline," -l %d", numloops); + strcat(commandline,tmpcommandline); + } + if (portnum) + { + sprintf(tmpcommandline," -p %d", portnum); + strcat(commandline,tmpcommandline); + } + if (redirect) + { + strcat(commandline," -r"); + } + if (savefile) + { + strcat(commandline," -s"); + } + if (uil_filelist_f) + { + strcat(commandline," -u "); + strcat(commandline,uil_filelist); + } + if (record_all_transactions) + { + strcat(commandline," -R"); + } + if (testtime != 0) + { + sprintf(tmpcommandline," -t %d", testtime); + strcat(commandline,tmpcommandline); + } + + /* + * SET UP A SPACE FOR THE NUMBER OF CLIENTS ON THE commandline. + */ + sprintf(tmpcommandline,"%s -n %%d -w %%s -c %%s:%%d", commandline); + strcpy(commandline,tmpcommandline); + + if (uil_filelist_f == 0) + { + cnt = 0; + while(cnt < number_of_pages) + { + /* + * PUT THE FILES AT THE END OF THE LIST. + */ + strcat(commandline," "); + strcat(commandline,filelist[cnt]); + cnt++; + } + } + puts(commandline); +} + +/* + rexec to the client hosts and start the webclients +*/ +int RexecClients( commandline, clienthostname, serveraddr) +char *commandline; +char clienthostname[MAXCLIENTS][MAXHOSTNAMELEN]; +struct sockaddr_in *serveraddr; + +{ + int tmpfd; + int numclients = 0; + char tmpcommandline[NCCARGS]; + struct servent *inetport; + int cnt; + char buffer[NCCARGS]; + char login[MAXUSERNAME]; + char password[MAXPASSWD]; + FILE *fp; + int returnval; + char *tmphostname; + + memset(buffer, 0, sizeof(buffer)); + + /* + * OPEN UP THE CONFIG FILE. FOR EACH LINE IN THE CONFIG FILE, CHECK + * ITS VALIDITY AND THEN rexec A COMMAND ON THE CLIENT. + */ + + if ((fp = fopen(configfile,"r")) == 0) + { + errexit("Could not open config file %s\n", configfile); + } + + if ((inetport = getservbyname("exec","tcp")) == 0) + { + errexit("Could not get service name for exec/tcp\n"); + } + D_PRINTF( "getservbyname returned %d\n", ntohs(inetport->s_port) ); + + cnt = 0; + + D_PRINTF( "rexec loop\n" ); + while(1) + { + char webserver2[MAXHOSTNAMELEN]; + char linebuf[150]; + int num; + char *primename; + + if (0 == fgets(linebuf, sizeof(linebuf), fp)) + break; + num = sscanf(linebuf,"%s %s %s %d %s",clienthostname[cnt],login,password, + &numclients, webserver2); + if (num < 4) + break; + if (servaddrin_config) { + if (num == 4) { + errexit("No webserver specified in config file for %s\n", clienthostname[cnt]); + } + strcpy(webserver, webserver2); + } + + if (numclients <= 0) + errexit("Number of clients must be >= 0\n"); + if (numclients > MAXPROCSPERNODE) + { + errexit("Number of clients per node can't exceed %d\n", MAXPROCSPERNODE); + } + totalnumclients += numclients; + + primename = pick_webmaster_IP_address(clienthostname[cnt], master_phe, network_mask); + if (primename == 0) { + errexit("Bad client address %s for Client %d\n", clienthostname[cnt], cnt); + } + + fprintf(stdout,"Client %d: %s \t# Processes: %d\n Webserver: %s\tWebmaster: %s:%d\n", + cnt, clienthostname[cnt], numclients, webserver, primename, + ntohs(serveraddr->sin_port)); + fflush(stdout); + sprintf(tmpcommandline, commandline, numclients, webserver, primename, + ntohs(serveraddr->sin_port)); + + fprintf(stderr, "tmpcommandline: %s\n", tmpcommandline); + + D_PRINTF( "%s rexec %s\n",&clienthostname[cnt],tmpcommandline ); + if (norexec) { + sleep(30); /* gives some time to start clients for debugging */ + } else { + + tmphostname = &(clienthostname[cnt][0]); + tmpfd = rexec(&tmphostname, inetport->s_port, login, password, + tmpcommandline, &sockErr[cnt]); + if((sockIO[cnt] = tmpfd) < 0) + { + errexit("Could not rexec: rexec to client %s, cmdline %s failed\n", + clienthostname[cnt],tmpcommandline); + } + } + + + returnval = NETREAD(tmpfd, buffer, OKSTRLEN); + D_PRINTF( "read returns %d, %s\n", returnval, buffer ); + + if (returnval <= 0 || memcmp(buffer, OKSTR, OKSTRLEN) != 0) + { + errexit("rexec to client %s, cmdline %s received error %s\n", + clienthostname[cnt],tmpcommandline, buffer); + } + + + cnt++; + if (cnt > MAXCLIENTS || cnt > FD_SETSIZE) + { + errexit("Number of Clients can't exceed %d\n", MAXCLIENTS); + } + } + + num_rexecs = cnt; + if (totalnumclients > MAXTOTALPROCS) + { + errexit("Total number of processes can't exceed %d\n", + MAXTOTALPROCS); + } + +#ifndef WIN32 + /* NOW WE NEED TO HANDLE THE OUTPUT FROM THE REXEC. + * TO DO THIS, WE FORK, THEN HAVE ONE PROCESS READ FROM TMPFD. + * THE OTHER PROCESS CONTINUES WITH THE PROGRAM + */ + D_PRINTF( "Forking webclient stderr/stdout processes\n" ); + switch (fork()) + { + case -1: /* ERROR */ + errexit("fork: %s\n", strerror(errno)); + case 0: /* CHILD */ + exit(echo_client(clienthostname[cnt], tmpfd)); + default: /* PARENT */ + break; + } +#else + /* start threads to echo stdout/stderr from clients */ + _beginthread(echo_client, 0, (void *)0); + _beginthread(echo_client, 0, (void *)1); +#endif /* WIN32 */ + + fprintf(stdout,"\n"); + fprintf(stdout,"\n"); + fclose(fp); + + return totalnumclients; +} + +void GetReady( fdset, totalnumclients, sock ) +fd_set *fdset; +int totalnumclients; +int sock; +{ + int cnt,len; + fd_set tmpfdset, leftfdset; + char buffer[NCCARGS]; + + /* + * NOW WE NEED TO ACCEPT ALL THE CONNECTIONS FROM THE CLIENTS, + * ACCEPT ALL THE READY MESSAGES + */ + + D_PRINTF( "Beginning accept loop\n" ); + for (cnt = 0; cnt < totalnumclients; cnt++) + { + D_PRINTF( "Client %d:\t", cnt ); + + { + fd_set readfds; + struct timeval timeout; + int rv; + + timeout.tv_sec = MAX_ACCEPT_SECS; + timeout.tv_usec = 0; + FD_ZERO(&readfds); + FD_SET(sock, &readfds); + + /* if we're hung, quit */ + D_PRINTF("Before select() on listen() socket\n"); + if (!(rv = select(FD_SETSIZE, &readfds, 0, 0, &timeout))) { + fprintf(stdout, + "Listen timeout after %d seconds (%d clients so far)\n", + MAX_ACCEPT_SECS, cnt); + D_PRINTF("select() timed out after %d seconds\n", MAX_ACCEPT_SECS); + errexit("Webmaster terminating\n"); + } + } + + if(BADSOCKET(socknum[cnt] = accept(sock, 0, 0))) + { + /* + * ERROR accepting FROM THE CLIENTS. WE NEED TO ISSUE AN + * ABORT TO ALL. + */ + abort_clients(); + errexit("Error accepting from one of the clients: %s", neterrstr()); + } else + { + /* + * SET THE FD IN THE MASK + */ + FD_SET(socknum[cnt],fdset); + } + D_PRINTF( "on socket %d\n",socknum[cnt] ); + } + D_PRINTF( "\n" ); + + /* + * WAIT FOR A READY. + */ + sleep(1); + fprintf(stdout,"Waiting for READY from %d clients\n",totalnumclients); + fflush(stdout); + leftfdset = *fdset; +#ifndef WIN32 + while(memcmp(&leftfdset,&zerofdset,sizeof(fd_set))) + { + tmpfdset = leftfdset; + + if(select(FD_SETSIZE,&tmpfdset,NULL,NULL,NULL) < 0) + { + /* + * ERROR SELECTING. ABORT ALL. + */ + abort_clients(); + errexit("Error accepting from one of the clients: %s\n", + neterrstr()); + break; + } +#else + /* I don't see why a select is needed at all--all clients must respond + * and there is no synchronization/timing issue. + */ + tmpfdset = leftfdset; + { +#endif /* WIN32 */ + + for (cnt = 0; cnt < totalnumclients; cnt++) + { + /* + * SEE WHICH SOCKETS HAVE A INPUT ON THEM PENDING + * AND RECEIVE IT. + */ + if(!BADSOCKET(socknum[cnt]) && (FD_ISSET(socknum[cnt],&tmpfdset))) + { + /* + * GET THE READY FROM THIS GUY. + * DON'T FORGET TO CLEAR HIS BIT IN THE tmpfdset + */ + len = NETREAD(socknum[cnt],buffer,READYSTRLEN); + if(len != READYSTRLEN) + { + abort_clients(); + errexit("Error reading from client #%d\n", cnt); + } + if(memcmp(buffer, READYSTR, READYSTRLEN)) + { + abort_clients(); + fprintf(stdout,"Received bad READY string: len %d, value %s\n", + len,buffer); + } + FD_CLR(socknum[cnt],&leftfdset); + } + } + } + sleep(1); + fprintf(stdout,"All READYs received\n"); + fflush(stdout); +} + +/* + Start all the clients by sending them a GO signal + totalnumclients is the total number of clients + socknum is an int array with the filedescriptors for all the + client connections +*/ +void SendGo( totalnumclients, socknum) +int totalnumclients; +int *socknum; +{ + int cnt; + fprintf(stdout,"Sending GO to all clients\n"); + for(cnt = 0; cnt < totalnumclients; cnt++) + { + if(socknum[cnt] > 0) + { + /* + * SEND A GO + */ + if(NETWRITE(socknum[cnt], GOSTR, GOSTRLEN) != GOSTRLEN) + { + abort_clients(); + errexit("Error sending GO to client %d: %s\n", cnt, neterrstr()); + } + } + } +} + +/* + This function gathers statistics from all the clients +*/ + +void GetResults(fdset, page_stats, endtime, timestr, totalnumclients, + statarray) +fd_set *fdset; +page_stats_t **page_stats; +time_t *endtime; +char *timestr; +int totalnumclients; +stats_t statarray[MAXCLIENTS]; +{ + fd_set leftfdset,tmpfdset; + char *stats_as_text; + char *page_stats_as_text; + int returnval; + int cnt,i; + + + /* DOESN'T ACTUALLY PRINT UNTIL THE FIRST CLIENT REPORTS */ + fprintf(stdout,"Reading results "); + + /* + * COPY THE FILE DESCRIPTORS TO A TMP LIST, + * ALLOCATE MEMORY FOR STATS, PAGESTATS IN TEXT FORM + */ + leftfdset = *fdset; + stats_as_text = (char *)mymalloc(SIZEOF_STATSTEXT+1); + page_stats_as_text = (char *)mymalloc(SIZEOF_PAGESTATSTEXT+1); + + /* + * COPY THE FILE DESCRIPTORS TO A TMP LIST, + * PLUS A LIST OF REMAINING FDs + */ + leftfdset = *fdset; + /* + * LOOP UNTIL ALL CLIENTS HAVE REPORTED + * AND tmpfdset IS EMPTY + */ +#ifndef WIN32 + while(memcmp(&leftfdset,&zerofdset,sizeof(fd_set))) + { + tmpfdset = leftfdset; + sleep(1); + returnval = select(FD_SETSIZE,&tmpfdset,NULL,NULL,NULL); + D_PRINTF( "Call to select returned %d, errno %d\n", + returnval, errno ); + if(returnval < 0) + { + /* + * ERROR SELECTING. ABORT ALL. + */ + D_PRINTF( "select() error %s\n", neterrstr() ); + abort_clients(); + errexit("Error selecting from one of the clients\n"); + } +#else + /* I don't see why a select is needed at all */ + tmpfdset = leftfdset; + { +#endif /* WIN32 */ + for(cnt = 0; cnt < totalnumclients; cnt++) + { + /* + * SEE WHICH SOCKETS HAVE A INPUT ON THEM PENDING AND + * RECEIVE IT. + */ + + /* IS THIS A VALID SOCKET? IS IT READY TO READ? */ + if(!BADSOCKET(socknum[cnt]) && (FD_ISSET(socknum[cnt],&tmpfdset))) + { + int len; + + /* + * GET THE TIMING DATA FROM THIS GUY + * THEN REMOVE HIM FROM THE tmpfdset + */ + /* + * READ TIME STATS + * DOES READ() RETURN THE CORRECT LENGTH? + */ + D_PRINTF( "About to read timestats, count %d, errno %d\n", + cnt, errno ); + len = SIZEOF_STATSTEXTBASE + number_of_pages*SIZEOF_DOUBLETEXT; + returnval = recvdata(socknum[cnt], stats_as_text, + len); + D_PRINTF( "Read time stats %d\n", returnval ); + if (returnval != len) /* <= 0) */ + { + D_PRINTF( "Error reading timing stats: %s\n", + neterrstr() ); + fprintf(stderr, "Error reading timing stats: %s\nSocket number %d\n", + neterrstr(),socknum[cnt]); + abort_clients(); + errexit(""); + } /* end if */ + + /* convert text to stats */ + stats_as_text[returnval] = 0; /* add an end marker */ + statarray[cnt] = *text_to_stats(stats_as_text); + + fputc('.', stdout); /* PROGRESS MARKER */ + fflush(stdout); + + if(uil_filelist_f) /* READ PAGE STATS */ + { + for (i = 0; i < number_of_pages; i++) + { + D_PRINTF( "On page_stats[%d][%d]\n", cnt, i ); + returnval = recvdata(socknum[cnt], page_stats_as_text, + SIZEOF_PAGESTATSTEXT); + D_PRINTF( "Read page stats %d\n", returnval ); + + if (returnval != SIZEOF_PAGESTATSTEXT) /* <= 0) */ + { + D_PRINTF( "Error reading page_stats[%d][%d]: %s\n", + cnt, i, neterrstr() ); + fprintf(stderr, "Error reading page_stats[%d][%d]: %s\n", + cnt, i, neterrstr()); + abort_clients(); + errexit(""); + } + D_PRINTF( "Page stats: read %d bytes\n", + returnval ); + + page_stats_as_text[returnval] = 0; /* add an end marker */ + D_PRINTF("strlen(page_stats_as_text) = %d\n", + strlen(page_stats_as_text)); + page_stats[cnt][i] = + *text_to_page_stats(page_stats_as_text); + + } /* end for */ + } /* end if filelist */ + + FD_CLR(socknum[cnt],&leftfdset); + NETCLOSE(socknum[cnt]); + socknum[cnt] = BADSOCKET_VALUE; + } /* end if socknum */ + } /* end for cnt */ + } /* end while memcmp fd */ + + /* + * DONE READING RESULTS FROM CLIENTS + */ + + *endtime = time(0); + timestr = asctime(localtime(endtime)); + fprintf(stdout,"\nAll clients ended at %s\n",timestr); + fflush(stdout); + + /* FREE MEMORY ALLOCATED FOR CLIENT STATS, PAGESTATS AS TEXT */ + free(stats_as_text); + free(page_stats_as_text); + +} + +/* + Prints out all the results +*/ +void PrintResults( page_stats, endtime, timestr, totalnumclients, statarray, + page_stats_total) +page_stats_t **page_stats; +time_t endtime; +char *timestr; +int totalnumclients; +stats_t statarray[MAXCLIENTS]; +page_stats_t *page_stats_total; +{ + stats_t masterstat; + int cnt,i,j; + double thruput; + struct timeval dtime; + + /* + * PRINT EVERYTHING OUT + */ + stats_init(&masterstat); + for(cnt = 0; cnt < totalnumclients; cnt++) + { + if((statarray[cnt].rs.totalconnects > 0) && (dumpall)) + { + fprintf(stdout,"----------------------------------\n"); + /* fprintf(stdout,"Test for host: %s\n",statarray[cnt].hostname); */ + fprintf(stdout,"Total number of pages retrieved from server: %u\n", + statarray[cnt].totalpages); + + rqstat_fprint(stdout, &(statarray[cnt].rs)); + + thruput = thruputpersec((double)(statarray[cnt].rs.totalbytes), + &(statarray[cnt].rs.totalresponsetime)); + + fprintf(stdout, "Thruput average per connection: %.0f bytes/sec\n", + thruput); + } + if(statarray[cnt].rs.totalconnects > 0) + { + D_PRINTF( "Summing stats for %d, with %ld total connections\n", + cnt, statarray[cnt].rs.totalconnects ); + rqstat_sum(&masterstat.rs, &(statarray[cnt].rs)); + } + else + { + masterstat.rs.totalerrs += statarray[cnt].rs.totalerrs; + } + } + + for (i=0; i < totalnumclients; i++) + { + for (j=0; j < number_of_pages; j++) + { + D_PRINTF( "Summing page stats for %d, page %d, with %d connects\n", + i, j, statarray[i].page_numbers[j] ); + + if (statarray[i].page_numbers[j] != 0) + { + rqst_stats_t *pst_rs; + rqst_stats_t *ps_rs; + + pst_rs = &(page_stats_total[j].rs); + ps_rs = &(page_stats[i][j].rs); + + rqstat_sum(pst_rs, ps_rs); + + page_stats_total[j].totalpages += page_stats[i][j].totalpages; + masterstat.totalpages += page_stats[i][j].totalpages; + + /* yes, this is assignment, not sum */ + page_stats_total[j].page_size = page_stats[i][j].page_size; + + page_stats_total[j].page_valid = 1; + } + } + } + + /* print page statistics */ + if (verbose) { + for (i = 0; i < number_of_pages; i++) + { + if (page_stats_total[i].page_valid == 1) + { + page_stats_t *pst; + + pst = &(page_stats_total[i]); + + printf ("===============================================================================\n"); + printf ("Page # %d\n\n", i); + printf ("Total number of times page was hit %u\n", + pst->totalpages); + + rqstat_print(&(pst->rs)); + + printf ("Page size %u \n", pst->page_size); + printf ("===============================================================================\n\n"); + } + } + } + + fprintf(stdout,"===============================================================================\n"); + + /* + * Validate run. + */ + masterstat.total_num_of_files = statarray[0].total_num_of_files; + for (i=1; i < totalnumclients; i++) + { + if ((statarray[i].rs.totalconnects > 0) && + (statarray[i].total_num_of_files != masterstat.total_num_of_files)) + { + fprintf(stdout,"**********************************************************************\n"); + fprintf(stdout,"**** ERROR: number of files in each test configuration is not the same\n"); + fprintf(stdout,"**** ERROR: Check configuration file %s on each client\n", configfile); + fprintf(stdout,"**********************************************************************\n"); + break; + } + } + + + /* + * Print summary statistics + */ + fprintf(stdout, "WEBSTONE 2.0 results:\n"); + + fprintf(stdout, "Total number of clients: \t%d\n", totalnumclients); + testtime = sumedh_end.tv_sec - sumedh_start.tv_sec; + fprintf(stdout,"Test time: \t\t\t%d seconds\n", testtime); + + fprintf(stdout, "Server connection rate: \t%3.2f connections/sec\n", + (double)(masterstat.rs.totalconnects)/(testtime)); + + fprintf(stdout, "Server error rate: \t\t%4.4f err/sec\n", + (double)(masterstat.rs.totalerrs)/(testtime)); + + fprintf(stdout, "Server thruput: \t\t%2.2f Mbit/sec\n", + (double)(8*masterstat.rs.totalbytes)/(testtime*1024*1024)); + + fprintf(stdout, "Little's Load Factor: \t\t%3.2f \n", + (double)(masterstat.rs.totalresponsetime.tv_sec) + /(testtime)); + avgtime(&masterstat.rs.totalresponsetime, + masterstat.rs.totalconnects, &dtime); + + fprintf(stdout, "Average response time: \t\t%4.4f millisec\n", + (double)1000*(dtime.tv_sec + (double)dtime.tv_usec / 1000000)); + + fprintf(stdout, "Error Level:\t\t\t%4.4f %%\n", + (double)(100 * masterstat.rs.totalerrs)/(masterstat.rs.totalconnects)); + + /* so much for the key metrics */ + + thruput = 8 * thruputpersec((double)(masterstat.rs.totalbytes), + &(masterstat.rs.totalresponsetime)); + + fprintf(stdout, "Average client thruput: \t%4.4f Mbit/sec\n", + thruput/(1024*1024)); + + fprintf(stdout,"Sum of client response times:\t%u.%u sec\n", + masterstat.rs.totalresponsetime.tv_sec, + masterstat.rs.totalresponsetime.tv_usec); + + fprintf(stdout,"Total number of pages read:\t%u\n\n", + masterstat.totalpages); + + /* Remaining stats are the same as usual */ + + rqstat_fprint(stdout, &(masterstat.rs)); + fflush(stdout); + +} + +#ifdef WIN32 +/* close socket library */ +void sock_cleanup(void) { + + WSACleanup(); +} +#endif /* WIN32 */ + +void +main(const int argc, char *argv[]) +{ + + int sync_sock; + int i; + int j; + char buffer[NCCARGS]; + char commandline[NCCARGS]; + char *timestr; + time_t starttime; + time_t endtime; + fd_set fdset; + /* make the big arrays static to avoid stack overflow */ + static char clienthostname[MAXCLIENTS][MAXHOSTNAMELEN]; + static stats_t statarray[MAXCLIENTS]; + page_stats_t **page_stats; + page_stats_t *page_stats_total; + struct sockaddr_in serveraddr; + + +#ifdef WIN32 + WSADATA WSAData; + COORD dwSize; + + if ((WSAStartup(MAKEWORD(1,1), &WSAData)) != 0) { + errexit("Error in WSAStartup()\n"); + } + atexit(sock_cleanup); + + /* increase size of output window */ + dwSize.X = 80; + dwSize.Y = 500; + SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), dwSize); +#endif /* WIN32 */ + + + /* Initalization of variables. */ + debugfile = stdout; + memset(buffer, 0, NCCARGS); + memset(webserver, 0, MAXHOSTNAMELEN); + memset(configfile, 0, MAXPATHLEN); + FD_ZERO(&zerofdset); + FD_ZERO(&fdset); + + for(i = 0; i < MAXCLIENTS; i++) + { + socknum[i] = BADSOCKET_VALUE; + statarray[i].rs.totalconnects = 0; + } + + signal(SIGINT, sig_int); + + ParseCmdLine( argc, argv); + + sync_sock = SetupSyncSocket( &serveraddr ); + + MakeCmdLine( commandline); + + totalnumclients = RexecClients( commandline, clienthostname, &serveraddr); + + /* Initalization of variables. */ + page_stats = + (page_stats_t **) + mymalloc(totalnumclients*sizeof(page_stats_t *)); + for (i=0; i < totalnumclients; i++) + { + page_stats[i] = (page_stats_t *) + mymalloc(number_of_pages*sizeof(page_stats_t)); + } + page_stats_total = + (page_stats_t *)mymalloc(number_of_pages*sizeof(page_stats_t)); + + for (i=0; i < totalnumclients; i++) { + stats_init(&(statarray[i])); + } + for (i=0; i < totalnumclients; i++) { + for (j=0; j < number_of_pages; j++) { + page_stats_init(&(page_stats[i][j])); + } + } + for (i=0; i < number_of_pages; i++) { + page_stats_init(&(page_stats_total[i])); + } + + for(i = 0; i < totalnumclients; i++) + { + socknum[i] = BADSOCKET_VALUE; + statarray[i].rs.totalconnects = 0; + } + + GetReady( &fdset, totalnumclients, sync_sock ); + NETCLOSE(sync_sock); + + /* + * START ALL OF THE CLIENTS BY SENDING THEM A GO SIGNAL. + */ + + + gettimeofday (&sumedh_start, 0); + SendGo( totalnumclients, socknum); + + /* + * WAIT FOR ALL OF THE CLIENTS TO COMPLETE. WE SHOULD GET A REPLY + * FOR EACH SOCKET WE HAVE OPEN. THE REPLY WILL BE THE TIMING + * INFORMATION WE USE. + */ + + starttime = time(0); + timestr = asctime(localtime(&starttime)); + fprintf(stdout,"All clients started at %s\n",timestr); + fprintf(stdout,"Waiting for clients completion\n"); + fflush(stdout); + + /* IF THIS IS A TIMED TEST, WE MIGHT AS WELL SNOOZE */ + if (testtime) { + sleep(testtime * 60); + } + + GetResults( &fdset, page_stats, &endtime, timestr, totalnumclients, + statarray); + + gettimeofday (&sumedh_end, 0); + PrintResults( page_stats, endtime, timestr, totalnumclients, statarray, + page_stats_total); + + /* free memory */ + for (i = 0; i < totalnumclients; i++) + { + free(page_stats[i]); + } + free(page_stats); + free(page_stats_total); + + exit(0); +} + +/* Added by Rajesh Shah 5/18/96 */ +void +HostEntCpy(struct hostent *dest, struct hostent *src) +{ + + dest->h_name = (char *)malloc(strlen(src->h_name)+1); + strcpy(dest->h_name, src->h_name); + printf("WebMaster name = %s\n", dest->h_name); + dest->h_aliases = src->h_aliases; + dest->h_addrtype = src->h_addrtype; + dest->h_length = src->h_length; + dest->h_addr_list = src->h_addr_list; +} + -- cgit v1.2.1