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