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