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 | BEV_EVENT_ERROR)) { 99 bufferevent_free(bev); 100 } 101 } 102 103 /* Accept a client socket and set it up to for reading & writing */ 104 static void 105 listener_accept_cb(struct evconnlistener *listener, evutil_socket_t sock, 106 struct sockaddr *addr, int len, void *ptr) 107 { 108 struct event_base *base = evconnlistener_get_base(listener); 109 struct bufferevent *bev = bufferevent_socket_new(base, sock, 110 BEV_OPT_CLOSE_ON_FREE); 111 112 bufferevent_setcb(bev, server_read_cb, NULL, server_event_cb, NULL); 113 bufferevent_enable(bev, EV_READ|EV_WRITE); 114 } 115 116 /* Start the server listening on a random port and start the first client. */ 117 static void 118 start_loop(void) 119 { 120 struct event_base *base; 121 struct evconnlistener *listener; 122 struct sockaddr_storage ss; 123 ev_socklen_t socklen = sizeof(ss); 124 evutil_socket_t fd; 125 126 base = event_base_new(); 127 if (base == NULL) { 128 puts("Could not open event base!"); 129 exit(1); 130 } 131 132 listener = evconnlistener_new_bind(base, listener_accept_cb, NULL, 133 LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE, 134 -1, (struct sockaddr *)&saddr, sizeof(saddr)); 135 if (listener == NULL) { 136 my_perror("Could not create listener!"); 137 exit(1); 138 } 139 fd = evconnlistener_get_fd(listener); 140 if (fd < 0) { 141 puts("Couldn't get fd from listener"); 142 exit(1); 143 } 144 if (getsockname(fd, (struct sockaddr *)&ss, &socklen) < 0) { 145 my_perror("getsockname()"); 146 exit(1); 147 } 148 memcpy(&saddr, &ss, sizeof(saddr)); 149 if (saddr.sin_family != AF_INET) { 150 puts("AF mismatch from getsockname()."); 151 exit(1); 152 } 153 154 start_client(base); 155 156 event_base_dispatch(base); 157 } 158 159 /* 160 =============================================== 161 Client functions 162 =============================================== 163 */ 164 165 /* Check that the server sends back the same byte that the client sent. 166 If MAX_REQUESTS have been reached, exit. Otherwise, start another client. */ 167 static void 168 client_read_cb(struct bufferevent *bev, void *ctx) 169 { 170 unsigned char tmp; 171 struct event_base *base = bufferevent_get_base(bev); 172 173 bufferevent_read(bev, &tmp, 1); 174 if (tmp != 'A') { 175 puts("Incorrect data received!"); 176 exit(2); 177 } 178 bufferevent_free(bev); 179 180 num_requests++; 181 if (num_requests == MAX_REQUESTS) { 182 event_base_loopbreak(base); 183 } else { 184 start_client(base); 185 } 186 } 187 188 /* Send a byte to the server. */ 189 static void 190 client_event_cb(struct bufferevent *bev, short events, void *ctx) 191 { 192 if (events & BEV_EVENT_CONNECTED) { 193 unsigned char tmp = 'A'; 194 bufferevent_write(bev, &tmp, 1); 195 } else if (events & BEV_EVENT_ERROR) { 196 puts("Client socket got error!"); 197 exit(2); 198 } 199 200 bufferevent_enable(bev, EV_READ); 201 } 202 203 /* Open a client socket to connect to localhost on sin */ 204 static void 205 start_client(struct event_base *base) 206 { 207 struct bufferevent *bev = bufferevent_socket_new(base, -1, 208 BEV_OPT_CLOSE_ON_FREE); 209 bufferevent_setcb(bev, client_read_cb, NULL, client_event_cb, NULL); 210 211 if (bufferevent_socket_connect(bev, (struct sockaddr *)&saddr, 212 sizeof(saddr)) < 0) { 213 my_perror("Could not connect!"); 214 bufferevent_free(bev); 215 exit(2); 216 } 217 } 218 219 int 220 main(int argc, char **argv) 221 { 222 #ifdef EVENT__HAVE_SETRLIMIT 223 /* Set the fd limit to a low value so that any fd leak is caught without 224 making many requests. */ 225 struct rlimit rl; 226 rl.rlim_cur = rl.rlim_max = 20; 227 if (setrlimit(RLIMIT_NOFILE, &rl) == -1) { 228 my_perror("setrlimit"); 229 exit(3); 230 } 231 #endif 232 233 #ifdef _WIN32 234 WSADATA WSAData; 235 WSAStartup(0x101, &WSAData); 236 #endif 237 238 /* Set up an address, used by both client & server. */ 239 memset(&saddr, 0, sizeof(saddr)); 240 saddr.sin_family = AF_INET; 241 saddr.sin_addr.s_addr = htonl(0x7f000001); 242 saddr.sin_port = 0; /* Tell the implementation to pick a port. */ 243 244 start_loop(); 245 246 return 0; 247 } 248 249 /* XXX why does this test cause so much latency sometimes (OSX 10.5)? */ 250