diff -r -u siege-2.58/doc/siege.1.in siege-2.58-userfile/doc/siege.1.in --- siege-2.58/doc/siege.1.in 2003-01-20 16:23:06.000000000 +0200 +++ siege-2.58-userfile/doc/siege.1.in 2003-12-19 18:34:12.000000000 +0200 @@ -75,6 +75,19 @@ \fB\-u URL\fR, \fB\-\-url=URL\fR URL, use this option to stress a single URL. This option overrides the URL file and stresses just the URL selected at the command line. This feature has been \fBdeprecated.\fR The new format for invoking siege is siege [options] when using an urls.txt file and siege [options] [url] +.TP +\fB\-U USERFILE\fR, \fB\-\-users=USERFILE\fR +With this you can add multiple users to requests. +Users are read from users file, where user can have multiple. +Every client takes a user data from user list and uses that data for every request in url-list. +Look forward for file format. +.TP +\fB\-Y CHAR\fR, \fB\-\-user\-delim=CHAR\fR +Delimeter char in userfile. default \fB';'\fR. +.TP +\fB\-Z CHAR\fR, \fB\-\-user\-marker=CHAR\fR +Marker character for in urls and headers for user data. Default is \fB'@'\fR. + .SH URL FORMAT Siege understands the following URL formats: \fR .br @@ -146,6 +159,41 @@ .br http://${HOST}/howto.jsp\fR .br + +.SH USER FILE FORMAT +In user file every line gives information about one user. +You can have multiple data values for one user separated by ';' default. +File could be like:\fR + +.br +# (0)userid; (1)name; (2)phone-number\fR +# +.br +.br +42;Milo+Moros;555-384958\fR +.br +49;Arthur+Miller;555-192938\fR +.br +\fR +For every url and extra-headers. string @1 is changed to userid. +@1 to name and @2 to phone-number. @0 is whole line. @@ is plain @.\fR + +.br +FROM: http://xxxyyy.com/hello?userid=@1\fR +.br +.br +TO: http://xxxyyy.com/hello?userid=42\fR +.br\fR +.br + +One Client goes throw all urls in urls.txt using one user and takes next "free" user +from user-file. After all users are handled user list is started again.\fR +.br +.br + +Both url and extra macro-expaned with this user-data.\fR +.br + .SH PERFORMANCE STATISTICS Performance measures include elapsed time of the test, the amount of data transferred ( including headers ), the response time of the server, its transaction rate, its throughput, its concurrency and the number of times it returned OK. These measures are quantified and reported at the end of each run. The reporting format is modeled after Lincoln Stein's torture.pl script:\fR .br Only in siege-2.58-userfile/doc: siege.1.in~ Only in siege-2.58/include: stamp-h.in Only in siege-2.58-userfile/src: cfg.c~ diff -r -u siege-2.58/src/cfg.h siege-2.58-userfile/src/cfg.h --- siege-2.58/src/cfg.h 2003-03-27 17:47:43.000000000 +0200 +++ siege-2.58-userfile/src/cfg.h 2003-12-19 17:33:41.000000000 +0200 @@ -27,4 +27,5 @@ int read_cfg_file( LINES *l, char *filename ); int read_cmd_line( LINES *l, char *url ); + #endif/*CFG_H*/ Only in siege-2.58-userfile/src: cfg.h~ diff -r -u siege-2.58/src/client.c siege-2.58-userfile/src/client.c --- siege-2.58/src/client.c 2003-12-05 22:50:47.000000000 +0200 +++ siege-2.58-userfile/src/client.c 2003-12-19 18:08:44.000000000 +0200 @@ -29,6 +29,7 @@ #include #include #include +#include /** * see below at "start_routine( CLIENT *c )" for more info on that: */ @@ -55,6 +56,19 @@ #endif/*SIGNAL_CLIENT_PLATFORM*/ +static void get_next_user(CLIENT *client) +{ + if(our.next_user) { + pthread_mutex_lock( &our.user_lock ); + client->user = our.next_user; + our.next_user = our.next_user->next; + pthread_mutex_unlock( &our.user_lock ); + } else { + client->user = NULL; + } +} + + /** * The thread entry point for clients. * @@ -105,6 +119,7 @@ pthread_cond_signal(&our.exit_cond); + #ifdef SIGNAL_CLIENT_PLATFORM #else/*CANCEL_CLIENT_PLATFORM*/ /** @@ -127,13 +142,19 @@ http_request( C, add_url( my.loginurl ), client ); } + if(our.next_user) get_next_user(client); + for( x = 0, y = 0; x < my.reps; x++, y++ ){ x = (( my.secs > 0 ) && (( my.reps <= 0 )||( my.reps == MAXREPS))) ? 0 : x; + + + if( my.internet == TRUE ){ y = (unsigned int) (((double)pthread_rand_np(&(client->rand_r_SEED)) / ((double)RAND_MAX + 1) * my.length ) + .5); y = (y >= my.length)?my.length-1:y; y = (y < 0)?0:y; + if(our.next_user) get_next_user(client); } else{ /** @@ -146,6 +167,7 @@ if( my.expire ){ delete_all_cookies((int)pthread_self()); } + if(our.next_user) get_next_user(client); } } if( y >= my.length || y < 0 ){ printf("y out of bounds: %d", y); y = 0; } @@ -195,7 +217,9 @@ float etime; /* trans. elapsed time */ clock_t start, stop; /* time structs for elaps. */ struct tms t_start, t_stop; /* time structs for elaps. */ - HEADERS *head; /* HTTP header structure */ + HEADERS *head; /* HTTP header structure */ + char *pathname; + char pathbuffer[4096]; C->pos_ini = 0; C->inbuffer = 0; @@ -208,6 +232,7 @@ C->auth.proxy = client->auth.proxy; C->auth.type.www = client->auth.type.www; C->auth.type.proxy = client->auth.type.proxy; + C->user = client->user; memset( C->buffer, 0, sizeof( C->buffer )); if( U->protocol == UNSUPPORTED ){ @@ -263,19 +288,22 @@ else{ okay = 1; } if( !okay ){ return -1; } if( my.debug ){ printf( "connention made.\n" ); fflush( stdout ); } + + + pathname = add_user(U->pathname, pathbuffer, client->user); /** * write to socket with a POST or GET */ if( U->calltype == URL_POST ){ - if(( SIEGEhttp_post( C, U->hostname, U->port, U->pathname, U->postdata, U->postlen )) < 0 ){ + if(( SIEGEhttp_post( C, U->hostname, U->port, pathname, U->postdata, U->postlen )) < 0 ){ C->connection.reuse = 0; SIEGEclose( C ); return -1; } } else{ - if(( SIEGEhttp_send( C, U->hostname, U->port, U->pathname )) < 0 ){ + if(( SIEGEhttp_send( C, U->hostname, U->port, pathname )) < 0 ){ C->connection.reuse = 0; SIEGEclose( C ); return -1; @@ -312,12 +340,12 @@ if( my.display ) printf( "%4d: %s %d %6.2f secs: %7d bytes ==> %s\n", client->id, - head->head, head->code, etime, bytes, U->pathname + head->head, head->code, etime, bytes, pathname ); else printf( "%s %d %6.2f secs: %7d bytes ==> %s\n", - head->head, head->code, etime, bytes, U->pathname + head->head, head->code, etime, bytes, pathname ); } Only in siege-2.58-userfile/src: client.c~ diff -r -u siege-2.58/src/http.c siege-2.58-userfile/src/http.c --- siege-2.58/src/http.c 2003-11-22 19:59:17.000000000 +0200 +++ siege-2.58-userfile/src/http.c 2003-12-19 17:58:49.000000000 +0200 @@ -26,6 +26,8 @@ #include #include +#include + #define MAXFILE 10240 #define REQBUF 40960 @@ -73,6 +75,8 @@ return NULL; } + + /** * returns int, ( < 0 == error ) * formats and sends an HTTP/1.0 request @@ -87,6 +91,8 @@ char authwww[128]; char authpxy[128]; char request[REQBUF]; + char *extra; + char extrabuf[4096]; /* Request path based on proxy settings */ char fullpath[4096]; @@ -96,6 +102,7 @@ else{ sprintf( fullpath, "%s", path ); } + extra = add_user(my.extra, extrabuf, C->user); memset( cookie, 0, sizeof( cookie )); memset( request, 0, sizeof( request )); @@ -136,7 +143,7 @@ fullpath, protocol, host, port, (C->auth.www==TRUE)?authwww:"", (C->auth.proxy==TRUE)?authpxy:"", - cookie, my.uagent, my.extra, keepalive + cookie, my.uagent, extra, keepalive ); if( my.debug ){ printf("%s\n", request); fflush(stdout); } @@ -167,6 +174,8 @@ char request[REQBUF]; char *protocol; char *keepalive; + char *extra; + char extrabuf[4096]; /* cookie value */ char cookie[MAX_COOKIE_SIZE]; @@ -179,7 +188,11 @@ else{ sprintf( fullpath, "%s", path ); } - + if(C->user) { + extra = add_user(my.extra,extrabuf, C->user); + } else { + extra = my.extra; + } memset( cookie, 0, sizeof( cookie )); memset( request, 0, sizeof( request )); @@ -220,7 +233,7 @@ fullpath, protocol, host, port, (C->auth.www==TRUE)?authwww:"", (C->auth.proxy==TRUE)?authpxy:"", - cookie, my.uagent, my.extra, keepalive, len + cookie, my.uagent, extra, keepalive, len ); if( rlen + len < sizeof(request)){ Only in siege-2.58-userfile/src: http.c~ diff -r -u siege-2.58/src/init.c siege-2.58-userfile/src/init.c --- siege-2.58/src/init.c 2003-08-25 21:36:31.000000000 +0300 +++ siege-2.58-userfile/src/init.c 2003-12-19 18:21:34.000000000 +0200 @@ -64,6 +64,8 @@ my.extra[0] = 0; my.follow = TRUE; my.zero_ok = TRUE; + my.user_marker = '@'; + my.user_delim = ';'; if( load_conf( filename ) < 0 ){ fprintf( stderr, "****************************************************\n" ); @@ -416,3 +418,127 @@ } } +/** + * read user file + */ + +int read_user_file(char *filename) +{ + FILE *fp; + int line_num = 0; + char *line; + int delim = my.user_delim; + TESTUSER *latest = NULL; + + if (( fp = fopen(filename, "r")) == NULL ) { + return -1; + } + + while(( line = chomp_line( fp, &line, &line_num )) != NULL ) { + int i; + int cnt; + char *ptr; + char *ep; + TESTUSER *user; + + while(*line > 0 && *line <= 32) + line++; + if(!*line) continue; + if(*line == '#') continue; + if(line[0] == '@' && line[1] == '=' && line[2]) { + my.user_marker = line[3]; + continue; + } + if(line[0] == '!' && line[1] == '=' && line[2]) { + delim = line[3]; + continue; + } + + // count how many pars in line + ptr = line; + cnt = 1; + while((ptr = strchr(ptr,delim))) { + cnt++; + ptr++; + } + // mak it. + user = xcalloc(sizeof(*user) + ((cnt+2) * sizeof(char*)), 1); + user->next = NULL; + user->varcount = cnt; + user->vars[0] = strdup(line); + ptr = line; + i = 1; + while((ep = strchr(ptr,delim))) { + *ep = '\0'; + user->vars[i] = xstrdup(ptr); + i++; + ptr = ep + 1; + } + if(*ptr) { + user->vars[i] = xstrdup(ptr); + } + + if(latest) { + latest->next = user; + } else { + my.users = user; + } + latest = user; + } + fclose(fp); + if(latest) latest->next = my.users; + return 0; +} + +/** + * add user data to string + * + * returns changed string. + * + */ + +char *add_user(char *src, char *buffer, TESTUSER *user) +{ + char *e; + char *d; + char *s; + + + // printf("[add-user: %s]\n", src ? src : ""); + + if(!user || !src || !*src || !(e = strchr(src,my.user_marker))) + return src; + + s = src; + + //printf("[add-user: %s]\n", src ? src : ""); + d= buffer; + while(e) { + for(;s < e;) { + *d++ = *s++; + } + e++; + if(*e == my.user_marker) { + *d++ = my.user_marker; + } else if(isdigit(*e)) { + int digit = *e - '0'; + if(digit >= 0 && digit <= user->varcount && user->vars[digit]) { + char *p = user->vars[digit]; + while(*p) { + *d++ = *p++; + } + } + } else { + *d++ = my.user_marker; + *d++ = *e; + } + s = e + 1; + e = strchr(s,my.user_marker); + } + while(*s) { + *d++ = *s++; + } + *d = 0; + // printf("[ADD:%s][%s]\n", buffer, src); + return buffer; +} Only in siege-2.58-userfile/src: init.c~ diff -r -u siege-2.58/src/init.h siege-2.58-userfile/src/init.h --- siege-2.58/src/init.h 2002-01-14 20:55:31.000000000 +0200 +++ siege-2.58-userfile/src/init.h 2003-12-19 17:35:34.000000000 +0200 @@ -23,10 +23,14 @@ #ifndef INIT_H #define INIT_H #include +#include "setup.h" int init_config( void ); int show_config( int EXIT ); int load_conf( char *filename ); void ds_module_check(); +int read_user_file(char *filename); + +char *add_user(char *src, char *buffer, TESTUSER *user); #endif/*INIT_H*/ Only in siege-2.58-userfile/src: init.h~ diff -r -u siege-2.58/src/main.c siege-2.58-userfile/src/main.c --- siege-2.58/src/main.c 2003-07-17 16:04:47.000000000 +0300 +++ siege-2.58-userfile/src/main.c 2003-12-19 18:04:28.000000000 +0200 @@ -45,6 +45,8 @@ #include #include +#include + int fd = 0; /* tmp file, for user defined URL */ int count = 0; /* count messages processes, ie. transacts */ int code = 0; /* count HTTP successes, i.e., < 400 */ @@ -74,7 +76,11 @@ { "file", required_argument, NULL, 'f' }, { "url", required_argument, NULL, 'u' }, { "mark", required_argument, NULL, 'm' }, - { "header", required_argument, NULL, 'H' } + { "header", required_argument, NULL, 'H' }, + { "users", required_argument, NULL, 'U' }, + { "user-delim", required_argument, NULL, 'Y' }, + { "user-marker",required_argument, NULL, 'Z' }, + { NULL, 0, NULL, 0 } }; /** @@ -132,12 +138,17 @@ puts(" -d, --delay=NUM Time DELAY, random delay between 1 and num designed" ); puts(" to simulate human activity. Default value is 3" ); puts(" -H, --header=\"text\" Add a header to request (can be many)" ); + puts(" -U, --users=\"users file\" Add unsers to request" ); + puts(" -Y, --user-delim=CHR User file delimeter" ); + puts(" -Z, --user-marker=CHR User marker in urs" ); /** * our work is done, exit nicely */ exit( EXIT_SUCCESS ); } + + /** * parses command line arguments and assigns * values to run time variables. relies on GNU @@ -148,7 +159,7 @@ { int c = 0; int nargs; - while(( c = getopt_long( argc, argv, "VhvCDlibr:t:f:d:c:u:m:H:", + while(( c = getopt_long( argc, argv, "VhvCDlibr:t:f:d:c:u:m:H:U:Z:Y:", long_options, (int *)0)) != EOF ){ switch( c ){ case 'V': @@ -214,6 +225,20 @@ strcat(my.extra,"\015\012"); } break; + case 'U': + { + struct stat st; + if(stat(optarg,&st) < 0) + joe_fatal("no user file found: %s", optarg); + my.user_file = xstrdup(optarg); + } + break; + case 'Y': + my.user_delim = *optarg; + break; + case 'Z': + my.user_marker = *optarg; + break; } /* end of switch( c ) */ } /* end of while c = getopt_long */ @@ -266,9 +291,16 @@ if( my.url != NULL ) my.length = 1; else my.length = read_cfg_file( lines, my.file ); + if( my.length == 0 ) display_help(); + if(my.user_file) { + if(read_user_file(my.user_file) < 0) { + joe_fatal("illegal user file: %s", my.user_file); + } + } + /* cookie is an EXTERN, defined in setup */ cookie = (COOKIE*)xmalloc(sizeof(COOKIE)); cookie->first = NULL; @@ -332,6 +364,9 @@ SSL_thread_setup(); #endif + pthread_mutex_init(&our.user_lock, NULL); + our.next_user = my.users; + /** * create the signal handler and timer; the * signal handler thread (cease) responds to @@ -349,6 +384,8 @@ randrseed = time(0); + + /** * loop until my.cusers and create a corresponding thread... */ Only in siege-2.58-userfile/src: main.c~ Only in siege-2.58-userfile/src: Makefile~ diff -r -u siege-2.58/src/setup.h siege-2.58-userfile/src/setup.h --- siege-2.58/src/setup.h 2003-03-27 17:42:30.000000000 +0200 +++ siege-2.58-userfile/src/setup.h 2003-12-19 17:50:55.000000000 +0200 @@ -144,6 +144,20 @@ void display_version( int i ); void display_help(); +/** + * TEST user + * + */ +typedef struct TESTUSER TESTUSER; + +struct TESTUSER +{ + TESTUSER *next; + int varcount; + char *vars[0]; +}; + + /** * configuration struct; * NOTE: this data is writeable ONLY during @@ -201,6 +215,11 @@ int expire; /* boolean, TRUE == expire cookies ea. run */ int follow; /* boolean, TRUE == follow 302 */ int zero_ok; /* boolean, TRUE == zero bytes data is OK. */ + + char user_marker; /* user marker char in urls/headers */ + char user_delim; /* user field delimeter in user file */ + char *user_file; /* filename for users */ + TESTUSER *users; /* testuser list (circular) */ }; struct O_STATUS @@ -210,6 +229,8 @@ pthread_cond_t exit_cond; /* pthread cond. variable */ pthread_mutex_t mutex_lock; /* w lock for total_threads */ int shutting_down; /* boolean: 1=TRUE, 0=FALSE */ + pthread_mutex_t user_lock; /* lock for getting next user */ + TESTUSER *next_user; /* next user */ }; /** @@ -289,6 +310,7 @@ int status; float time; unsigned int rand_r_SEED; + TESTUSER *user; } CLIENT; Only in siege-2.58-userfile/src: setup.h~ diff -r -u siege-2.58/src/sock.h siege-2.58-userfile/src/sock.h --- siege-2.58/src/sock.h 2003-01-14 23:22:41.000000000 +0200 +++ siege-2.58-userfile/src/sock.h 2003-12-19 16:08:59.000000000 +0200 @@ -107,6 +107,7 @@ char buffer[4096]; fd_set rset; fd_set wset; + TESTUSER *user; } CONN; /** Only in siege-2.58-userfile/src: sock.h~ Only in siege-2.58-userfile/src: users.txt Only in siege-2.58-userfile/src: users.txt~ diff -r -u siege-2.58/src/util.c siege-2.58-userfile/src/util.c --- siege-2.58/src/util.c 2003-04-14 16:05:00.000000000 +0300 +++ siege-2.58-userfile/src/util.c 2003-12-19 17:32:29.000000000 +0200 @@ -189,3 +189,6 @@ } + + + Only in siege-2.58-userfile/src: util.c~ Only in siege-2.58-userfile/src: .#util.h Only in siege-2.58-userfile/src: #util.h# Only in siege-2.58-userfile/src: u.txt Only in siege-2.58-userfile/src: u.txt~