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