client.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571
  1. /*
  2. * weighttp - a lightweight and simple webserver benchmarking tool
  3. *
  4. * Author:
  5. * Copyright (c) 2009-2011 Thomas Porzelt
  6. *
  7. * License:
  8. * MIT, see COPYING file
  9. */
  10. #include "weighttp.h"
  11. static uint8_t client_parse(Client *client, int size);
  12. static void client_io_cb(struct ev_loop *loop, ev_io *w, int revents);
  13. static void client_set_events(Client *client, int events);
  14. /*
  15. static void client_add_events(Client *client, int events);
  16. static void client_rem_events(Client *client, int events);
  17. static void client_add_events(Client *client, int events) {
  18. struct ev_loop *loop = client->worker->loop;
  19. ev_io *watcher = &client->sock_watcher;
  20. if ((watcher->events & events) == events)
  21. return;
  22. ev_io_stop(loop, watcher);
  23. ev_io_set(watcher, watcher->fd, watcher->events | events);
  24. ev_io_start(loop, watcher);
  25. }
  26. static void client_rem_events(Client *client, int events) {
  27. struct ev_loop *loop = client->worker->loop;
  28. ev_io *watcher = &client->sock_watcher;
  29. if (0 == (watcher->events & events))
  30. return;
  31. ev_io_stop(loop, watcher);
  32. ev_io_set(watcher, watcher->fd, watcher->events & ~events);
  33. ev_io_start(loop, watcher);
  34. }
  35. */
  36. static void client_set_events(Client *client, int events) {
  37. struct ev_loop *loop = client->worker->loop;
  38. ev_io *watcher = &client->sock_watcher;
  39. if (events == (watcher->events & (EV_READ | EV_WRITE)))
  40. return;
  41. ev_io_stop(loop, watcher);
  42. ev_io_set(watcher, watcher->fd, (watcher->events & ~(EV_READ | EV_WRITE)) | events);
  43. ev_io_start(loop, watcher);
  44. }
  45. Client *client_new(Worker *worker) {
  46. Client *client;
  47. client = W_MALLOC(Client, 1);
  48. client->state = CLIENT_START;
  49. client->worker = worker;
  50. client->sock_watcher.fd = -1;
  51. client->sock_watcher.data = client;
  52. client->content_length = -1;
  53. client->buffer_offset = 0;
  54. client->request_offset = 0;
  55. client->keepalive = client->worker->config->keep_alive;
  56. client->chunked = 0;
  57. client->chunk_size = -1;
  58. client->chunk_received = 0;
  59. return client;
  60. }
  61. void client_free(Client *client) {
  62. if (client->sock_watcher.fd != -1) {
  63. ev_io_stop(client->worker->loop, &client->sock_watcher);
  64. shutdown(client->sock_watcher.fd, SHUT_WR);
  65. close(client->sock_watcher.fd);
  66. }
  67. free(client);
  68. }
  69. static void client_reset(Client *client) {
  70. //printf("keep alive: %d\n", client->keepalive);
  71. if (!client->keepalive) {
  72. if (client->sock_watcher.fd != -1) {
  73. ev_io_stop(client->worker->loop, &client->sock_watcher);
  74. shutdown(client->sock_watcher.fd, SHUT_WR);
  75. close(client->sock_watcher.fd);
  76. client->sock_watcher.fd = -1;
  77. }
  78. client->state = CLIENT_START;
  79. } else {
  80. client_set_events(client, EV_WRITE);
  81. client->state = CLIENT_WRITING;
  82. client->worker->stats.req_started++;
  83. }
  84. client->parser_state = PARSER_START;
  85. client->buffer_offset = 0;
  86. client->parser_offset = 0;
  87. client->request_offset = 0;
  88. client->ts_start = 0;
  89. client->ts_end = 0;
  90. client->status_success = 0;
  91. client->success = 0;
  92. client->content_length = -1;
  93. client->bytes_received = 0;
  94. client->header_size = 0;
  95. client->keepalive = client->worker->config->keep_alive;
  96. client->chunked = 0;
  97. client->chunk_size = -1;
  98. client->chunk_received = 0;
  99. }
  100. static uint8_t client_connect(Client *client) {
  101. //printf("connecting...\n");
  102. start:
  103. if (-1 == connect(client->sock_watcher.fd, client->worker->config->saddr->ai_addr, client->worker->config->saddr->ai_addrlen)) {
  104. switch (errno) {
  105. case EINPROGRESS:
  106. case EALREADY:
  107. /* async connect now in progress */
  108. client->state = CLIENT_CONNECTING;
  109. return 1;
  110. case EISCONN:
  111. break;
  112. case EINTR:
  113. goto start;
  114. default:
  115. {
  116. strerror_r(errno, client->buffer, sizeof(client->buffer));
  117. W_ERROR("connect() failed: %s (%d)", client->buffer, errno);
  118. return 0;
  119. }
  120. }
  121. }
  122. /* successfully connected */
  123. client->state = CLIENT_WRITING;
  124. return 1;
  125. }
  126. static void client_io_cb(struct ev_loop *loop, ev_io *w, int revents) {
  127. Client *client = w->data;
  128. UNUSED(loop);
  129. UNUSED(revents);
  130. client_state_machine(client);
  131. }
  132. void client_state_machine(Client *client) {
  133. int r;
  134. Config *config = client->worker->config;
  135. start:
  136. //printf("state: %d\n", client->state);
  137. switch (client->state) {
  138. case CLIENT_START:
  139. client->worker->stats.req_started++;
  140. do {
  141. r = socket(config->saddr->ai_family, config->saddr->ai_socktype, config->saddr->ai_protocol);
  142. } while (-1 == r && errno == EINTR);
  143. if (-1 == r) {
  144. client->state = CLIENT_ERROR;
  145. strerror_r(errno, client->buffer, sizeof(client->buffer));
  146. W_ERROR("socket() failed: %s (%d)", client->buffer, errno);
  147. goto start;
  148. }
  149. /* set non-blocking */
  150. fcntl(r, F_SETFL, O_NONBLOCK | O_RDWR);
  151. ev_init(&client->sock_watcher, client_io_cb);
  152. ev_io_set(&client->sock_watcher, r, EV_WRITE);
  153. ev_io_start(client->worker->loop, &client->sock_watcher);
  154. if (!client_connect(client)) {
  155. client->state = CLIENT_ERROR;
  156. goto start;
  157. } else {
  158. client_set_events(client, EV_WRITE);
  159. return;
  160. }
  161. case CLIENT_CONNECTING:
  162. if (!client_connect(client)) {
  163. client->state = CLIENT_ERROR;
  164. goto start;
  165. }
  166. case CLIENT_WRITING:
  167. while (1) {
  168. r = write(client->sock_watcher.fd, &config->request[client->request_offset], config->request_size - client->request_offset);
  169. //printf("write(%d - %d = %d): %d\n", config->request_size, client->request_offset, config->request_size - client->request_offset, r);
  170. if (r == -1) {
  171. /* error */
  172. if (errno == EINTR)
  173. continue;
  174. strerror_r(errno, client->buffer, sizeof(client->buffer));
  175. W_ERROR("write() failed: %s (%d)", client->buffer, errno);
  176. client->state = CLIENT_ERROR;
  177. goto start;
  178. } else if (r != 0) {
  179. /* success */
  180. client->request_offset += r;
  181. if (client->request_offset == config->request_size) {
  182. /* whole request was sent, start reading */
  183. client->state = CLIENT_READING;
  184. client_set_events(client, EV_READ);
  185. }
  186. return;
  187. } else {
  188. /* disconnect */
  189. client->state = CLIENT_END;
  190. goto start;
  191. }
  192. }
  193. case CLIENT_READING:
  194. while (1) {
  195. r = read(client->sock_watcher.fd, &client->buffer[client->buffer_offset], sizeof(client->buffer) - client->buffer_offset - 1);
  196. //printf("read(): %d, offset was: %d\n", r, client->buffer_offset);
  197. if (r == -1) {
  198. /* error */
  199. if (errno == EINTR)
  200. continue;
  201. strerror_r(errno, client->buffer, sizeof(client->buffer));
  202. W_ERROR("read() failed: %s (%d)", client->buffer, errno);
  203. client->state = CLIENT_ERROR;
  204. } else if (r != 0) {
  205. /* success */
  206. client->bytes_received += r;
  207. client->buffer_offset += r;
  208. client->worker->stats.bytes_total += r;
  209. if (client->buffer_offset >= sizeof(client->buffer)) {
  210. /* too big response header */
  211. client->state = CLIENT_ERROR;
  212. break;
  213. }
  214. client->buffer[client->buffer_offset] = '\0';
  215. //printf("buffer:\n==========\n%s\n==========\n", client->buffer);
  216. if (!client_parse(client, r)) {
  217. client->state = CLIENT_ERROR;
  218. //printf("parser failed\n");
  219. break;
  220. } else {
  221. if (client->state == CLIENT_END)
  222. goto start;
  223. else
  224. return;
  225. }
  226. } else {
  227. /* disconnect */
  228. if (client->parser_state == PARSER_BODY && !client->keepalive && client->status_success
  229. && !client->chunked && client->content_length == -1) {
  230. client->success = 1;
  231. client->state = CLIENT_END;
  232. } else {
  233. client->state = CLIENT_ERROR;
  234. }
  235. goto start;
  236. }
  237. }
  238. case CLIENT_ERROR:
  239. //printf("client error\n");
  240. client->worker->stats.req_error++;
  241. client->keepalive = 0;
  242. client->success = 0;
  243. client->state = CLIENT_END;
  244. case CLIENT_END:
  245. /* update worker stats */
  246. client->worker->stats.req_done++;
  247. if (client->success) {
  248. client->worker->stats.req_success++;
  249. client->worker->stats.bytes_body += client->bytes_received - client->header_size;
  250. } else {
  251. client->worker->stats.req_failed++;
  252. }
  253. /* print progress every 10% done */
  254. if (client->worker->id == 1 && client->worker->stats.req_done % client->worker->progress_interval == 0) {
  255. printf("progress: %3d%% done\n",
  256. (int) (client->worker->stats.req_done * 100 / client->worker->stats.req_todo)
  257. );
  258. }
  259. if (client->worker->stats.req_started == client->worker->stats.req_todo) {
  260. /* this worker has started all requests */
  261. client->keepalive = 0;
  262. client_reset(client);
  263. if (client->worker->stats.req_done == client->worker->stats.req_todo) {
  264. /* this worker has finished all requests */
  265. ev_unref(client->worker->loop);
  266. }
  267. } else {
  268. client_reset(client);
  269. goto start;
  270. }
  271. }
  272. }
  273. static uint8_t client_parse(Client *client, int size) {
  274. char *end, *str;
  275. uint16_t status_code;
  276. const int MAX_BUFF = 2048;
  277. char* print_buff = malloc(MAX_BUFF);
  278. int buff_length = 0;
  279. switch (client->parser_state) {
  280. case PARSER_START:
  281. //buff_length += snprintf(print_buff+buff_length, MAX_BUFF-buff_length, "parse (START):\n%s\n", &client->buffer[client->parser_offset]);
  282. /* look for HTTP/1.1 200 OK */
  283. if (client->buffer_offset < sizeof("HTTP/1.1 200\r\n")) {
  284. buff_length += snprintf(print_buff+buff_length, MAX_BUFF-buff_length, "error 1\n", client->buffer_offset);
  285. printf(print_buff);
  286. return 1;
  287. }
  288. if (strncmp(client->buffer, "HTTP/1.1 ", sizeof("HTTP/1.1 ")-1) != 0) {
  289. //buff_length += snprintf(print_buff+buff_length, MAX_BUFF-buff_length, "success 1\n");
  290. printf(print_buff);
  291. return 0;
  292. }
  293. // now the status code
  294. status_code = 0;
  295. str = client->buffer + sizeof("HTTP/1.1 ")-1;
  296. for (end = str + 3; str != end; str++) {
  297. if (*str < '0' || *str > '9') {
  298. //buff_length += snprintf(print_buff+buff_length, MAX_BUFF-buff_length, "success 2\n");
  299. printf(print_buff);
  300. return 0;
  301. }
  302. status_code *= 10;
  303. status_code += *str - '0';
  304. }
  305. if (status_code >= 200 && status_code < 300) {
  306. client->worker->stats.req_2xx++;
  307. client->status_success = 1;
  308. } else if (status_code < 400) {
  309. client->worker->stats.req_3xx++;
  310. client->status_success = 1;
  311. } else if (status_code < 500) {
  312. client->worker->stats.req_4xx++;
  313. } else if (status_code < 600) {
  314. client->worker->stats.req_5xx++;
  315. } else {
  316. // invalid status code
  317. //buff_length += snprintf(print_buff+buff_length, MAX_BUFF-buff_length, "success 3\n");
  318. printf(print_buff);
  319. return 0;
  320. }
  321. // look for next \r\n
  322. end = strchr(end, '\r');
  323. if (!end || *(end+1) != '\n') {
  324. //buff_length += snprintf(print_buff+buff_length, MAX_BUFF-buff_length, "success 4\n");
  325. printf(print_buff);
  326. return 0;
  327. }
  328. client->parser_offset = end + 2 - client->buffer;
  329. client->parser_state = PARSER_HEADER;
  330. case PARSER_HEADER:
  331. //buff_length += snprintf(print_buff+buff_length, MAX_BUFF-buff_length, "parse (HEADER)\n");
  332. /* look for Content-Length and Connection header */
  333. while (NULL != (end = strchr(&client->buffer[client->parser_offset], '\r'))) {
  334. if (*(end+1) != '\n') {
  335. //buff_length += snprintf(print_buff+buff_length, MAX_BUFF-buff_length, "success 5\n");
  336. printf(print_buff);
  337. return 0;
  338. }
  339. if (end == &client->buffer[client->parser_offset]) {
  340. /* body reached */
  341. client->parser_state = PARSER_BODY;
  342. client->header_size = end + 2 - client->buffer;
  343. //buff_length += snprintf(print_buff+buff_length, MAX_BUFF-buff_length, "body reached\n");
  344. return client_parse(client, size - client->header_size);
  345. }
  346. *end = '\0';
  347. str = &client->buffer[client->parser_offset];
  348. //buff_length += snprintf(print_buff+buff_length, MAX_BUFF-buff_length, "checking header: '%s'\n", str);
  349. if (strncasecmp(str, "Content-Length: ", sizeof("Content-Length: ")-1) == 0) {
  350. /* content length header */
  351. client->content_length = str_to_uint64(str + sizeof("Content-Length: ") - 1);
  352. } else if (strncasecmp(str, "Connection: ", sizeof("Connection: ")-1) == 0) {
  353. /* connection header */
  354. str += sizeof("Connection: ") - 1;
  355. if (strncasecmp(str, "close", sizeof("close")-1) == 0)
  356. client->keepalive = 0;
  357. else if (strncasecmp(str, "keep-alive", sizeof("keep-alive")-1) == 0)
  358. client->keepalive = client->worker->config->keep_alive;
  359. else {
  360. //buff_length += snprintf(print_buff+buff_length, MAX_BUFF-buff_length, "success 6\n");
  361. printf(print_buff);
  362. return 0;
  363. }
  364. } else if (strncasecmp(str, "Transfer-Encoding: ", sizeof("Transfer-Encoding: ")-1) == 0) {
  365. /* transfer encoding header */
  366. str += sizeof("Transfer-Encoding: ") - 1;
  367. if (strncasecmp(str, "chunked", sizeof("chunked")-1) == 0)
  368. client->chunked = 1;
  369. else {
  370. //buff_length += snprintf(print_buff+buff_length, MAX_BUFF-buff_length, "success 7\n");
  371. printf(print_buff);
  372. return 0;
  373. }
  374. }
  375. if (*(end+2) == '\r' && *(end+3) == '\n') {
  376. /* body reached */
  377. client->parser_state = PARSER_BODY;
  378. client->header_size = end + 4 - client->buffer;
  379. client->parser_offset = client->header_size;
  380. //buff_length += snprintf(print_buff+buff_length, MAX_BUFF-buff_length, "body reached\n");
  381. return client_parse(client, size - client->header_size);
  382. }
  383. client->parser_offset = end - client->buffer + 2;
  384. }
  385. buff_length += snprintf(print_buff+buff_length, MAX_BUFF-buff_length, "error 2\n");
  386. printf(print_buff);
  387. return 1;
  388. case PARSER_BODY:
  389. //buff_length += snprintf(print_buff+buff_length, MAX_BUFF-buff_length, "parse (BODY)\n");
  390. /* do nothing, just consume the data */
  391. /*buff_length += snprintf(print_buff+buff_length, MAX_BUFF-buff_length, "content-l: %"PRIu64", header: %d, recevied: %"PRIu64"\n",
  392. client->content_length, client->header_size, client->bytes_received);*/
  393. if (client->chunked) {
  394. int consume_max;
  395. str = &client->buffer[client->parser_offset];
  396. /*buff_length += snprintf(print_buff+buff_length, MAX_BUFF-buff_length, "parsing chunk: '%s'\n(%"PRIi64" received, %"PRIi64" size, %d parser offset)\n",
  397. str, client->chunk_received, client->chunk_size, client->parser_offset
  398. );*/
  399. if (client->chunk_size == -1) {
  400. /* read chunk size */
  401. client->chunk_size = 0;
  402. client->chunk_received = 0;
  403. end = str + size;
  404. for (; str < end; str++) {
  405. if (*str == ';' || *str == '\r')
  406. break;
  407. client->chunk_size *= 16;
  408. if (*str >= '0' && *str <= '9')
  409. client->chunk_size += *str - '0';
  410. else if (*str >= 'A' && *str <= 'Z')
  411. client->chunk_size += 10 + *str - 'A';
  412. else if (*str >= 'a' && *str <= 'z')
  413. client->chunk_size += 10 + *str - 'a';
  414. else {
  415. //buff_length += snprintf(print_buff+buff_length, MAX_BUFF-buff_length, "success 8\n");
  416. printf(print_buff);
  417. return 0;
  418. }
  419. }
  420. str = strstr(str, "\r\n");
  421. if (!str) {
  422. //buff_length += snprintf(print_buff+buff_length, MAX_BUFF-buff_length, "success 9\n");
  423. printf(print_buff);
  424. return 0;
  425. }
  426. str += 2;
  427. //buff_length += snprintf(print_buff+buff_length, MAX_BUFF-buff_length, "---------- chunk size: %"PRIi64", %d read, %d offset, data: '%s'\n", client->chunk_size, size, client->parser_offset, str);
  428. if (client->chunk_size == 0) {
  429. /* chunk of size 0 marks end of content body */
  430. client->state = CLIENT_END;
  431. client->success = client->status_success ? 1 : 0;
  432. if(client->success == 0) {
  433. buff_length += snprintf(print_buff+buff_length, MAX_BUFF-buff_length, "error 3\n");
  434. }
  435. printf(print_buff);
  436. return 1;
  437. }
  438. size -= str - &client->buffer[client->parser_offset];
  439. client->parser_offset = str - client->buffer;
  440. }
  441. /* consume chunk till chunk_size is reached */
  442. consume_max = client->chunk_size - client->chunk_received;
  443. if (size < consume_max)
  444. consume_max = size;
  445. client->chunk_received += consume_max;
  446. client->parser_offset += consume_max;
  447. //buff_length += snprintf(print_buff+buff_length, MAX_BUFF-buff_length, "---------- chunk consuming: %d, received: %"PRIi64" of %"PRIi64", offset: %d\n", consume_max, client->chunk_received, client->chunk_size, client->parser_offset);
  448. if (client->chunk_received == client->chunk_size) {
  449. if (client->buffer[client->parser_offset] != '\r' || client->buffer[client->parser_offset+1] != '\n') {
  450. // TE: This was causing problems with resin, which was artificially slowing down the results of some java tests
  451. //buff_length += snprintf(print_buff+buff_length, MAX_BUFF-buff_length, "success 10\n");
  452. //printf(print_buff);
  453. //return 0;
  454. }
  455. /* got whole chunk, next! */
  456. //buff_length += snprintf(print_buff+buff_length, MAX_BUFF-buff_length, "---------- got whole chunk!!\n");
  457. client->chunk_size = -1;
  458. client->chunk_received = 0;
  459. client->parser_offset += 2;
  460. consume_max += 2;
  461. /* there is stuff left to parse */
  462. if (size - consume_max > 0)
  463. return client_parse(client, size - consume_max);
  464. }
  465. client->parser_offset = 0;
  466. client->buffer_offset = 0;
  467. //buff_length += snprintf(print_buff+buff_length, MAX_BUFF-buff_length, "error 4\n");
  468. printf(print_buff);
  469. return 1;
  470. } else {
  471. /* not chunked, just consume all data till content-length is reached */
  472. client->buffer_offset = 0;
  473. if (client->content_length == -1) {
  474. //buff_length += snprintf(print_buff+buff_length, MAX_BUFF-buff_length, "success 11\n");
  475. printf(print_buff);
  476. return 0;
  477. }
  478. if (client->bytes_received == (uint64_t) (client->header_size + client->content_length)) {
  479. /* full response received */
  480. client->state = CLIENT_END;
  481. client->success = client->status_success ? 1 : 0;
  482. }
  483. }
  484. buff_length += snprintf(print_buff+buff_length, MAX_BUFF-buff_length, "error 5\n");
  485. printf(print_buff);
  486. return 1;
  487. }
  488. buff_length += snprintf(print_buff+buff_length, MAX_BUFF-buff_length, "error 6\n");
  489. printf(print_buff);
  490. return 1;
  491. }