blob: f4917a639278d1263416c24414de78bf39bc3c5d [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
11 Copyright (C) 2000-2002 Julian Seward
12 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
35#include <sys/types.h>
36#include <sys/socket.h>
37#include <netinet/in.h>
38#include <arpa/inet.h>
39#include <netdb.h>
40#include <stdio.h>
41#include <unistd.h> /* close */
42#include <string.h>
sewardj5ed7a392002-11-03 23:03:24 +000043#include <sys/poll.h>
44#include <time.h>
45#include <fcntl.h>
46#include <stdlib.h>
47
sewardj43354092002-11-06 00:15:50 +000048/* For VG_CLO_DEFAULT_LOGPORT and VG_EMAIL_ADDR. */
49#include "vg_include.h"
50
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,
67 "Please report this bug to: %s\n\n", VG_EMAIL_ADDR);
68 exit(1);
69}
70
71__attribute__ ((noreturn))
72static void my_assert_fail ( Char* expr, Char* file, Int line, Char* fn )
73{
74 fprintf(stderr,
75 "\nvalgrind-listener: %s:%d (%s): Assertion `%s' failed.\n",
76 file, line, fn, expr );
77 fprintf(stderr,
78 "Please report this bug to: %s\n\n", VG_EMAIL_ADDR);
79 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{
139 char buf[100];
140 int n;
141
142 set_blocking(sd);
143 n = read(sd, buf, 99);
144 if (n <= 0) return 0; /* closed */
145 copyout(buf, n);
146
147 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 }
153}
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
sewardj43354092002-11-06 00:15:50 +0000165int main (int argc, char** argv)
166{
167 int i, j, k, res;
168 int main_sd, newSd, client_len;
sewardj5ed7a392002-11-03 23:03:24 +0000169
sewardj43354092002-11-06 00:15:50 +0000170 struct sockaddr_in client_addr, server_addr;
sewardj5ed7a392002-11-03 23:03:24 +0000171
sewardj43354092002-11-06 00:15:50 +0000172 conn_count = 0;
173 for (i = 0; i < M_CONNECTIONS; i++)
174 conn_fd[i] = 0;
sewardj5ed7a392002-11-03 23:03:24 +0000175
sewardj43354092002-11-06 00:15:50 +0000176 /* create socket */
177 main_sd = socket(AF_INET, SOCK_STREAM, 0);
sewardj5ed7a392002-11-03 23:03:24 +0000178 if (main_sd < 0) {
sewardj43354092002-11-06 00:15:50 +0000179 perror("cannot open socket ");
180 panic("main -- create socket");
181 }
sewardj5ed7a392002-11-03 23:03:24 +0000182
sewardj43354092002-11-06 00:15:50 +0000183 /* bind server port */
184 server_addr.sin_family = AF_INET;
185 server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
186 server_addr.sin_port = htons(VG_CLO_DEFAULT_LOGPORT);
sewardj5ed7a392002-11-03 23:03:24 +0000187
sewardj43354092002-11-06 00:15:50 +0000188 if (bind(main_sd, (struct sockaddr *) &server_addr,
189 sizeof(server_addr) ) < 0) {
190 perror("cannot bind port ");
191 panic("main -- bind port");
192 }
sewardj5ed7a392002-11-03 23:03:24 +0000193
sewardj43354092002-11-06 00:15:50 +0000194 res = listen(main_sd,M_CONNECTIONS);
195 if (res != 0) {
196 perror("listen failed ");
197 panic("main -- listen");
198 }
sewardj5ed7a392002-11-03 23:03:24 +0000199
sewardj43354092002-11-06 00:15:50 +0000200 while(1) {
sewardj5ed7a392002-11-03 23:03:24 +0000201
sewardj43354092002-11-06 00:15:50 +0000202 snooze();
sewardj5ed7a392002-11-03 23:03:24 +0000203
sewardj43354092002-11-06 00:15:50 +0000204 /* enquire, using poll, whether there is any activity available on
205 the main socket descriptor. If so, someone is trying to
206 connect; get the fd and add it to our table thereof. */
207 { struct pollfd ufd;
208 while (1) {
209 ufd.fd = main_sd;
210 ufd.events = POLLIN;
211 ufd.revents = 0;
212 res = poll(&ufd, 1, 0);
213 if (res == 0) break;
sewardj5ed7a392002-11-03 23:03:24 +0000214
sewardj43354092002-11-06 00:15:50 +0000215 /* ok, we have someone waiting to connect. Get the sd. */
216 client_len = sizeof(client_addr);
217 newSd = accept(main_sd, (struct sockaddr *) &client_addr,
218 &client_len);
219 if (newSd < 0) {
220 perror("cannot accept connection ");
221 panic("main -- accept connection");
222 }
223
224 /* find a place to put it. */
225 assert(newSd > 0);
226 for (i = 0; i < M_CONNECTIONS; i++)
227 if (conn_fd[i] == 0)
228 break;
229
230 if (i >= M_CONNECTIONS) {
231 fprintf(stderr, "Too many concurrent connections. "
232 "Increase M_CONNECTIONS and recompile.\n");
233 panic("main -- too many concurrent connections");
234 }
235
236 conn_fd[i] = newSd;
237 conn_count++;
238 printf("\n(%d) -------------------- CONNECT "
239 "--------------------\n(%d)\n(%d) ",
240 conn_count, conn_count, conn_count);
241 fflush(stdout);
242 } /* while (1) */
243 }
244
245 /* We've processed all new connect requests. Listen for changes
246 to the current set of fds. */
247 j = 0;
248 for (i = 0; i < M_CONNECTIONS; i++) {
249 if (conn_fd[i] == 0)
250 continue;
251 conn_pollfd[j].fd = conn_fd[i];
252 conn_pollfd[j].events = POLLIN /* | POLLHUP | POLLNVAL */;
253 conn_pollfd[j].revents = 0;
254 j++;
255 }
256
257 res = poll(conn_pollfd, j, 0 /* return immediately. */ );
258 if (res < 0) {
259 perror("poll(main) failed");
260 panic("poll(main) failed");
261 }
262
263 /* nothing happened. go round again. */
264 if (res == 0) {
265 continue;
266 }
267
268 /* inspect the fds. */
269 for (i = 0; i < j; i++) {
270
271 if (conn_pollfd[i].revents & POLLIN) {
272 /* data is available on this fd */
273 res = read_from_sd(conn_pollfd[i].fd);
274
275 if (res == 0) {
276 /* the connection has been closed. */
277 /* this fd has been closed or otherwise gone bad; forget
278 about it. */
279 for (k = 0; k < M_CONNECTIONS; k++)
280 if (conn_fd[k] == conn_pollfd[i].fd)
281 break;
282 assert(k < M_CONNECTIONS);
283 conn_fd[k] = 0;
284 conn_count--;
285 printf("\n(%d) ------------------- DISCONNECT "
286 "-------------------\n(%d)\n(%d) ",
287 conn_count, conn_count, conn_count);
288 fflush(stdout);
289 }
sewardj5ed7a392002-11-03 23:03:24 +0000290 }
291
sewardj43354092002-11-06 00:15:50 +0000292 } /* for (i = 0; i < j; i++) */
293
sewardj5ed7a392002-11-03 23:03:24 +0000294 } /* while (1) */
295
296}
297
298
299/*--------------------------------------------------------------------*/
300/*--- end valgrind-listener.c ---*/
301/*--------------------------------------------------------------------*/