1 /**************************************************************************
3 * Copyright (C) 1995 Silicon Graphics, Inc. *
5 * These coded instructions, statements, and computer programs were *
6 * developed by SGI for public use. If any changes are made to this code*
7 * please try to get the changes back to the author. Feel free to make *
8 * modifications and changes to the code and release it. *
10 **************************************************************************/
12 /* FUZZ: disable check_for_math_include */
13 /* FUZZ: disable check_for_improper_main_declaration */
41 #include <sys/param.h>
44 #include <sys/types.h>
49 #include <sys/errno.h>
50 #include <sys/socket.h>
53 #include <netinet/in.h>
54 #include <arpa/inet.h>
63 #define INFINITY 100000000
64 #define DEFAULTWWWPORT 80
65 #define LOG_FILE "logfile"
67 #define DEBUG_FILE "c:/tmp/webstone-debug"
69 #define DEBUG_FILE "/tmp/webstone-debug"
73 /* global variables */
75 THREAD
FILE *debugfile
= stderr
;
76 page_list_t
*load_file_list
; /* actually a dynamic array */
79 int havewebserver
= 0;
80 int haveproxyserver
= 0;
82 NETPORT portnum
= DEFAULTWWWPORT
;
85 long int number_of_pages
= 0;
86 char webmaster
[MAXHOSTNAMELEN
];
87 char webserver
[MAXHOSTNAMELEN
];
88 char proxyserver
[MAXHOSTNAMELEN
];
93 int CounterSemaphore
= 0; /* counter semaphore for children */
96 static void ClientThread(void *);
98 /* used to bypass DNS/YP name resolution for every page */
99 struct hostent webserv_phe
, webmast_phe
;
100 struct protoent webserv_ppe
, webmast_ppe
;
101 unsigned long webserv_addr
, webmast_addr
;
102 short webserv_type
, webmast_type
; /* socket type */
108 usage(const char *progname
)
110 returnerr("Usage: %s [-d] [-w webserver] [-p port_num]\n",
112 returnerr("\t[-c masterhost:port] [-t run_time | -l loops]\n");
113 returnerr("\t[-n numclients] [-R]\n");
114 returnerr("\t[-f config_file] [-u uilfile | url ...]\n");
121 /* RECEIVED AN ALARM SIGNAL */
123 } /* END alarmhandler() */
131 /* RECEIVED A SIGNAL THAT A CHILD PROCESS HAS DIED */
132 D_PRINTF( "A child process has died\n" );
133 while (wait3(&status
, WNOHANG
, (struct rusage
*)0) >= 0)
138 } /* END childhandler() */
142 /* look up the host name and protocol
143 * called once by main() since all threads
144 * use the same protocol and address
147 int resolve_addrs(char *host
, char *protocol
, struct hostent
*host_phe
, struct protoent
*proto_ppe
, unsigned long *addr
,
150 struct protoent
*ppe
;
152 /* if IP address given, convert to internal form */
153 if (host
[0] >= '0' && host
[0] <= '9') {
154 *addr
= inet_addr(host
);
155 if (*addr
== INADDR_NONE
)
156 return(returnerr("Invalid IP address %s\n", host
));
159 /* look up by name */
160 phe
= gethostbyname(host
);
163 D_PRINTF( "Gethostbyname failed: %s", neterrstr() );
164 return(returnerr("Can't get %s host entry\n", host
));
166 memcpy(host_phe
, phe
, sizeof(struct hostent
));
167 memcpy((char *)addr
, phe
->h_addr
, sizeof(*addr
));
170 /* Map protocol name to protocol number */
171 ppe
= getprotobyname(protocol
);
175 D_PRINTF( "protobyname returned %d\n", ppe
);
176 return(returnerr("Can't get %s protocol entry\n",protocol
));
178 memcpy(proto_ppe
, ppe
, sizeof(struct protoent
));
180 D_PRINTF( "Protocol number %d\n", ppe
->p_proto
);
182 /* Use protocol to choose a socket type */
183 if (strcmp(protocol
,"udp") == 0)
190 D_PRINTF( "Choosing SOCK_STREAM %d type %d %s\n",
191 SOCK_STREAM
, *type
, neterrstr() );
197 /* connect to a socket given the hostname and protocol */
199 connectsock(char *host
, NETPORT portnum
, char *protocol
)
201 struct sockaddr_in sin
; /* an Internet endpoint address */
202 SOCKET s
; /* socket descriptor */
203 int type
; /* socket type */
205 int returnval
; /* temporary return value */
207 D_PRINTF( "Beginning connectsock; host=%s port=%d proto=%s\n", host
,
210 sin
.sin_family
= AF_INET
;
211 memset((char *)&sin
, 0, sizeof(sin
));
212 D_PRINTF( "Zeroed address structure\n" );
214 sin
.sin_port
= htons(portnum
);
215 D_PRINTF( "Set port number %d\n", portnum
);
217 /* get the contact information */
218 if (strcmp(host
, webserver
) == 0) {
219 sin
.sin_addr
.S_ADDR
= webserv_addr
;
220 sin
.sin_family
= PF_INET
;
221 proto
= webserv_ppe
.p_proto
;
223 } else if (strcmp(host
, webmaster
) == 0) {
224 sin
.sin_addr
.S_ADDR
= webmast_addr
;
225 sin
.sin_family
= PF_INET
;
226 proto
= webmast_ppe
.p_proto
;
229 struct hostent host_phe
;
230 struct protoent host_ppe
;
231 unsigned long host_addr
;
232 short host_type
; /* socket type */
234 if (resolve_addrs(host
, "tcp", &host_phe
, &host_ppe
, &host_addr
, &host_type
))
235 return returnerr("Can't resolve hostname %s in get()\n", host
);
236 sin
.sin_addr
.S_ADDR
= host_addr
;
237 sin
.sin_family
= PF_INET
;
238 proto
= host_ppe
.p_proto
;
242 /* Allocate a socket */
243 s
= socket(PF_INET
, type
, proto
);
244 D_PRINTF( "Socket %d returned %d, %s\n",
245 type
, s
, neterrstr() );
249 D_PRINTF( "Can't create socket: %s\n",neterrstr() );
250 return BADSOCKET_VALUE
;
253 /* Connect the socket */
254 D_PRINTF( "Trying to connect %d with size %d, %s\n",
255 s
, sizeof(sin
), neterrstr() );
256 D_PRINTF( "Address is family %d, port %d, addr %s\n",
257 sin
.sin_family
, ntohs(sin
.sin_port
),
258 inet_ntoa(sin
.sin_addr
) );
260 returnval
= connect(s
, (struct sockaddr
*)&sin
, sizeof(sin
));
261 D_PRINTF( "Connect returned %d, %s\n",
262 returnval
, neterrstr() );
265 D_PRINTF( "Can't connect: %s\n", neterrstr() );
267 return BADSOCKET_VALUE
;
270 /* all done, returning socket descriptor */
271 D_PRINTF( "Returning %d from connectsock call\n", s
);
274 } /* END connectsock() */
277 connecttomaster(char *str
)
282 char ConnectStr
[100]; /* Fix to handle multiple threads */
285 strcpy(ConnectStr
, str
);
288 * BREAK UP THE connectstr INTO A HOSTNAME/HOST-IP AND A PORT NUMBER.
290 if((tempch
= strpbrk(ConnectStr
,":")) == 0)
293 * INCORRECT FORMAT OF ConnectStr. CORRECT FORMAT IS
294 * HOSTNAME:PORT OR HOST-IP:PORT
296 D_PRINTF( "Incorrect format %s: use hostname:port or ip_addr:port\n",
298 return(returnerr("Incorrect format %s: use host:port or ip_addr:port\n",
303 * ZERO OUT THE COLON SO WE HAVE TWO STRINGS, THE HOSTNAME AND THE PORT
308 /* loop here to connect to webmaster - TCP/IP allows no more than 5
309 * connection requests outstanding at once and thus the webmaster may
310 * reject a connection if there are a lot of client processes
313 #define TRYDELAY_SEC 1
314 for (tries
= 0; tries
< MAXTRIES
; tries
++) {
316 sock
= connectsock(ConnectStr
,(NETPORT
)atoi(tempch
),"tcp");
318 if (!BADSOCKET(sock
))
326 /* ERROR CONNECTING TO MASTER PROCESS */
327 return(returnerr("Could not connect to master process\n"));
331 * SIGNAL THE MASTER THAT WE ARE READY TO PROCEED. WHEN ALL
332 * CHILD PROCESSES HAVE CONNECTED AND SENT THIS SIGNAL,
333 * THE MASTER WILL ISSUE US A GO SIGNAL.
335 if(NETWRITE(sock
,READYSTR
,READYSTRLEN
) != READYSTRLEN
)
337 return(returnerr("Error sending READY message to master"));
340 memset(msg
,0,GOSTRLEN
+1);
341 if(NETREAD(sock
,msg
,GOSTRLEN
) != GOSTRLEN
)
343 D_PRINTF( "Error receiving GO message from master: %s\n", neterrstr()
345 return(returnerr("Error receiving GO message from master\n"));
348 if(strncmp(GOSTR
,msg
,GOSTRLEN
))
351 * WE RECEIVED A MESSAGE OTHER THAN GO. PRINT IT OUT AND RETURN ERROR
353 return(returnerr("Received non-GO message %s\n",msg
));
358 } /* END connecttomaster() */
362 accumstats(rqst_timer_t
*rqsttimer
, page_stats_t
*pagestats
, stats_t
*timestat
)
364 rqst_stats_t rqststats
;
366 #define TFMT "%10u:%10u"
368 * DUMP THE TIMING INFORMATION HERE, OR COMPUTE WHAT YOU WANT TO
372 D_PRINTF( "Total bytes read: %d \t Body size read: %d\n",
373 rqsttimer
->totalbytes
,
374 rqsttimer
->bodybytes
);
376 D_PRINTF( "Enter time: " TFMT
" \t Exit Time: " TFMT
"\n",
377 rqsttimer
->entertime
.tv_sec
,
378 rqsttimer
->entertime
.tv_usec
,
379 rqsttimer
->exittime
.tv_sec
,
380 rqsttimer
->exittime
.tv_usec
);
381 D_PRINTF( "Before connect: " TFMT
" \t After connect: " TFMT
"\n",
382 rqsttimer
->beforeconnect
.tv_sec
,
383 rqsttimer
->beforeconnect
.tv_usec
,
384 rqsttimer
->afterconnect
.tv_sec
,
385 rqsttimer
->afterconnect
.tv_usec
);
386 D_PRINTF( "Before header: " TFMT
" \t After header: " TFMT
"\n",
387 rqsttimer
->beforeheader
.tv_sec
,
388 rqsttimer
->beforeheader
.tv_usec
,
389 rqsttimer
->afterheader
.tv_sec
,
390 rqsttimer
->afterheader
.tv_usec
);
391 D_PRINTF( "After body: " TFMT
"\n",
392 rqsttimer
->afterbody
.tv_sec
,
393 rqsttimer
->afterbody
.tv_usec
);
395 rqstat_times(&(rqststats
), rqsttimer
);
396 rqstat_sum(&(timestat
->rs
), &(rqststats
));
397 rqstat_sum(&(pagestats
->rs
), &(rqststats
));
399 if (rqsttimer
->page_number
!= 999)
401 timestat
->page_numbers
[rqsttimer
->page_number
] += 1;
405 } /* END accumstats */
409 * fetch the set of files that constitute a page
411 * maxcount = the number of files in the WWW page
412 * pageval = the number of the WWW page (offset in load_file_list[])
413 * (if -1, use page # 0 - does this still work?)
415 * returns the number of files retrieved
418 makeload(int maxcount
, int pageval
, THREAD rqst_timer_t
*timerarray
, THREAD stats_t
*timestat
, THREAD SOCKET mastersock
, THREAD page_stats_t
*page_stats
)
422 page_stats_t page_stats_tmp
;
423 char server
[MAXHOSTNAMELEN
];
427 D_PRINTF( "Starting makeload(maxcount %d, pageval %d)\n",
430 strcpy( server
, webserver
); /* Put in default value */
432 page_stats_init(&page_stats_tmp
);
433 D_PRINTF( "Page stats initialized\n" );
435 for (cnt
= 0; cnt
< maxcount
; cnt
++)
437 D_PRINTF( "Loop count %d in makeload()\n", cnt
);
447 /* check for a filename */
448 if (strlen(load_file_list
[pageval
].filename
[cnt
]) < 1)
450 D_PRINTF( "Bad filename at pageval %d, count %d\n",
452 return(returnerr("Bad filename at pageval %d, count %d\n",
456 /* if (load_file_list[pageval].port_number[cnt] != 0)
458 loc_portnum = load_file_list[pageval].port_number[cnt];
462 loc_portnum = portnum;
464 loc_portnum
= portnum
;
465 if ((load_file_list
[pageval
].servername
[cnt
] != 0)
467 *load_file_list
[pageval
].servername
[cnt
])
469 D_PRINTF( "Copying URL server %s to server\n",
470 load_file_list
[pageval
].servername
[cnt
] );
471 strcpy(server
, load_file_list
[pageval
].servername
[cnt
]);
476 D_PRINTF( "Copying proxy %s to webserver\n", proxyserver
);
477 strcpy(server
, proxyserver
);
481 D_PRINTF( "Calling get(%s, %d, %s, &(timearray[%d]))\n",
482 server
, loc_portnum
, load_file_list
[pageval
].filename
[cnt
],
485 returnval
= get(server
, loc_portnum
,
486 load_file_list
[pageval
].filename
[cnt
],
490 D_PRINTF( "***GET() RETURNED AN ERROR\n" );
494 * DID GET() RETURN A VALID TIME?
496 if ((returnval
== 0) && (timerarray
[cnt
].valid
== 2))
498 timerarray
[cnt
].page_number
= pageval
;
500 accumstats(&timerarray
[cnt
], &page_stats_tmp
, timestat
);
502 else if (!timeexpired
) /* INVALID, INCREMENT THE ERROR COUNTER */
504 D_PRINTF( "GET error counter incremented\n" );
505 timestat
->rs
.totalerrs
++;
510 struct timeval timeout
;
516 FD_SET(mastersock
, &readfds
);
518 /* if the webmaster has aborted, quit */
519 D_PRINTF("Before select() on webmaster socket\n");
520 if (rv
= select(FD_SETSIZE
, &readfds
, 0, 0, &timeout
)) {
521 D_PRINTF("select() returned %d\n", rv
);
522 D_PRINTF("Client terminating at request of webmaster\n");
530 * DO WE HAVE A VALID RETURN FROM GET()?
531 * WHY NOT USE returnval HERE?
533 if ((returnval
== 0) &&
534 (cnt
== load_file_list
[pageval
].num_of_files
) &&
535 (timerarray
[cnt
-1].valid
== 2))
538 rqst_stats_t
*pst_rs
;
540 ps_rs
= &(page_stats
[pageval
].rs
);
541 pst_rs
= &(page_stats_tmp
.rs
);
543 rqstat_sum(ps_rs
, pst_rs
);
545 page_stats
[pageval
].totalpages
++;
547 if (page_stats
[pageval
].page_size
== 0)
549 page_stats
[pageval
].page_size
= (unsigned)
550 page_stats_tmp
.rs
.totalbody
;
554 D_PRINTF( "\nMakeload output page %d: %d errors, %d pages\n",
555 pageval
, timestat
->rs
.totalerrs
, page_stats
[pageval
].totalpages
);
556 D_PRINTF( "Makeload returning %d\n", cnt
);
560 } /* END makeload() */
563 /* close socket library at exit() time */
564 void sock_cleanup(void) {
570 /* globalize variables that were in main() */
571 long int numfiles
= 0;
575 int record_all_transactions
= 0;
576 int uil_filelist_f
= 0; /* filedescriptor of URLs to fetch? */
579 char uil_filelist
[NCCARGS
];
580 char filelist
[MAXNUMOFFILES
][MAXPATHLEN
];
581 char configfile
[MAXPATHLEN
];
582 char connectstr
[MAXHOSTNAMELEN
+10];
585 ACE_TMAIN(int argc
, ACE_TCHAR
*argv
[])
596 #define SLEEP_USEC 100
601 struct timeval sleeptime
;
603 /* set the amount of time that we'll pause before sending a "." to the
606 sleeptime
.tv_sec
= SLEEP_USEC
/1000000;
607 sleeptime
.tv_usec
= SLEEP_USEC
% 1000000;
613 MessageBeep(~0U); /* announce our existence */
617 err
= WSAStartup(MAKEWORD(1,1), &WSAData
);
619 errexit("Error in WSAStartup()\n");
622 atexit(sock_cleanup
);
624 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST
);
626 /* create semaphore in locked state */
627 hSemaphore
= CreateSemaphore(0, 0, 1, 0);
630 errexit("Create semaphore failed: %d", GetLastError());
634 memset(webserver
, 0, sizeof(webserver
));
635 memset(webmaster
, 0, sizeof(webmaster
));
636 memset(proxyserver
, 0, sizeof(proxyserver
));
637 memset(connectstr
, 0, sizeof(connectstr
));
640 * PARSE THE COMMAND LINE OPTIONS
643 while((getoptch
= getopt(argc
,argv
,"P:f:t:l:p:u:R:w:c:n:sdv")) != EOF
)
648 sprintf(connectstr
, "%s", optarg
);
650 printf("%s", OKSTR
); /* sent back to webmaster */
654 debug
= 0; /* sumedh */
657 sprintf(configfile
, "%s", optarg
);
660 numloops
= atoi(optarg
);
663 numclients
= atoi(optarg
);
666 sprintf(uil_filelist
, "%s", optarg
);
670 portnum
= atoi(optarg
);
676 testtime
= 60 * atoi(optarg
);
683 sprintf(webserver
,"%s",optarg
);
687 sprintf(proxyserver
, "%s", optarg
);
690 record_all_transactions
= 1;
697 returnerr("Client begins...\n");
698 D_PRINTF( "Running in debug mode\n\n" );
700 /* print the command line */
701 for (i
= 0; i
< argc
; i
++)
702 D_PRINTF( "%s ", argv
[i
] );
705 if(testtime
&& numloops
)
708 * EITHER numloops OR testtime, BUT NOT BOTH.
713 if(havewebserver
!= 1)
717 * THE SERVER'S NAME MUST BE SPECIFIED
719 returnerr("No WWW Server specified\n");
722 /* IF IT ISN'T, WE ASSUME LOCALHOST */
723 sprintf(webserver
, "%s", "localhost");
730 while(currarg
!= argc
)
733 * GET THE URLS TO RETRIEVE.
735 if (numfiles
== MAXNUMOFFILES
) {
736 returnerr("Maximum of %d files on the command line.\n");
739 sscanf(argv
[currarg
],"%s",filelist
[numfiles
]);
744 if ((numfiles
!= 0) && uil_filelist_f
)
746 returnerr("Both a filelist and UIL specified.\n");
750 if((numfiles
== 0) && !(uil_filelist_f
))
753 * AT LEAST ONE FILE MUST BE SPECIFIED
755 returnerr("No UIL resources or filelist specified \n");
759 if((numloops
== 0) && (testtime
== 0))
762 * NO SPECIFIED NUMBER OF LOOPS, AND NO TEST TIME
766 if(numclients
> MAXPROCSPERNODE
|| numclients
< 1)
768 returnerr("Number of Clients must be between 1 and %d\n", MAXPROCSPERNODE
);
772 /* allow use of IP address */
774 if((tempch
= strpbrk(connectstr
,":")) == 0)
777 * INCORRECT FORMAT OF ConnectStr. CORRECT FORMAT IS
778 * HOSTNAME:PORT OR HOST-IP:PORT
780 D_PRINTF( "Incorrect format %s: use hostname:port or ip_addr:port\n",
782 returnerr("Incorrect format %s: use host:port or ip_addr:port\n", connectstr
);
785 strncpy(webmaster
, connectstr
, tempch
-connectstr
);
787 if(resolve_addrs(webmaster
, "tcp", &webmast_phe
, &webmast_ppe
, &webmast_addr
, &webmast_type
))
793 D_PRINTF( "Copying proxy %s to webserver\n", proxyserver
);
794 strcpy(webserver
, proxyserver
);
797 if (resolve_addrs(webserver
, "tcp", &webserv_phe
, &webserv_ppe
, &webserv_addr
, &webserv_type
))
803 /* allocate space for dynamic arrays */
805 (page_list_t
*)mymalloc((MAXNUMOFPAGES
)*sizeof(page_list_t
));
809 /* take a guess at the number of URLs in the file */
810 D_PRINTF( "About to parse filelist %s\n", uil_filelist
);
811 number_of_pages
= count_file_list(uil_filelist
);
814 /* IF WE HAVE A FILELIST, PARSE IT */
815 /* allocate memory */
816 D_PRINTF( "Allocating page list: %ld by %d\n",
817 number_of_pages
, numfiles
);
818 for (i
=0; i
<number_of_pages
; i
++)
820 for (j
=0; j
<MAXNUMOFFILES
; j
++)
822 load_file_list
[i
].servername
[j
] =
823 (char *)mymalloc(URL_SIZE
);
824 load_file_list
[i
].filename
[j
] =
825 (char *)mymalloc(URL_SIZE
);
829 D_PRINTF( "Parsing file list: %s\n", uil_filelist
);
830 parse_file_list(uil_filelist
, load_file_list
,
831 &number_of_pages
, &numfiles
);
832 /* free memory for pages that won't be used? */
833 D_PRINTF( "Actual page list: %ld by %d\n",
834 number_of_pages
, MAXNUMOFFILES
);
836 D_PRINTF( "Setting up weighting for %ld pages\n",
838 total_weight
= load_percent(load_file_list
, number_of_pages
);
839 /* total_weight = load_percent(load_file_list, number_of_pages, pages); */
844 number_of_pages
= numfiles
;
847 if (number_of_pages
< 1)
849 /* no pages - exit */
850 D_PRINTF( "No valid URLs found\n" );
851 errexit("No valid URLs found\n");
856 * IF WE ARE TO FORK ADDITIONAL CLIENTS ON THIS MACHINE,
857 * WE MUST DO IT BEFORE WE CONNECT TO THE MASTER.
859 * FIRST, SET UP SIGNAL HANDLING
861 signal(SIGCHLD
, childhandler
);
862 for(i
= 0; i
< numclients
; i
++)
864 thr_create (0, 0, ClientThread
, 0, THR_BOUND
, 0);
874 errexit("Error forking child processes\n");
879 select(0,(fd_set
*)0,(fd_set
*)0, (fd_set
*)0, &sleeptime
);
883 * Wait for all children to exit.
886 while (thr_join(0, 0, 0) == 0);
890 int pid = wait((int*)0);
891 if ((pid == -1) && errno == ECHILD) break;
894 /* start threads on NT */
895 for (i
= 0; i
< numclients
; i
++)
897 if (_beginthread(ClientThread
, 0, 0) == -1)
899 errexit("_beginthread failed: %d", GetLastError());
905 /* wait for children to get to sync point */
906 while (CounterSemaphore
< numclients
)
908 CounterSemaphore
= 0;
910 /* start all children simultaneously */
911 ReleaseSemaphore(hSemaphore
, 1, 0);
915 alarmhandler(); /* signal end of test to threads */
919 * Wait for all threads to exit.
921 while (CounterSemaphore
< numclients
)
924 CloseHandle(hSemaphore
);
930 void ClientThread(void *dummy
)
933 THREAD
FILE *logfile
;
935 THREAD stats_t timestat
;
937 THREAD rqst_timer_t timerarray
[MAXNUMOFFILES
];
938 THREAD SOCKET mastersock
= BADSOCKET_VALUE
; /* connection to webmaster */
941 THREAD page_stats_t
*page_stats
; /* actually a dynamic array */
951 struct timeval runningtime
;
961 (page_stats_t
*)mymalloc((number_of_pages
)*sizeof(page_stats_t
));
963 for (i
=0; i
< number_of_pages
; i
++) {
964 page_stats_init(&(page_stats
[i
]));
973 sprintf(file_name
, "%s.%d", DEBUG_FILE
, (int)getpid());
974 debugfile
= fopen(file_name
, "w+");
976 errexit("Can't open debug file\n");
977 D_PRINTF( "Running in debug mode, %d\n",amclient
);
980 if (record_all_transactions
)
985 sprintf(file_name
, "%s%d", LOG_FILE
, (int)getpid());
986 returnerr("Log file is %s\n", file_name
);
987 logfile
= fopen(file_name
, "w+");
990 /* Initialize random number generator */
993 D_PRINTF( "Random seed: %d\n", junk
);
995 for (i
=0; i
< MAXNUMOFFILES
; i
++)
997 rqtimer_init(&(timerarray
[i
]));
999 stats_init(×tat
);
1001 D_PRINTF( "Number of files %d\n", numfiles
);
1003 timestat
.total_num_of_files
= numfiles
;
1008 * WE ARE A CLIENT PROCESS. (i.e. WE ARE NOT RUN BY A USER, BUT BY
1009 * THE MASTER WWWSTONE PROCESS. WE NEED TO CONNECT TO THE
1010 * MASTER WHO WILL SYNCHRONIZE ALL THE CLIENTS.
1012 D_PRINTF( "Trying to connect with %s\n",connectstr
);
1014 mastersock
= connecttomaster(connectstr
);
1016 D_PRINTF( "connecttomaster returns %d, %s\n",
1017 mastersock
, neterrstr() );
1019 if(BADSOCKET(mastersock
))
1022 * ERROR CONNECTING TO THE MASTER. ABORT.
1024 errexit("Error connecting to the master: %s\n", neterrstr());
1026 } /* END IF CLIENT */
1029 /* Tell parent we're ready */
1030 InterlockedIncrement(&CounterSemaphore
);
1032 /* Wait for main() thread to release us */
1033 WaitForSingleObject(hSemaphore
, INFINITE
);
1034 ReleaseSemaphore(hSemaphore
, 1, 0);
1039 * IF RUNNING A TIMED TEST, WE WILL LOOP
1040 * UNTIL THE ALARM GOES OFF.
1041 * WE'LL ALSO NEED TO SET THE SIGNAL HANDLER
1044 /*signal(SIGALRM, alarmhandler);*/
1046 * SEND SIGALRM IN testtime SECONDS
1048 /*alarm(testtime);*/
1053 * AND THEY'RE OFF...
1057 numloops
= INFINITY
;
1058 GETTIMEOFDAY(&(timestat
.starttime
), &(timestat
.starttimezone
));
1060 /* LOOP UNTIL WE HIT numloops, OR WE RUN OUT OF TIME */
1061 for(loopcnt
= 0; (loopcnt
< numloops
) && !timeexpired
; loopcnt
++)
1064 * THIS IS WHERE LOAD TESTING IS DONE.
1065 * GET A RANDOM NUMBER, THEN INDEX INTO THE
1066 * PAGE, AND THEN REQUEST THAT SET OF FILES.
1068 if (uil_filelist_f
) /* HAVE FILELIST */
1070 D_PRINTF( "Have filelist\n" );
1071 /* if (testtime != 0) /* RUNNING IN TIMED MODE */
1074 D_PRINTF( "Running in timed mode\n" );
1075 /* random number between 0 and totalweight-1 */
1077 ran_number
= (rand_r(&junk
) % total_weight
);
1078 D_PRINTF( "random %ld\n", ran_number
);
1080 /* loop through pages, find correct one
1081 * while ran_number is positive, decrement it
1082 * by the load_num of the current page
1083 * example: ran_number is 5, pages have weights of 10 and 10
1084 * first iteration page_index = 0, ran_number = -5
1085 * iteration halted, page_index = 0
1088 while (ran_number
>= 0)
1091 D_PRINTF( "Current page index %d: %ld - %d\n",
1092 page_index
, ran_number
,
1093 load_file_list
[page_index
].load_num
1095 ran_number
-= load_file_list
[page_index
].load_num
;
1098 if (page_index
>= number_of_pages
) { page_index
--; }
1100 D_PRINTF( "Final page index %d\n", page_index
);
1101 filecnt
= makeload(load_file_list
[page_index
].num_of_files
,
1102 page_index
, timerarray
, ×tat
, mastersock
, page_stats
);
1105 else /* NOT RUNNING IN TIMED MODE */
1107 for (page_number
= 0;
1108 page_number
< number_of_pages
;
1111 filecnt
= makeload(load_file_list
[page_number
].num_of_files
,
1112 page_number
, timerarray
, ×tat
, mastersock
, page_stats
);
1114 } /* END for page_number */
1115 } /* END if/else TIMED MODE */
1117 else /* NO FILELIST */
1119 D_PRINTF( "No filelist\n" );
1121 * LOOP THROUGH UNTIL numfiles TIMES OR UNTIL TIMER EXPIRES
1122 * AND ALARM SETS filecnt TO INFINITY.
1125 /* does this still work?? */
1126 /* filecnt = makeload(numfiles, -1, timerarray); */
1127 } /* END if HAVE FILELIST */
1130 file_count
+= filecnt
;
1132 } /* END while loopcnt */
1134 GETTIMEOFDAY(&(timestat
.endtime
), &(timestat
.endtimezone
));
1135 D_PRINTF( "Test run complete\n" );
1144 numfiles
= file_count
;
1148 /* This option ( "-R" ) looks broken (e.g. l > 50) -- JEF 2/15/96 */
1149 if (record_all_transactions
)
1152 * DUMP THE LOG FILE INFORMATION.
1154 for (loop
=0; loop
< (loopcnt
* file_count
); loop
++)
1156 fprintf(logfile
, " entertime \t%d.%d\n"
1157 " beforeconnect \t%d.%d\n"
1158 " afterconnect \t%d.%d\n"
1159 " beforeheader \t%d.%d\n"
1160 " afterheader \t%d.%d\n"
1161 " afterbody \t%d.%d\n"
1162 " exittime \t%d.%d\n"
1163 " total bytes \t%d\n"
1164 " body bytes\t%d\n",
1165 timerarray
[loop
].entertime
.tv_sec
,
1166 timerarray
[loop
].entertime
.tv_usec
,
1167 timerarray
[loop
].beforeconnect
.tv_sec
,
1168 timerarray
[loop
].beforeconnect
.tv_usec
,
1169 timerarray
[loop
].afterconnect
.tv_sec
,
1170 timerarray
[loop
].afterconnect
.tv_usec
,
1171 timerarray
[loop
].beforeheader
.tv_sec
,
1172 timerarray
[loop
].beforeheader
.tv_usec
,
1173 timerarray
[loop
].afterheader
.tv_sec
,
1174 timerarray
[loop
].afterheader
.tv_usec
,
1175 timerarray
[loop
].afterbody
.tv_sec
,
1176 timerarray
[loop
].afterbody
.tv_usec
,
1177 timerarray
[loop
].exittime
.tv_sec
,
1178 timerarray
[loop
].exittime
.tv_usec
,
1179 timerarray
[loop
].totalbytes
,
1180 timerarray
[loop
].bodybytes
);
1181 } /* end for loop */
1182 } /* end if recording all transactions */
1184 D_PRINTF( "total errors: %d\n",timestat
.rs
.totalerrs
);
1185 /* gethostname(timestat.hostname,MAXHOSTNAMELEN); */
1186 /* D_PRINTF( "Test for host: %s\n",timestat.hostname ); */
1187 D_PRINTF( "Server is: %s running at port number: %d\n",
1188 webserver
,portnum
);
1190 /* sprintf(timestat.hostname,"%s:%d",timestat.hostname,getpid()); */
1191 if (amclient
) /* CLIENT TO A WEBMASTER */
1193 char *stats_as_text
;
1196 * SEND THE TIMING DATA TO THE MASTER
1198 stats_as_text
= stats_to_text(×tat
);
1199 D_PRINTF( "stats_to_text returned %s\n", stats_as_text
);
1201 returnval
= senddata(mastersock
, stats_as_text
,
1202 SIZEOF_STATSTEXTBASE
+ number_of_pages
*SIZEOF_DOUBLETEXT
);
1203 D_PRINTF( "Wrote time stats to master %d\n", returnval
);
1207 D_PRINTF( "Error while writing time stats: %s\n",
1209 errexit("Error while writing time stats: %s\n",
1214 /* write pagestats */
1216 char *page_stats_as_text
;
1217 for (i
= 0; i
< number_of_pages
; i
++)
1219 D_PRINTF( "On page_stats[%d]\n", i
);
1220 page_stats_as_text
= page_stats_to_text(&page_stats
[i
]);
1221 returnval
= strlen(page_stats_as_text
);
1222 D_PRINTF( "page_stats_to_text[%d] returned %d\n",
1224 returnval
= senddata(mastersock
, page_stats_as_text
,
1225 SIZEOF_PAGESTATSTEXT
);
1228 D_PRINTF( "Error while writing page_stats[%d]: %s\n",
1230 errexit("Error while writing page_stats[%d]: %s\n",
1233 D_PRINTF( "Wrote %d bytes of page_stats[%d] to master\n",
1236 } /* end if filelist */
1238 D_PRINTF( "About to close socket\n" );
1239 if (NETCLOSE(mastersock
))
1240 D_PRINTF( "Close socket error: %s\n", neterrstr() );
1242 else /* NOT A CLIENT TO A WEBMASTER */
1246 printf("Test ran for: %d minutes\n",(testtime
/60));
1250 printf("Test ran for: %d iterations.\n",numloops
);
1252 compdifftime(&(timestat
.endtime
), &(timestat
.starttime
),
1254 printf("Total time of test (sec) %d.%d\n", runningtime
.tv_sec
,
1255 runningtime
.tv_usec
);
1256 printf("Files retrieved per iteration: %d\n",numfiles
); /* 'per iteration' */
1257 printf("----------------------------------\n");
1258 printf("Totals:\n\n");
1259 rqstat_print(&(timestat
.rs
));
1261 if (timestat
.rs
.totalconnects
== 0)
1263 printf("Thruput = %5.2lf Kbytes/sec\n",
1264 thruputpersec(timestat
.rs
.totalbytes
, &runningtime
) / 1000);
1266 if (uil_filelist_f
&& numloops
&& verbose
)
1268 for (loop
= 0; loop
< number_of_pages
; loop
++)
1270 if (timestat
.page_numbers
[loop
] != 0)
1272 printf ("===============================================================================\n");
1273 printf ("Page # %d\n\n", loop
);
1274 printf ("Total number of times page was hit %d\n",
1275 page_stats
[loop
].totalpages
);
1276 rqstat_print(&(page_stats
[loop
].rs
));
1277 printf ("Page size %d \n", page_stats
[loop
].page_size
);
1278 printf ("===============================================================================\n\n");
1279 } /* END if timestat */
1280 } /* END for loop */
1281 } /* END if filelist */
1282 } /* END if client */
1285 if(record_all_transactions
)
1289 D_PRINTF( "Client exiting.\n" );
1294 /* tell parent we're done */
1295 InterlockedIncrement(&CounterSemaphore
);
1298 } /* END ClientThread() */