1275970Scy/* 2275970Scy * Copyright (c) 2012 Ross Lagerwall <rosslagerwall@gmail.com> 3275970Scy * 4275970Scy * Redistribution and use in source and binary forms, with or without 5275970Scy * modification, are permitted provided that the following conditions 6275970Scy * are met: 7275970Scy * 1. Redistributions of source code must retain the above copyright 8275970Scy * notice, this list of conditions and the following disclaimer. 9275970Scy * 2. Redistributions in binary form must reproduce the above copyright 10275970Scy * notice, this list of conditions and the following disclaimer in the 11275970Scy * documentation and/or other materials provided with the distribution. 12275970Scy * 3. The name of the author may not be used to endorse or promote products 13275970Scy * derived from this software without specific prior written permission. 14275970Scy * 15275970Scy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16275970Scy * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17275970Scy * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18275970Scy * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19275970Scy * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20275970Scy * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21275970Scy * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22275970Scy * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23275970Scy * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24275970Scy * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25275970Scy */ 26275970Scy 27275970Scy#include "event2/event-config.h" 28275970Scy 29275970Scy#ifdef _WIN32 30275970Scy#define WIN32_LEAN_AND_MEAN 31275970Scy#include <windows.h> 32275970Scy#endif 33275970Scy#include <string.h> 34275970Scy#include <stdlib.h> 35275970Scy#include <errno.h> 36275970Scy#ifdef EVENT__HAVE_SYS_TIME_H 37275970Scy#include <sys/time.h> 38275970Scy#endif 39275970Scy#ifdef EVENT__HAVE_SYS_RESOURCE_H 40275970Scy#include <sys/resource.h> 41275970Scy#endif 42275970Scy#ifdef EVENT__HAVE_NETINET_IN_H 43275970Scy#include <netinet/in.h> 44275970Scy#endif 45275970Scy 46275970Scy#include "event2/event.h" 47275970Scy#include "event2/bufferevent.h" 48275970Scy#include "event2/buffer.h" 49275970Scy#include "event2/listener.h" 50275970Scy 51275970Scy/* Number of requests to make. Setting this too high might result in the machine 52275970Scy running out of ephemeral ports */ 53275970Scy#ifdef _WIN32 54275970Scy#define MAX_REQUESTS 1000 55275970Scy#else 56275970Scy#define MAX_REQUESTS 4000 57275970Scy#endif 58275970Scy 59275970Scy/* Provide storage for the address, both for the server & the clients */ 60282408Scystatic struct sockaddr_in saddr; 61275970Scy 62275970Scy/* Number of sucessful requests so far */ 63275970Scystatic int num_requests; 64275970Scy 65275970Scystatic void start_client(struct event_base *base); 66275970Scy 67275970Scystatic void 68275970Scymy_perror(const char *s) 69275970Scy{ 70275970Scy fprintf(stderr, "%s: %s", 71275970Scy s, evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR())); 72275970Scy} 73275970Scy 74275970Scy/* 75275970Scy=============================================== 76275970ScyServer functions 77275970Scy=============================================== 78275970Scy*/ 79275970Scy 80275970Scy/* Read a byte from the client and write it back */ 81275970Scystatic void 82275970Scyserver_read_cb(struct bufferevent *bev, void *ctx) 83275970Scy{ 84275970Scy while (evbuffer_get_length(bufferevent_get_input(bev))) { 85275970Scy unsigned char tmp; 86275970Scy bufferevent_read(bev, &tmp, 1); 87275970Scy bufferevent_write(bev, &tmp, 1); 88275970Scy } 89275970Scy} 90275970Scy 91275970Scy/* Wait for an EOF and then free the bufferevent */ 92275970Scystatic void 93275970Scyserver_event_cb(struct bufferevent *bev, short events, void *ctx) 94275970Scy{ 95275970Scy if (events & BEV_EVENT_ERROR) { 96275970Scy my_perror("Error from bufferevent"); 97275970Scy exit(1); 98275970Scy } else if (events & (BEV_EVENT_EOF | BEV_EVENT_ERROR)) { 99275970Scy bufferevent_free(bev); 100275970Scy } 101275970Scy} 102275970Scy 103275970Scy/* Accept a client socket and set it up to for reading & writing */ 104275970Scystatic void 105275970Scylistener_accept_cb(struct evconnlistener *listener, evutil_socket_t sock, 106275970Scy struct sockaddr *addr, int len, void *ptr) 107275970Scy{ 108275970Scy struct event_base *base = evconnlistener_get_base(listener); 109275970Scy struct bufferevent *bev = bufferevent_socket_new(base, sock, 110275970Scy BEV_OPT_CLOSE_ON_FREE); 111275970Scy 112275970Scy bufferevent_setcb(bev, server_read_cb, NULL, server_event_cb, NULL); 113275970Scy bufferevent_enable(bev, EV_READ|EV_WRITE); 114275970Scy} 115275970Scy 116275970Scy/* Start the server listening on a random port and start the first client. */ 117275970Scystatic void 118275970Scystart_loop(void) 119275970Scy{ 120275970Scy struct event_base *base; 121275970Scy struct evconnlistener *listener; 122275970Scy struct sockaddr_storage ss; 123275970Scy ev_socklen_t socklen = sizeof(ss); 124275970Scy evutil_socket_t fd; 125275970Scy 126275970Scy base = event_base_new(); 127275970Scy if (base == NULL) { 128275970Scy puts("Could not open event base!"); 129275970Scy exit(1); 130275970Scy } 131275970Scy 132275970Scy listener = evconnlistener_new_bind(base, listener_accept_cb, NULL, 133275970Scy LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE, 134282408Scy -1, (struct sockaddr *)&saddr, sizeof(saddr)); 135275970Scy if (listener == NULL) { 136275970Scy my_perror("Could not create listener!"); 137275970Scy exit(1); 138275970Scy } 139275970Scy fd = evconnlistener_get_fd(listener); 140275970Scy if (fd < 0) { 141275970Scy puts("Couldn't get fd from listener"); 142275970Scy exit(1); 143275970Scy } 144275970Scy if (getsockname(fd, (struct sockaddr *)&ss, &socklen) < 0) { 145275970Scy my_perror("getsockname()"); 146275970Scy exit(1); 147275970Scy } 148282408Scy memcpy(&saddr, &ss, sizeof(saddr)); 149282408Scy if (saddr.sin_family != AF_INET) { 150275970Scy puts("AF mismatch from getsockname()."); 151275970Scy exit(1); 152275970Scy } 153275970Scy 154275970Scy start_client(base); 155275970Scy 156275970Scy event_base_dispatch(base); 157275970Scy} 158275970Scy 159275970Scy/* 160275970Scy=============================================== 161275970ScyClient functions 162275970Scy=============================================== 163275970Scy*/ 164275970Scy 165275970Scy/* Check that the server sends back the same byte that the client sent. 166275970Scy If MAX_REQUESTS have been reached, exit. Otherwise, start another client. */ 167275970Scystatic void 168275970Scyclient_read_cb(struct bufferevent *bev, void *ctx) 169275970Scy{ 170275970Scy unsigned char tmp; 171275970Scy struct event_base *base = bufferevent_get_base(bev); 172275970Scy 173275970Scy bufferevent_read(bev, &tmp, 1); 174275970Scy if (tmp != 'A') { 175275970Scy puts("Incorrect data received!"); 176275970Scy exit(2); 177275970Scy } 178275970Scy bufferevent_free(bev); 179275970Scy 180275970Scy num_requests++; 181275970Scy if (num_requests == MAX_REQUESTS) { 182275970Scy event_base_loopbreak(base); 183275970Scy } else { 184275970Scy start_client(base); 185275970Scy } 186275970Scy} 187275970Scy 188275970Scy/* Send a byte to the server. */ 189275970Scystatic void 190275970Scyclient_event_cb(struct bufferevent *bev, short events, void *ctx) 191275970Scy{ 192275970Scy if (events & BEV_EVENT_CONNECTED) { 193275970Scy unsigned char tmp = 'A'; 194275970Scy bufferevent_write(bev, &tmp, 1); 195275970Scy } else if (events & BEV_EVENT_ERROR) { 196275970Scy puts("Client socket got error!"); 197275970Scy exit(2); 198275970Scy } 199275970Scy 200275970Scy bufferevent_enable(bev, EV_READ); 201275970Scy} 202275970Scy 203275970Scy/* Open a client socket to connect to localhost on sin */ 204275970Scystatic void 205275970Scystart_client(struct event_base *base) 206275970Scy{ 207275970Scy struct bufferevent *bev = bufferevent_socket_new(base, -1, 208275970Scy BEV_OPT_CLOSE_ON_FREE); 209275970Scy bufferevent_setcb(bev, client_read_cb, NULL, client_event_cb, NULL); 210275970Scy 211282408Scy if (bufferevent_socket_connect(bev, (struct sockaddr *)&saddr, 212282408Scy sizeof(saddr)) < 0) { 213275970Scy my_perror("Could not connect!"); 214275970Scy bufferevent_free(bev); 215275970Scy exit(2); 216275970Scy } 217275970Scy} 218275970Scy 219275970Scyint 220275970Scymain(int argc, char **argv) 221275970Scy{ 222275970Scy#ifdef EVENT__HAVE_SETRLIMIT 223275970Scy /* Set the fd limit to a low value so that any fd leak is caught without 224275970Scy making many requests. */ 225275970Scy struct rlimit rl; 226275970Scy rl.rlim_cur = rl.rlim_max = 20; 227275970Scy if (setrlimit(RLIMIT_NOFILE, &rl) == -1) { 228275970Scy my_perror("setrlimit"); 229275970Scy exit(3); 230275970Scy } 231275970Scy#endif 232275970Scy 233275970Scy#ifdef _WIN32 234275970Scy WSADATA WSAData; 235275970Scy WSAStartup(0x101, &WSAData); 236275970Scy#endif 237275970Scy 238275970Scy /* Set up an address, used by both client & server. */ 239282408Scy memset(&saddr, 0, sizeof(saddr)); 240282408Scy saddr.sin_family = AF_INET; 241282408Scy saddr.sin_addr.s_addr = htonl(0x7f000001); 242282408Scy saddr.sin_port = 0; /* Tell the implementation to pick a port. */ 243275970Scy 244275970Scy start_loop(); 245275970Scy 246275970Scy return 0; 247275970Scy} 248275970Scy 249275970Scy/* XXX why does this test cause so much latency sometimes (OSX 10.5)? */ 250