1 /* http_load - multiprocessing http test client
2 **
3 ** Copyright � 1998,1999,2001 by Jef Poskanzer <jef@mail.acme.com>.
4 ** All rights reserved.
5 **
6 ** Redistribution and use in source and binary forms, with or without
7 ** modification, are permitted provided that the following conditions
8 ** are met:
9 ** 1. Redistributions of source code must retain the above copyright
10 ** notice, this list of conditions and the following disclaimer.
11 ** 2. Redistributions in binary form must reproduce the above copyright
12 ** notice, this list of conditions and the following disclaimer in the
13 ** documentation and/or other materials provided with the distribution.
14 **
15 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 ** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 ** SUCH DAMAGE.
26 */
27
28 #include "tscore/ink_config.h"
29
30 #include <sys/epoll.h>
31 #include <unistd.h>
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <fcntl.h>
36 #include <sys/types.h>
37 #include <sys/time.h>
38 #include <time.h>
39 #include <sys/resource.h>
40 #include <sys/socket.h>
41 #include <netinet/in.h>
42 #include <arpa/inet.h>
43 #include <netdb.h>
44 #include <errno.h>
45 #include <signal.h>
46
47 #include <openssl/ssl.h>
48 #include <openssl/rand.h>
49 #include <openssl/err.h>
50
51 #include "port.h"
52 #include "timers.h"
53
54 #if defined(AF_INET6) && defined(IN6_IS_ADDR_V4MAPPED)
55 #define USE_IPV6
56 #endif
57
58 #define max(a, b) ((a) >= (b) ? (a) : (b))
59 #define min(a, b) ((a) <= (b) ? (a) : (b))
60
61 /* How long a connection can stay idle before we give up on it. */
62 #define IDLE_SECS 60
63
64 /* Default max bytes/second in throttle mode. */
65 #define THROTTLE 3360
66
67 /* How often to show progress reports. */
68 #define PROGRESS_SECS 60
69
70 /* How many file descriptors to not use. */
71 #define RESERVED_FDS 3
72
73 typedef struct {
74 char *url_str;
75 int protocol;
76 char *hostname;
77 unsigned short port;
78 #ifdef USE_IPV6
79 struct sockaddr_in6 sa;
80 #else /* USE_IPV6 */
81 struct sockaddr_in sa;
82 #endif /* USE_IPV6 */
83 int sa_len, sock_family, sock_type, sock_protocol;
84 char *filename;
85 int got_bytes;
86 long bytes;
87 int got_checksum;
88 long checksum;
89 char *buf;
90 int buf_bytes;
91 int unique_id_offset;
92 struct {
93 int completed;
94 int max_response;
95 int min_response;
96 } stats;
97
98 } url;
99 static url *urls;
100 static int num_urls, max_urls, cur_url;
101
102 typedef struct {
103 char *str;
104 struct sockaddr_in sa;
105 } sip;
106 static sip *sips;
107 static int num_sips, max_sips;
108
109 /* Protocol symbols. */
110 #define PROTO_HTTP 0
111 #define PROTO_HTTPS 1
112
113 /* Connection states */
114 typedef enum {
115 CNST_FREE = 0,
116 CNST_CONNECTING,
117 CNST_HEADERS,
118 CNST_READING,
119 CNST_PAUSING,
120 } connection_states;
121
122 /* States for the Header State Machine */
123 typedef enum {
124 /* SM basic states */
125 HDST_LINE1_PROTOCOL = 0,
126 HDST_LINE1_WS,
127 HDST_LINE1_STATUS,
128 HDST_BOL,
129 HDST_TEXT,
130 HDST_LF,
131 HDST_CR,
132 HDST_CRLF,
133 HDST_CRLFCR,
134 /* SM states for Content-Length header */
135 HDST_C,
136 HDST_CO,
137 HDST_CON,
138 HDST_CONT,
139 HDST_CONTE,
140 HDST_CONTEN,
141 HDST_CONTENT,
142 HDST_CONTENT_,
143 HDST_CONTENT_L,
144 HDST_CONTENT_LE,
145 HDST_CONTENT_LEN,
146 HDST_CONTENT_LENG,
147 HDST_CONTENT_LENGT,
148 HDST_CONTENT_LENGTH,
149 HDST_CONTENT_LENGTH_COLON,
150 HDST_CONTENT_LENGTH_COLON_WS,
151 HDST_CONTENT_LENGTH_COLON_WS_NUM,
152 /* SM states for Connection: close */
153 HDST_CONN,
154 HDST_CONNE,
155 HDST_CONNEC,
156 HDST_CONNECT,
157 HDST_CONNECTI,
158 HDST_CONNECTIO,
159 HDST_CONNECTION,
160 HDST_CONNECTION_COLON,
161 HDST_CONNECTION_COLON_WS,
162 HDST_CONNECTION_COLON_WS_C,
163 HDST_CONNECTION_COLON_WS_CL,
164 HDST_CONNECTION_COLON_WS_CLO,
165 HDST_CONNECTION_COLON_WS_CLOS,
166 HDST_CONNECTION_COLON_WS_CLOSE,
167 /* SM states for Connection: keep-alive */
168 HDST_CONNECTION_COLON_WS_K,
169 HDST_CONNECTION_COLON_WS_KE,
170 HDST_CONNECTION_COLON_WS_KEE,
171 HDST_CONNECTION_COLON_WS_KEEP,
172 HDST_CONNECTION_COLON_WS_KEEP_,
173 HDST_CONNECTION_COLON_WS_KEEP_A,
174 HDST_CONNECTION_COLON_WS_KEEP_AL,
175 HDST_CONNECTION_COLON_WS_KEEP_ALI,
176 HDST_CONNECTION_COLON_WS_KEEP_ALIV,
177 HDST_CONNECTION_COLON_WS_KEEP_ALIVE,
178 /* SM states for Transfer-Encoding: chunked */
179 HDST_T,
180 HDST_TR,
181 HDST_TRA,
182 HDST_TRAN,
183 HDST_TRANS,
184 HDST_TRANSF,
185 HDST_TRANSFE,
186 HDST_TRANSFER,
187 HDST_TRANSFER_DASH,
188 HDST_TRANSFER_DASH_E,
189 HDST_TRANSFER_DASH_EN,
190 HDST_TRANSFER_DASH_ENC,
191 HDST_TRANSFER_DASH_ENCO,
192 HDST_TRANSFER_DASH_ENCOD,
193 HDST_TRANSFER_DASH_ENCODI,
194 HDST_TRANSFER_DASH_ENCODIN,
195 HDST_TRANSFER_DASH_ENCODING,
196 HDST_TRANSFER_DASH_ENCODING_COLON,
197 HDST_TRANSFER_DASH_ENCODING_COLON_WS,
198 HDST_TRANSFER_DASH_ENCODING_COLON_WS_C,
199 HDST_TRANSFER_DASH_ENCODING_COLON_WS_CH,
200 HDST_TRANSFER_DASH_ENCODING_COLON_WS_CHU,
201 HDST_TRANSFER_DASH_ENCODING_COLON_WS_CHUN,
202 HDST_TRANSFER_DASH_ENCODING_COLON_WS_CHUNK,
203 HDST_TRANSFER_DASH_ENCODING_COLON_WS_CHUNKE,
204 HDST_TRANSFER_DASH_ENCODING_COLON_WS_CHUNKED
205 } header_states;
206
207 typedef struct {
208 int url_num;
209 struct sockaddr_in sa;
210 int sa_len;
211 int conn_fd;
212 SSL *ssl;
213 connection_states conn_state;
214 header_states header_state;
215 int did_connect, did_response;
216 struct timeval started_at;
217 struct timeval connect_at;
218 struct timeval request_at;
219 struct timeval response_at;
220 Timer *idle_timer;
221 Timer *wakeup_timer;
222 long content_length;
223 long bytes;
224 long checksum;
225 int http_status;
226 int reusable;
227 int keep_alive;
228 int chunked;
229 unsigned int unique_id;
230 struct {
231 int connections;
232 int requests;
233 int responses;
234 int requests_per_connection;
235 } stats;
236 } connection;
237
238 static connection *connections;
239 static int max_connections, num_connections, max_parallel, num_ka_conns;
240
241 static int http_status_counts[1000]; /* room for all three-digit statuses */
242 static char *argv0;
243 static int do_checksum, do_throttle, do_verbose, do_jitter, do_proxy;
244 static int do_accept_gzip, do_sequential;
245 static float throttle;
246 static int idle_secs;
247 static char *proxy_hostname;
248 static unsigned short proxy_port;
249 static char *user_agent;
250 static char *cookie;
251 static char *http_version;
252 static int is_http_1_1;
253 static int ignore_bytes;
254 static int keep_alive;
255 static char *extra_headers;
256 static unsigned int unique_id_counter;
257 static int unique_id = 0;
258 static int socket_pool;
259 static int epfd;
260 static int max_connect_failures = 0;
261
262 static struct timeval start_at;
263 static int fetches_started, connects_completed, responses_completed, fetches_completed;
264 static long long total_bytes;
265 static long long total_connect_usecs, max_connect_usecs, min_connect_usecs;
266 static long long total_response_usecs, max_response_usecs, min_response_usecs;
267 int total_timeouts, total_badbytes, total_badchecksums;
268
269 static long start_interval, low_interval, high_interval, range_interval;
270
271 static SSL_CTX *ssl_ctx = (SSL_CTX *)0;
272 static char *cipher = (char *)0;
273
274 /* Forwards. */
275 static void usage(void);
276 static void read_url_file(char *url_file);
277 static void lookup_address(int url_num);
278 static void read_sip_file(char *sip_file);
279 static void start_connection(struct timeval *nowP);
280 static void start_socket(int url_num, int cnum, struct timeval *nowP);
281 static void handle_connect(int cnum, struct timeval *nowP, int double_check);
282 static void handle_read(int cnum, struct timeval *nowP);
283 static void idle_connection(ClientData client_data, struct timeval *nowP);
284 static void wakeup_connection(ClientData client_data, struct timeval *nowP);
285 static void close_connection(int cnum);
286 static void progress_report(ClientData client_data, struct timeval *nowP);
287 static void start_timer(ClientData client_data, struct timeval *nowP);
288 static void end_timer(ClientData client_data, struct timeval *nowP);
289 static void finish(struct timeval *nowP);
290 static long long delta_timeval(struct timeval *start, struct timeval *finish);
291 static void *malloc_check(size_t size);
292 static void *realloc_check(void *ptr, size_t size);
293 static char *strdup_check(char *str);
294 static void check(void *ptr);
295
296 int
main(int argc,char ** argv)297 main(int argc, char **argv)
298 {
299 int argn;
300 int start;
301 #define START_NONE 0
302 #define START_PARALLEL 1
303 #define START_RATE 2
304 int start_parallel = -1, start_rate = -1;
305 int end;
306 #define END_NONE 0
307 #define END_FETCHES 1
308 #define END_SECONDS 2
309 int end_fetches = -1, end_seconds = -1;
310 int cnum;
311 char *url_file;
312 char *sip_file;
313 #ifdef RLIMIT_NOFILE
314 struct rlimit limits;
315 #endif /* RLIMIT_NOFILE */
316 struct epoll_event *events;
317 struct timeval now;
318 int i, r, periodic_tmr;
319
320 max_connections = 64 - RESERVED_FDS; /* a guess */
321 #ifdef RLIMIT_NOFILE
322 /* Try and increase the limit on # of files to the maximum. */
323 if (getrlimit(RLIMIT_NOFILE, &limits) == 0) {
324 if (limits.rlim_cur != limits.rlim_max) {
325 if (limits.rlim_max == RLIM_INFINITY)
326 limits.rlim_cur = 8192; /* arbitrary */
327 else if (limits.rlim_max > limits.rlim_cur)
328 limits.rlim_cur = limits.rlim_max;
329 (void)setrlimit(RLIMIT_NOFILE, &limits);
330 }
331 max_connections = limits.rlim_cur - RESERVED_FDS;
332 }
333 #endif /* RLIMIT_NOFILE */
334
335 /* Parse args. */
336 argv0 = argv[0];
337 argn = 1;
338 do_checksum = do_throttle = do_verbose = do_jitter = do_proxy = 0;
339 do_accept_gzip = do_sequential = 0;
340 throttle = THROTTLE;
341 sip_file = (char *)0;
342 user_agent = VERSION;
343 cookie = NULL;
344 http_version = "1.1";
345 is_http_1_1 = 1;
346 idle_secs = IDLE_SECS;
347 start = START_NONE;
348 end = END_NONE;
349 keep_alive = 0;
350 socket_pool = 0;
351 extra_headers = NULL;
352 while (argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0') {
353 if (strncmp(argv[argn], "-checksum", strlen(argv[argn])) == 0)
354 do_checksum = 1;
355 else if (strncmp(argv[argn], "-sequential", strlen(argv[argn])) == 0)
356 do_sequential = 1;
357 else if (strncmp(argv[argn], "-throttle", strlen(argv[argn])) == 0)
358 do_throttle = 1;
359 else if (strncmp(argv[argn], "-Throttle", strlen(argv[argn])) == 0 && argn + 1 < argc) {
360 do_throttle = 1;
361 throttle = atoi(argv[++argn]) / 10.0;
362 } else if (strncmp(argv[argn], "-verbose", strlen(argv[argn])) == 0)
363 do_verbose = 1;
364 else if (strncmp(argv[argn], "-timeout", strlen(argv[argn])) == 0 && argn + 1 < argc)
365 idle_secs = atoi(argv[++argn]);
366 else if (strncmp(argv[argn], "-jitter", strlen(argv[argn])) == 0)
367 do_jitter = 1;
368 else if (strncmp(argv[argn], "-accept_gzip", strlen(argv[argn])) == 0)
369 do_accept_gzip = 1;
370 else if (strncmp(argv[argn], "-parallel", strlen(argv[argn])) == 0 && argn + 1 < argc) {
371 start = START_PARALLEL;
372 start_parallel = atoi(argv[++argn]);
373 if (start_parallel < 1) {
374 (void)fprintf(stderr, "%s: parallel must be at least 1\n", argv0);
375 exit(1);
376 }
377 if (start_parallel > max_connections) {
378 (void)fprintf(stderr, "%s: parallel may be at most %d\n", argv0, max_connections);
379 exit(1);
380 }
381 } else if (strncmp(argv[argn], "-rate", strlen(argv[argn])) == 0 && argn + 1 < argc) {
382 start = START_RATE;
383 start_rate = atoi(argv[++argn]);
384 if (start_rate < 1) {
385 (void)fprintf(stderr, "%s: rate must be at least 1\n", argv0);
386 exit(1);
387 }
388 if (start_rate > 1000) {
389 (void)fprintf(stderr, "%s: rate may be at most 1000\n", argv0);
390 exit(1);
391 }
392 } else if (strncmp(argv[argn], "-sockets", strlen(argv[argn])) == 0 && argn + 1 < argc) {
393 socket_pool = atoi(argv[++argn]) - 1;
394 if (socket_pool < 0) {
395 (void)fprintf(stderr, "%s: sockets must be at least 1\n", argv0);
396 exit(1);
397 }
398 } else if (strncmp(argv[argn], "-fetches", strlen(argv[argn])) == 0 && argn + 1 < argc) {
399 end = END_FETCHES;
400 end_fetches = atoi(argv[++argn]);
401 if (end_fetches < 1) {
402 (void)fprintf(stderr, "%s: fetches must be at least 1\n", argv0);
403 exit(1);
404 }
405 } else if (strncmp(argv[argn], "-seconds", strlen(argv[argn])) == 0 && argn + 1 < argc) {
406 end = END_SECONDS;
407 end_seconds = atoi(argv[++argn]);
408 if (end_seconds < 1) {
409 (void)fprintf(stderr, "%s: seconds must be at least 1\n", argv0);
410 exit(1);
411 }
412 } else if (strncmp(argv[argn], "-keep_alive", strlen(argv[argn])) == 0 && argn + 1 < argc) {
413 keep_alive = atoi(argv[++argn]);
414 if (keep_alive < 1) {
415 (void)fprintf(stderr, "%s: keep_alive must be at least 1\n", argv0);
416 exit(1);
417 }
418 } else if (strncmp(argv[argn], "-unique_id", strlen(argv[argn])) == 0) {
419 unique_id = 1;
420 } else if (strncmp(argv[argn], "-sip", strlen(argv[argn])) == 0 && argn + 1 < argc)
421 sip_file = argv[++argn];
422 else if (strncmp(argv[argn], "-agent", strlen(argv[argn])) == 0 && argn + 1 < argc)
423 user_agent = argv[++argn];
424 else if (strncmp(argv[argn], "-cookie", strlen(argv[argn])) == 0 && argn + 1 < argc)
425 cookie = argv[++argn];
426 else if (strncmp(argv[argn], "-ignore_bytes", strlen(argv[argn])) == 0)
427 ignore_bytes = 1;
428 else if (strncmp(argv[argn], "-max_connect_failures", strlen(argv[argn])) == 0) {
429 max_connect_failures = atoi(argv[++argn]);
430 if (max_connect_failures < 1) {
431 (void)fprintf(stderr, "%s: max_connection failures should be 1 or higher\n", argv0);
432 exit(1);
433 }
434 } else if (strncmp(argv[argn], "-header", strlen(argv[argn])) == 0 && argn + 1 < argc) {
435 if (extra_headers) {
436 strcat(extra_headers, "\r\n");
437 strcat(extra_headers, argv[++argn]);
438 } else {
439 extra_headers = malloc_check(65536);
440 strncpy(extra_headers, argv[++argn], 65536 - 1);
441 extra_headers[65536] = '\0';
442 }
443 } else if (strncmp(argv[argn], "-http_version", strlen(argv[argn])) == 0 && argn + 1 < argc) {
444 http_version = argv[++argn];
445 is_http_1_1 = (strcmp(http_version, "1.1") == 0);
446 } else if (strncmp(argv[argn], "-cipher", strlen(argv[argn])) == 0 && argn + 1 < argc) {
447 cipher = argv[++argn];
448 if (strcasecmp(cipher, "fastsec") == 0)
449 cipher = "RC4-MD5";
450 else if (strcasecmp(cipher, "highsec") == 0)
451 cipher = "DES-CBC3-SHA";
452 else if (strcasecmp(cipher, "paranoid") == 0)
453 cipher = "AES256-SHA";
454 } else if (strncmp(argv[argn], "-proxy", strlen(argv[argn])) == 0 && argn + 1 < argc) {
455 char *colon;
456 do_proxy = 1;
457 proxy_hostname = argv[++argn];
458 colon = strchr(proxy_hostname, ':');
459 if (colon == (char *)0)
460 proxy_port = 80;
461 else {
462 proxy_port = (unsigned short)atoi(colon + 1);
463 *colon = '\0';
464 }
465 } else
466 usage();
467 ++argn;
468 }
469 if (argn + 1 != argc)
470 usage();
471 if (start == START_NONE || end == END_NONE)
472 usage();
473 if (do_jitter && start != START_RATE)
474 usage();
475 url_file = argv[argn];
476
477 /* Read in and parse the URLs. */
478 read_url_file(url_file);
479
480 /* Read in the source IP file, if specified. */
481 if (sip_file != (char *)0)
482 read_sip_file(sip_file);
483
484 /* Initialize the connections table. */
485 if (start == START_PARALLEL)
486 max_connections = start_parallel;
487 connections = (connection *)malloc_check(max_connections * sizeof(connection));
488 for (cnum = 0; cnum < max_connections; ++cnum) {
489 connections[cnum].conn_state = CNST_FREE;
490 connections[cnum].reusable = 0;
491 connections[cnum].stats.requests = 0;
492 connections[cnum].stats.responses = 0;
493 connections[cnum].stats.connections = 0;
494 }
495 num_connections = max_parallel = num_ka_conns = 0;
496
497 /* Initialize the HTTP status-code histogram. */
498 for (i = 0; i < 1000; ++i)
499 http_status_counts[i] = 0;
500
501 /* Initialize the statistics. */
502 fetches_started = 0;
503 connects_completed = 0;
504 responses_completed = 0;
505 fetches_completed = 0;
506 total_bytes = 0;
507 total_connect_usecs = 0;
508 max_connect_usecs = 0;
509 min_connect_usecs = 1000000000L;
510 total_response_usecs = 0;
511 max_response_usecs = 0;
512 min_response_usecs = 1000000000L;
513 total_timeouts = 0;
514 total_badbytes = 0;
515 total_badchecksums = 0;
516
517 /* Initialize epoll() and kqueue() etc. */
518 epfd = epoll_create(max_connections);
519 if (epfd == -1) {
520 perror("epoll_create");
521 exit(1);
522 }
523 events = malloc(sizeof(struct epoll_event) * max_connections);
524
525 /* Initialize the random number generator. */
526 #ifdef HAVE_SRANDOMDEV
527 srandomdev();
528 #else
529 srandom((int)time((time_t *)0) ^ getpid());
530 #endif
531
532 /* Initialize the rest. */
533 tmr_init();
534 (void)gettimeofday(&now, (struct timezone *)0);
535 start_at = now;
536 if (do_verbose)
537 (void)tmr_create(&now, progress_report, JunkClientData, PROGRESS_SECS * 1000L, 1);
538 if (start == START_RATE) {
539 start_interval = 1000L / start_rate;
540 if (do_jitter) {
541 low_interval = start_interval * 9 / 10;
542 high_interval = start_interval * 11 / 10;
543 range_interval = high_interval - low_interval + 1;
544 }
545 (void)tmr_create(&now, start_timer, JunkClientData, start_interval, !do_jitter);
546 }
547 if (end == END_SECONDS)
548 (void)tmr_create(&now, end_timer, JunkClientData, end_seconds * 1000L, 0);
549 (void)signal(SIGPIPE, SIG_IGN);
550
551 /* Main loop. */
552 for (;;) {
553 if (end == END_FETCHES && fetches_completed >= end_fetches)
554 finish(&now);
555
556 if (start == START_PARALLEL) {
557 /* See if we need to start any new connections; but at most 10. */
558 for (i = 0; i < 10 && num_connections < start_parallel && (end != END_FETCHES || fetches_started < end_fetches); ++i) {
559 start_connection(&now);
560 (void)gettimeofday(&now, (struct timezone *)0);
561 tmr_run(&now);
562 }
563 }
564
565 r = epoll_wait(epfd, events, max_connections, tmr_mstimeout(&now));
566 #ifdef DEBUG
567 fprintf(stderr, "epoll_wait() got %d events\n", r);
568 #endif
569 if (r < 0) {
570 perror("epoll_wait");
571 exit(1);
572 }
573 (void)gettimeofday(&now, (struct timezone *)0);
574
575 /* Service them. */
576 periodic_tmr = 50;
577 while (r-- > 0) {
578 if (--periodic_tmr == 0) {
579 periodic_tmr = 50;
580 tmr_run(&now);
581 }
582 cnum = events[r].data.u32;
583 #ifdef DEBUG
584 fprintf(stderr, "processing event %d (%d), for CNUM %d\n", r + 1, events[r].events, cnum);
585 #endif
586 switch (connections[cnum].conn_state) {
587 case CNST_CONNECTING:
588 handle_connect(cnum, &now, 1);
589 break;
590 case CNST_HEADERS:
591 case CNST_READING:
592 handle_read(cnum, &now);
593 break;
594 default:
595 /* Nothing */
596 break;
597 }
598 }
599 /* And run the timers. */
600 tmr_run(&now);
601 }
602
603 /* NOT_REACHED */
604 }
605
606 static void
usage(void)607 usage(void)
608 {
609 (void)fprintf(stderr,
610 "usage: %s [-checksum] [-throttle] [-sequential] [-proxy host:port]\n"
611 " [-verbose] [-timeout secs] [-sip sip_file] [-agent user_agent]\n"
612 " [-cookie http_cookie] [-accept_gzip] [-http_version version_str]\n"
613 " [-keep_alive num_reqs_per_conn] [-unique_id]\n"
614 " [-max_connect_failures N] [-ignore_bytes] [ [-header str] ... ]\n",
615 argv0);
616 (void)fprintf(stderr, " [-cipher str]\n");
617 (void)fprintf(stderr, " -parallel N | -rate N [-jitter]\n");
618 (void)fprintf(stderr, " -fetches N | -seconds N\n");
619 (void)fprintf(stderr, " url_file\n");
620 (void)fprintf(stderr, "One start specifier, either -parallel or -rate, is required.\n");
621 (void)fprintf(stderr, "One end specifier, either -fetches or -seconds, is required.\n");
622 exit(1);
623 }
624
625 static void
read_url_file(char * url_file)626 read_url_file(char *url_file)
627 {
628 char line[5000], hostname[5000];
629 char *http = "http://";
630 int http_len = strlen(http);
631 char *https = "https://";
632 int https_len = strlen(https);
633 int proto_len, host_len;
634 char *cp;
635
636 FILE *fp = fopen(url_file, "r");
637 if (fp == NULL) {
638 perror(url_file);
639 exit(1);
640 }
641
642 max_urls = 100;
643 urls = (url *)malloc_check(max_urls * sizeof(url));
644 num_urls = 0;
645 cur_url = 0;
646
647 /* The Host: header can either be user provided (via -header), or
648 constructed by the URL host and possibly port (if not port 80) */
649
650 char hdr_buf[2048];
651 int hdr_bytes = 0;
652 hdr_bytes += snprintf(&hdr_buf[hdr_bytes], sizeof(hdr_buf) - hdr_bytes, "User-Agent: %s\r\n", user_agent);
653 if (cookie)
654 hdr_bytes += snprintf(&hdr_buf[hdr_bytes], sizeof(hdr_buf) - hdr_bytes, "Cookie: %s\r\n", cookie);
655 if (do_accept_gzip)
656 hdr_bytes += snprintf(&hdr_buf[hdr_bytes], sizeof(hdr_buf) - hdr_bytes, "Accept-Encoding: gzip\r\n");
657 /* Add Connection: keep-alive header if keep_alive requested, and version != "1.1" */
658 if ((keep_alive > 0) && !is_http_1_1)
659 hdr_bytes += snprintf(&hdr_buf[hdr_bytes], sizeof(hdr_buf) - hdr_bytes, "Connection: keep-alive\r\n");
660 if (extra_headers != NULL) {
661 hdr_bytes += snprintf(&hdr_buf[hdr_bytes], sizeof(hdr_buf) - hdr_bytes, "%s\r\n", extra_headers);
662 }
663 snprintf(&hdr_buf[hdr_bytes], sizeof(hdr_buf) - hdr_bytes, "\r\n");
664
665 while (fgets(line, sizeof(line), fp) != (char *)0) {
666 char req_buf[2048];
667 int req_bytes = 0;
668
669 /* Nuke trailing newline. */
670 if (line[strlen(line) - 1] == '\n')
671 line[strlen(line) - 1] = '\0';
672
673 /* Check for room in urls. */
674 if (num_urls >= max_urls) {
675 max_urls *= 2;
676 urls = (url *)realloc_check((void *)urls, max_urls * sizeof(url));
677 }
678
679 /* Add to table. */
680 urls[num_urls].url_str = strdup_check(line);
681
682 /* Parse it. */
683 if (strncmp(http, line, http_len) == 0) {
684 proto_len = http_len;
685 urls[num_urls].protocol = PROTO_HTTP;
686 } else if (strncmp(https, line, https_len) == 0) {
687 proto_len = https_len;
688 urls[num_urls].protocol = PROTO_HTTPS;
689 } else {
690 fprintf(stderr, "%s: unknown protocol - %s\n", argv0, line);
691 exit(1);
692 }
693 for (cp = line + proto_len; *cp != '\0' && *cp != ':' && *cp != '/'; ++cp)
694 ;
695 host_len = cp - line;
696 host_len -= proto_len;
697 strncpy(hostname, line + proto_len, host_len);
698 hostname[host_len] = '\0';
699 urls[num_urls].hostname = strdup_check(hostname);
700 if (*cp == ':') {
701 urls[num_urls].port = (unsigned short)atoi(++cp);
702 while (*cp != '\0' && *cp != '/')
703 ++cp;
704 } else if (urls[num_urls].protocol == PROTO_HTTPS)
705 urls[num_urls].port = 443;
706 else
707 urls[num_urls].port = 80;
708 if (*cp == '\0')
709 urls[num_urls].filename = strdup_check("/");
710 else
711 urls[num_urls].filename = strdup_check(cp);
712
713 lookup_address(num_urls);
714
715 urls[num_urls].got_bytes = 0;
716 urls[num_urls].got_checksum = 0;
717 urls[num_urls].unique_id_offset = 0;
718
719 /* Pre-generate the request string, major performance improvement. */
720 if (do_proxy) {
721 req_bytes = snprintf(req_buf, sizeof(req_buf), "GET %s://%.500s:%d%.500s HTTP/%s\r\n",
722 urls[num_urls].protocol == PROTO_HTTPS ? "https" : "http", urls[num_urls].hostname,
723 (int)urls[num_urls].port, urls[num_urls].filename, http_version);
724 } else
725 req_bytes = snprintf(req_buf, sizeof(req_buf), "GET %.500s HTTP/%s\r\n", urls[num_urls].filename, http_version);
726
727 if (extra_headers == NULL || !strstr(extra_headers, "Host:")) {
728 if (urls[num_urls].port != 80)
729 req_bytes += snprintf(&req_buf[req_bytes], sizeof(req_buf) - req_bytes, "Host: %s:%d\r\n", urls[num_urls].hostname,
730 urls[num_urls].port);
731 else
732 req_bytes += snprintf(&req_buf[req_bytes], sizeof(req_buf) - req_bytes, "Host: %s\r\n", urls[num_urls].hostname);
733 }
734 if (unique_id == 1) {
735 req_bytes += snprintf(&req_buf[req_bytes], sizeof(req_buf) - req_bytes, "X-ID: ");
736 urls[num_urls].unique_id_offset = req_bytes;
737 req_bytes += snprintf(&req_buf[req_bytes], sizeof(req_buf) - req_bytes, "%09u\r\n", 0);
738 }
739
740 // add the common hdr here
741 req_bytes += snprintf(&req_buf[req_bytes], sizeof(req_buf) - req_bytes, hdr_buf, 0);
742
743 urls[num_urls].buf_bytes = req_bytes;
744 urls[num_urls].buf = strdup_check(req_buf);
745
746 ++num_urls;
747 }
748 fclose(fp);
749 }
750
751 static void
lookup_address(int url_num)752 lookup_address(int url_num)
753 {
754 if (do_proxy && url_num > 0) {
755 urls[url_num].sock_family = urls[url_num - 1].sock_family;
756 urls[url_num].sock_type = urls[url_num - 1].sock_type;
757 urls[url_num].sock_protocol = urls[url_num - 1].sock_protocol;
758 urls[url_num].sa_len = urls[url_num - 1].sa_len;
759 urls[url_num].sa = urls[url_num - 1].sa;
760 return;
761 }
762 int i;
763 char *hostname;
764 unsigned short port;
765 #ifdef USE_IPV6
766 struct addrinfo hints;
767 char portstr[10];
768 int gaierr;
769 struct addrinfo *ai;
770 struct addrinfo *ai2;
771 struct addrinfo *aiv4;
772 struct addrinfo *aiv6;
773 #else /* USE_IPV6 */
774 struct hostent *he;
775 #endif /* USE_IPV6 */
776
777 urls[url_num].sa_len = sizeof(urls[url_num].sa);
778 (void)memset((void *)&urls[url_num].sa, 0, urls[url_num].sa_len);
779
780 if (do_proxy)
781 hostname = proxy_hostname;
782 else
783 hostname = urls[url_num].hostname;
784 if (do_proxy)
785 port = proxy_port;
786 else
787 port = urls[url_num].port;
788
789 /* Try to do this using existing information */
790 for (i = 0; i < url_num; i++) {
791 if ((strcmp(hostname, urls[i].hostname) == 0) && (port == urls[i].port)) {
792 urls[url_num].sock_family = urls[i].sock_family;
793 urls[url_num].sock_type = urls[i].sock_type;
794 urls[url_num].sock_protocol = urls[i].sock_protocol;
795 urls[url_num].sa = urls[i].sa;
796 urls[url_num].sa_len = urls[i].sa_len;
797 return;
798 }
799 }
800
801 #ifdef USE_IPV6
802
803 (void)memset(&hints, 0, sizeof(hints));
804 hints.ai_family = PF_UNSPEC;
805 hints.ai_socktype = SOCK_STREAM;
806 (void)snprintf(portstr, sizeof(portstr), "%d", (int)port);
807 if ((gaierr = getaddrinfo(hostname, portstr, &hints, &ai)) != 0) {
808 (void)fprintf(stderr, "%s: getaddrinfo %s - %s\n", argv0, hostname, gai_strerror(gaierr));
809 exit(1);
810 }
811
812 /* Find the first IPv4 and IPv6 entries. */
813 aiv4 = (struct addrinfo *)0;
814 aiv6 = (struct addrinfo *)0;
815 for (ai2 = ai; ai2 != (struct addrinfo *)0; ai2 = ai2->ai_next) {
816 switch (ai2->ai_family) {
817 case AF_INET:
818 if (aiv4 == (struct addrinfo *)0)
819 aiv4 = ai2;
820 break;
821 case AF_INET6:
822 if (aiv6 == (struct addrinfo *)0)
823 aiv6 = ai2;
824 break;
825 }
826 }
827
828 /* If there's an IPv4 address, use that, otherwise try IPv6. */
829 if (aiv4 != (struct addrinfo *)0) {
830 if (sizeof(urls[url_num].sa) < aiv4->ai_addrlen) {
831 (void)fprintf(stderr, "%s - sockaddr too small (%lu < %lu)\n", hostname, (unsigned long)sizeof(urls[url_num].sa),
832 (unsigned long)aiv4->ai_addrlen);
833 exit(1);
834 }
835 urls[url_num].sock_family = aiv4->ai_family;
836 urls[url_num].sock_type = aiv4->ai_socktype;
837 urls[url_num].sock_protocol = aiv4->ai_protocol;
838 urls[url_num].sa_len = aiv4->ai_addrlen;
839 (void)memmove(&urls[url_num].sa, aiv4->ai_addr, aiv4->ai_addrlen);
840 freeaddrinfo(ai);
841 return;
842 }
843 if (aiv6 != (struct addrinfo *)0) {
844 if (sizeof(urls[url_num].sa) < aiv6->ai_addrlen) {
845 (void)fprintf(stderr, "%s - sockaddr too small (%lu < %lu)\n", hostname, (unsigned long)sizeof(urls[url_num].sa),
846 (unsigned long)aiv6->ai_addrlen);
847 exit(1);
848 }
849 urls[url_num].sock_family = aiv6->ai_family;
850 urls[url_num].sock_type = aiv6->ai_socktype;
851 urls[url_num].sock_protocol = aiv6->ai_protocol;
852 urls[url_num].sa_len = aiv6->ai_addrlen;
853 (void)memmove(&urls[url_num].sa, aiv6->ai_addr, aiv6->ai_addrlen);
854 freeaddrinfo(ai);
855 return;
856 }
857
858 (void)fprintf(stderr, "%s: no valid address found for host %s\n", argv0, hostname);
859 exit(1);
860
861 #else /* USE_IPV6 */
862
863 /* No match in previous lookups */
864 he = gethostbyname(hostname);
865 if (he == (struct hostent *)0) {
866 (void)fprintf(stderr, "%s: unknown host - %s\n", argv0, hostname);
867 exit(1);
868 }
869 urls[url_num].sock_family = urls[url_num].sa.sin_family = he->h_addrtype;
870 urls[url_num].sock_type = SOCK_STREAM;
871 urls[url_num].sock_protocol = 0;
872 urls[url_num].sa_len = sizeof(urls[url_num].sa);
873 (void)memmove(&urls[url_num].sa.sin_addr, he->h_addr, he->h_length);
874 urls[url_num].sa.sin_port = htons(port);
875
876 #endif /* USE_IPV6 */
877 }
878
879 static void
read_sip_file(char * sip_file)880 read_sip_file(char *sip_file)
881 {
882 FILE *fp;
883 char line[5000];
884
885 fp = fopen(sip_file, "r");
886 if (fp == (FILE *)0) {
887 perror(sip_file);
888 exit(1);
889 }
890
891 max_sips = 100;
892 sips = (sip *)malloc_check(max_sips * sizeof(sip));
893 num_sips = 0;
894 while (fgets(line, sizeof(line), fp) != (char *)0) {
895 /* Nuke trailing newline. */
896 if (line[strlen(line) - 1] == '\n')
897 line[strlen(line) - 1] = '\0';
898
899 /* Check for room in sips. */
900 if (num_sips >= max_sips) {
901 max_sips *= 2;
902 sips = (sip *)realloc_check((void *)sips, max_sips * sizeof(sip));
903 }
904
905 /* Add to table. */
906 sips[num_sips].str = strdup_check(line);
907 (void)memset((void *)&sips[num_sips].sa, 0, sizeof(sips[num_sips].sa));
908 if (!inet_aton(sips[num_sips].str, &sips[num_sips].sa.sin_addr)) {
909 (void)fprintf(stderr, "%s: cannot convert source IP address %s\n", argv0, sips[num_sips].str);
910 exit(1);
911 }
912 ++num_sips;
913 }
914 fclose(fp);
915 }
916
917 static void
start_connection(struct timeval * nowP)918 start_connection(struct timeval *nowP)
919 {
920 int cnum, url_num;
921 static int cycle_slot = 0;
922
923 /* Find an empty connection slot. */
924 if (socket_pool > 0) {
925 int prev_cycle_slot = cycle_slot;
926
927 while (1) {
928 ++cycle_slot;
929 if (cycle_slot > socket_pool)
930 cycle_slot = 0;
931 if (prev_cycle_slot == cycle_slot) {
932 return;
933 #if 0
934 /* Unused right now, not sure why */
935 printf("Warning: cycling through all socket slots\n");
936 tmr_run(nowP);
937 #endif
938 }
939 if (connections[cycle_slot].conn_state == CNST_FREE) {
940 /* Choose a URL. */
941 if (do_sequential) {
942 url_num = cur_url++;
943 if (cur_url >= num_urls)
944 cur_url = 0;
945 } else {
946 url_num = ((unsigned long)random()) % ((unsigned int)num_urls);
947 }
948
949 /* Start the socket. */
950 start_socket(url_num, cycle_slot, nowP);
951 if (connections[cycle_slot].conn_state != CNST_FREE) {
952 ++num_connections;
953 /*
954 if ( num_connections > max_parallel )
955 max_parallel = num_connections;
956 */
957 }
958 ++fetches_started;
959 return;
960 }
961 }
962 } else {
963 for (cnum = 0; cnum < max_connections; ++cnum)
964 if (connections[cnum].conn_state == CNST_FREE) {
965 /* Choose a URL. */
966 if (do_sequential) {
967 url_num = cur_url++;
968 if (cur_url >= num_urls)
969 cur_url = 0;
970 } else {
971 url_num = ((unsigned long)random()) % ((unsigned int)num_urls);
972 }
973 /* Start the socket. */
974 start_socket(url_num, cnum, nowP);
975 if (connections[cnum].conn_state != CNST_FREE) {
976 ++num_connections;
977 /*
978 if ( num_connections > max_parallel )
979 max_parallel = num_connections;
980 */
981 }
982 ++fetches_started;
983 return;
984 }
985 }
986 /* No slots left. */
987 (void)fprintf(stderr, "%s: ran out of connection slots\n", argv0);
988 finish(nowP);
989 }
990
991 static void
start_socket(int url_num,int cnum,struct timeval * nowP)992 start_socket(int url_num, int cnum, struct timeval *nowP)
993 {
994 ClientData client_data;
995 int flags;
996 int sip_num;
997 int reusable = connections[cnum].reusable;
998
999 /* Start filling in the connection slot. */
1000 connections[cnum].url_num = url_num;
1001 connections[cnum].started_at = *nowP;
1002 client_data.i = cnum;
1003 connections[cnum].did_connect = 0;
1004 connections[cnum].did_response = 0;
1005 connections[cnum].idle_timer = tmr_create(nowP, idle_connection, client_data, idle_secs * 1000L, 0);
1006 connections[cnum].wakeup_timer = (Timer *)0;
1007 connections[cnum].content_length = -1;
1008 connections[cnum].bytes = 0;
1009 connections[cnum].checksum = 0;
1010 connections[cnum].http_status = -1;
1011 connections[cnum].reusable = 0;
1012 connections[cnum].chunked = 0;
1013 connections[cnum].unique_id = 0;
1014
1015 // set unique id
1016 if (unique_id == 1 && urls[url_num].unique_id_offset > 0) {
1017 char buffer[10];
1018 snprintf(buffer, 10, "%09u", ++unique_id_counter);
1019 // fprintf(stderr, "%s %s\n", buffer, &urls[url_num].buf[unique_id_offset]);
1020 memcpy((void *)&urls[url_num].buf[urls[url_num].unique_id_offset], (void *)buffer, 9);
1021 connections[cnum].unique_id = unique_id_counter;
1022 }
1023
1024 /* Make a socket. */
1025 if (!reusable) {
1026 struct epoll_event ev;
1027
1028 connections[cnum].keep_alive = keep_alive;
1029 connections[cnum].conn_fd = socket(urls[url_num].sock_family, urls[url_num].sock_type, urls[url_num].sock_protocol);
1030 if (connections[cnum].conn_fd < 0) {
1031 perror(urls[url_num].url_str);
1032 return;
1033 }
1034 connections[cnum].stats.connections++;
1035
1036 /* Set the file descriptor to no-delay mode. */
1037 flags = fcntl(connections[cnum].conn_fd, F_GETFL, 0);
1038 if (flags == -1) {
1039 perror(urls[url_num].url_str);
1040 (void)close(connections[cnum].conn_fd);
1041 return;
1042 }
1043 if (fcntl(connections[cnum].conn_fd, F_SETFL, flags | O_NDELAY) < 0) {
1044 perror(urls[url_num].url_str);
1045 (void)close(connections[cnum].conn_fd);
1046 return;
1047 }
1048
1049 if (num_sips > 0) {
1050 /* Try a random source IP address. */
1051 sip_num = ((unsigned long)random()) % ((unsigned int)num_sips);
1052 if (bind(connections[cnum].conn_fd, (struct sockaddr *)&sips[sip_num].sa, sizeof(sips[sip_num].sa)) < 0) {
1053 perror("binding local address");
1054 (void)close(connections[cnum].conn_fd);
1055 return;
1056 }
1057 }
1058 ev.events = EPOLLOUT;
1059 ev.data.u32 = cnum;
1060 #ifdef DEBUG
1061 fprintf(stderr, "Adding FD %d for CNUM %d\n", connections[cnum].conn_fd, cnum);
1062 #endif
1063 if (epoll_ctl(epfd, EPOLL_CTL_ADD, connections[cnum].conn_fd, &ev)) {
1064 perror("epoll add fd");
1065 (void)close(connections[cnum].conn_fd);
1066 return;
1067 }
1068 /* Connect to the host. */
1069 connections[cnum].sa_len = urls[url_num].sa_len;
1070 (void)memmove((void *)&connections[cnum].sa, (void *)&urls[url_num].sa, urls[url_num].sa_len);
1071 connections[cnum].connect_at = *nowP;
1072 if (connect(connections[cnum].conn_fd, (struct sockaddr *)&connections[cnum].sa, connections[cnum].sa_len) < 0) {
1073 if (errno == EINPROGRESS) {
1074 connections[cnum].conn_state = CNST_CONNECTING;
1075 return;
1076 } else {
1077 /* remove the FD from the epoll descriptor */
1078 if (epoll_ctl(epfd, EPOLL_CTL_DEL, connections[cnum].conn_fd, &ev) < 0)
1079 perror("epoll delete fd");
1080 perror(urls[url_num].url_str);
1081 (void)close(connections[cnum].conn_fd);
1082 return;
1083 }
1084 }
1085
1086 /* Connect succeeded instantly, so handle it now. */
1087 (void)gettimeofday(nowP, (struct timezone *)0);
1088 handle_connect(cnum, nowP, 0);
1089 } else {
1090 /* Send the request on a reused connection */
1091 int r;
1092
1093 connections[cnum].stats.requests++;
1094 connections[cnum].stats.requests_per_connection++;
1095 connections[cnum].request_at = *nowP;
1096
1097 if (urls[url_num].protocol == PROTO_HTTPS)
1098 r = SSL_write(connections[cnum].ssl, urls[url_num].buf, urls[url_num].buf_bytes);
1099 else
1100 r = write(connections[cnum].conn_fd, urls[url_num].buf, urls[url_num].buf_bytes);
1101 if (r <= 0) {
1102 perror(urls[url_num].url_str);
1103 connections[cnum].reusable = 0;
1104 close_connection(cnum);
1105 return;
1106 }
1107 connections[cnum].conn_state = CNST_HEADERS;
1108 connections[cnum].header_state = HDST_LINE1_PROTOCOL;
1109 }
1110 }
1111
1112 static int
cert_verify_callback(int ok,X509_STORE_CTX * ctx)1113 cert_verify_callback(int ok __attribute__((unused)), X509_STORE_CTX *ctx __attribute__((unused)))
1114 {
1115 return 1;
1116 }
1117
1118 static void
handle_connect(int cnum,struct timeval * nowP,int double_check)1119 handle_connect(int cnum, struct timeval *nowP, int double_check)
1120 {
1121 static int connect_failures = 0;
1122 int url_num;
1123 int r;
1124 struct epoll_event ev;
1125
1126 #ifdef DEBUG
1127 fprintf(stderr, "Entering handle_connect() for CNUM %d\n", cnum);
1128 #endif
1129
1130 url_num = connections[cnum].url_num;
1131 connections[cnum].stats.requests_per_connection = 0;
1132 if (double_check) {
1133 /* Check to make sure the non-blocking connect succeeded. */
1134 int err, errlen;
1135
1136 if (connect(connections[cnum].conn_fd, (struct sockaddr *)&connections[cnum].sa, connections[cnum].sa_len) < 0) {
1137 if (max_connect_failures && (++connect_failures > max_connect_failures))
1138 exit(0);
1139 switch (errno) {
1140 case EISCONN:
1141 /* Ok! */
1142 break;
1143 case EINVAL:
1144 errlen = sizeof(err);
1145 if (getsockopt(connections[cnum].conn_fd, SOL_SOCKET, SO_ERROR, (void *)&err, (socklen_t *)&errlen) < 0)
1146 (void)fprintf(stderr, "%s: unknown connect error\n", urls[url_num].url_str);
1147 else
1148 (void)fprintf(stderr, "%s: %s\n", urls[url_num].url_str, strerror(err));
1149 close_connection(cnum);
1150 return;
1151 default:
1152 perror(urls[url_num].url_str);
1153 close_connection(cnum);
1154 return;
1155 }
1156 }
1157 }
1158
1159 if (urls[url_num].protocol == PROTO_HTTPS) {
1160 int flags;
1161
1162 /* Make SSL connection. */
1163 if (ssl_ctx == (SSL_CTX *)0) {
1164 SSL_load_error_strings();
1165 SSL_library_init();
1166 ssl_ctx = SSL_CTX_new(SSLv23_client_method());
1167 /* For some reason this does not seem to work, but indications are that it should...
1168 Maybe something with how we create connections? TODO: Fix it... */
1169 SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_NONE, cert_verify_callback);
1170 if (cipher != (char *)0) {
1171 if (!SSL_CTX_set_cipher_list(ssl_ctx, cipher)) {
1172 (void)fprintf(stderr, "%s: cannot set cipher list\n", argv0);
1173 ERR_print_errors_fp(stderr);
1174 close_connection(cnum);
1175 return;
1176 }
1177 }
1178 }
1179
1180 if (!RAND_status()) {
1181 unsigned char bytes[1024];
1182 for (size_t i = 0; i < sizeof(bytes); ++i)
1183 bytes[i] = random() % 0xff;
1184 RAND_seed(bytes, sizeof(bytes));
1185 }
1186 flags = fcntl(connections[cnum].conn_fd, F_GETFL, 0);
1187 if (flags != -1)
1188 (void)fcntl(connections[cnum].conn_fd, F_SETFL, flags & ~(int)O_NDELAY);
1189 connections[cnum].ssl = SSL_new(ssl_ctx);
1190 SSL_set_fd(connections[cnum].ssl, connections[cnum].conn_fd);
1191 r = SSL_connect(connections[cnum].ssl);
1192 if (r <= 0) {
1193 (void)fprintf(stderr, "%s: SSL connection failed - %d\n", argv0, r);
1194 ERR_print_errors_fp(stderr);
1195 close_connection(cnum);
1196 return;
1197 }
1198 }
1199
1200 ev.events = EPOLLIN;
1201 ev.data.u32 = cnum;
1202
1203 #ifdef DEBUG
1204 fprintf(stderr, "Mod FD %d to read for CNUM %d\n", connections[cnum].conn_fd, cnum);
1205 #endif
1206 if (epoll_ctl(epfd, EPOLL_CTL_MOD, connections[cnum].conn_fd, &ev)) {
1207 perror("epoll mod fd");
1208 (void)close(connections[cnum].conn_fd);
1209 return;
1210 }
1211 /* Send the request. */
1212 connections[cnum].did_connect = 1;
1213 connections[cnum].request_at = *nowP;
1214 connections[cnum].stats.requests++;
1215 if (urls[url_num].protocol == PROTO_HTTPS)
1216 r = SSL_write(connections[cnum].ssl, urls[url_num].buf, urls[url_num].buf_bytes);
1217 else
1218 r = write(connections[cnum].conn_fd, urls[url_num].buf, urls[url_num].buf_bytes);
1219 if (r <= 0) {
1220 perror(urls[url_num].url_str);
1221 connections[cnum].reusable = 0;
1222 close_connection(cnum);
1223 return;
1224 }
1225 connections[cnum].conn_state = CNST_HEADERS;
1226 connections[cnum].header_state = HDST_LINE1_PROTOCOL;
1227 }
1228
1229 static void
handle_read(int cnum,struct timeval * nowP)1230 handle_read(int cnum, struct timeval *nowP)
1231 {
1232 char buf[30000]; /* must be larger than throttle / 2 */
1233 int bytes_to_read, bytes_read, bytes_handled;
1234 float elapsed;
1235 ClientData client_data;
1236 long checksum;
1237
1238 tmr_reset(nowP, connections[cnum].idle_timer);
1239
1240 if (do_throttle)
1241 bytes_to_read = throttle / 2.0;
1242 else
1243 bytes_to_read = sizeof(buf);
1244 if (!connections[cnum].did_response) {
1245 connections[cnum].did_response = 1;
1246 connections[cnum].response_at = *nowP;
1247 if (connections[cnum].did_connect) {
1248 if (connections[cnum].keep_alive == keep_alive) {
1249 num_ka_conns++;
1250 if (num_ka_conns > max_parallel) {
1251 max_parallel = num_ka_conns;
1252 }
1253 }
1254 }
1255 if (connections[cnum].keep_alive == 0) {
1256 num_ka_conns--;
1257 }
1258 }
1259 if (urls[connections[cnum].url_num].protocol == PROTO_HTTPS)
1260 bytes_read = SSL_read(connections[cnum].ssl, buf, bytes_to_read - 1);
1261 else
1262 bytes_read = read(connections[cnum].conn_fd, buf, bytes_to_read - 1);
1263 if (bytes_read <= 0) {
1264 connections[cnum].reusable = 0;
1265 close_connection(cnum);
1266 return;
1267 }
1268
1269 buf[bytes_read] = 0;
1270 for (bytes_handled = 0; bytes_handled < bytes_read;) {
1271 switch (connections[cnum].conn_state) {
1272 case CNST_HEADERS:
1273 /* State machine to read until we reach the file part. Looks for
1274 ** Content-Length header too.
1275 */
1276 for (; bytes_handled < bytes_read && connections[cnum].conn_state == CNST_HEADERS; ++bytes_handled) {
1277 switch (connections[cnum].header_state) {
1278 case HDST_LINE1_PROTOCOL:
1279 switch (buf[bytes_handled]) {
1280 case ' ':
1281 case '\t':
1282 connections[cnum].header_state = HDST_LINE1_WS;
1283 break;
1284 case '\n':
1285 connections[cnum].header_state = HDST_LF;
1286 break;
1287 case '\r':
1288 connections[cnum].header_state = HDST_CR;
1289 break;
1290 }
1291 break;
1292
1293 case HDST_LINE1_WS:
1294 switch (buf[bytes_handled]) {
1295 case ' ':
1296 case '\t':
1297 break;
1298 case '0':
1299 case '1':
1300 case '2':
1301 case '3':
1302 case '4':
1303 case '5':
1304 case '6':
1305 case '7':
1306 case '8':
1307 case '9':
1308 connections[cnum].http_status = buf[bytes_handled] - '0';
1309 connections[cnum].header_state = HDST_LINE1_STATUS;
1310 break;
1311 case '\n':
1312 connections[cnum].header_state = HDST_LF;
1313 break;
1314 case '\r':
1315 connections[cnum].header_state = HDST_CR;
1316 break;
1317 default:
1318 connections[cnum].header_state = HDST_TEXT;
1319 break;
1320 }
1321 break;
1322
1323 case HDST_LINE1_STATUS:
1324 switch (buf[bytes_handled]) {
1325 case '0':
1326 case '1':
1327 case '2':
1328 case '3':
1329 case '4':
1330 case '5':
1331 case '6':
1332 case '7':
1333 case '8':
1334 case '9':
1335 connections[cnum].http_status = connections[cnum].http_status * 10 + buf[bytes_handled] - '0';
1336 break;
1337 case '\n':
1338 connections[cnum].header_state = HDST_LF;
1339 break;
1340 case '\r':
1341 connections[cnum].header_state = HDST_CR;
1342 break;
1343 default:
1344 connections[cnum].header_state = HDST_TEXT;
1345 break;
1346 }
1347 break;
1348
1349 case HDST_BOL:
1350 switch (buf[bytes_handled]) {
1351 case '\n':
1352 connections[cnum].header_state = HDST_LF;
1353 break;
1354 case '\r':
1355 connections[cnum].header_state = HDST_CR;
1356 break;
1357 case 'C':
1358 case 'c':
1359 connections[cnum].header_state = HDST_C;
1360 break;
1361 case 'T':
1362 case 't':
1363 connections[cnum].header_state = HDST_T;
1364 break;
1365 default:
1366 connections[cnum].header_state = HDST_TEXT;
1367 break;
1368 }
1369 break;
1370
1371 case HDST_TEXT:
1372 switch (buf[bytes_handled]) {
1373 case '\n':
1374 connections[cnum].header_state = HDST_LF;
1375 break;
1376 case '\r':
1377 connections[cnum].header_state = HDST_CR;
1378 break;
1379 default:
1380 break;
1381 }
1382 break;
1383
1384 case HDST_LF:
1385 switch (buf[bytes_handled]) {
1386 case '\n':
1387 connections[cnum].conn_state = CNST_READING;
1388 break;
1389 case '\r':
1390 connections[cnum].header_state = HDST_CR;
1391 break;
1392 case 'C':
1393 case 'c':
1394 connections[cnum].header_state = HDST_C;
1395 break;
1396 case 'T':
1397 case 't':
1398 connections[cnum].header_state = HDST_T;
1399 break;
1400 default:
1401 connections[cnum].header_state = HDST_TEXT;
1402 break;
1403 }
1404 break;
1405
1406 case HDST_CR:
1407 switch (buf[bytes_handled]) {
1408 case '\n':
1409 connections[cnum].header_state = HDST_CRLF;
1410 break;
1411 case '\r':
1412 connections[cnum].conn_state = CNST_READING;
1413 break;
1414 case 'C':
1415 case 'c':
1416 connections[cnum].header_state = HDST_C;
1417 break;
1418 case 'T':
1419 case 't':
1420 connections[cnum].header_state = HDST_T;
1421 break;
1422 default:
1423 connections[cnum].header_state = HDST_TEXT;
1424 break;
1425 }
1426 break;
1427
1428 case HDST_CRLF:
1429 switch (buf[bytes_handled]) {
1430 case '\n':
1431 connections[cnum].conn_state = CNST_READING;
1432 break;
1433 case '\r':
1434 connections[cnum].header_state = HDST_CRLFCR;
1435 break;
1436 case 'C':
1437 case 'c':
1438 connections[cnum].header_state = HDST_C;
1439 break;
1440 case 'T':
1441 case 't':
1442 connections[cnum].header_state = HDST_T;
1443 break;
1444 default:
1445 connections[cnum].header_state = HDST_TEXT;
1446 break;
1447 }
1448 break;
1449
1450 case HDST_CRLFCR:
1451 switch (buf[bytes_handled]) {
1452 case '\n':
1453 case '\r':
1454 connections[cnum].conn_state = CNST_READING;
1455 break;
1456 case 'C':
1457 case 'c':
1458 connections[cnum].header_state = HDST_C;
1459 break;
1460 case 'T':
1461 case 't':
1462 connections[cnum].header_state = HDST_T;
1463 break;
1464 default:
1465 connections[cnum].header_state = HDST_TEXT;
1466 break;
1467 }
1468 break;
1469
1470 case HDST_C:
1471 switch (buf[bytes_handled]) {
1472 case 'O':
1473 case 'o':
1474 connections[cnum].header_state = HDST_CO;
1475 break;
1476 case '\n':
1477 connections[cnum].header_state = HDST_LF;
1478 break;
1479 case '\r':
1480 connections[cnum].header_state = HDST_CR;
1481 break;
1482 default:
1483 connections[cnum].header_state = HDST_TEXT;
1484 break;
1485 }
1486 break;
1487
1488 case HDST_CO:
1489 switch (buf[bytes_handled]) {
1490 case 'N':
1491 case 'n':
1492 connections[cnum].header_state = HDST_CON;
1493 break;
1494 case '\n':
1495 connections[cnum].header_state = HDST_LF;
1496 break;
1497 case '\r':
1498 connections[cnum].header_state = HDST_CR;
1499 break;
1500 default:
1501 connections[cnum].header_state = HDST_TEXT;
1502 break;
1503 }
1504 break;
1505
1506 case HDST_CON:
1507 switch (buf[bytes_handled]) {
1508 case 'T':
1509 case 't':
1510 connections[cnum].header_state = HDST_CONT;
1511 break;
1512 case 'N':
1513 case 'n':
1514 connections[cnum].header_state = HDST_CONN;
1515 break;
1516 case '\n':
1517 connections[cnum].header_state = HDST_LF;
1518 break;
1519 case '\r':
1520 connections[cnum].header_state = HDST_CR;
1521 break;
1522 default:
1523 connections[cnum].header_state = HDST_TEXT;
1524 break;
1525 }
1526 break;
1527
1528 case HDST_CONT:
1529 switch (buf[bytes_handled]) {
1530 case 'E':
1531 case 'e':
1532 connections[cnum].header_state = HDST_CONTE;
1533 break;
1534 case '\n':
1535 connections[cnum].header_state = HDST_LF;
1536 break;
1537 case '\r':
1538 connections[cnum].header_state = HDST_CR;
1539 break;
1540 default:
1541 connections[cnum].header_state = HDST_TEXT;
1542 break;
1543 }
1544 break;
1545
1546 case HDST_CONTE:
1547 switch (buf[bytes_handled]) {
1548 case 'N':
1549 case 'n':
1550 connections[cnum].header_state = HDST_CONTEN;
1551 break;
1552 case '\n':
1553 connections[cnum].header_state = HDST_LF;
1554 break;
1555 case '\r':
1556 connections[cnum].header_state = HDST_CR;
1557 break;
1558 default:
1559 connections[cnum].header_state = HDST_TEXT;
1560 break;
1561 }
1562 break;
1563
1564 case HDST_CONTEN:
1565 switch (buf[bytes_handled]) {
1566 case 'T':
1567 case 't':
1568 connections[cnum].header_state = HDST_CONTENT;
1569 break;
1570 case '\n':
1571 connections[cnum].header_state = HDST_LF;
1572 break;
1573 case '\r':
1574 connections[cnum].header_state = HDST_CR;
1575 break;
1576 default:
1577 connections[cnum].header_state = HDST_TEXT;
1578 break;
1579 }
1580 break;
1581
1582 case HDST_CONTENT:
1583 switch (buf[bytes_handled]) {
1584 case '-':
1585 connections[cnum].header_state = HDST_CONTENT_;
1586 break;
1587 case '\n':
1588 connections[cnum].header_state = HDST_LF;
1589 break;
1590 case '\r':
1591 connections[cnum].header_state = HDST_CR;
1592 break;
1593 default:
1594 connections[cnum].header_state = HDST_TEXT;
1595 break;
1596 }
1597 break;
1598
1599 case HDST_CONTENT_:
1600 switch (buf[bytes_handled]) {
1601 case 'L':
1602 case 'l':
1603 connections[cnum].header_state = HDST_CONTENT_L;
1604 break;
1605 case '\n':
1606 connections[cnum].header_state = HDST_LF;
1607 break;
1608 case '\r':
1609 connections[cnum].header_state = HDST_CR;
1610 break;
1611 default:
1612 connections[cnum].header_state = HDST_TEXT;
1613 break;
1614 }
1615 break;
1616
1617 case HDST_CONTENT_L:
1618 switch (buf[bytes_handled]) {
1619 case 'E':
1620 case 'e':
1621 connections[cnum].header_state = HDST_CONTENT_LE;
1622 break;
1623 case '\n':
1624 connections[cnum].header_state = HDST_LF;
1625 break;
1626 case '\r':
1627 connections[cnum].header_state = HDST_CR;
1628 break;
1629 default:
1630 connections[cnum].header_state = HDST_TEXT;
1631 break;
1632 }
1633 break;
1634
1635 case HDST_CONTENT_LE:
1636 switch (buf[bytes_handled]) {
1637 case 'N':
1638 case 'n':
1639 connections[cnum].header_state = HDST_CONTENT_LEN;
1640 break;
1641 case '\n':
1642 connections[cnum].header_state = HDST_LF;
1643 break;
1644 case '\r':
1645 connections[cnum].header_state = HDST_CR;
1646 break;
1647 default:
1648 connections[cnum].header_state = HDST_TEXT;
1649 break;
1650 }
1651 break;
1652
1653 case HDST_CONTENT_LEN:
1654 switch (buf[bytes_handled]) {
1655 case 'G':
1656 case 'g':
1657 connections[cnum].header_state = HDST_CONTENT_LENG;
1658 break;
1659 case '\n':
1660 connections[cnum].header_state = HDST_LF;
1661 break;
1662 case '\r':
1663 connections[cnum].header_state = HDST_CR;
1664 break;
1665 default:
1666 connections[cnum].header_state = HDST_TEXT;
1667 break;
1668 }
1669 break;
1670
1671 case HDST_CONTENT_LENG:
1672 switch (buf[bytes_handled]) {
1673 case 'T':
1674 case 't':
1675 connections[cnum].header_state = HDST_CONTENT_LENGT;
1676 break;
1677 case '\n':
1678 connections[cnum].header_state = HDST_LF;
1679 break;
1680 case '\r':
1681 connections[cnum].header_state = HDST_CR;
1682 break;
1683 default:
1684 connections[cnum].header_state = HDST_TEXT;
1685 break;
1686 }
1687 break;
1688
1689 case HDST_CONTENT_LENGT:
1690 switch (buf[bytes_handled]) {
1691 case 'H':
1692 case 'h':
1693 connections[cnum].header_state = HDST_CONTENT_LENGTH;
1694 break;
1695 case '\n':
1696 connections[cnum].header_state = HDST_LF;
1697 break;
1698 case '\r':
1699 connections[cnum].header_state = HDST_CR;
1700 break;
1701 default:
1702 connections[cnum].header_state = HDST_TEXT;
1703 break;
1704 }
1705 break;
1706
1707 case HDST_CONTENT_LENGTH:
1708 switch (buf[bytes_handled]) {
1709 case ':':
1710 connections[cnum].header_state = HDST_CONTENT_LENGTH_COLON;
1711 break;
1712 case '\n':
1713 connections[cnum].header_state = HDST_LF;
1714 break;
1715 case '\r':
1716 connections[cnum].header_state = HDST_CR;
1717 break;
1718 default:
1719 connections[cnum].header_state = HDST_TEXT;
1720 break;
1721 }
1722 break;
1723
1724 case HDST_CONTENT_LENGTH_COLON:
1725 switch (buf[bytes_handled]) {
1726 case ' ':
1727 case '\t':
1728 connections[cnum].header_state = HDST_CONTENT_LENGTH_COLON_WS;
1729 break;
1730 case '\n':
1731 connections[cnum].header_state = HDST_LF;
1732 break;
1733 case '\r':
1734 connections[cnum].header_state = HDST_CR;
1735 break;
1736 default:
1737 connections[cnum].header_state = HDST_TEXT;
1738 break;
1739 }
1740 break;
1741
1742 case HDST_CONTENT_LENGTH_COLON_WS:
1743 switch (buf[bytes_handled]) {
1744 case ' ':
1745 case '\t':
1746 break;
1747 case '0':
1748 case '1':
1749 case '2':
1750 case '3':
1751 case '4':
1752 case '5':
1753 case '6':
1754 case '7':
1755 case '8':
1756 case '9':
1757 connections[cnum].content_length = buf[bytes_handled] - '0';
1758 connections[cnum].header_state = HDST_CONTENT_LENGTH_COLON_WS_NUM;
1759 break;
1760 case '\n':
1761 connections[cnum].header_state = HDST_LF;
1762 break;
1763 case '\r':
1764 connections[cnum].header_state = HDST_CR;
1765 break;
1766 default:
1767 connections[cnum].header_state = HDST_TEXT;
1768 break;
1769 }
1770 break;
1771
1772 case HDST_CONTENT_LENGTH_COLON_WS_NUM:
1773 switch (buf[bytes_handled]) {
1774 case '0':
1775 case '1':
1776 case '2':
1777 case '3':
1778 case '4':
1779 case '5':
1780 case '6':
1781 case '7':
1782 case '8':
1783 case '9':
1784 connections[cnum].content_length = connections[cnum].content_length * 10 + buf[bytes_handled] - '0';
1785 break;
1786 case '\n':
1787 connections[cnum].header_state = HDST_LF;
1788 break;
1789 case '\r':
1790 connections[cnum].header_state = HDST_CR;
1791 break;
1792 default:
1793 connections[cnum].header_state = HDST_TEXT;
1794 break;
1795 }
1796 break;
1797
1798 /* Stuff for Connection: close */
1799 case HDST_CONN:
1800 switch (buf[bytes_handled]) {
1801 case 'E':
1802 case 'e':
1803 connections[cnum].header_state = HDST_CONNE;
1804 break;
1805 case '\n':
1806 connections[cnum].header_state = HDST_LF;
1807 break;
1808 case '\r':
1809 connections[cnum].header_state = HDST_CR;
1810 break;
1811 default:
1812 connections[cnum].header_state = HDST_TEXT;
1813 break;
1814 }
1815 break;
1816
1817 case HDST_CONNE:
1818 switch (buf[bytes_handled]) {
1819 case 'C':
1820 case 'c':
1821 connections[cnum].header_state = HDST_CONNEC;
1822 break;
1823 case '\n':
1824 connections[cnum].header_state = HDST_LF;
1825 break;
1826 case '\r':
1827 connections[cnum].header_state = HDST_CR;
1828 break;
1829 default:
1830 connections[cnum].header_state = HDST_TEXT;
1831 break;
1832 }
1833 break;
1834
1835 case HDST_CONNEC:
1836 switch (buf[bytes_handled]) {
1837 case 'T':
1838 case 't':
1839 connections[cnum].header_state = HDST_CONNECT;
1840 break;
1841 case '\n':
1842 connections[cnum].header_state = HDST_LF;
1843 break;
1844 case '\r':
1845 connections[cnum].header_state = HDST_CR;
1846 break;
1847 default:
1848 connections[cnum].header_state = HDST_TEXT;
1849 break;
1850 }
1851 break;
1852
1853 case HDST_CONNECT:
1854 switch (buf[bytes_handled]) {
1855 case 'I':
1856 case 'i':
1857 connections[cnum].header_state = HDST_CONNECTI;
1858 break;
1859 case '\n':
1860 connections[cnum].header_state = HDST_LF;
1861 break;
1862 case '\r':
1863 connections[cnum].header_state = HDST_CR;
1864 break;
1865 default:
1866 connections[cnum].header_state = HDST_TEXT;
1867 break;
1868 }
1869 break;
1870
1871 case HDST_CONNECTI:
1872 switch (buf[bytes_handled]) {
1873 case 'O':
1874 case 'o':
1875 connections[cnum].header_state = HDST_CONNECTIO;
1876 break;
1877 case '\n':
1878 connections[cnum].header_state = HDST_LF;
1879 break;
1880 case '\r':
1881 connections[cnum].header_state = HDST_CR;
1882 break;
1883 default:
1884 connections[cnum].header_state = HDST_TEXT;
1885 break;
1886 }
1887 break;
1888
1889 case HDST_CONNECTIO:
1890 switch (buf[bytes_handled]) {
1891 case 'N':
1892 case 'n':
1893 connections[cnum].header_state = HDST_CONNECTION;
1894 break;
1895 case '\n':
1896 connections[cnum].header_state = HDST_LF;
1897 break;
1898 case '\r':
1899 connections[cnum].header_state = HDST_CR;
1900 break;
1901 default:
1902 connections[cnum].header_state = HDST_TEXT;
1903 break;
1904 }
1905 break;
1906
1907 case HDST_CONNECTION:
1908 switch (buf[bytes_handled]) {
1909 case ':':
1910 connections[cnum].header_state = HDST_CONNECTION_COLON;
1911 break;
1912 case '\n':
1913 connections[cnum].header_state = HDST_LF;
1914 break;
1915 case '\r':
1916 connections[cnum].header_state = HDST_CR;
1917 break;
1918 default:
1919 connections[cnum].header_state = HDST_TEXT;
1920 break;
1921 }
1922 break;
1923
1924 case HDST_CONNECTION_COLON:
1925 switch (buf[bytes_handled]) {
1926 case ' ':
1927 case '\t':
1928 connections[cnum].header_state = HDST_CONNECTION_COLON_WS;
1929 break;
1930 case '\n':
1931 connections[cnum].header_state = HDST_LF;
1932 break;
1933 case '\r':
1934 connections[cnum].header_state = HDST_CR;
1935 break;
1936 default:
1937 connections[cnum].header_state = HDST_TEXT;
1938 break;
1939 }
1940 break;
1941
1942 case HDST_CONNECTION_COLON_WS:
1943 switch (buf[bytes_handled]) {
1944 case 'C':
1945 case 'c':
1946 connections[cnum].header_state = HDST_CONNECTION_COLON_WS_C;
1947 break;
1948 case 'K':
1949 case 'k':
1950 connections[cnum].header_state = HDST_CONNECTION_COLON_WS_K;
1951 break;
1952 case '\n':
1953 connections[cnum].header_state = HDST_LF;
1954 break;
1955 case '\r':
1956 connections[cnum].header_state = HDST_CR;
1957 break;
1958 default:
1959 connections[cnum].header_state = HDST_TEXT;
1960 break;
1961 }
1962 break;
1963
1964 case HDST_CONNECTION_COLON_WS_C:
1965 switch (buf[bytes_handled]) {
1966 case 'L':
1967 case 'l':
1968 connections[cnum].header_state = HDST_CONNECTION_COLON_WS_CL;
1969 break;
1970 case '\n':
1971 connections[cnum].header_state = HDST_LF;
1972 break;
1973 case '\r':
1974 connections[cnum].header_state = HDST_CR;
1975 break;
1976 default:
1977 connections[cnum].header_state = HDST_TEXT;
1978 break;
1979 }
1980 break;
1981
1982 case HDST_CONNECTION_COLON_WS_CL:
1983 switch (buf[bytes_handled]) {
1984 case 'O':
1985 case 'o':
1986 connections[cnum].header_state = HDST_CONNECTION_COLON_WS_CLO;
1987 break;
1988 case '\n':
1989 connections[cnum].header_state = HDST_LF;
1990 break;
1991 case '\r':
1992 connections[cnum].header_state = HDST_CR;
1993 break;
1994 default:
1995 connections[cnum].header_state = HDST_TEXT;
1996 break;
1997 }
1998 break;
1999
2000 case HDST_CONNECTION_COLON_WS_CLO:
2001 switch (buf[bytes_handled]) {
2002 case 'S':
2003 case 's':
2004 connections[cnum].header_state = HDST_CONNECTION_COLON_WS_CLOS;
2005 break;
2006 case '\n':
2007 connections[cnum].header_state = HDST_LF;
2008 break;
2009 case '\r':
2010 connections[cnum].header_state = HDST_CR;
2011 break;
2012 default:
2013 connections[cnum].header_state = HDST_TEXT;
2014 break;
2015 }
2016 break;
2017
2018 case HDST_CONNECTION_COLON_WS_CLOS:
2019 switch (buf[bytes_handled]) {
2020 case 'E':
2021 case 'e':
2022 connections[cnum].header_state = HDST_CONNECTION_COLON_WS_CLOSE;
2023 break;
2024 case '\n':
2025 connections[cnum].header_state = HDST_LF;
2026 break;
2027 case '\r':
2028 connections[cnum].header_state = HDST_CR;
2029 break;
2030 default:
2031 connections[cnum].header_state = HDST_TEXT;
2032 break;
2033 }
2034 break;
2035
2036 case HDST_CONNECTION_COLON_WS_CLOSE:
2037 /* Got the complete HTTP/1.1 "Connection: close" header, make sure this
2038 is the last request on this connection. */
2039 /* Close ToDo: Fix this */
2040 switch (buf[bytes_handled]) {
2041 case '\n':
2042 connections[cnum].header_state = HDST_LF;
2043 break;
2044 case '\r':
2045 connections[cnum].header_state = HDST_CR;
2046 break;
2047 default:
2048 connections[cnum].header_state = HDST_TEXT;
2049 break;
2050 }
2051 break;
2052
2053 case HDST_CONNECTION_COLON_WS_K:
2054 switch (buf[bytes_handled]) {
2055 case 'E':
2056 case 'e':
2057 connections[cnum].header_state = HDST_CONNECTION_COLON_WS_KE;
2058 break;
2059 case '\n':
2060 connections[cnum].header_state = HDST_LF;
2061 break;
2062 case '\r':
2063 connections[cnum].header_state = HDST_CR;
2064 break;
2065 default:
2066 connections[cnum].header_state = HDST_TEXT;
2067 break;
2068 }
2069 break;
2070
2071 case HDST_CONNECTION_COLON_WS_KE:
2072 switch (buf[bytes_handled]) {
2073 case 'E':
2074 case 'e':
2075 connections[cnum].header_state = HDST_CONNECTION_COLON_WS_KEE;
2076 break;
2077 case '\n':
2078 connections[cnum].header_state = HDST_LF;
2079 break;
2080 case '\r':
2081 connections[cnum].header_state = HDST_CR;
2082 break;
2083 default:
2084 connections[cnum].header_state = HDST_TEXT;
2085 break;
2086 }
2087 break;
2088
2089 case HDST_CONNECTION_COLON_WS_KEE:
2090 switch (buf[bytes_handled]) {
2091 case 'P':
2092 case 'p':
2093 connections[cnum].header_state = HDST_CONNECTION_COLON_WS_KEEP;
2094 break;
2095 case '\n':
2096 connections[cnum].header_state = HDST_LF;
2097 break;
2098 case '\r':
2099 connections[cnum].header_state = HDST_CR;
2100 break;
2101 default:
2102 connections[cnum].header_state = HDST_TEXT;
2103 break;
2104 }
2105 break;
2106
2107 case HDST_CONNECTION_COLON_WS_KEEP:
2108 switch (buf[bytes_handled]) {
2109 case '-':
2110 connections[cnum].header_state = HDST_CONNECTION_COLON_WS_KEEP_;
2111 break;
2112 case '\n':
2113 connections[cnum].header_state = HDST_LF;
2114 break;
2115 case '\r':
2116 connections[cnum].header_state = HDST_CR;
2117 break;
2118 default:
2119 connections[cnum].header_state = HDST_TEXT;
2120 break;
2121 }
2122 break;
2123
2124 case HDST_CONNECTION_COLON_WS_KEEP_:
2125 switch (buf[bytes_handled]) {
2126 case 'A':
2127 case 'a':
2128 connections[cnum].header_state = HDST_CONNECTION_COLON_WS_KEEP_A;
2129 break;
2130 case '\n':
2131 connections[cnum].header_state = HDST_LF;
2132 break;
2133 case '\r':
2134 connections[cnum].header_state = HDST_CR;
2135 break;
2136 default:
2137 connections[cnum].header_state = HDST_TEXT;
2138 break;
2139 }
2140 break;
2141
2142 case HDST_CONNECTION_COLON_WS_KEEP_A:
2143 switch (buf[bytes_handled]) {
2144 case 'L':
2145 case 'l':
2146 connections[cnum].header_state = HDST_CONNECTION_COLON_WS_KEEP_AL;
2147 break;
2148 case '\n':
2149 connections[cnum].header_state = HDST_LF;
2150 break;
2151 case '\r':
2152 connections[cnum].header_state = HDST_CR;
2153 break;
2154 default:
2155 connections[cnum].header_state = HDST_TEXT;
2156 break;
2157 }
2158 break;
2159
2160 case HDST_CONNECTION_COLON_WS_KEEP_AL:
2161 switch (buf[bytes_handled]) {
2162 case 'I':
2163 case 'i':
2164 connections[cnum].header_state = HDST_CONNECTION_COLON_WS_KEEP_ALI;
2165 break;
2166 case '\n':
2167 connections[cnum].header_state = HDST_LF;
2168 break;
2169 case '\r':
2170 connections[cnum].header_state = HDST_CR;
2171 break;
2172 default:
2173 connections[cnum].header_state = HDST_TEXT;
2174 break;
2175 }
2176 break;
2177
2178 case HDST_CONNECTION_COLON_WS_KEEP_ALI:
2179 switch (buf[bytes_handled]) {
2180 case 'V':
2181 case 'v':
2182 connections[cnum].header_state = HDST_CONNECTION_COLON_WS_KEEP_ALIV;
2183 break;
2184 case '\n':
2185 connections[cnum].header_state = HDST_LF;
2186 break;
2187 case '\r':
2188 connections[cnum].header_state = HDST_CR;
2189 break;
2190 default:
2191 connections[cnum].header_state = HDST_TEXT;
2192 break;
2193 }
2194 break;
2195
2196 case HDST_CONNECTION_COLON_WS_KEEP_ALIV:
2197 switch (buf[bytes_handled]) {
2198 case 'E':
2199 case 'e':
2200 connections[cnum].header_state = HDST_CONNECTION_COLON_WS_KEEP_ALIVE;
2201 break;
2202 case '\n':
2203 connections[cnum].header_state = HDST_LF;
2204 break;
2205 case '\r':
2206 connections[cnum].header_state = HDST_CR;
2207 break;
2208 default:
2209 connections[cnum].header_state = HDST_TEXT;
2210 break;
2211 }
2212 break;
2213
2214 case HDST_CONNECTION_COLON_WS_KEEP_ALIVE:
2215 /* Handle Connection: keep-alive response header, make the
2216 connection reusable if we have some keep_alive quota left. */
2217 /* ToDo: Fix this */
2218 switch (buf[bytes_handled]) {
2219 case '\n':
2220 connections[cnum].header_state = HDST_LF;
2221 break;
2222 case '\r':
2223 connections[cnum].header_state = HDST_CR;
2224 break;
2225 default:
2226 connections[cnum].header_state = HDST_TEXT;
2227 break;
2228 }
2229 break;
2230
2231 /* States for Transfer-Encoding: chunked */
2232 case HDST_T:
2233 switch (buf[bytes_handled]) {
2234 case 'R':
2235 case 'r':
2236 connections[cnum].header_state = HDST_TR;
2237 break;
2238 case '\n':
2239 connections[cnum].header_state = HDST_LF;
2240 break;
2241 case '\r':
2242 connections[cnum].header_state = HDST_CR;
2243 break;
2244 default:
2245 connections[cnum].header_state = HDST_TEXT;
2246 break;
2247 }
2248 break;
2249
2250 case HDST_TR:
2251 switch (buf[bytes_handled]) {
2252 case 'A':
2253 case 'a':
2254 connections[cnum].header_state = HDST_TRA;
2255 break;
2256 case '\n':
2257 connections[cnum].header_state = HDST_LF;
2258 break;
2259 case '\r':
2260 connections[cnum].header_state = HDST_CR;
2261 break;
2262 default:
2263 connections[cnum].header_state = HDST_TEXT;
2264 break;
2265 }
2266 break;
2267
2268 case HDST_TRA:
2269 switch (buf[bytes_handled]) {
2270 case 'N':
2271 case 'n':
2272 connections[cnum].header_state = HDST_TRAN;
2273 break;
2274 case '\n':
2275 connections[cnum].header_state = HDST_LF;
2276 break;
2277 case '\r':
2278 connections[cnum].header_state = HDST_CR;
2279 break;
2280 default:
2281 connections[cnum].header_state = HDST_TEXT;
2282 break;
2283 }
2284 break;
2285
2286 case HDST_TRAN:
2287 switch (buf[bytes_handled]) {
2288 case 'S':
2289 case 's':
2290 connections[cnum].header_state = HDST_TRANS;
2291 break;
2292 case '\n':
2293 connections[cnum].header_state = HDST_LF;
2294 break;
2295 case '\r':
2296 connections[cnum].header_state = HDST_CR;
2297 break;
2298 default:
2299 connections[cnum].header_state = HDST_TEXT;
2300 break;
2301 }
2302 break;
2303
2304 case HDST_TRANS:
2305 switch (buf[bytes_handled]) {
2306 case 'F':
2307 case 'f':
2308 connections[cnum].header_state = HDST_TRANSF;
2309 break;
2310 case '\n':
2311 connections[cnum].header_state = HDST_LF;
2312 break;
2313 case '\r':
2314 connections[cnum].header_state = HDST_CR;
2315 break;
2316 default:
2317 connections[cnum].header_state = HDST_TEXT;
2318 break;
2319 }
2320 break;
2321
2322 case HDST_TRANSF:
2323 switch (buf[bytes_handled]) {
2324 case 'E':
2325 case 'e':
2326 connections[cnum].header_state = HDST_TRANSFE;
2327 break;
2328 case '\n':
2329 connections[cnum].header_state = HDST_LF;
2330 break;
2331 case '\r':
2332 connections[cnum].header_state = HDST_CR;
2333 break;
2334 default:
2335 connections[cnum].header_state = HDST_TEXT;
2336 break;
2337 }
2338 break;
2339
2340 case HDST_TRANSFE:
2341 switch (buf[bytes_handled]) {
2342 case 'R':
2343 case 'r':
2344 connections[cnum].header_state = HDST_TRANSFER;
2345 break;
2346 case '\n':
2347 connections[cnum].header_state = HDST_LF;
2348 break;
2349 case '\r':
2350 connections[cnum].header_state = HDST_CR;
2351 break;
2352 default:
2353 connections[cnum].header_state = HDST_TEXT;
2354 break;
2355 }
2356 break;
2357
2358 case HDST_TRANSFER:
2359 switch (buf[bytes_handled]) {
2360 case '-':
2361 connections[cnum].header_state = HDST_TRANSFER_DASH;
2362 break;
2363 case '\n':
2364 connections[cnum].header_state = HDST_LF;
2365 break;
2366 case '\r':
2367 connections[cnum].header_state = HDST_CR;
2368 break;
2369 default:
2370 connections[cnum].header_state = HDST_TEXT;
2371 break;
2372 }
2373 break;
2374
2375 case HDST_TRANSFER_DASH:
2376 switch (buf[bytes_handled]) {
2377 case 'E':
2378 case 'e':
2379 connections[cnum].header_state = HDST_TRANSFER_DASH_E;
2380 break;
2381 case '\n':
2382 connections[cnum].header_state = HDST_LF;
2383 break;
2384 case '\r':
2385 connections[cnum].header_state = HDST_CR;
2386 break;
2387 default:
2388 connections[cnum].header_state = HDST_TEXT;
2389 break;
2390 }
2391 break;
2392
2393 case HDST_TRANSFER_DASH_E:
2394 switch (buf[bytes_handled]) {
2395 case 'N':
2396 case 'n':
2397 connections[cnum].header_state = HDST_TRANSFER_DASH_EN;
2398 break;
2399 case '\n':
2400 connections[cnum].header_state = HDST_LF;
2401 break;
2402 case '\r':
2403 connections[cnum].header_state = HDST_CR;
2404 break;
2405 default:
2406 connections[cnum].header_state = HDST_TEXT;
2407 break;
2408 }
2409 break;
2410
2411 case HDST_TRANSFER_DASH_EN:
2412 switch (buf[bytes_handled]) {
2413 case 'C':
2414 case 'c':
2415 connections[cnum].header_state = HDST_TRANSFER_DASH_ENC;
2416 break;
2417 case '\n':
2418 connections[cnum].header_state = HDST_LF;
2419 break;
2420 case '\r':
2421 connections[cnum].header_state = HDST_CR;
2422 break;
2423 default:
2424 connections[cnum].header_state = HDST_TEXT;
2425 break;
2426 }
2427 break;
2428
2429 case HDST_TRANSFER_DASH_ENC:
2430 switch (buf[bytes_handled]) {
2431 case 'O':
2432 case 'o':
2433 connections[cnum].header_state = HDST_TRANSFER_DASH_ENCO;
2434 break;
2435 case '\n':
2436 connections[cnum].header_state = HDST_LF;
2437 break;
2438 case '\r':
2439 connections[cnum].header_state = HDST_CR;
2440 break;
2441 default:
2442 connections[cnum].header_state = HDST_TEXT;
2443 break;
2444 }
2445 break;
2446
2447 case HDST_TRANSFER_DASH_ENCO:
2448 switch (buf[bytes_handled]) {
2449 case 'D':
2450 case 'd':
2451 connections[cnum].header_state = HDST_TRANSFER_DASH_ENCOD;
2452 break;
2453 case '\n':
2454 connections[cnum].header_state = HDST_LF;
2455 break;
2456 case '\r':
2457 connections[cnum].header_state = HDST_CR;
2458 break;
2459 default:
2460 connections[cnum].header_state = HDST_TEXT;
2461 break;
2462 }
2463 break;
2464
2465 case HDST_TRANSFER_DASH_ENCOD:
2466 switch (buf[bytes_handled]) {
2467 case 'I':
2468 case 'i':
2469 connections[cnum].header_state = HDST_TRANSFER_DASH_ENCODI;
2470 break;
2471 case '\n':
2472 connections[cnum].header_state = HDST_LF;
2473 break;
2474 case '\r':
2475 connections[cnum].header_state = HDST_CR;
2476 break;
2477 default:
2478 connections[cnum].header_state = HDST_TEXT;
2479 break;
2480 }
2481 break;
2482
2483 case HDST_TRANSFER_DASH_ENCODI:
2484 switch (buf[bytes_handled]) {
2485 case 'N':
2486 case 'n':
2487 connections[cnum].header_state = HDST_TRANSFER_DASH_ENCODIN;
2488 break;
2489 case '\n':
2490 connections[cnum].header_state = HDST_LF;
2491 break;
2492 case '\r':
2493 connections[cnum].header_state = HDST_CR;
2494 break;
2495 default:
2496 connections[cnum].header_state = HDST_TEXT;
2497 break;
2498 }
2499 break;
2500
2501 case HDST_TRANSFER_DASH_ENCODIN:
2502 switch (buf[bytes_handled]) {
2503 case 'G':
2504 case 'g':
2505 connections[cnum].header_state = HDST_TRANSFER_DASH_ENCODING;
2506 break;
2507 case '\n':
2508 connections[cnum].header_state = HDST_LF;
2509 break;
2510 case '\r':
2511 connections[cnum].header_state = HDST_CR;
2512 break;
2513 default:
2514 connections[cnum].header_state = HDST_TEXT;
2515 break;
2516 }
2517 break;
2518
2519 case HDST_TRANSFER_DASH_ENCODING:
2520 switch (buf[bytes_handled]) {
2521 case ':':
2522 connections[cnum].header_state = HDST_TRANSFER_DASH_ENCODING_COLON;
2523 break;
2524 case '\n':
2525 connections[cnum].header_state = HDST_LF;
2526 break;
2527 case '\r':
2528 connections[cnum].header_state = HDST_CR;
2529 break;
2530 default:
2531 connections[cnum].header_state = HDST_TEXT;
2532 break;
2533 }
2534 break;
2535
2536 case HDST_TRANSFER_DASH_ENCODING_COLON:
2537 switch (buf[bytes_handled]) {
2538 case ' ':
2539 connections[cnum].header_state = HDST_TRANSFER_DASH_ENCODING_COLON_WS;
2540 break;
2541 case '\n':
2542 connections[cnum].header_state = HDST_LF;
2543 break;
2544 case '\r':
2545 connections[cnum].header_state = HDST_CR;
2546 break;
2547 default:
2548 connections[cnum].header_state = HDST_TEXT;
2549 break;
2550 }
2551 break;
2552
2553 case HDST_TRANSFER_DASH_ENCODING_COLON_WS:
2554 switch (buf[bytes_handled]) {
2555 case 'C':
2556 case 'c':
2557 connections[cnum].header_state = HDST_TRANSFER_DASH_ENCODING_COLON_WS_C;
2558 break;
2559 case '\n':
2560 connections[cnum].header_state = HDST_LF;
2561 break;
2562 case '\r':
2563 connections[cnum].header_state = HDST_CR;
2564 break;
2565 default:
2566 connections[cnum].header_state = HDST_TEXT;
2567 break;
2568 }
2569 break;
2570
2571 case HDST_TRANSFER_DASH_ENCODING_COLON_WS_C:
2572 switch (buf[bytes_handled]) {
2573 case 'H':
2574 case 'h':
2575 connections[cnum].header_state = HDST_TRANSFER_DASH_ENCODING_COLON_WS_CH;
2576 break;
2577 case '\n':
2578 connections[cnum].header_state = HDST_LF;
2579 break;
2580 case '\r':
2581 connections[cnum].header_state = HDST_CR;
2582 break;
2583 default:
2584 connections[cnum].header_state = HDST_TEXT;
2585 break;
2586 }
2587 break;
2588
2589 case HDST_TRANSFER_DASH_ENCODING_COLON_WS_CH:
2590 switch (buf[bytes_handled]) {
2591 case 'U':
2592 case 'u':
2593 connections[cnum].header_state = HDST_TRANSFER_DASH_ENCODING_COLON_WS_CHU;
2594 break;
2595 case '\n':
2596 connections[cnum].header_state = HDST_LF;
2597 break;
2598 case '\r':
2599 connections[cnum].header_state = HDST_CR;
2600 break;
2601 default:
2602 connections[cnum].header_state = HDST_TEXT;
2603 break;
2604 }
2605 break;
2606
2607 case HDST_TRANSFER_DASH_ENCODING_COLON_WS_CHU:
2608 switch (buf[bytes_handled]) {
2609 case 'N':
2610 case 'n':
2611 connections[cnum].header_state = HDST_TRANSFER_DASH_ENCODING_COLON_WS_CHUN;
2612 break;
2613 case '\n':
2614 connections[cnum].header_state = HDST_LF;
2615 break;
2616 case '\r':
2617 connections[cnum].header_state = HDST_CR;
2618 break;
2619 default:
2620 connections[cnum].header_state = HDST_TEXT;
2621 break;
2622 }
2623 break;
2624
2625 case HDST_TRANSFER_DASH_ENCODING_COLON_WS_CHUN:
2626 switch (buf[bytes_handled]) {
2627 case 'K':
2628 case 'k':
2629 connections[cnum].header_state = HDST_TRANSFER_DASH_ENCODING_COLON_WS_CHUNK;
2630 break;
2631 case '\n':
2632 connections[cnum].header_state = HDST_LF;
2633 break;
2634 case '\r':
2635 connections[cnum].header_state = HDST_CR;
2636 break;
2637 default:
2638 connections[cnum].header_state = HDST_TEXT;
2639 break;
2640 }
2641 break;
2642
2643 case HDST_TRANSFER_DASH_ENCODING_COLON_WS_CHUNK:
2644 switch (buf[bytes_handled]) {
2645 case 'E':
2646 case 'e':
2647 connections[cnum].header_state = HDST_TRANSFER_DASH_ENCODING_COLON_WS_CHUNKE;
2648 break;
2649 case '\n':
2650 connections[cnum].header_state = HDST_LF;
2651 break;
2652 case '\r':
2653 connections[cnum].header_state = HDST_CR;
2654 break;
2655 default:
2656 connections[cnum].header_state = HDST_TEXT;
2657 break;
2658 }
2659 break;
2660
2661 case HDST_TRANSFER_DASH_ENCODING_COLON_WS_CHUNKE:
2662 switch (buf[bytes_handled]) {
2663 case 'D':
2664 case 'd':
2665 connections[cnum].header_state = HDST_TRANSFER_DASH_ENCODING_COLON_WS_CHUNKED;
2666 break;
2667 case '\n':
2668 connections[cnum].header_state = HDST_LF;
2669 break;
2670 case '\r':
2671 connections[cnum].header_state = HDST_CR;
2672 break;
2673 default:
2674 connections[cnum].header_state = HDST_TEXT;
2675 break;
2676 }
2677 break;
2678
2679 case HDST_TRANSFER_DASH_ENCODING_COLON_WS_CHUNKED:
2680 /* ToDo: what to do here? */
2681 connections[cnum].chunked = 1;
2682 switch (buf[bytes_handled]) {
2683 case '\n':
2684 connections[cnum].header_state = HDST_LF;
2685 break;
2686 case '\r':
2687 connections[cnum].header_state = HDST_CR;
2688 break;
2689 default:
2690 connections[cnum].header_state = HDST_TEXT;
2691 break;
2692 }
2693 break;
2694 }
2695 }
2696
2697 if (connections[cnum].conn_state == CNST_READING && connections[cnum].content_length == 0) {
2698 #ifdef DEBUG
2699 fprintf(stderr, "[handle_read] content_length is 0, close connection\n");
2700 #endif
2701 if (connections[cnum].keep_alive > 0)
2702 connections[cnum].reusable = 1;
2703
2704 close_connection(cnum);
2705
2706 return;
2707 }
2708
2709 break;
2710
2711 case CNST_READING:
2712 connections[cnum].bytes += bytes_read - bytes_handled;
2713 if (do_throttle) {
2714 /* Check if we're reading too fast. */
2715 elapsed = delta_timeval(&connections[cnum].started_at, nowP) / 1000000.0;
2716 if (elapsed > 0.01 && connections[cnum].bytes / elapsed > throttle) {
2717 connections[cnum].conn_state = CNST_PAUSING;
2718 client_data.i = cnum;
2719 connections[cnum].wakeup_timer = tmr_create(nowP, wakeup_connection, client_data, 1000L, 0);
2720 }
2721 }
2722 if (do_checksum) {
2723 checksum = connections[cnum].checksum;
2724 for (; bytes_handled < bytes_read; ++bytes_handled) {
2725 if (checksum & 1)
2726 checksum = (checksum >> 1) + 0x8000;
2727 else
2728 checksum >>= 1;
2729 checksum += buf[bytes_handled];
2730 checksum &= 0xffff;
2731 }
2732 connections[cnum].checksum = checksum;
2733 } else
2734 bytes_handled = bytes_read;
2735
2736 /* This is an utter hack, to try to support chunked encodings... I only
2737 examine the "footer", to see if it looks like a chunked "end".
2738 ToDo: We should properly parse the body, and find the chunked sizes. */
2739 if (connections[cnum].chunked && !strncmp(buf + bytes_read - 5, "0\r\n\r\n", 5))
2740 connections[cnum].content_length = connections[cnum].bytes;
2741
2742 if (connections[cnum].content_length != -1 && connections[cnum].bytes >= connections[cnum].content_length) {
2743 if (connections[cnum].keep_alive > 0)
2744 connections[cnum].reusable = 1;
2745 close_connection(cnum);
2746 return;
2747 }
2748
2749 break;
2750 default:
2751 /* Nothing */
2752 break;
2753 }
2754 }
2755 }
2756
2757 static void
idle_connection(ClientData client_data,struct timeval * nowP)2758 idle_connection(ClientData client_data, struct timeval *nowP __attribute__((unused)))
2759 {
2760 int cnum;
2761 struct timeval tv;
2762 char strTime[32];
2763 struct tm localtv;
2764 gettimeofday(&tv, NULL);
2765 strftime(strTime, 32, "%T", localtime_r(&tv.tv_sec, &localtv));
2766
2767 cnum = client_data.i;
2768 connections[cnum].idle_timer = (Timer *)0;
2769 if (unique_id) {
2770 (void)fprintf(stderr, "[%s.%lld] %s: timed out (%d sec) in state %d, requests %d, unique id: %u\n", strTime,
2771 (long long)tv.tv_usec, urls[connections[cnum].url_num].url_str, idle_secs, connections[cnum].conn_state,
2772 connections[cnum].stats.requests_per_connection, connections[cnum].unique_id);
2773 } else {
2774 (void)fprintf(stderr, "[%s.%lld] %s: timed out (%d sec) in state %d, requests %d\n", strTime, (long long)tv.tv_usec,
2775 urls[connections[cnum].url_num].url_str, idle_secs, connections[cnum].conn_state,
2776 connections[cnum].stats.requests_per_connection);
2777 }
2778 connections[cnum].reusable = 0;
2779 close_connection(cnum);
2780 ++total_timeouts;
2781 }
2782
2783 static void
wakeup_connection(ClientData client_data,struct timeval * nowP)2784 wakeup_connection(ClientData client_data, struct timeval *nowP __attribute__((unused)))
2785 {
2786 int cnum;
2787
2788 cnum = client_data.i;
2789 connections[cnum].wakeup_timer = (Timer *)0;
2790 connections[cnum].conn_state = CNST_READING;
2791 }
2792
2793 static void
close_connection(int cnum)2794 close_connection(int cnum)
2795 {
2796 int url_num;
2797
2798 if (!connections[cnum].reusable) {
2799 struct epoll_event ev;
2800
2801 ev.events = EPOLLIN | EPOLLOUT;
2802 ev.data.u32 = cnum;
2803 if (epoll_ctl(epfd, EPOLL_CTL_DEL, connections[cnum].conn_fd, &ev) < 0)
2804 perror("epoll delete fd");
2805 if (urls[connections[cnum].url_num].protocol == PROTO_HTTPS)
2806 SSL_free(connections[cnum].ssl);
2807 (void)close(connections[cnum].conn_fd);
2808 } else {
2809 --connections[cnum].keep_alive;
2810 }
2811 connections[cnum].conn_state = CNST_FREE;
2812 if (connections[cnum].idle_timer != (Timer *)0)
2813 tmr_cancel(connections[cnum].idle_timer);
2814 if (connections[cnum].wakeup_timer != (Timer *)0)
2815 tmr_cancel(connections[cnum].wakeup_timer);
2816 --num_connections;
2817 ++fetches_completed;
2818 total_bytes += connections[cnum].bytes;
2819 if (connections[cnum].did_connect) {
2820 long long connect_usecs = delta_timeval(&connections[cnum].connect_at, &connections[cnum].request_at);
2821 /*
2822 if ( connect_usecs > ( max_connect_usecs << 3 ) && max_connect_usecs )
2823 connect_usecs = max_connect_usecs;
2824 */
2825 total_connect_usecs += connect_usecs;
2826 max_connect_usecs = max(max_connect_usecs, connect_usecs);
2827 min_connect_usecs = min(min_connect_usecs, connect_usecs);
2828 ++connects_completed;
2829 }
2830 if (connections[cnum].did_response) {
2831 long long response_usecs = delta_timeval(&connections[cnum].request_at, &connections[cnum].response_at);
2832 /*
2833 if ( response_usecs > ( max_response_usecs << 1 ) && max_response_usecs )
2834 response_usecs = max_response_usecs;
2835 */
2836 total_response_usecs += response_usecs;
2837 max_response_usecs = max(max_response_usecs, response_usecs);
2838 min_response_usecs = min(min_response_usecs, response_usecs);
2839 ++responses_completed;
2840 }
2841 if (connections[cnum].http_status >= 0 && connections[cnum].http_status <= 999) {
2842 ++http_status_counts[connections[cnum].http_status];
2843 connections[cnum].stats.responses++;
2844 }
2845
2846 url_num = connections[cnum].url_num;
2847
2848 /* Only check to update got_bytes, byte count errors and/or checksums
2849 if the request was successful (i.e. no HTTP error). */
2850 if (connections[cnum].http_status >= 0 && connections[cnum].http_status < 400) {
2851 if (do_checksum) {
2852 if (!urls[url_num].got_checksum) {
2853 urls[url_num].checksum = connections[cnum].checksum;
2854 urls[url_num].got_checksum = 1;
2855 } else {
2856 if (connections[cnum].checksum != urls[url_num].checksum) {
2857 (void)fprintf(stderr, "%s: checksum wrong\n", urls[url_num].url_str);
2858 ++total_badchecksums;
2859 }
2860 }
2861 } else {
2862 if (!urls[url_num].got_bytes) {
2863 urls[url_num].bytes = connections[cnum].bytes;
2864 urls[url_num].got_bytes = 1;
2865 } else {
2866 if (connections[cnum].bytes != urls[url_num].bytes) {
2867 if (!ignore_bytes)
2868 (void)fprintf(stderr, "%s: byte count wrong (expected %ld, got %ld)\n", urls[url_num].url_str, urls[url_num].bytes,
2869 connections[cnum].bytes);
2870 ++total_badbytes;
2871 }
2872 }
2873 }
2874 }
2875 }
2876
2877 static void
progress_report(ClientData client_data,struct timeval * nowP)2878 progress_report(ClientData client_data __attribute__((unused)), struct timeval *nowP __attribute__((unused)))
2879 {
2880 float elapsed;
2881
2882 elapsed = delta_timeval(&start_at, nowP) / 1000000.0;
2883 (void)fprintf(stderr, "--- %g secs, %d fetches started, %d completed, %d current\n", elapsed, fetches_started, fetches_completed,
2884 num_connections);
2885 }
2886
2887 static void
start_timer(ClientData client_data,struct timeval * nowP)2888 start_timer(ClientData client_data __attribute__((unused)), struct timeval *nowP __attribute__((unused)))
2889 {
2890 start_connection(nowP);
2891 if (do_jitter)
2892 (void)tmr_create(nowP, start_timer, JunkClientData, (long)(random() % range_interval) + low_interval, 0);
2893 }
2894
2895 static void
end_timer(ClientData client_data,struct timeval * nowP)2896 end_timer(ClientData client_data __attribute__((unused)), struct timeval *nowP __attribute__((unused)))
2897 {
2898 finish(nowP);
2899 }
2900
2901 static void
finish(struct timeval * nowP)2902 finish(struct timeval *nowP)
2903 {
2904 float elapsed;
2905 int i;
2906
2907 /* Report statistics. */
2908 elapsed = delta_timeval(&start_at, nowP) / 1000000.0;
2909 (void)printf("%d fetches on %d conns, %d max parallel, %g bytes, in %g seconds\n", fetches_completed, connects_completed,
2910 max_parallel, (float)total_bytes, elapsed);
2911 if (fetches_completed > 0)
2912 (void)printf("%g mean bytes/fetch\n", (float)total_bytes / (float)fetches_completed);
2913 if (elapsed > 0.01) {
2914 (void)printf("%g fetches/sec, %g bytes/sec\n", (float)fetches_completed / elapsed, (float)total_bytes / elapsed);
2915 }
2916 if (connects_completed > 0)
2917 (void)printf("msecs/connect: %g mean, %g max, %g min\n", (float)total_connect_usecs / (float)connects_completed / 1000.0,
2918 (float)max_connect_usecs / 1000.0, (float)min_connect_usecs / 1000.0);
2919 if (responses_completed > 0)
2920 (void)printf("msecs/first-response: %g mean, %g max, %g min\n",
2921 (float)total_response_usecs / (float)responses_completed / 1000.0, (float)max_response_usecs / 1000.0,
2922 (float)min_response_usecs / 1000.0);
2923 if (total_timeouts != 0)
2924 (void)printf("%d timeouts\n", total_timeouts);
2925 if (do_checksum) {
2926 if (total_badchecksums != 0)
2927 (void)printf("%d bad checksums\n", total_badchecksums);
2928 } else {
2929 if (total_badbytes != 0)
2930 (void)printf("%d bad byte counts\n", total_badbytes);
2931 }
2932
2933 (void)printf("HTTP response codes:\n");
2934 for (i = 0; i < 1000; ++i)
2935 if (http_status_counts[i] > 0)
2936 (void)printf(" code %03d -- %d\n", i, http_status_counts[i]);
2937 if (do_verbose) {
2938 (void)printf("Socket slot stats:\n");
2939 for (i = 0; i < max_connections; i++)
2940 if (connections[i].stats.connections > 0)
2941 (void)printf(" slot %04d -- %d connections, %d requests, %d responses\n", i, connections[i].stats.connections,
2942 connections[i].stats.requests, connections[i].stats.responses);
2943 }
2944
2945 tmr_destroy();
2946 if (ssl_ctx != (SSL_CTX *)0)
2947 SSL_CTX_free(ssl_ctx);
2948 exit(0);
2949 }
2950
2951 static long long
delta_timeval(struct timeval * start,struct timeval * finish)2952 delta_timeval(struct timeval *start, struct timeval *finish)
2953 {
2954 long long delta_secs = finish->tv_sec - start->tv_sec;
2955 long long delta_usecs = finish->tv_usec - start->tv_usec;
2956 return delta_secs * (long long)1000000L + delta_usecs;
2957 }
2958
2959 static void *
malloc_check(size_t size)2960 malloc_check(size_t size)
2961 {
2962 void *ptr = malloc(size);
2963 check(ptr);
2964 return ptr;
2965 }
2966
2967 static void *
realloc_check(void * ptr,size_t size)2968 realloc_check(void *ptr, size_t size)
2969 {
2970 ptr = realloc(ptr, size);
2971 check(ptr);
2972 return ptr;
2973 }
2974
2975 static char *
strdup_check(char * str)2976 strdup_check(char *str)
2977 {
2978 str = strdup(str);
2979 check((void *)str);
2980 return str;
2981 }
2982
2983 static void
check(void * ptr)2984 check(void *ptr)
2985 {
2986 if (ptr == (void *)0) {
2987 (void)fprintf(stderr, "%s: out of memory\n", argv0);
2988 exit(1);
2989 }
2990 }
2991