1 /* $NetBSD: test-fdleak.c,v 1.1.1.1 2017/01/31 21:14:53 christos Exp $ */ 2 /* 3 * Copyright (c) 2012 Ross Lagerwall <rosslagerwall@gmail.com> 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include "event2/event-config.h" 29 #include <sys/cdefs.h> 30 __RCSID("$NetBSD: test-fdleak.c,v 1.1.1.1 2017/01/31 21:14:53 christos Exp $"); 31 32 #ifdef _WIN32 33 #define WIN32_LEAN_AND_MEAN 34 #include <windows.h> 35 #endif 36 #include <string.h> 37 #include <stdlib.h> 38 #include <errno.h> 39 #ifdef EVENT__HAVE_SYS_TIME_H 40 #include <sys/time.h> 41 #endif 42 #ifdef EVENT__HAVE_SYS_RESOURCE_H 43 #include <sys/resource.h> 44 #endif 45 #ifdef EVENT__HAVE_NETINET_IN_H 46 #include <netinet/in.h> 47 #endif 48 49 #include "event2/event.h" 50 #include "event2/bufferevent.h" 51 #include "event2/buffer.h" 52 #include "event2/listener.h" 53 54 /* Number of requests to make. Setting this too high might result in the machine 55 running out of ephemeral ports */ 56 #ifdef _WIN32 57 #define MAX_REQUESTS 1000 58 #else 59 #define MAX_REQUESTS 4000 60 #endif 61 62 /* Provide storage for the address, both for the server & the clients */ 63 static struct sockaddr_in saddr; 64 65 /* Number of sucessful requests so far */ 66 static int num_requests; 67 68 static void start_client(struct event_base *base); 69 70 static void 71 my_perror(const char *s) 72 { 73 fprintf(stderr, "%s: %s", 74 s, evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR())); 75 } 76 77 /* 78 =============================================== 79 Server functions 80 =============================================== 81 */ 82 83 /* Read a byte from the client and write it back */ 84 static void 85 server_read_cb(struct bufferevent *bev, void *ctx) 86 { 87 while (evbuffer_get_length(bufferevent_get_input(bev))) { 88 unsigned char tmp; 89 bufferevent_read(bev, &tmp, 1); 90 bufferevent_write(bev, &tmp, 1); 91 } 92 } 93 94 /* Wait for an EOF and then free the bufferevent */ 95 static void 96 server_event_cb(struct bufferevent *bev, short events, void *ctx) 97 { 98 if (events & BEV_EVENT_ERROR) { 99 my_perror("Error from bufferevent"); 100 exit(1); 101 } else if (events & (BEV_EVENT_EOF | BEV_EVENT_ERROR)) { 102 bufferevent_free(bev); 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 115 bufferevent_setcb(bev, server_read_cb, NULL, server_event_cb, NULL); 116 bufferevent_enable(bev, EV_READ|EV_WRITE); 117 } 118 119 /* Start the server listening on a random port and start the first client. */ 120 static void 121 start_loop(void) 122 { 123 struct event_base *base; 124 struct evconnlistener *listener; 125 struct sockaddr_storage ss; 126 ev_socklen_t socklen = sizeof(ss); 127 evutil_socket_t fd; 128 129 base = event_base_new(); 130 if (base == NULL) { 131 puts("Could not open event base!"); 132 exit(1); 133 } 134 135 listener = evconnlistener_new_bind(base, listener_accept_cb, NULL, 136 LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE, 137 -1, (struct sockaddr *)&saddr, sizeof(saddr)); 138 if (listener == NULL) { 139 my_perror("Could not create listener!"); 140 exit(1); 141 } 142 fd = evconnlistener_get_fd(listener); 143 if (fd < 0) { 144 puts("Couldn't get fd from listener"); 145 exit(1); 146 } 147 if (getsockname(fd, (struct sockaddr *)&ss, &socklen) < 0) { 148 my_perror("getsockname()"); 149 exit(1); 150 } 151 memcpy(&saddr, &ss, sizeof(saddr)); 152 if (saddr.sin_family != AF_INET) { 153 puts("AF mismatch from getsockname()."); 154 exit(1); 155 } 156 157 start_client(base); 158 159 event_base_dispatch(base); 160 } 161 162 /* 163 =============================================== 164 Client functions 165 =============================================== 166 */ 167 168 /* Check that the server sends back the same byte that the client sent. 169 If MAX_REQUESTS have been reached, exit. Otherwise, start another client. */ 170 static void 171 client_read_cb(struct bufferevent *bev, void *ctx) 172 { 173 unsigned char tmp; 174 struct event_base *base = bufferevent_get_base(bev); 175 176 bufferevent_read(bev, &tmp, 1); 177 if (tmp != 'A') { 178 puts("Incorrect data received!"); 179 exit(2); 180 } 181 bufferevent_free(bev); 182 183 num_requests++; 184 if (num_requests == MAX_REQUESTS) { 185 event_base_loopbreak(base); 186 } else { 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