1e4f24219SNick Mathewson /* 2e49e2891SNick Mathewson * Copyright 2009-2012 Niels Provos and Nick Mathewson 3e4f24219SNick Mathewson * 4e4f24219SNick Mathewson * Redistribution and use in source and binary forms, with or without 5e4f24219SNick Mathewson * modification, are permitted provided that the following conditions 6e4f24219SNick Mathewson * are met: 7e4f24219SNick Mathewson * 1. Redistributions of source code must retain the above copyright 8e4f24219SNick Mathewson * notice, this list of conditions and the following disclaimer. 9e4f24219SNick Mathewson * 2. Redistributions in binary form must reproduce the above copyright 10e4f24219SNick Mathewson * notice, this list of conditions and the following disclaimer in the 11e4f24219SNick Mathewson * documentation and/or other materials provided with the distribution. 12e4f24219SNick Mathewson * 4. The name of the author may not be used to endorse or promote products 13e4f24219SNick Mathewson * derived from this software without specific prior written permission. 14e4f24219SNick Mathewson * 15e4f24219SNick Mathewson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16e4f24219SNick Mathewson * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17e4f24219SNick Mathewson * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18e4f24219SNick Mathewson * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19e4f24219SNick Mathewson * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20e4f24219SNick Mathewson * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21e4f24219SNick Mathewson * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22e4f24219SNick Mathewson * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23e4f24219SNick Mathewson * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24e4f24219SNick Mathewson * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25e4f24219SNick Mathewson * 26e4f24219SNick Mathewson */ 27e4f24219SNick Mathewson 2895e2455cSNick Mathewson /* for EVUTIL_ERR_CONNECT_RETRIABLE macro */ 2995e2455cSNick Mathewson #include "util-internal.h" 3095e2455cSNick Mathewson 31e4f24219SNick Mathewson #include <sys/types.h> 329f560bfaSNick Mathewson #ifdef _WIN32 331ad03264SNick Mathewson #include <winsock2.h> 341ad03264SNick Mathewson #else 35e4f24219SNick Mathewson #include <sys/socket.h> 36e4f24219SNick Mathewson #include <netinet/in.h> 3710c834c4SHarlan Stenn # ifdef _XOPEN_SOURCE_EXTENDED 3810c834c4SHarlan Stenn # include <arpa/inet.h> 3910c834c4SHarlan Stenn # endif 401ad03264SNick Mathewson #endif 41e4f24219SNick Mathewson #include <stdlib.h> 42646f9febSSebastian Hahn #include <string.h> 43e4f24219SNick Mathewson #include <errno.h> 44e4f24219SNick Mathewson 45c0bf63ceSEvan Jones #include "event2/event.h" 46c0bf63ceSEvan Jones #include "event2/bufferevent.h" 47c0bf63ceSEvan Jones #include "event2/buffer.h" 48c0bf63ceSEvan Jones #include "event2/util.h" 49e4f24219SNick Mathewson 50e4f24219SNick Mathewson const char *resource = NULL; 51e4f24219SNick Mathewson struct event_base *base = NULL; 52e4f24219SNick Mathewson 53e4f24219SNick Mathewson int total_n_handled = 0; 54e4f24219SNick Mathewson int total_n_errors = 0; 55e4f24219SNick Mathewson int total_n_launched = 0; 56e4f24219SNick Mathewson size_t total_n_bytes = 0; 57e4f24219SNick Mathewson struct timeval total_time = {0,0}; 58e4f24219SNick Mathewson int n_errors = 0; 59e4f24219SNick Mathewson 60b182ed76SNick Mathewson const int PARALLELISM = 200; 61b182ed76SNick Mathewson const int N_REQUESTS = 20000; 62e4f24219SNick Mathewson 63e4f24219SNick Mathewson struct request_info { 64e4f24219SNick Mathewson size_t n_read; 65e4f24219SNick Mathewson struct timeval started; 66e4f24219SNick Mathewson }; 67e4f24219SNick Mathewson 68e4f24219SNick Mathewson static int launch_request(void); 69e4f24219SNick Mathewson static void readcb(struct bufferevent *b, void *arg); 70e4f24219SNick Mathewson static void errorcb(struct bufferevent *b, short what, void *arg); 71e4f24219SNick Mathewson 72e4f24219SNick Mathewson static void 73e4f24219SNick Mathewson readcb(struct bufferevent *b, void *arg) 74e4f24219SNick Mathewson { 75e4f24219SNick Mathewson struct request_info *ri = arg; 76e4f24219SNick Mathewson struct evbuffer *input = bufferevent_get_input(b); 77e4f24219SNick Mathewson size_t n = evbuffer_get_length(input); 78e4f24219SNick Mathewson 79e4f24219SNick Mathewson ri->n_read += n; 80e4f24219SNick Mathewson evbuffer_drain(input, n); 81e4f24219SNick Mathewson } 82e4f24219SNick Mathewson 83e4f24219SNick Mathewson static void 84e4f24219SNick Mathewson errorcb(struct bufferevent *b, short what, void *arg) 85e4f24219SNick Mathewson { 86e4f24219SNick Mathewson struct request_info *ri = arg; 87e4f24219SNick Mathewson struct timeval now, diff; 8883f46e51SNick Mathewson if (what & BEV_EVENT_EOF) { 89e4f24219SNick Mathewson ++total_n_handled; 90e4f24219SNick Mathewson total_n_bytes += ri->n_read; 910de87fe6SPeter Rosin evutil_gettimeofday(&now, NULL); 92e4f24219SNick Mathewson evutil_timersub(&now, &ri->started, &diff); 93e4f24219SNick Mathewson evutil_timeradd(&diff, &total_time, &total_time); 94e4f24219SNick Mathewson 95e4f24219SNick Mathewson if (total_n_handled && (total_n_handled%1000)==0) 96e4f24219SNick Mathewson printf("%d requests done\n",total_n_handled); 97e4f24219SNick Mathewson 98e4f24219SNick Mathewson if (total_n_launched < N_REQUESTS) { 99e4f24219SNick Mathewson if (launch_request() < 0) 100e4f24219SNick Mathewson perror("Can't launch"); 101e4f24219SNick Mathewson } 102e4f24219SNick Mathewson } else { 103e4f24219SNick Mathewson ++total_n_errors; 104e4f24219SNick Mathewson perror("Unexpected error"); 105e4f24219SNick Mathewson } 106e4f24219SNick Mathewson 107e4f24219SNick Mathewson bufferevent_setcb(b, NULL, NULL, NULL, NULL); 108e4f24219SNick Mathewson free(ri); 109e4f24219SNick Mathewson bufferevent_disable(b, EV_READ|EV_WRITE); 110e4f24219SNick Mathewson bufferevent_free(b); 111e4f24219SNick Mathewson } 112e4f24219SNick Mathewson 113b182ed76SNick Mathewson static void 114c7cf6f00SNick Mathewson frob_socket(evutil_socket_t sock) 115b182ed76SNick Mathewson { 1160dda56a4SNicholas Heath #ifdef HAVE_SO_LINGER 117b182ed76SNick Mathewson struct linger l; 1180dda56a4SNicholas Heath #endif 119b182ed76SNick Mathewson int one = 1; 120b9e73297SNick Mathewson if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*)&one, sizeof(one))<0) 121b9e73297SNick Mathewson perror("setsockopt(SO_REUSEADDR)"); 1220dda56a4SNicholas Heath #ifdef HAVE_SO_LINGER 123b182ed76SNick Mathewson l.l_onoff = 1; 124b182ed76SNick Mathewson l.l_linger = 0; 1251ad03264SNick Mathewson if (setsockopt(sock, SOL_SOCKET, SO_LINGER, (void*)&l, sizeof(l))<0) 126b9e73297SNick Mathewson perror("setsockopt(SO_LINGER)"); 1270dda56a4SNicholas Heath #endif 128b182ed76SNick Mathewson } 129b182ed76SNick Mathewson 130e4f24219SNick Mathewson static int 131e4f24219SNick Mathewson launch_request(void) 132e4f24219SNick Mathewson { 133c7cf6f00SNick Mathewson evutil_socket_t sock; 134e4f24219SNick Mathewson struct sockaddr_in sin; 135e4f24219SNick Mathewson struct bufferevent *b; 136e4f24219SNick Mathewson 137e4f24219SNick Mathewson struct request_info *ri; 138e4f24219SNick Mathewson 139646f9febSSebastian Hahn memset(&sin, 0, sizeof(sin)); 140646f9febSSebastian Hahn 141e4f24219SNick Mathewson ++total_n_launched; 142e4f24219SNick Mathewson 143e4f24219SNick Mathewson sin.sin_family = AF_INET; 144e4f24219SNick Mathewson sin.sin_addr.s_addr = htonl(0x7f000001); 145e4f24219SNick Mathewson sin.sin_port = htons(8080); 146e4f24219SNick Mathewson if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) 147e4f24219SNick Mathewson return -1; 148ea92fba3SNick Mathewson if (evutil_make_socket_nonblocking(sock) < 0) { 149ea92fba3SNick Mathewson evutil_closesocket(sock); 150e4f24219SNick Mathewson return -1; 151ea92fba3SNick Mathewson } 152b182ed76SNick Mathewson frob_socket(sock); 153e4f24219SNick Mathewson if (connect(sock, (struct sockaddr*)&sin, sizeof(sin)) < 0) { 154cb969312SSeungmo Koo int e = evutil_socket_geterror(sock); 1551ad03264SNick Mathewson if (! EVUTIL_ERR_CONNECT_RETRIABLE(e)) { 156ea92fba3SNick Mathewson evutil_closesocket(sock); 157e4f24219SNick Mathewson return -1; 158e4f24219SNick Mathewson } 159e4f24219SNick Mathewson } 160e4f24219SNick Mathewson 161e4f24219SNick Mathewson ri = malloc(sizeof(*ri)); 162e4f24219SNick Mathewson ri->n_read = 0; 1630de87fe6SPeter Rosin evutil_gettimeofday(&ri->started, NULL); 164e4f24219SNick Mathewson 165e4f24219SNick Mathewson b = bufferevent_socket_new(base, sock, BEV_OPT_CLOSE_ON_FREE); 166e4f24219SNick Mathewson 167e4f24219SNick Mathewson bufferevent_setcb(b, readcb, NULL, errorcb, ri); 168e4f24219SNick Mathewson bufferevent_enable(b, EV_READ|EV_WRITE); 169e4f24219SNick Mathewson 170e4f24219SNick Mathewson evbuffer_add_printf(bufferevent_get_output(b), 171e4f24219SNick Mathewson "GET %s HTTP/1.0\r\n\r\n", resource); 172e4f24219SNick Mathewson 173e4f24219SNick Mathewson return 0; 174e4f24219SNick Mathewson } 175e4f24219SNick Mathewson 176e4f24219SNick Mathewson 177e4f24219SNick Mathewson int 178e4f24219SNick Mathewson main(int argc, char **argv) 179e4f24219SNick Mathewson { 180e4f24219SNick Mathewson int i; 181e4f24219SNick Mathewson struct timeval start, end, total; 182e4f24219SNick Mathewson long long usec; 183b182ed76SNick Mathewson double throughput; 184e4f24219SNick Mathewson 1854e9325e8Szeliard #ifdef _WIN32 1864e9325e8Szeliard WSADATA WSAData; 1874e9325e8Szeliard WSAStartup(0x101, &WSAData); 1884e9325e8Szeliard #endif 1894e9325e8Szeliard 190*6bf2061cSPhilip Prindeville resource = "/ref"; 191*6bf2061cSPhilip Prindeville 192e4f24219SNick Mathewson setvbuf(stdout, NULL, _IONBF, 0); 193e4f24219SNick Mathewson 194e4f24219SNick Mathewson base = event_base_new(); 195e4f24219SNick Mathewson 196e4f24219SNick Mathewson for (i=0; i < PARALLELISM; ++i) { 197e4f24219SNick Mathewson if (launch_request() < 0) 198e4f24219SNick Mathewson perror("launch"); 199e4f24219SNick Mathewson } 200e4f24219SNick Mathewson 2010de87fe6SPeter Rosin evutil_gettimeofday(&start, NULL); 202e4f24219SNick Mathewson 203e4f24219SNick Mathewson event_base_dispatch(base); 204e4f24219SNick Mathewson 2050de87fe6SPeter Rosin evutil_gettimeofday(&end, NULL); 206e4f24219SNick Mathewson evutil_timersub(&end, &start, &total); 20756710337SNick Mathewson usec = total_time.tv_sec * (long long)1000000 + total_time.tv_usec; 208e4f24219SNick Mathewson 209b182ed76SNick Mathewson if (!total_n_handled) { 210b182ed76SNick Mathewson puts("Nothing worked. You probably did something dumb."); 211b182ed76SNick Mathewson return 0; 212b182ed76SNick Mathewson } 213b182ed76SNick Mathewson 214b182ed76SNick Mathewson 215b182ed76SNick Mathewson throughput = total_n_handled / 216b182ed76SNick Mathewson (total.tv_sec+ ((double)total.tv_usec)/1000000.0); 217b182ed76SNick Mathewson 2189f560bfaSNick Mathewson #ifdef _WIN32 2195b7a3706SNick Mathewson #define I64_FMT "%I64d" 2205b7a3706SNick Mathewson #define I64_TYP __int64 2215b7a3706SNick Mathewson #else 2225b7a3706SNick Mathewson #define I64_FMT "%lld" 2235b7a3706SNick Mathewson #define I64_TYP long long int 2245b7a3706SNick Mathewson #endif 2255b7a3706SNick Mathewson 226b182ed76SNick Mathewson printf("\n%d requests in %d.%06d sec. (%.2f throughput)\n" 227b182ed76SNick Mathewson "Each took about %.02f msec latency\n" 2285b7a3706SNick Mathewson I64_FMT "bytes read. %d errors.\n", 229e4f24219SNick Mathewson total_n_handled, 2301bb8e010SNick Mathewson (int)total.tv_sec, (int)total.tv_usec, 231b182ed76SNick Mathewson throughput, 232b182ed76SNick Mathewson (double)(usec/1000) / total_n_handled, 2335b7a3706SNick Mathewson (I64_TYP)total_n_bytes, n_errors); 234e4f24219SNick Mathewson 2354e9325e8Szeliard #ifdef _WIN32 2364e9325e8Szeliard WSACleanup(); 2374e9325e8Szeliard #endif 2384e9325e8Szeliard 239e4f24219SNick Mathewson return 0; 240e4f24219SNick Mathewson } 241