blob: 1ab139cfe3654fa11c6534ca4ac451e1dcf856df [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/*
8 This file is part of Valgrind, an extensible x86 protected-mode
9 emulator for monitoring program execution on x86-Unixes.
10
nethercotebb1c9912004-01-04 16:43:23 +000011 Copyright (C) 2000-2004 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
sewardj5ed7a392002-11-03 23:03:24 +000047
nethercote421281e2003-11-20 16:20:55 +000048/* For VG_CLO_DEFAULT_LOGPORT and VG_BUGS_TO. */
nethercotef1e5e152004-09-01 23:58:16 +000049#include "core.h"
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 "
65 "`impossible' happened:\n %s\n", str);
66 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,
75 "\nvalgrind-listener: %s:%d (%s): Assertion `%s' failed.\n",
76 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
83#undef VG__STRING
84
85#define VG__STRING(__str) #__str
86#define assert(expr) \
87 ((void) ((expr) ? 0 : \
88 (my_assert_fail (VG__STRING(expr), \
89 __FILE__, __LINE__, \
90 __PRETTY_FUNCTION__), 0)))
91
sewardj5ed7a392002-11-03 23:03:24 +000092
93/*---------------------------------------------------------------*/
94
95/* holds the fds for connections; zero if slot not in use. */
96int conn_count = 0;
sewardj43354092002-11-06 00:15:50 +000097int conn_fd[M_CONNECTIONS];
98struct pollfd conn_pollfd[M_CONNECTIONS];
sewardj5ed7a392002-11-03 23:03:24 +000099
100
101void set_nonblocking ( int sd )
102{
103 int res;
104 res = fcntl(sd, F_GETFL);
105 res = fcntl(sd, F_SETFL, res | O_NONBLOCK);
106 if (res != 0) {
107 perror("fcntl failed");
sewardj43354092002-11-06 00:15:50 +0000108 panic("set_nonblocking");
sewardj5ed7a392002-11-03 23:03:24 +0000109 }
110}
111
112void set_blocking ( int sd )
113{
114 int res;
115 res = fcntl(sd, F_GETFL);
116 res = fcntl(sd, F_SETFL, res & ~O_NONBLOCK);
117 if (res != 0) {
118 perror("fcntl failed");
sewardj43354092002-11-06 00:15:50 +0000119 panic("set_blocking");
sewardj5ed7a392002-11-03 23:03:24 +0000120 }
121}
122
123
124void copyout ( char* buf, int nbuf )
125{
126 int i;
127 for (i = 0; i < nbuf; i++) {
sewardj43354092002-11-06 00:15:50 +0000128 if (buf[i] == '\n') {
129 fprintf(stdout, "\n(%d) ", conn_count);
130 } else {
131 fwrite(&buf[i], 1, 1, stdout);
132 }
sewardj5ed7a392002-11-03 23:03:24 +0000133 }
sewardj7d3d1e62002-11-03 23:27:40 +0000134 fflush(stdout);
sewardj5ed7a392002-11-03 23:03:24 +0000135}
136
137int read_from_sd ( int sd )
138{
sewardjad19c692002-11-09 10:24:01 +0000139 char buf[100];
140 int n;
sewardj5ed7a392002-11-03 23:03:24 +0000141
sewardjad19c692002-11-09 10:24:01 +0000142 set_blocking(sd);
143 n = read(sd, buf, 99);
144 if (n <= 0) return 0; /* closed */
145 copyout(buf, n);
sewardj5ed7a392002-11-03 23:03:24 +0000146
sewardjad19c692002-11-09 10:24:01 +0000147 set_nonblocking(sd);
148 while (1) {
149 n = read(sd, buf, 100);
150 if (n <= 0) return 1; /* not closed */
151 copyout(buf, n);
152 }
sewardj5ed7a392002-11-03 23:03:24 +0000153}
154
155
156void snooze ( void )
157{
sewardj43354092002-11-06 00:15:50 +0000158 struct timespec req;
159 req.tv_sec = 0;
160 req.tv_nsec = 200 * 1000 * 1000;
161 nanosleep(&req,NULL);
sewardj5ed7a392002-11-03 23:03:24 +0000162}
163
164
sewardjad19c692002-11-09 10:24:01 +0000165/* returns 0 if invalid, else port # */
166int atoi_portno ( char* str )
167{
168 int n = 0;
169 while (1) {
170 if (*str == 0)
171 break;
172 if (*str < '0' || *str > '9')
173 return 0;
174 n = 10*n + (int)(*str - '0');
175 str++;
176 if (n >= 65536)
177 return 0;
178 }
179 if (n < 1024)
180 return 0;
181 return n;
182}
183
184
185void usage ( void )
186{
187 fprintf(stderr,
188 "\n"
189 "usage is:\n"
190 "\n"
sewardjcbf216e2002-11-13 19:42:30 +0000191 " valgrind-listener [--exit-at-zero|-e] [port-number]\n"
sewardjad19c692002-11-09 10:24:01 +0000192 "\n"
sewardjcbf216e2002-11-13 19:42:30 +0000193 " where --exit-at-zero or -e causes the listener to exit\n"
sewardjad19c692002-11-09 10:24:01 +0000194 " when the number of connections falls back to zero\n"
195 " (the default is to keep listening forever)\n"
196 "\n"
197 " port-number is the default port on which to listen for\n"
198 " connections. It must be between 1024 and 65535.\n"
199 " Current default is %d.\n"
200 "\n"
201 ,
202 VG_CLO_DEFAULT_LOGPORT
203 );
204 exit(1);
205}
206
207
208void banner ( char* str )
209{
210 time_t t;
211 t = time(NULL);
212 printf("valgrind-listener %s at %s", str, ctime(&t));
sewardj68948f72002-11-16 20:15:16 +0000213 fflush(stdout);
sewardjad19c692002-11-09 10:24:01 +0000214}
215
216
217void exit_routine ( void )
218{
219 banner("exited");
220 exit(0);
221}
222
223
224void sigint_handler ( int signo )
225{
226 exit_routine();
227}
228
229
sewardj43354092002-11-06 00:15:50 +0000230int main (int argc, char** argv)
231{
sewardj9ac747a2003-07-06 01:34:13 +0000232 int i, j, k, res, one;
sewardjad19c692002-11-09 10:24:01 +0000233 int main_sd, new_sd, client_len;
sewardj43354092002-11-06 00:15:50 +0000234 struct sockaddr_in client_addr, server_addr;
sewardj5ed7a392002-11-03 23:03:24 +0000235
sewardjad19c692002-11-09 10:24:01 +0000236 char /*bool*/ exit_when_zero = 0;
237 int port = VG_CLO_DEFAULT_LOGPORT;
238
239 for (i = 1; i < argc; i++) {
sewardjcbf216e2002-11-13 19:42:30 +0000240 if (0==strcmp(argv[i], "--exit-at-zero")
sewardjad19c692002-11-09 10:24:01 +0000241 || 0==strcmp(argv[i], "-e")) {
242 exit_when_zero = 1;
243 }
244 else
245 if (atoi_portno(argv[i]) > 0) {
246 port = atoi_portno(argv[i]);
247 }
248 else
249 usage();
250 }
251
252 banner("started");
253 signal(SIGINT, sigint_handler);
254
sewardj43354092002-11-06 00:15:50 +0000255 conn_count = 0;
256 for (i = 0; i < M_CONNECTIONS; i++)
257 conn_fd[i] = 0;
sewardj5ed7a392002-11-03 23:03:24 +0000258
sewardj43354092002-11-06 00:15:50 +0000259 /* create socket */
260 main_sd = socket(AF_INET, SOCK_STREAM, 0);
sewardj5ed7a392002-11-03 23:03:24 +0000261 if (main_sd < 0) {
sewardj43354092002-11-06 00:15:50 +0000262 perror("cannot open socket ");
263 panic("main -- create socket");
264 }
sewardj9ac747a2003-07-06 01:34:13 +0000265
266 /* allow address reuse to avoid "address already in use" errors */
267
268 one = 1;
269 if (setsockopt(main_sd, SOL_SOCKET, SO_REUSEADDR,
270 &one, sizeof(int)) < 0) {
271 perror("cannot enable address reuse ");
272 panic("main -- enable address reuse");
273 }
274
sewardj43354092002-11-06 00:15:50 +0000275 /* bind server port */
276 server_addr.sin_family = AF_INET;
277 server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
sewardjad19c692002-11-09 10:24:01 +0000278 server_addr.sin_port = htons(port);
sewardj5ed7a392002-11-03 23:03:24 +0000279
sewardj43354092002-11-06 00:15:50 +0000280 if (bind(main_sd, (struct sockaddr *) &server_addr,
281 sizeof(server_addr) ) < 0) {
282 perror("cannot bind port ");
283 panic("main -- bind port");
284 }
sewardj5ed7a392002-11-03 23:03:24 +0000285
sewardj43354092002-11-06 00:15:50 +0000286 res = listen(main_sd,M_CONNECTIONS);
287 if (res != 0) {
288 perror("listen failed ");
289 panic("main -- listen");
290 }
sewardj5ed7a392002-11-03 23:03:24 +0000291
sewardjad19c692002-11-09 10:24:01 +0000292 while (1) {
sewardj5ed7a392002-11-03 23:03:24 +0000293
sewardj43354092002-11-06 00:15:50 +0000294 snooze();
sewardj5ed7a392002-11-03 23:03:24 +0000295
sewardj43354092002-11-06 00:15:50 +0000296 /* enquire, using poll, whether there is any activity available on
297 the main socket descriptor. If so, someone is trying to
298 connect; get the fd and add it to our table thereof. */
299 { struct pollfd ufd;
300 while (1) {
301 ufd.fd = main_sd;
302 ufd.events = POLLIN;
303 ufd.revents = 0;
304 res = poll(&ufd, 1, 0);
305 if (res == 0) break;
sewardj5ed7a392002-11-03 23:03:24 +0000306
sewardj43354092002-11-06 00:15:50 +0000307 /* ok, we have someone waiting to connect. Get the sd. */
308 client_len = sizeof(client_addr);
sewardjad19c692002-11-09 10:24:01 +0000309 new_sd = accept(main_sd, (struct sockaddr *) &client_addr,
sewardj43354092002-11-06 00:15:50 +0000310 &client_len);
sewardjad19c692002-11-09 10:24:01 +0000311 if (new_sd < 0) {
sewardj43354092002-11-06 00:15:50 +0000312 perror("cannot accept connection ");
313 panic("main -- accept connection");
314 }
315
316 /* find a place to put it. */
sewardjad19c692002-11-09 10:24:01 +0000317 assert(new_sd > 0);
sewardj43354092002-11-06 00:15:50 +0000318 for (i = 0; i < M_CONNECTIONS; i++)
319 if (conn_fd[i] == 0)
320 break;
321
322 if (i >= M_CONNECTIONS) {
323 fprintf(stderr, "Too many concurrent connections. "
324 "Increase M_CONNECTIONS and recompile.\n");
325 panic("main -- too many concurrent connections");
326 }
327
sewardjad19c692002-11-09 10:24:01 +0000328 conn_fd[i] = new_sd;
sewardj43354092002-11-06 00:15:50 +0000329 conn_count++;
330 printf("\n(%d) -------------------- CONNECT "
331 "--------------------\n(%d)\n(%d) ",
332 conn_count, conn_count, conn_count);
333 fflush(stdout);
334 } /* while (1) */
335 }
336
337 /* We've processed all new connect requests. Listen for changes
338 to the current set of fds. */
339 j = 0;
340 for (i = 0; i < M_CONNECTIONS; i++) {
341 if (conn_fd[i] == 0)
342 continue;
343 conn_pollfd[j].fd = conn_fd[i];
344 conn_pollfd[j].events = POLLIN /* | POLLHUP | POLLNVAL */;
345 conn_pollfd[j].revents = 0;
346 j++;
347 }
348
349 res = poll(conn_pollfd, j, 0 /* return immediately. */ );
350 if (res < 0) {
351 perror("poll(main) failed");
352 panic("poll(main) failed");
353 }
354
355 /* nothing happened. go round again. */
356 if (res == 0) {
357 continue;
358 }
359
360 /* inspect the fds. */
361 for (i = 0; i < j; i++) {
362
363 if (conn_pollfd[i].revents & POLLIN) {
364 /* data is available on this fd */
365 res = read_from_sd(conn_pollfd[i].fd);
366
367 if (res == 0) {
368 /* the connection has been closed. */
sewardje188abf2003-07-20 22:39:58 +0000369 close(conn_pollfd[i].fd);
sewardj43354092002-11-06 00:15:50 +0000370 /* this fd has been closed or otherwise gone bad; forget
sewardje188abf2003-07-20 22:39:58 +0000371 about it. */
sewardj43354092002-11-06 00:15:50 +0000372 for (k = 0; k < M_CONNECTIONS; k++)
373 if (conn_fd[k] == conn_pollfd[i].fd)
374 break;
375 assert(k < M_CONNECTIONS);
376 conn_fd[k] = 0;
377 conn_count--;
378 printf("\n(%d) ------------------- DISCONNECT "
379 "-------------------\n(%d)\n(%d) ",
380 conn_count, conn_count, conn_count);
381 fflush(stdout);
sewardjad19c692002-11-09 10:24:01 +0000382 if (conn_count == 0 && exit_when_zero) {
383 printf("\n");
sewardj68948f72002-11-16 20:15:16 +0000384 fflush(stdout);
sewardjad19c692002-11-09 10:24:01 +0000385 exit_routine();
386 }
sewardj43354092002-11-06 00:15:50 +0000387 }
sewardj5ed7a392002-11-03 23:03:24 +0000388 }
389
sewardj43354092002-11-06 00:15:50 +0000390 } /* for (i = 0; i < j; i++) */
391
sewardjad19c692002-11-09 10:24:01 +0000392 } /* while (1) */
sewardj5ed7a392002-11-03 23:03:24 +0000393
sewardjad19c692002-11-09 10:24:01 +0000394 /* NOTREACHED */
sewardj5ed7a392002-11-03 23:03:24 +0000395}
396
397
398/*--------------------------------------------------------------------*/
399/*--- end valgrind-listener.c ---*/
400/*--------------------------------------------------------------------*/