/** * sleep and usleep work on all supported * platforms except solaris, so we'll use * those functions on non-solaris, but we * still need to sleep. The macro handles * that for us. */ void pthread_sleep_np( unsigned int secs ) { #if defined( SOLARIS ) || defined( sun ) /* Theoretically, this could fail for sizeof(int)==sizeof(long) and * very large values of secs due to an overflow. * NB: for 64-bit int, that would mean waiting until the year 584543. */ pthread_usleep_np (secs*1000000); #else sleep(secs); #endif/*pthread_sleep_np*/ return; }
int main(int argc, char *argv[]) { int x; int result; DATA D = new_data(); ARRAY urls = new_array(); CREW crew; LINES *lines; CLIENT *client; pthread_t cease; pthread_t timer; pthread_attr_t scope_attr; void *statusp; sigset_t sigs; sigemptyset(&sigs); sigaddset(&sigs, SIGHUP); sigaddset(&sigs, SIGINT); sigaddset(&sigs, SIGALRM); sigaddset(&sigs, SIGTERM); sigprocmask(SIG_BLOCK, &sigs, NULL); lines = xcalloc(1, sizeof *lines); lines->index = 0; lines->line = NULL; memset(&my, 0, sizeof(struct CONFIG)); parse_rc_cmdline(argc, argv); if (init_config() < 0) { /* defined in init.h */ exit( EXIT_FAILURE ); /* polly was a girl... */ } parse_cmdline(argc, argv); /* defined above */ ds_module_check(); /* check config integ */ /** * XXX: we should consider moving the following * if-checks into the ds_module_check */ if (my.config) { show_config(TRUE); } if (my.url != NULL) { my.length = 1; } else { my.length = read_cfg_file(lines, my.file); } if (my.reps < 0) { my.reps = my.length; } if (my.length == 0) { display_help(); } /* cookie is an EXTERN, defined in setup */ cookie = xcalloc(sizeof(COOKIE), 1); cookie->first = NULL; if ((result = pthread_mutex_init( &(cookie->mutex), NULL)) !=0) { NOTIFY(FATAL, "pthread_mutex_init" ); } /* memory allocation for threads and clients */ client = xcalloc(my.cusers, sizeof(CLIENT)); if ((crew = new_crew(my.cusers, my.cusers, FALSE)) == NULL) { NOTIFY(FATAL, "unable to allocate memory for %d simulated browser", my.cusers); } /** * determine the source of the url(s), * command line or file, and add them * to the urls struct. */ if (my.url != NULL) { URL tmp = new_url(my.url); url_set_ID(tmp, 0); if (my.get && url_get_method(tmp) != POST && url_get_method(tmp) != PUT) { url_set_method(tmp, my.method); } array_npush(urls, tmp, URLSIZE); // from cmd line } else { for (x = 0; x < my.length; x++) { URL tmp = new_url(lines->line[x]); url_set_ID(tmp, x); array_npush(urls, tmp, URLSIZE); } } /** * display information about the siege * to the user and prepare for verbose * output if necessary. */ if (!my.get && !my.quiet) { fprintf(stderr, "** "); display_version(FALSE); fprintf(stderr, "** Preparing %d concurrent users for battle.\n", my.cusers); fprintf(stderr, "The server is now under siege..."); if (my.verbose) { fprintf(stderr, "\n"); } } /** * record start time before spawning threads * as the threads begin hitting the server as * soon as they are created. */ data_set_start(D); /** * for each concurrent user, spawn a thread and * loop until condition or pthread_cancel from the * handler thread. */ pthread_attr_init(&scope_attr); pthread_attr_setscope(&scope_attr, PTHREAD_SCOPE_SYSTEM); #if defined(_AIX) /* AIX, for whatever reason, defies the pthreads standard and * * creates threads detached by default. (see pthread.h on AIX) */ pthread_attr_setdetachstate(&scope_attr, PTHREAD_CREATE_JOINABLE); #endif /** * invoke OpenSSL's thread safety */ #ifdef HAVE_SSL SSL_thread_setup(); #endif /** * create the signal handler and timer; the * signal handler thread (cease) responds to * ctrl-C (sigterm) and the timer thread sends * sigterm to cease on time out. */ if ((result = pthread_create(&cease, NULL, (void*)sig_handler, (void*)crew)) < 0) { NOTIFY(FATAL, "failed to create handler: %d\n", result); } if (my.secs > 0) { if ((result = pthread_create(&timer, NULL, (void*)siege_timer, (void*)cease)) < 0) { NOTIFY(FATAL, "failed to create handler: %d\n", result); } } /** * loop until my.cusers and create a corresponding thread... */ for (x = 0; x < my.cusers && crew_get_shutdown(crew) != TRUE; x++) { client[x].id = x; client[x].bytes = 0; client[x].time = 0.0; client[x].hits = 0; client[x].code = 0; client[x].ok200 = 0; client[x].fail = 0; client[x].urls = urls; client[x].auth.www = 0; client[x].auth.proxy = 0; client[x].auth.type.www = BASIC; client[x].auth.type.proxy = BASIC; client[x].rand_r_SEED = urandom(); result = crew_add(crew, (void*)start_routine, &(client[x])); if (result == FALSE) { my.verbose = FALSE; fprintf(stderr, "Unable to spawn additional threads; you may need to\n"); fprintf(stderr, "upgrade your libraries or tune your system in order\n"); fprintf(stderr, "to exceed %d users.\n", my.cusers); NOTIFY(FATAL, "system resources exhausted"); } } /* end of for pthread_create */ crew_join(crew, TRUE, &statusp); #ifdef HAVE_SSL SSL_thread_cleanup(); #endif /** * collect all the data from all the threads that * were spawned by the run. */ for (x = 0; x < ((crew_get_total(crew) > my.cusers || crew_get_total(crew)==0 ) ? my.cusers : crew_get_total(crew)); x++) { data_increment_count(D, client[x].hits); data_increment_bytes(D, client[x].bytes); data_increment_total(D, client[x].time); data_increment_code (D, client[x].code); data_increment_ok200(D, client[x].ok200); data_increment_fail (D, client[x].fail); data_set_highest (D, client[x].himark); data_set_lowest (D, client[x].lomark); client[x].rand_r_SEED = urandom(); } /* end of stats accumulation */ /** * record stop time */ data_set_stop(D); /** * cleanup crew */ crew_destroy(crew); for (x = 0; x < my.cusers; x++) { // XXX: TODO //digest_challenge_destroy(client[x].auth.wwwchlg); //digest_credential_destroy(client[x].auth.wwwcred); //digest_challenge_destroy(client[x].auth.proxychlg); //digest_credential_destroy(client[x].auth.proxycred); } array_destroy(my.lurl); xfree(client); if (my.get) { if (data_get_ok200(D) > 0) { exit(EXIT_SUCCESS); } else { if (!my.quiet) echo("[done]\n"); exit(EXIT_FAILURE); } } /** * take a short nap for cosmetic effect * this does NOT affect performance stats. */ pthread_usleep_np(10000); if (my.verbose) fprintf(stderr, "done.\n"); else fprintf(stderr, "\b done.\n"); /** * prepare and print statistics. */ if (my.failures > 0 && my.failed >= my.failures) { fprintf(stderr, "%s aborted due to excessive socket failure; you\n", program_name); fprintf(stderr, "can change the failure threshold in $HOME/.%src\n", program_name); } fprintf(stderr, "\nTransactions:\t\t%12u hits\n", data_get_count(D)); fprintf(stderr, "Availability:\t\t%12.2f %%\n", data_get_count(D)==0 ? 0 : (double)data_get_count(D) / (data_get_count(D)+my.failed) *100 ); fprintf(stderr, "Elapsed time:\t\t%12.2f secs\n", data_get_elapsed(D)); fprintf(stderr, "Data transferred:\t%12.2f MB\n", data_get_megabytes(D)); /*%12llu*/ fprintf(stderr, "Response time:\t\t%12.3f secs\n", data_get_response_time(D)); fprintf(stderr, "Transaction rate:\t%12.2f trans/sec\n", data_get_transaction_rate(D)); fprintf(stderr, "Throughput:\t\t%12.2f MB/sec\n", data_get_throughput(D)); fprintf(stderr, "Concurrency:\t\t%12.2f\n", data_get_concurrency(D)); fprintf(stderr, "Successful transactions:%12u\n", data_get_code(D)); if (my.debug) { fprintf(stderr, "HTTP OK received:\t%12u\n", data_get_ok200(D)); } fprintf(stderr, "Failed transactions:\t%12u\n", my.failed); fprintf(stderr, "Longest transaction:\t%12.3f\n", data_get_highest(D)); fprintf(stderr, "Shortest transaction:\t%12.3f\n", data_get_lowest(D)); fprintf(stderr, " \n"); if(my.mark) mark_log_file(my.markstr); if(my.logging) log_transaction(D); data_destroy(D); if (my.url == NULL) { for (x = 0; x < my.length; x++) xfree(lines->line[x]); xfree(lines->line); xfree(lines); } else { xfree(lines->line); xfree(lines); } pthread_mutex_destroy( &(cookie->mutex)); /** * I should probably take a deeper look * at cookie content to free it but at * this point we're two lines from exit */ xfree (cookie); xfree (my.url); exit(EXIT_SUCCESS); } /* end of int main **/