blob: e6f067bd6b99abdc4d067e115e5036d7ad06b473 [file] [log] [blame]
sewardj5ed7a392002-11-03 23:03:24 +00001
2/*--------------------------------------------------------------------*/
3/*--- A simple program to listen for valgrind logfile data. ---*/
4/*--- valgrind-listener.c ---*/
5/*--------------------------------------------------------------------*/
6
7/*
njnb9c427c2004-12-01 14:14:42 +00008 This file is part of Valgrind, a dynamic binary instrumentation
9 framework.
sewardj5ed7a392002-11-03 23:03:24 +000010
njn53612422005-03-12 16:22:54 +000011 Copyright (C) 2000-2005 Julian Seward
sewardj5ed7a392002-11-03 23:03:24 +000012 jseward@acm.org
13
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.
18
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.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27 02111-1307, USA.
28
29 The GNU General Public License is contained in the file COPYING.
30*/
31
32
33/*---------------------------------------------------------------*/
34
sewardj5ed7a392002-11-03 23:03:24 +000035#include <stdio.h>
sewardjad19c692002-11-09 10:24:01 +000036#include <unistd.h>
sewardj5ed7a392002-11-03 23:03:24 +000037#include <string.h>
sewardj5ed7a392002-11-03 23:03:24 +000038#include <time.h>
39#include <fcntl.h>
40#include <stdlib.h>
sewardjad19c692002-11-09 10:24:01 +000041#include <signal.h>
42#include <sys/poll.h>
43#include <sys/types.h>
44#include <sys/socket.h>
45#include <netinet/in.h>
46
njnc7561b92005-06-19 01:24:32 +000047#include "pub_core_basics.h"
njn24153ed2005-06-18 02:25:16 +000048#include "pub_core_libcassert.h" // For VG_BUGS_TO
njne38e2332005-06-18 04:13:54 +000049#include "pub_core_libcfile.h" // For VG_CLO_DEFAULT_LOGPORT
sewardj43354092002-11-06 00:15:50 +000050
51
sewardj5ed7a392002-11-03 23:03:24 +000052/*---------------------------------------------------------------*/
53
sewardj43354092002-11-06 00:15:50 +000054/* The maximum allowable number concurrent connections. */
55#define M_CONNECTIONS 50
sewardj5ed7a392002-11-03 23:03:24 +000056
sewardj43354092002-11-06 00:15:50 +000057
58/*---------------------------------------------------------------*/
59
60__attribute__ ((noreturn))
61static void panic ( Char* str )
62{
63 fprintf(stderr,
64 "\nvalgrind-listener: the "
njn02bc4b82005-05-15 17:28:26 +000065 "'impossible' happened:\n %s\n", str);
sewardj43354092002-11-06 00:15:50 +000066 fprintf(stderr,
nethercote421281e2003-11-20 16:20:55 +000067 "Please report this bug at: %s\n\n", VG_BUGS_TO);
sewardj43354092002-11-06 00:15:50 +000068 exit(1);
69}
70
71__attribute__ ((noreturn))
daywalkerdf9ae422003-09-18 01:41:48 +000072static void my_assert_fail ( const Char* expr, const Char* file, Int line, const Char* fn )
sewardj43354092002-11-06 00:15:50 +000073{
74 fprintf(stderr,
njn02bc4b82005-05-15 17:28:26 +000075 "\nvalgrind-listener: %s:%d (%s): Assertion '%s' failed.\n",
sewardj43354092002-11-06 00:15:50 +000076 file, line, fn, expr );
77 fprintf(stderr,
nethercote421281e2003-11-20 16:20:55 +000078 "Please report this bug at: %s\n\n", VG_BUGS_TO);
sewardj43354092002-11-06 00:15:50 +000079 exit(1);
80}
81
82#undef assert
sewardj43354092002-11-06 00:15:50 +000083
sewardj43354092002-11-06 00:15:50 +000084#define assert(expr) \
85 ((void) ((expr) ? 0 : \
sewardj7d15e512005-09-30 01:20:47 +000086 (my_assert_fail (VG_STRINGIFY(expr), \
sewardj43354092002-11-06 00:15:50 +000087 __FILE__, __LINE__, \
88 __PRETTY_FUNCTION__), 0)))
89
sewardj5ed7a392002-11-03 23:03:24 +000090
91/*---------------------------------------------------------------*/
92
93/* holds the fds for connections; zero if slot not in use. */
94int conn_count = 0;
sewardj43354092002-11-06 00:15:50 +000095int conn_fd[M_CONNECTIONS];
96struct pollfd conn_pollfd[M_CONNECTIONS];
sewardj5ed7a392002-11-03 23:03:24 +000097
98
njn778f7f82005-05-17 21:07:46 +000099static void set_nonblocking ( int sd )
sewardj5ed7a392002-11-03 23:03:24 +0000100{
101 int res;
102 res = fcntl(sd, F_GETFL);
103 res = fcntl(sd, F_SETFL, res | O_NONBLOCK);
104 if (res != 0) {
105 perror("fcntl failed");
sewardj43354092002-11-06 00:15:50 +0000106 panic("set_nonblocking");
sewardj5ed7a392002-11-03 23:03:24 +0000107 }
108}
109
njn778f7f82005-05-17 21:07:46 +0000110static void set_blocking ( int sd )
sewardj5ed7a392002-11-03 23:03:24 +0000111{
112 int res;
113 res = fcntl(sd, F_GETFL);
114 res = fcntl(sd, F_SETFL, res & ~O_NONBLOCK);
115 if (res != 0) {
116 perror("fcntl failed");
sewardj43354092002-11-06 00:15:50 +0000117 panic("set_blocking");
sewardj5ed7a392002-11-03 23:03:24 +0000118 }
119}
120
121
njn778f7f82005-05-17 21:07:46 +0000122static void copyout ( char* buf, int nbuf )
sewardj5ed7a392002-11-03 23:03:24 +0000123{
124 int i;
125 for (i = 0; i < nbuf; i++) {
sewardj43354092002-11-06 00:15:50 +0000126 if (buf[i] == '\n') {
127 fprintf(stdout, "\n(%d) ", conn_count);
128 } else {
129 fwrite(&buf[i], 1, 1, stdout);
130 }
sewardj5ed7a392002-11-03 23:03:24 +0000131 }
sewardj7d3d1e62002-11-03 23:27:40 +0000132 fflush(stdout);
sewardj5ed7a392002-11-03 23:03:24 +0000133}
134
njn778f7f82005-05-17 21:07:46 +0000135static int read_from_sd ( int sd )
sewardj5ed7a392002-11-03 23:03:24 +0000136{
sewardjad19c692002-11-09 10:24:01 +0000137 char buf[100];
138 int n;
sewardj5ed7a392002-11-03 23:03:24 +0000139
sewardjad19c692002-11-09 10:24:01 +0000140 set_blocking(sd);
141 n = read(sd, buf, 99);
142 if (n <= 0) return 0; /* closed */
143 copyout(buf, n);
sewardj5ed7a392002-11-03 23:03:24 +0000144
sewardjad19c692002-11-09 10:24:01 +0000145 set_nonblocking(sd);
146 while (1) {
147 n = read(sd, buf, 100);
148 if (n <= 0) return 1; /* not closed */
149 copyout(buf, n);
150 }
sewardj5ed7a392002-11-03 23:03:24 +0000151}
152
153
njn778f7f82005-05-17 21:07:46 +0000154static void snooze ( void )
sewardj5ed7a392002-11-03 23:03:24 +0000155{
sewardj43354092002-11-06 00:15:50 +0000156 struct timespec req;
157 req.tv_sec = 0;
158 req.tv_nsec = 200 * 1000 * 1000;
159 nanosleep(&req,NULL);
sewardj5ed7a392002-11-03 23:03:24 +0000160}
161
162
sewardjad19c692002-11-09 10:24:01 +0000163/* returns 0 if invalid, else port # */
njn778f7f82005-05-17 21:07:46 +0000164static int atoi_portno ( char* str )
sewardjad19c692002-11-09 10:24:01 +0000165{
166 int n = 0;
167 while (1) {
168 if (*str == 0)
169 break;
170 if (*str < '0' || *str > '9')
171 return 0;
172 n = 10*n + (int)(*str - '0');
173 str++;
174 if (n >= 65536)
175 return 0;
176 }
177 if (n < 1024)
178 return 0;
179 return n;
180}
181
182
njn778f7f82005-05-17 21:07:46 +0000183static void usage ( void )
sewardjad19c692002-11-09 10:24:01 +0000184{
185 fprintf(stderr,
186 "\n"
187 "usage is:\n"
188 "\n"
sewardjcbf216e2002-11-13 19:42:30 +0000189 " valgrind-listener [--exit-at-zero|-e] [port-number]\n"
sewardjad19c692002-11-09 10:24:01 +0000190 "\n"
sewardjcbf216e2002-11-13 19:42:30 +0000191 " where --exit-at-zero or -e causes the listener to exit\n"
sewardjad19c692002-11-09 10:24:01 +0000192 " when the number of connections falls back to zero\n"
193 " (the default is to keep listening forever)\n"
194 "\n"
195 " port-number is the default port on which to listen for\n"
196 " connections. It must be between 1024 and 65535.\n"
197 " Current default is %d.\n"
198 "\n"
199 ,
200 VG_CLO_DEFAULT_LOGPORT
201 );
202 exit(1);
203}
204
205
njn778f7f82005-05-17 21:07:46 +0000206static void banner ( char* str )
sewardjad19c692002-11-09 10:24:01 +0000207{
208 time_t t;
209 t = time(NULL);
210 printf("valgrind-listener %s at %s", str, ctime(&t));
sewardj68948f72002-11-16 20:15:16 +0000211 fflush(stdout);
sewardjad19c692002-11-09 10:24:01 +0000212}
213
214
njn778f7f82005-05-17 21:07:46 +0000215static void exit_routine ( void )
sewardjad19c692002-11-09 10:24:01 +0000216{
217 banner("exited");
218 exit(0);
219}
220
221
njn778f7f82005-05-17 21:07:46 +0000222static void sigint_handler ( int signo )
sewardjad19c692002-11-09 10:24:01 +0000223{
224 exit_routine();
225}
226
227
sewardj43354092002-11-06 00:15:50 +0000228int main (int argc, char** argv)
229{
sewardj9ac747a2003-07-06 01:34:13 +0000230 int i, j, k, res, one;
sewardjad19c692002-11-09 10:24:01 +0000231 int main_sd, new_sd, client_len;
sewardj43354092002-11-06 00:15:50 +0000232 struct sockaddr_in client_addr, server_addr;
sewardj5ed7a392002-11-03 23:03:24 +0000233
sewardjad19c692002-11-09 10:24:01 +0000234 char /*bool*/ exit_when_zero = 0;
235 int port = VG_CLO_DEFAULT_LOGPORT;
236
237 for (i = 1; i < argc; i++) {
sewardjcbf216e2002-11-13 19:42:30 +0000238 if (0==strcmp(argv[i], "--exit-at-zero")
sewardjad19c692002-11-09 10:24:01 +0000239 || 0==strcmp(argv[i], "-e")) {
240 exit_when_zero = 1;
241 }
242 else
243 if (atoi_portno(argv[i]) > 0) {
244 port = atoi_portno(argv[i]);
245 }
246 else
247 usage();
248 }
249
250 banner("started");
251 signal(SIGINT, sigint_handler);
252
sewardj43354092002-11-06 00:15:50 +0000253 conn_count = 0;
254 for (i = 0; i < M_CONNECTIONS; i++)
255 conn_fd[i] = 0;
sewardj5ed7a392002-11-03 23:03:24 +0000256
sewardj43354092002-11-06 00:15:50 +0000257 /* create socket */
258 main_sd = socket(AF_INET, SOCK_STREAM, 0);
sewardj5ed7a392002-11-03 23:03:24 +0000259 if (main_sd < 0) {
sewardj43354092002-11-06 00:15:50 +0000260 perror("cannot open socket ");
261 panic("main -- create socket");
262 }
sewardj9ac747a2003-07-06 01:34:13 +0000263
264 /* allow address reuse to avoid "address already in use" errors */
265
266 one = 1;
267 if (setsockopt(main_sd, SOL_SOCKET, SO_REUSEADDR,
268 &one, sizeof(int)) < 0) {
269 perror("cannot enable address reuse ");
270 panic("main -- enable address reuse");
271 }
272
sewardj43354092002-11-06 00:15:50 +0000273 /* bind server port */
274 server_addr.sin_family = AF_INET;
275 server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
sewardjad19c692002-11-09 10:24:01 +0000276 server_addr.sin_port = htons(port);
sewardj5ed7a392002-11-03 23:03:24 +0000277
sewardj43354092002-11-06 00:15:50 +0000278 if (bind(main_sd, (struct sockaddr *) &server_addr,
279 sizeof(server_addr) ) < 0) {
280 perror("cannot bind port ");
281 panic("main -- bind port");
282 }
sewardj5ed7a392002-11-03 23:03:24 +0000283
sewardj43354092002-11-06 00:15:50 +0000284 res = listen(main_sd,M_CONNECTIONS);
285 if (res != 0) {
286 perror("listen failed ");
287 panic("main -- listen");
288 }
sewardj5ed7a392002-11-03 23:03:24 +0000289
sewardjad19c692002-11-09 10:24:01 +0000290 while (1) {
sewardj5ed7a392002-11-03 23:03:24 +0000291
sewardj43354092002-11-06 00:15:50 +0000292 snooze();
sewardj5ed7a392002-11-03 23:03:24 +0000293
sewardj43354092002-11-06 00:15:50 +0000294 /* enquire, using poll, whether there is any activity available on
295 the main socket descriptor. If so, someone is trying to
296 connect; get the fd and add it to our table thereof. */
297 { struct pollfd ufd;
298 while (1) {
299 ufd.fd = main_sd;
300 ufd.events = POLLIN;
301 ufd.revents = 0;
302 res = poll(&ufd, 1, 0);
303 if (res == 0) break;
sewardj5ed7a392002-11-03 23:03:24 +0000304
sewardj43354092002-11-06 00:15:50 +0000305 /* ok, we have someone waiting to connect. Get the sd. */
306 client_len = sizeof(client_addr);
sewardjad19c692002-11-09 10:24:01 +0000307 new_sd = accept(main_sd, (struct sockaddr *) &client_addr,
sewardj43354092002-11-06 00:15:50 +0000308 &client_len);
sewardjad19c692002-11-09 10:24:01 +0000309 if (new_sd < 0) {
sewardj43354092002-11-06 00:15:50 +0000310 perror("cannot accept connection ");
311 panic("main -- accept connection");
312 }
313
314 /* find a place to put it. */
sewardjad19c692002-11-09 10:24:01 +0000315 assert(new_sd > 0);
sewardj43354092002-11-06 00:15:50 +0000316 for (i = 0; i < M_CONNECTIONS; i++)
317 if (conn_fd[i] == 0)
318 break;
319
320 if (i >= M_CONNECTIONS) {
321 fprintf(stderr, "Too many concurrent connections. "
322 "Increase M_CONNECTIONS and recompile.\n");
323 panic("main -- too many concurrent connections");
324 }
325
sewardjad19c692002-11-09 10:24:01 +0000326 conn_fd[i] = new_sd;
sewardj43354092002-11-06 00:15:50 +0000327 conn_count++;
328 printf("\n(%d) -------------------- CONNECT "
329 "--------------------\n(%d)\n(%d) ",
330 conn_count, conn_count, conn_count);
331 fflush(stdout);
332 } /* while (1) */
333 }
334
335 /* We've processed all new connect requests. Listen for changes
336 to the current set of fds. */
337 j = 0;
338 for (i = 0; i < M_CONNECTIONS; i++) {
339 if (conn_fd[i] == 0)
340 continue;
341 conn_pollfd[j].fd = conn_fd[i];
342 conn_pollfd[j].events = POLLIN /* | POLLHUP | POLLNVAL */;
343 conn_pollfd[j].revents = 0;
344 j++;
345 }
346
347 res = poll(conn_pollfd, j, 0 /* return immediately. */ );
348 if (res < 0) {
349 perror("poll(main) failed");
350 panic("poll(main) failed");
351 }
352
353 /* nothing happened. go round again. */
354 if (res == 0) {
355 continue;
356 }
357
358 /* inspect the fds. */
359 for (i = 0; i < j; i++) {
360
361 if (conn_pollfd[i].revents & POLLIN) {
362 /* data is available on this fd */
363 res = read_from_sd(conn_pollfd[i].fd);
364
365 if (res == 0) {
366 /* the connection has been closed. */
sewardje188abf2003-07-20 22:39:58 +0000367 close(conn_pollfd[i].fd);
sewardj43354092002-11-06 00:15:50 +0000368 /* this fd has been closed or otherwise gone bad; forget
sewardje188abf2003-07-20 22:39:58 +0000369 about it. */
sewardj43354092002-11-06 00:15:50 +0000370 for (k = 0; k < M_CONNECTIONS; k++)
371 if (conn_fd[k] == conn_pollfd[i].fd)
372 break;
373 assert(k < M_CONNECTIONS);
374 conn_fd[k] = 0;
375 conn_count--;
376 printf("\n(%d) ------------------- DISCONNECT "
377 "-------------------\n(%d)\n(%d) ",
378 conn_count, conn_count, conn_count);
379 fflush(stdout);
sewardjad19c692002-11-09 10:24:01 +0000380 if (conn_count == 0 && exit_when_zero) {
381 printf("\n");
sewardj68948f72002-11-16 20:15:16 +0000382 fflush(stdout);
sewardjad19c692002-11-09 10:24:01 +0000383 exit_routine();
384 }
sewardj43354092002-11-06 00:15:50 +0000385 }
sewardj5ed7a392002-11-03 23:03:24 +0000386 }
387
sewardj43354092002-11-06 00:15:50 +0000388 } /* for (i = 0; i < j; i++) */
389
sewardjad19c692002-11-09 10:24:01 +0000390 } /* while (1) */
sewardj5ed7a392002-11-03 23:03:24 +0000391
sewardjad19c692002-11-09 10:24:01 +0000392 /* NOTREACHED */
sewardj5ed7a392002-11-03 23:03:24 +0000393}
394
395
396/*--------------------------------------------------------------------*/
397/*--- end valgrind-listener.c ---*/
398/*--------------------------------------------------------------------*/