1 /* 2 * Copyright (c) 2012 Ross Lagerwall <rosslagerwall@gmail.com> 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 3. The name of the author may not be used to endorse or promote products 13 * derived from this software without specific prior written permission. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include "event2/event-config.h" 28 29 #ifdef _WIN32 30 #define WIN32_LEAN_AND_MEAN 31 #include <windows.h> 32 #endif 33 #include <string.h> 34 #include <stdlib.h> 35 #include <errno.h> 36 #ifdef EVENT__HAVE_SYS_TIME_H 37 #include <sys/time.h> 38 #endif 39 #ifdef EVENT__HAVE_SYS_RESOURCE_H 40 #include <sys/resource.h> 41 #endif 42 #ifdef EVENT__HAVE_NETINET_IN_H 43 #include <netinet/in.h> 44 #endif 45 46 #include "event2/event.h" 47 #include "event2/bufferevent.h" 48 #include "event2/buffer.h" 49 #include "event2/listener.h" 50 51 /* Number of requests to make. Setting this too high might result in the machine 52 running out of ephemeral ports */ 53 #ifdef _WIN32 54 #define MAX_REQUESTS 1000 55 #else 56 #define MAX_REQUESTS 4000 57 #endif 58 59 /* Provide storage for the address, both for the server & the clients */ 60 static struct sockaddr_in saddr; 61 62 /* Number of sucessful requests so far */ 63 static int num_requests; 64 65 static void start_client(struct event_base *base); 66 67 static void 68 my_perror(const char *s) 69 { 70 fprintf(stderr, "%s: %s", 71 s, evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR())); 72 } 73 74 /* 75 =============================================== 76 Server functions 77 =============================================== 78 */ 79 80 /* Read a byte from the client and write it back */ 81 static void 82 server_read_cb(struct bufferevent *bev, void *ctx) 83 { 84 while (evbuffer_get_length(bufferevent_get_input(bev))) { 85 unsigned char tmp; 86 bufferevent_read(bev, &tmp, 1); 87 bufferevent_write(bev, &tmp, 1); 88 } 89 } 90 91 /* Wait for an EOF and then free the bufferevent */ 92 static void 93 server_event_cb(struct bufferevent *bev, short events, void *ctx) 94 { 95 if (events & BEV_EVENT_ERROR) { 96 my_perror("Error from bufferevent"); 97 exit(1); 98 } else if (events & BEV_EVENT_EOF) { 99 bufferevent_free(bev); 100 if (num_requests == MAX_REQUESTS) { 101 event_base_loopbreak(bufferevent_get_base(bev)); 102 } 103 } 104 } 105 106 /* Accept a client socket and set it up to for reading & writing */ 107 static void 108 listener_accept_cb(struct evconnlistener *listener, evutil_socket_t sock, 109 struct sockaddr *addr, int len, void *ptr) 110 { 111 struct event_base *base = evconnlistener_get_base(listener); 112 struct bufferevent *bev = bufferevent_socket_new(base, sock, 113 BEV_OPT_CLOSE_ON_FREE); 114 bufferevent_setcb(bev, server_read_cb, NULL, server_event_cb, NULL); 115 bufferevent_enable(bev, EV_READ|EV_WRITE); 116 } 117 118 /* Start the server listening on a random port and start the first client. */ 119 static void 120 start_loop(void) 121 { 122 struct event_base *base; 123 struct evconnlistener *listener; 124 struct sockaddr_storage ss; 125 ev_socklen_t socklen = sizeof(ss); 126 evutil_socket_t fd; 127 128 base = event_base_new(); 129 if (base == NULL) { 130 puts("Could not open event base!"); 131 exit(1); 132 } 133 134 listener = evconnlistener_new_bind(base, listener_accept_cb, NULL, 135 LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE, 136 -1, (struct sockaddr *)&saddr, sizeof(saddr)); 137 if (listener == NULL) { 138 my_perror("Could not create listener!"); 139 exit(1); 140 } 141 fd = evconnlistener_get_fd(listener); 142 if (fd < 0) { 143 puts("Couldn't get fd from listener"); 144 exit(1); 145 } 146 if (getsockname(fd, (struct sockaddr *)&ss, &socklen) < 0) { 147 my_perror("getsockname()"); 148 exit(1); 149 } 150 memcpy(&saddr, &ss, sizeof(saddr)); 151 if (saddr.sin_family != AF_INET) { 152 puts("AF mismatch from getsockname()."); 153 exit(1); 154 } 155 156 start_client(base); 157 158 event_base_dispatch(base); 159 160 evconnlistener_free(listener); 161 event_base_free(base); 162 } 163 164 /* 165 =============================================== 166 Client functions 167 =============================================== 168 */ 169 170 /* Check that the server sends back the same byte that the client sent. 171 If MAX_REQUESTS have been reached, exit. Otherwise, start another client. */ 172 static void 173 client_read_cb(struct bufferevent *bev, void *ctx) 174 { 175 unsigned char tmp; 176 struct event_base *base = bufferevent_get_base(bev); 177 178 bufferevent_read(bev, &tmp, 1); 179 if (tmp != 'A') { 180 puts("Incorrect data received!"); 181 exit(2); 182 } 183 bufferevent_free(bev); 184 185 num_requests++; 186 if (++num_requests < MAX_REQUESTS) { 187 start_client(base); 188 } 189 } 190 191 /* Send a byte to the server. */ 192 static void 193 client_event_cb(struct bufferevent *bev, short events, void *ctx) 194 { 195 if (events & BEV_EVENT_CONNECTED) { 196 unsigned char tmp = 'A'; 197 bufferevent_write(bev, &tmp, 1); 198 } else if (events & BEV_EVENT_ERROR) { 199 puts("Client socket got error!"); 200 exit(2); 201 } 202 203 bufferevent_enable(bev, EV_READ); 204 } 205 206 /* Open a client socket to connect to localhost on sin */ 207 static void 208 start_client(struct event_base *base) 209 { 210 struct bufferevent *bev = bufferevent_socket_new(base, -1, 211 BEV_OPT_CLOSE_ON_FREE); 212 bufferevent_setcb(bev, client_read_cb, NULL, client_event_cb, NULL); 213 214 if (bufferevent_socket_connect(bev, (struct sockaddr *)&saddr, 215 sizeof(saddr)) < 0) { 216 my_perror("Could not connect!"); 217 bufferevent_free(bev); 218 exit(2); 219 } 220 } 221 222 int 223 main(int argc, char **argv) 224 { 225 #ifdef EVENT__HAVE_SETRLIMIT 226 /* Set the fd limit to a low value so that any fd leak is caught without 227 making many requests. */ 228 struct rlimit rl; 229 rl.rlim_cur = rl.rlim_max = 20; 230 if (setrlimit(RLIMIT_NOFILE, &rl) == -1) { 231 my_perror("setrlimit"); 232 exit(3); 233 } 234 #endif 235 236 #ifdef _WIN32 237 WSADATA WSAData; 238 WSAStartup(0x101, &WSAData); 239 #endif 240 241 /* Set up an address, used by both client & server. */ 242 memset(&saddr, 0, sizeof(saddr)); 243 saddr.sin_family = AF_INET; 244 saddr.sin_addr.s_addr = htonl(0x7f000001); 245 saddr.sin_port = 0; /* Tell the implementation to pick a port. */ 246 247 start_loop(); 248 249 return 0; 250 } 251 252 /* XXX why does this test cause so much latency sometimes (OSX 10.5)? */ 253