/[hyperestraier]/trunk/estload.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/estload.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3 - (show annotations)
Fri Jul 29 21:57:20 2005 UTC (18 years, 9 months ago) by dpavlin
File MIME type: text/plain
File size: 9739 byte(s)
make working copy from version 0.5.1

1 /*************************************************************************************************
2 * The load tester for web applications
3 * Copyright (C) 2004-2005 Mikio Hirabayashi
4 * This file is part of Hyper Estraier.
5 * Hyper Estraier is free software; you can redistribute it and/or modify it under the terms of
6 * the GNU Lesser General Public License as published by the Free Software Foundation; either
7 * version 2.1 of the License or any later version. Hyper Estraier is distributed in the hope
8 * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
10 * License for more details.
11 * You should have received a copy of the GNU Lesser General Public License along with Hyper
12 * Estraier; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
13 * Boston, MA 02111-1307 USA.
14 *************************************************************************************************/
15
16
17 #include "estraier.h"
18 #include "estmtdb.h"
19 #include "estnode.h"
20 #include "myconf.h"
21
22 #define AGENTNAME "estload" /* name of the user agent */
23 #define IOBUFSIZ 8192 /* size of a buffer for I/O */
24
25 typedef struct { /* type of structure for a target URL */
26 char *host; /* hostname */
27 char *addr; /* IP address */
28 int port; /* port number */
29 char *auth; /* authority */
30 char *path; /* path */
31 char *query; /* query string */
32 } TARGET;
33
34 typedef struct { /* type of structure for a worker thread */
35 int id; /* ID number */
36 int ims; /* interval time in milliseconds */
37 int pb; /* to print received data */
38 int qb; /* to be quiet */
39 CBLIST *targets; /* list of targets */
40 int alive; /* to be alive */
41 } MISSION;
42
43
44 /* global variables */
45 const char *g_progname; /* program name */
46
47
48 /* function prototypes */
49 int main(int argc, char **argv);
50 static void usage(void);
51 static void printferror(const char *format, ...);
52 static void printfinfo(const char *format, ...);
53 static int procmain(const char *file, int tnum, int lnum, int ims, int pb, int qb);
54 static void *procthread(void *arg);
55
56
57 /* main routine */
58 int main(int argc, char **argv){
59 char *file;
60 int i, tnum, lnum, ims, pb, qb, rv;
61 cbstdiobin();
62 g_progname = argv[0];
63 if(!est_init_net_env()){
64 printferror("could not initialize network environment");
65 exit(1);
66 }
67 atexit(est_free_net_env);
68 file = NULL;
69 tnum = 1;
70 lnum = 1;
71 ims = 0;
72 pb = FALSE;
73 qb = FALSE;
74 for(i = 1; i < argc; i++){
75 if(!file && argv[i][0] == '-'){
76 if(!strcmp(argv[i], "-t")){
77 if(++i >= argc) usage();
78 tnum = atoi(argv[i]);
79 } else if(!strcmp(argv[i], "-l")){
80 if(++i >= argc) usage();
81 lnum = atoi(argv[i]);
82 } else if(!strcmp(argv[i], "-i")){
83 if(++i >= argc) usage();
84 ims = atoi(argv[i]);
85 } else if(!strcmp(argv[i], "-p")){
86 pb = TRUE;
87 } else if(!strcmp(argv[i], "-q")){
88 qb = TRUE;
89 } else {
90 usage();
91 }
92 } else if(!file){
93 file = argv[i];
94 } else {
95 usage();
96 }
97 }
98 if(!file || tnum < 1 || lnum < 1) usage();
99 rv = procmain(file, tnum, lnum, ims, pb, qb);
100 return rv;
101 }
102
103
104 /* print the usage and exit */
105 static void usage(void){
106 fprintf(stderr, "%s: stresser for web applications\n", g_progname);
107 fprintf(stderr, "\n");
108 fprintf(stderr, "usage:\n");
109 fprintf(stderr, " %s [-t num] [-l num] [-i num] [-p] [-q] [file|url]\n", g_progname);
110 fprintf(stderr, "\n");
111 exit(1);
112 }
113
114
115 /* print formatted error string and flush the buffer */
116 static void printferror(const char *format, ...){
117 va_list ap;
118 va_start(ap, format);
119 fprintf(stderr, "%s: ERROR: ", g_progname);
120 vfprintf(stderr, format, ap);
121 fputc('\n', stderr);
122 fflush(stderr);
123 va_end(ap);
124 }
125
126
127 /* print formatted information string and flush the buffer */
128 static void printfinfo(const char *format, ...){
129 va_list ap;
130 va_start(ap, format);
131 printf("%s: INFO: ", g_progname);
132 vprintf(format, ap);
133 putchar('\n');
134 fflush(stdout);
135 va_end(ap);
136 }
137
138
139 /* proc the main command */
140 static int procmain(const char *file, int tnum, int lnum, int ims, int pb, int qb){
141 pthread_t *threads;
142 MISSION *missions;
143 TARGET target;
144 CBLIST *list;
145 CBMAP *elems;
146 const char *line, *host, *pstr, *auth, *path, *query;
147 int i, j, cnt, pnum, err;
148 double etime;
149 if(cbstrfwimatch(file, "http://")){
150 list = cblistopen();
151 cblistpush(list, file, -1);
152 } else if(!(list = cbreadlines(file))){
153 printferror("%s: could not open", file);
154 return 1;
155 }
156 threads = cbmalloc(tnum * sizeof(pthread_t));
157 missions = cbmalloc(tnum * sizeof(MISSION));
158 for(i = 0; i < tnum; i++){
159 missions[i].id = i + 1;
160 missions[i].ims = ims;
161 missions[i].pb = pb;
162 missions[i].qb = qb;
163 missions[i].targets = cblistopen();
164 }
165 cnt = 0;
166 for(i = 0; i < lnum; i++){
167 for(j = 0; j < cblistnum(list); j++){
168 line = cblistval(list, j, NULL);
169 if((line[0] == '\0')) continue;
170 elems = cburlbreak(line);
171 host = cbmapget(elems, "host", -1, NULL);
172 pnum = (pstr = cbmapget(elems, "port", -1, NULL)) ? atoi(pstr) : 80;
173 auth = cbmapget(elems, "authority", -1, NULL);
174 path = cbmapget(elems, "path", -1, NULL);
175 query = cbmapget(elems, "query", -1, NULL);
176 if(!host || pnum < 1){
177 printferror("%s: invalid URL", line);
178 cbmapclose(elems);
179 continue;
180 }
181 if(!auth) auth = "";
182 if(!path) path = "/";
183 if(!query) query = "";
184 if(!(target.addr = est_get_host_addr(host))){
185 printferror("%s: unknown host", host);
186 cbmapclose(elems);
187 continue;
188 }
189 target.host = cbmemdup(host, -1);
190 target.port = pnum;
191 target.auth = cbmemdup(auth, -1);
192 target.path = cbmemdup(path, -1);
193 target.query = cbmemdup(query, -1);
194 cblistpush(missions[cnt++%tnum].targets, (char *)&target, sizeof(TARGET));
195 cbmapclose(elems);
196 }
197 }
198 cblistclose(list);
199 err = FALSE;
200 etime = est_gettimeofday();
201 if(tnum > 1){
202 for(i = 0; i < tnum; i++){
203 missions[i].alive = FALSE;
204 if(pthread_create(threads + i, NULL, procthread, missions + i) == 0){
205 missions[i].alive = TRUE;
206 } else {
207 printferror("thread creation failed");
208 err = TRUE;
209 }
210 }
211 for(i = 0; i < tnum; i++){
212 if(!missions[i].alive) continue;
213 if(pthread_join(threads[i], NULL) != 0){
214 printferror("thread join failed");
215 err = TRUE;
216 }
217 }
218 } else {
219 procthread(missions);
220 }
221 etime = est_gettimeofday() - etime;
222 if(cnt > 0 && !err)
223 printfinfo("finished: elepsed time: %.3f sec. (average: %.3f)",
224 etime / 1000, etime / cnt / 1000);
225 for(i = 0; i < tnum; i++){
226 for(j = 0; j < cblistnum(missions[i].targets); j++){
227 target = *(TARGET *)cblistval(missions[i].targets, j, NULL);
228 free(target.query);
229 free(target.path);
230 free(target.auth);
231 free(target.addr);
232 free(target.host);
233 }
234 cblistclose(missions[i].targets);
235 }
236 free(missions);
237 free(threads);
238 return err ? 1 : 0;
239 }
240
241
242 /* process as a child thread */
243 static void *procthread(void *arg){
244 CBLIST *targets;
245 TARGET target;
246 char iobuf[IOBUFSIZ], *wp, *tmp;
247 int i, id, ims, pb, qb, clsock, size;
248 double etime;
249 targets = ((MISSION *)arg)->targets;
250 id = ((MISSION *)arg)->id;
251 ims = ((MISSION *)arg)->ims;
252 pb = ((MISSION *)arg)->pb;
253 qb = ((MISSION *)arg)->qb;
254 if(cblistnum(targets) < 1) return NULL;
255 printfinfo("%d: started", id);
256 etime = est_gettimeofday();
257 for(i = 0; i < cblistnum(targets); i++){
258 target = *(TARGET *)cblistval(targets, i, NULL);
259 if(!qb) printfinfo("%d(%d/%d): http://%s:%d%s%s%s",
260 id, i + 1, cblistnum(targets), target.host, target.port,
261 target.path, target.query[0] != '\0' ? "?" : "", target.query);
262 if((clsock = est_get_client_sock(target.addr, target.port)) != -1){
263 wp = iobuf;
264 wp += sprintf(wp, "GET %s%s%s HTTP/1.0\r\n",
265 target.path, target.query[0] != '\0' ? "?" : "", target.query);
266 wp += sprintf(wp, "Host: %s:%d\r\n", target.host, target.port);
267 wp += sprintf(wp, "Connection: close\r\n");
268 if(target.auth[0] != '\0'){
269 tmp = cbbaseencode(target.auth, -1);
270 wp += sprintf(wp, "Authorization: Basic %s\r\n", tmp);
271 free(tmp);
272 }
273 wp += sprintf(wp, "Referer: http://%s:%d%s%s%s\r\n", target.host, target.port,
274 target.path, target.query[0] != '\0' ? "?" : "", target.query);
275 wp += sprintf(wp, "User-Agent: %s/%s\r\n", AGENTNAME, est_version);
276 wp += sprintf(wp, "\r\n");
277 est_sock_send_all(clsock, iobuf, wp - iobuf);
278 while((size = recv(clsock, iobuf, IOBUFSIZ, 0)) > 0){
279 if(pb) fwrite(iobuf, 1, size, stdout);
280 }
281 est_sock_down(clsock);
282 } else {
283 printferror("%d(%d/%d): connection failed", id, i + 1, cblistnum(targets));
284 }
285 if(ims > 0) est_usleep(ims * 1000);
286 }
287 etime = est_gettimeofday() - etime;
288 printfinfo("%d: finished: elapsed time: %.3f sec. (average: %.3f)",
289 id, etime / 1000, etime / cblistnum(targets) / 1000);
290 return NULL;
291 }
292
293
294
295 /* END OF FILE */

  ViewVC Help
Powered by ViewVC 1.1.26