FreeBSD regtest: add fakes for FreeBSD < 13
[valgrind.git] / auxprogs / valgrind-listener.c
blob158f11c088cb2830d43879d4896d88f745af852c
2 /*--------------------------------------------------------------------*/
3 /*--- A simple program to listen for valgrind logfile data. ---*/
4 /*--- valgrind-listener.c ---*/
5 /*--------------------------------------------------------------------*/
7 /*
8 This file is part of Valgrind, a dynamic binary instrumentation
9 framework.
11 Copyright (C) 2000-2017 Julian Seward
12 jseward@acm.org
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, see <http://www.gnu.org/licenses/>.
27 The GNU General Public License is contained in the file COPYING.
31 /*---------------------------------------------------------------*/
33 /* Include valgrind headers before system headers to avoid problems
34 with the system headers #defining things which are used as names
35 of structure members in vki headers. */
37 #include "pub_core_basics.h"
38 #include "pub_core_libcassert.h" // For VG_BUGS_TO
39 #include "pub_core_vki.h" // Avoids warnings from
40 // pub_core_libcfile.h
41 #include "pub_core_libcfile.h" // For VG_CLO_DEFAULT_LOGPORT
43 #include <stdio.h>
44 #include <unistd.h>
45 #include <string.h>
46 #include <time.h>
47 #include <fcntl.h>
48 #include <stdlib.h>
49 #include <signal.h>
50 #include <poll.h>
51 #include <sys/types.h>
52 #include <sys/socket.h>
53 #include <netinet/in.h>
56 /*---------------------------------------------------------------*/
58 /* The default allowable number of concurrent connections. */
59 #define M_CONNECTIONS_DEFAULT 50
60 /* The maximum allowable number of concurrent connections. */
61 #define M_CONNECTIONS_MAX 5000
63 /* The maximum allowable number of concurrent connections. */
64 unsigned M_CONNECTIONS = 0;
66 /*---------------------------------------------------------------*/
68 __attribute__ ((noreturn))
69 static void panic ( const char* str )
71 fprintf(stderr,
72 "\nvalgrind-listener: the "
73 "'impossible' happened:\n %s\n", str);
74 fprintf(stderr,
75 "Please report this bug at: %s\n\n", VG_BUGS_TO);
76 exit(1);
79 __attribute__ ((noreturn))
80 static void my_assert_fail ( const char* expr, const char* file, int line, const char* fn )
82 fprintf(stderr,
83 "\nvalgrind-listener: %s:%d (%s): Assertion '%s' failed.\n",
84 file, line, fn, expr );
85 fprintf(stderr,
86 "Please report this bug at: %s\n\n", VG_BUGS_TO);
87 exit(1);
90 #undef assert
92 #define assert(expr) \
93 ((void) ((expr) ? 0 : \
94 (my_assert_fail (VG_STRINGIFY(expr), \
95 __FILE__, __LINE__, \
96 __PRETTY_FUNCTION__), 0)))
99 /*---------------------------------------------------------------*/
101 /* holds the fds for connections; zero if slot not in use. */
102 int conn_count = 0;
103 int *conn_fd;
104 struct pollfd *conn_pollfd;
107 static void set_nonblocking ( int sd )
109 int res;
110 res = fcntl(sd, F_GETFL);
111 res = fcntl(sd, F_SETFL, res | O_NONBLOCK);
112 if (res != 0) {
113 perror("fcntl failed");
114 panic("set_nonblocking");
118 static void set_blocking ( int sd )
120 int res;
121 res = fcntl(sd, F_GETFL);
122 res = fcntl(sd, F_SETFL, res & ~O_NONBLOCK);
123 if (res != 0) {
124 perror("fcntl failed");
125 panic("set_blocking");
130 static void copyout ( char* buf, int nbuf )
132 int i;
133 for (i = 0; i < nbuf; i++) {
134 if (buf[i] == '\n') {
135 fprintf(stdout, "\n(%d) ", conn_count);
136 } else {
137 __attribute__((unused)) size_t ignored
138 = fwrite(&buf[i], 1, 1, stdout);
141 fflush(stdout);
144 static int read_from_sd ( int sd )
146 char buf[100];
147 int n;
149 set_blocking(sd);
150 n = read(sd, buf, 99);
151 if (n <= 0) return 0; /* closed */
152 copyout(buf, n);
154 set_nonblocking(sd);
155 while (1) {
156 n = read(sd, buf, 100);
157 if (n <= 0) return 1; /* not closed */
158 copyout(buf, n);
163 static void snooze ( void )
165 struct timespec req;
166 req.tv_sec = 0;
167 req.tv_nsec = 200 * 1000 * 1000;
168 nanosleep(&req,NULL);
172 /* returns 0 if negative, or > BOUND or invalid characters were found */
173 static int atoi_with_bound ( const char* str, int bound )
175 int n = 0;
176 while (1) {
177 if (*str == 0)
178 break;
179 if (*str < '0' || *str > '9')
180 return 0;
181 n = 10*n + (int)(*str - '0');
182 str++;
183 if (n >= bound)
184 return 0;
186 return n;
189 /* returns 0 if invalid, else port # */
190 static int atoi_portno ( const char* str )
192 int n = atoi_with_bound(str, 65536);
194 if (n < 1024)
195 return 0;
196 return n;
200 static void usage ( void )
202 fprintf(stderr,
203 "\n"
204 "usage is:\n"
205 "\n"
206 " valgrind-listener [--exit-at-zero|-e] [--max-connect=INT] [port-number]\n"
207 "\n"
208 " where --exit-at-zero or -e causes the listener to exit\n"
209 " when the number of connections falls back to zero\n"
210 " (the default is to keep listening forever)\n"
211 "\n"
212 " --max-connect=INT can be used to increase the maximum\n"
213 " number of connected processes (default = %d).\n"
214 " INT must be positive and less than %d.\n"
215 "\n"
216 " port-number is the default port on which to listen for\n"
217 " connections. It must be between 1024 and 65535.\n"
218 " Current default is %d.\n"
219 "\n"
221 M_CONNECTIONS_DEFAULT, M_CONNECTIONS_MAX, VG_CLO_DEFAULT_LOGPORT
223 exit(1);
227 static void banner ( const char* str )
229 time_t t;
230 t = time(NULL);
231 printf("valgrind-listener %s at %s", str, ctime(&t));
232 fflush(stdout);
236 static void exit_routine ( void )
238 banner("exited");
239 exit(0);
243 static void sigint_handler ( int signo )
245 exit_routine();
249 int main (int argc, char** argv)
251 int i, j, k, res, one;
252 int main_sd, new_sd;
253 socklen_t client_len;
254 struct sockaddr_in client_addr, server_addr;
256 char /*bool*/ exit_when_zero = 0;
257 int port = VG_CLO_DEFAULT_LOGPORT;
259 for (i = 1; i < argc; i++) {
260 if (0==strcmp(argv[i], "--exit-at-zero")
261 || 0==strcmp(argv[i], "-e")) {
262 exit_when_zero = 1;
264 else if (0 == strncmp(argv[i], "--max-connect=", 14)) {
265 M_CONNECTIONS = atoi_with_bound(strchr(argv[i], '=') + 1, 5000);
266 if (M_CONNECTIONS <= 0 || M_CONNECTIONS > M_CONNECTIONS_MAX)
267 usage();
269 else
270 if (atoi_portno(argv[i]) > 0) {
271 port = atoi_portno(argv[i]);
273 else
274 usage();
277 if (M_CONNECTIONS == 0) // nothing specified on command line
278 M_CONNECTIONS = M_CONNECTIONS_DEFAULT;
280 conn_fd = malloc(M_CONNECTIONS * sizeof conn_fd[0]);
281 conn_pollfd = malloc(M_CONNECTIONS * sizeof conn_pollfd[0]);
282 if (conn_fd == NULL || conn_pollfd == NULL) {
283 fprintf(stderr, "Memory allocation failed; cannot continue.\n");
284 exit(1);
287 banner("started");
288 signal(SIGINT, sigint_handler);
290 conn_count = 0;
291 for (i = 0; i < M_CONNECTIONS; i++)
292 conn_fd[i] = 0;
294 /* create socket */
295 main_sd = socket(AF_INET, SOCK_STREAM, 0);
296 if (main_sd < 0) {
297 perror("cannot open socket ");
298 panic("main -- create socket");
301 /* allow address reuse to avoid "address already in use" errors */
303 one = 1;
304 if (setsockopt(main_sd, SOL_SOCKET, SO_REUSEADDR,
305 &one, sizeof(int)) < 0) {
306 perror("cannot enable address reuse ");
307 panic("main -- enable address reuse");
310 /* bind server port */
311 server_addr.sin_family = AF_INET;
312 server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
313 server_addr.sin_port = htons(port);
315 if (bind(main_sd, (struct sockaddr *) &server_addr,
316 sizeof(server_addr) ) < 0) {
317 perror("cannot bind port ");
318 panic("main -- bind port");
321 res = listen(main_sd,M_CONNECTIONS);
322 if (res != 0) {
323 perror("listen failed ");
324 panic("main -- listen");
327 while (1) {
329 snooze();
331 /* enquire, using poll, whether there is any activity available on
332 the main socket descriptor. If so, someone is trying to
333 connect; get the fd and add it to our table thereof. */
334 { struct pollfd ufd;
335 while (1) {
336 ufd.fd = main_sd;
337 ufd.events = POLLIN;
338 ufd.revents = 0;
339 res = poll(&ufd, 1, 0);
340 if (res == 0) break;
342 /* ok, we have someone waiting to connect. Get the sd. */
343 client_len = sizeof(client_addr);
344 new_sd = accept(main_sd, (struct sockaddr *)&client_addr,
345 &client_len);
346 if (new_sd < 0) {
347 perror("cannot accept connection ");
348 panic("main -- accept connection");
351 /* find a place to put it. */
352 assert(new_sd > 0);
353 for (i = 0; i < M_CONNECTIONS; i++)
354 if (conn_fd[i] == 0)
355 break;
357 if (i >= M_CONNECTIONS) {
358 fprintf(stderr, "\n\nMore than %d concurrent connections.\n"
359 "Restart the listener giving --max-connect=INT on the\n"
360 "commandline to increase the limit.\n\n",
361 M_CONNECTIONS);
362 exit(1);
365 conn_fd[i] = new_sd;
366 conn_count++;
367 printf("\n(%d) -------------------- CONNECT "
368 "--------------------\n(%d)\n(%d) ",
369 conn_count, conn_count, conn_count);
370 fflush(stdout);
371 } /* while (1) */
374 /* We've processed all new connect requests. Listen for changes
375 to the current set of fds. */
376 j = 0;
377 for (i = 0; i < M_CONNECTIONS; i++) {
378 if (conn_fd[i] == 0)
379 continue;
380 conn_pollfd[j].fd = conn_fd[i];
381 conn_pollfd[j].events = POLLIN /* | POLLHUP | POLLNVAL */;
382 conn_pollfd[j].revents = 0;
383 j++;
386 res = poll(conn_pollfd, j, 0 /* return immediately. */ );
387 if (res < 0) {
388 perror("poll(main) failed");
389 panic("poll(main) failed");
392 /* nothing happened. go round again. */
393 if (res == 0) {
394 continue;
397 /* inspect the fds. */
398 for (i = 0; i < j; i++) {
400 if (conn_pollfd[i].revents & POLLIN) {
401 /* data is available on this fd */
402 res = read_from_sd(conn_pollfd[i].fd);
404 if (res == 0) {
405 /* the connection has been closed. */
406 close(conn_pollfd[i].fd);
407 /* this fd has been closed or otherwise gone bad; forget
408 about it. */
409 for (k = 0; k < M_CONNECTIONS; k++)
410 if (conn_fd[k] == conn_pollfd[i].fd)
411 break;
412 assert(k < M_CONNECTIONS);
413 conn_fd[k] = 0;
414 conn_count--;
415 printf("\n(%d) ------------------- DISCONNECT "
416 "-------------------\n(%d)\n(%d) ",
417 conn_count, conn_count, conn_count);
418 fflush(stdout);
419 if (conn_count == 0 && exit_when_zero) {
420 printf("\n");
421 fflush(stdout);
422 exit_routine();
427 } /* for (i = 0; i < j; i++) */
429 } /* while (1) */
431 /* NOTREACHED */
435 /*--------------------------------------------------------------------*/
436 /*--- end valgrind-listener.c ---*/
437 /*--------------------------------------------------------------------*/