12b15cb3dSCy Schubert /*
22b15cb3dSCy Schubert * Copyright (c) 2012 Ross Lagerwall <rosslagerwall@gmail.com>
32b15cb3dSCy Schubert *
42b15cb3dSCy Schubert * Redistribution and use in source and binary forms, with or without
52b15cb3dSCy Schubert * modification, are permitted provided that the following conditions
62b15cb3dSCy Schubert * are met:
72b15cb3dSCy Schubert * 1. Redistributions of source code must retain the above copyright
82b15cb3dSCy Schubert * notice, this list of conditions and the following disclaimer.
92b15cb3dSCy Schubert * 2. Redistributions in binary form must reproduce the above copyright
102b15cb3dSCy Schubert * notice, this list of conditions and the following disclaimer in the
112b15cb3dSCy Schubert * documentation and/or other materials provided with the distribution.
122b15cb3dSCy Schubert * 3. The name of the author may not be used to endorse or promote products
132b15cb3dSCy Schubert * derived from this software without specific prior written permission.
142b15cb3dSCy Schubert *
152b15cb3dSCy Schubert * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
162b15cb3dSCy Schubert * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
172b15cb3dSCy Schubert * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
182b15cb3dSCy Schubert * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
192b15cb3dSCy Schubert * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
202b15cb3dSCy Schubert * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
212b15cb3dSCy Schubert * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
222b15cb3dSCy Schubert * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
232b15cb3dSCy Schubert * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
242b15cb3dSCy Schubert * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
252b15cb3dSCy Schubert */
262b15cb3dSCy Schubert
272b15cb3dSCy Schubert #include "event2/event-config.h"
282b15cb3dSCy Schubert
292b15cb3dSCy Schubert #ifdef _WIN32
302b15cb3dSCy Schubert #define WIN32_LEAN_AND_MEAN
312b15cb3dSCy Schubert #include <windows.h>
322b15cb3dSCy Schubert #endif
332b15cb3dSCy Schubert #include <string.h>
342b15cb3dSCy Schubert #include <stdlib.h>
352b15cb3dSCy Schubert #include <errno.h>
362b15cb3dSCy Schubert #ifdef EVENT__HAVE_SYS_TIME_H
372b15cb3dSCy Schubert #include <sys/time.h>
382b15cb3dSCy Schubert #endif
392b15cb3dSCy Schubert #ifdef EVENT__HAVE_SYS_RESOURCE_H
402b15cb3dSCy Schubert #include <sys/resource.h>
412b15cb3dSCy Schubert #endif
422b15cb3dSCy Schubert #ifdef EVENT__HAVE_NETINET_IN_H
432b15cb3dSCy Schubert #include <netinet/in.h>
442b15cb3dSCy Schubert #endif
452b15cb3dSCy Schubert
462b15cb3dSCy Schubert #include "event2/event.h"
472b15cb3dSCy Schubert #include "event2/bufferevent.h"
482b15cb3dSCy Schubert #include "event2/buffer.h"
492b15cb3dSCy Schubert #include "event2/listener.h"
502b15cb3dSCy Schubert
512b15cb3dSCy Schubert /* Number of requests to make. Setting this too high might result in the machine
522b15cb3dSCy Schubert running out of ephemeral ports */
532b15cb3dSCy Schubert #ifdef _WIN32
542b15cb3dSCy Schubert #define MAX_REQUESTS 1000
552b15cb3dSCy Schubert #else
562b15cb3dSCy Schubert #define MAX_REQUESTS 4000
572b15cb3dSCy Schubert #endif
582b15cb3dSCy Schubert
592b15cb3dSCy Schubert /* Provide storage for the address, both for the server & the clients */
60a25439b6SCy Schubert static struct sockaddr_in saddr;
612b15cb3dSCy Schubert
622b15cb3dSCy Schubert /* Number of sucessful requests so far */
632b15cb3dSCy Schubert static int num_requests;
642b15cb3dSCy Schubert
652b15cb3dSCy Schubert static void start_client(struct event_base *base);
662b15cb3dSCy Schubert
672b15cb3dSCy Schubert static void
my_perror(const char * s)682b15cb3dSCy Schubert my_perror(const char *s)
692b15cb3dSCy Schubert {
702b15cb3dSCy Schubert fprintf(stderr, "%s: %s",
712b15cb3dSCy Schubert s, evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR()));
722b15cb3dSCy Schubert }
732b15cb3dSCy Schubert
742b15cb3dSCy Schubert /*
752b15cb3dSCy Schubert ===============================================
762b15cb3dSCy Schubert Server functions
772b15cb3dSCy Schubert ===============================================
782b15cb3dSCy Schubert */
792b15cb3dSCy Schubert
802b15cb3dSCy Schubert /* Read a byte from the client and write it back */
812b15cb3dSCy Schubert static void
server_read_cb(struct bufferevent * bev,void * ctx)822b15cb3dSCy Schubert server_read_cb(struct bufferevent *bev, void *ctx)
832b15cb3dSCy Schubert {
842b15cb3dSCy Schubert while (evbuffer_get_length(bufferevent_get_input(bev))) {
852b15cb3dSCy Schubert unsigned char tmp;
862b15cb3dSCy Schubert bufferevent_read(bev, &tmp, 1);
872b15cb3dSCy Schubert bufferevent_write(bev, &tmp, 1);
882b15cb3dSCy Schubert }
892b15cb3dSCy Schubert }
902b15cb3dSCy Schubert
912b15cb3dSCy Schubert /* Wait for an EOF and then free the bufferevent */
922b15cb3dSCy Schubert static void
server_event_cb(struct bufferevent * bev,short events,void * ctx)932b15cb3dSCy Schubert server_event_cb(struct bufferevent *bev, short events, void *ctx)
942b15cb3dSCy Schubert {
952b15cb3dSCy Schubert if (events & BEV_EVENT_ERROR) {
962b15cb3dSCy Schubert my_perror("Error from bufferevent");
972b15cb3dSCy Schubert exit(1);
98*a466cc55SCy Schubert } else if (events & BEV_EVENT_EOF) {
992b15cb3dSCy Schubert bufferevent_free(bev);
100*a466cc55SCy Schubert if (num_requests == MAX_REQUESTS) {
101*a466cc55SCy Schubert event_base_loopbreak(bufferevent_get_base(bev));
102*a466cc55SCy Schubert }
1032b15cb3dSCy Schubert }
1042b15cb3dSCy Schubert }
1052b15cb3dSCy Schubert
1062b15cb3dSCy Schubert /* Accept a client socket and set it up to for reading & writing */
1072b15cb3dSCy Schubert static void
listener_accept_cb(struct evconnlistener * listener,evutil_socket_t sock,struct sockaddr * addr,int len,void * ptr)1082b15cb3dSCy Schubert listener_accept_cb(struct evconnlistener *listener, evutil_socket_t sock,
1092b15cb3dSCy Schubert struct sockaddr *addr, int len, void *ptr)
1102b15cb3dSCy Schubert {
1112b15cb3dSCy Schubert struct event_base *base = evconnlistener_get_base(listener);
1122b15cb3dSCy Schubert struct bufferevent *bev = bufferevent_socket_new(base, sock,
1132b15cb3dSCy Schubert BEV_OPT_CLOSE_ON_FREE);
1142b15cb3dSCy Schubert bufferevent_setcb(bev, server_read_cb, NULL, server_event_cb, NULL);
1152b15cb3dSCy Schubert bufferevent_enable(bev, EV_READ|EV_WRITE);
1162b15cb3dSCy Schubert }
1172b15cb3dSCy Schubert
1182b15cb3dSCy Schubert /* Start the server listening on a random port and start the first client. */
1192b15cb3dSCy Schubert static void
start_loop(void)1202b15cb3dSCy Schubert start_loop(void)
1212b15cb3dSCy Schubert {
1222b15cb3dSCy Schubert struct event_base *base;
1232b15cb3dSCy Schubert struct evconnlistener *listener;
1242b15cb3dSCy Schubert struct sockaddr_storage ss;
1252b15cb3dSCy Schubert ev_socklen_t socklen = sizeof(ss);
1262b15cb3dSCy Schubert evutil_socket_t fd;
1272b15cb3dSCy Schubert
1282b15cb3dSCy Schubert base = event_base_new();
1292b15cb3dSCy Schubert if (base == NULL) {
1302b15cb3dSCy Schubert puts("Could not open event base!");
1312b15cb3dSCy Schubert exit(1);
1322b15cb3dSCy Schubert }
1332b15cb3dSCy Schubert
1342b15cb3dSCy Schubert listener = evconnlistener_new_bind(base, listener_accept_cb, NULL,
1352b15cb3dSCy Schubert LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE,
136a25439b6SCy Schubert -1, (struct sockaddr *)&saddr, sizeof(saddr));
1372b15cb3dSCy Schubert if (listener == NULL) {
1382b15cb3dSCy Schubert my_perror("Could not create listener!");
1392b15cb3dSCy Schubert exit(1);
1402b15cb3dSCy Schubert }
1412b15cb3dSCy Schubert fd = evconnlistener_get_fd(listener);
1422b15cb3dSCy Schubert if (fd < 0) {
1432b15cb3dSCy Schubert puts("Couldn't get fd from listener");
1442b15cb3dSCy Schubert exit(1);
1452b15cb3dSCy Schubert }
1462b15cb3dSCy Schubert if (getsockname(fd, (struct sockaddr *)&ss, &socklen) < 0) {
1472b15cb3dSCy Schubert my_perror("getsockname()");
1482b15cb3dSCy Schubert exit(1);
1492b15cb3dSCy Schubert }
150a25439b6SCy Schubert memcpy(&saddr, &ss, sizeof(saddr));
151a25439b6SCy Schubert if (saddr.sin_family != AF_INET) {
1522b15cb3dSCy Schubert puts("AF mismatch from getsockname().");
1532b15cb3dSCy Schubert exit(1);
1542b15cb3dSCy Schubert }
1552b15cb3dSCy Schubert
1562b15cb3dSCy Schubert start_client(base);
1572b15cb3dSCy Schubert
1582b15cb3dSCy Schubert event_base_dispatch(base);
159*a466cc55SCy Schubert
160*a466cc55SCy Schubert evconnlistener_free(listener);
161*a466cc55SCy Schubert event_base_free(base);
1622b15cb3dSCy Schubert }
1632b15cb3dSCy Schubert
1642b15cb3dSCy Schubert /*
1652b15cb3dSCy Schubert ===============================================
1662b15cb3dSCy Schubert Client functions
1672b15cb3dSCy Schubert ===============================================
1682b15cb3dSCy Schubert */
1692b15cb3dSCy Schubert
1702b15cb3dSCy Schubert /* Check that the server sends back the same byte that the client sent.
1712b15cb3dSCy Schubert If MAX_REQUESTS have been reached, exit. Otherwise, start another client. */
1722b15cb3dSCy Schubert static void
client_read_cb(struct bufferevent * bev,void * ctx)1732b15cb3dSCy Schubert client_read_cb(struct bufferevent *bev, void *ctx)
1742b15cb3dSCy Schubert {
1752b15cb3dSCy Schubert unsigned char tmp;
1762b15cb3dSCy Schubert struct event_base *base = bufferevent_get_base(bev);
1772b15cb3dSCy Schubert
1782b15cb3dSCy Schubert bufferevent_read(bev, &tmp, 1);
1792b15cb3dSCy Schubert if (tmp != 'A') {
1802b15cb3dSCy Schubert puts("Incorrect data received!");
1812b15cb3dSCy Schubert exit(2);
1822b15cb3dSCy Schubert }
1832b15cb3dSCy Schubert bufferevent_free(bev);
1842b15cb3dSCy Schubert
1852b15cb3dSCy Schubert num_requests++;
186*a466cc55SCy Schubert if (++num_requests < MAX_REQUESTS) {
1872b15cb3dSCy Schubert start_client(base);
1882b15cb3dSCy Schubert }
1892b15cb3dSCy Schubert }
1902b15cb3dSCy Schubert
1912b15cb3dSCy Schubert /* Send a byte to the server. */
1922b15cb3dSCy Schubert static void
client_event_cb(struct bufferevent * bev,short events,void * ctx)1932b15cb3dSCy Schubert client_event_cb(struct bufferevent *bev, short events, void *ctx)
1942b15cb3dSCy Schubert {
1952b15cb3dSCy Schubert if (events & BEV_EVENT_CONNECTED) {
1962b15cb3dSCy Schubert unsigned char tmp = 'A';
1972b15cb3dSCy Schubert bufferevent_write(bev, &tmp, 1);
1982b15cb3dSCy Schubert } else if (events & BEV_EVENT_ERROR) {
1992b15cb3dSCy Schubert puts("Client socket got error!");
2002b15cb3dSCy Schubert exit(2);
2012b15cb3dSCy Schubert }
2022b15cb3dSCy Schubert
2032b15cb3dSCy Schubert bufferevent_enable(bev, EV_READ);
2042b15cb3dSCy Schubert }
2052b15cb3dSCy Schubert
2062b15cb3dSCy Schubert /* Open a client socket to connect to localhost on sin */
2072b15cb3dSCy Schubert static void
start_client(struct event_base * base)2082b15cb3dSCy Schubert start_client(struct event_base *base)
2092b15cb3dSCy Schubert {
2102b15cb3dSCy Schubert struct bufferevent *bev = bufferevent_socket_new(base, -1,
2112b15cb3dSCy Schubert BEV_OPT_CLOSE_ON_FREE);
2122b15cb3dSCy Schubert bufferevent_setcb(bev, client_read_cb, NULL, client_event_cb, NULL);
2132b15cb3dSCy Schubert
214a25439b6SCy Schubert if (bufferevent_socket_connect(bev, (struct sockaddr *)&saddr,
215a25439b6SCy Schubert sizeof(saddr)) < 0) {
2162b15cb3dSCy Schubert my_perror("Could not connect!");
2172b15cb3dSCy Schubert bufferevent_free(bev);
2182b15cb3dSCy Schubert exit(2);
2192b15cb3dSCy Schubert }
2202b15cb3dSCy Schubert }
2212b15cb3dSCy Schubert
2222b15cb3dSCy Schubert int
main(int argc,char ** argv)2232b15cb3dSCy Schubert main(int argc, char **argv)
2242b15cb3dSCy Schubert {
2252b15cb3dSCy Schubert #ifdef EVENT__HAVE_SETRLIMIT
2262b15cb3dSCy Schubert /* Set the fd limit to a low value so that any fd leak is caught without
2272b15cb3dSCy Schubert making many requests. */
2282b15cb3dSCy Schubert struct rlimit rl;
2292b15cb3dSCy Schubert rl.rlim_cur = rl.rlim_max = 20;
2302b15cb3dSCy Schubert if (setrlimit(RLIMIT_NOFILE, &rl) == -1) {
2312b15cb3dSCy Schubert my_perror("setrlimit");
2322b15cb3dSCy Schubert exit(3);
2332b15cb3dSCy Schubert }
2342b15cb3dSCy Schubert #endif
2352b15cb3dSCy Schubert
2362b15cb3dSCy Schubert #ifdef _WIN32
2372b15cb3dSCy Schubert WSADATA WSAData;
2382b15cb3dSCy Schubert WSAStartup(0x101, &WSAData);
2392b15cb3dSCy Schubert #endif
2402b15cb3dSCy Schubert
2412b15cb3dSCy Schubert /* Set up an address, used by both client & server. */
242a25439b6SCy Schubert memset(&saddr, 0, sizeof(saddr));
243a25439b6SCy Schubert saddr.sin_family = AF_INET;
244a25439b6SCy Schubert saddr.sin_addr.s_addr = htonl(0x7f000001);
245a25439b6SCy Schubert saddr.sin_port = 0; /* Tell the implementation to pick a port. */
2462b15cb3dSCy Schubert
2472b15cb3dSCy Schubert start_loop();
2482b15cb3dSCy Schubert
2492b15cb3dSCy Schubert return 0;
2502b15cb3dSCy Schubert }
2512b15cb3dSCy Schubert
2522b15cb3dSCy Schubert /* XXX why does this test cause so much latency sometimes (OSX 10.5)? */
253