blob: d7f8561e2e84163ea3232c6c308316b757aaa679 [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>
43#include <assert.h>
44#include <sys/poll.h>
45#include <time.h>
46#include <fcntl.h>
47#include <stdlib.h>
48
49/*---------------------------------------------------------------*/
50
51#define SUCCESS 0
52#define ERROR 1
53
54#define END_LINE '\n'
55#define SERVER_PORT 1500
56#define MAX_CONNS 50
57
58/*---------------------------------------------------------------*/
59
60/* holds the fds for connections; zero if slot not in use. */
61int conn_count = 0;
62int conn_fd[MAX_CONNS];
63struct pollfd conn_pollfd[MAX_CONNS];
64
65
66void set_nonblocking ( int sd )
67{
68 int res;
69 res = fcntl(sd, F_GETFL);
70 res = fcntl(sd, F_SETFL, res | O_NONBLOCK);
71 if (res != 0) {
72 perror("fcntl failed");
73 exit(ERROR);
74 }
75}
76
77void set_blocking ( int sd )
78{
79 int res;
80 res = fcntl(sd, F_GETFL);
81 res = fcntl(sd, F_SETFL, res & ~O_NONBLOCK);
82 if (res != 0) {
83 perror("fcntl failed");
84 exit(ERROR);
85 }
86}
87
88
89void copyout ( char* buf, int nbuf )
90{
91 int i;
92 for (i = 0; i < nbuf; i++) {
93 if (buf[i] == '\n') {
94 fprintf(stdout, "\n(%d) ", conn_count);
95 } else {
96 fwrite(&buf[i], 1, 1, stdout);
97 }
98 }
99}
100
101int read_from_sd ( int sd )
102{
103 char buf[100];
104 int n;
105
106 set_blocking(sd);
107 n = read(sd, buf, 99);
108 if (n <= 0) return 0; /* closed */
109 copyout(buf, n);
110
111 set_nonblocking(sd);
112 while (1) {
113 n = read(sd, buf, 100);
114 if (n <= 0) return 1; /* not closed */
115 copyout(buf, n);
116 }
117}
118
119
120void snooze ( void )
121{
122 struct timespec req;
123 req.tv_sec = 0;
124 req.tv_nsec = 200 * 1000 * 1000;
125 nanosleep(&req,NULL);
126}
127
128
129/* function readline */
130int read_line();
131
132int main (int argc, char *argv[]) {
133 int i, j, k, res;
134 int main_sd, newSd, cliLen;
135
136 struct sockaddr_in cliAddr, servAddr;
137
138 conn_count = 0;
139 for (i = 0; i < MAX_CONNS; i++)
140 conn_fd[i] = 0;
141
142 /* create socket */
143 main_sd = socket(AF_INET, SOCK_STREAM, 0);
144 if (main_sd < 0) {
145 perror("cannot open socket ");
146 return ERROR;
147 }
148
149 /* bind server port */
150 servAddr.sin_family = AF_INET;
151 servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
152 servAddr.sin_port = htons(SERVER_PORT);
153
154 if(bind(main_sd, (struct sockaddr *) &servAddr, sizeof(servAddr))<0) {
155 perror("cannot bind port ");
156 return ERROR;
157 }
158
159 res = listen(main_sd,MAX_CONNS);
160 if (res != 0) {
161 perror("listen failed ");
162 return ERROR;
163 }
164
165 while(1) {
166
167 snooze();
168
169 /* enquire, using poll, whether there is any activity available on
170 the main socket descriptor. If so, someone is trying to
171 connect; get the fd and add it to our table thereof. */
172 { struct pollfd ufd;
173 while (1) {
174 ufd.fd = main_sd;
175 ufd.events = POLLIN;
176 ufd.revents = 0;
177 res = poll(&ufd, 1, 0);
178 if (res == 0) break;
179
180 /* ok, we have someone waiting to connect. Get the sd. */
181 cliLen = sizeof(cliAddr);
182 newSd = accept(main_sd, (struct sockaddr *) &cliAddr, &cliLen);
183 if(newSd<0) {
184 perror("cannot accept connection ");
185 return ERROR;
186 }
187
188 /* find a place to put it. */
189 assert(newSd > 0);
190 for (i = 0; i < MAX_CONNS; i++)
191 if (conn_fd[i] == 0)
192 break;
193
194 if (i >= MAX_CONNS) {
195 printf("too many concurrent connections\n");
196 return ERROR;
197 }
198 conn_fd[i] = newSd;
199 conn_count++;
200 printf("\n(%d) -------------------- CONNECT "
201 "--------------------\n(%d)\n(%d) ",
202 conn_count, conn_count, conn_count);
203 }
204 }
205
206
207 /* We've processed all new connect requests. Listen for changes
208 to the current set of fds. */
209 j = 0;
210 for (i = 0; i < MAX_CONNS; i++) {
211 if (conn_fd[i] == 0)
212 continue;
213 conn_pollfd[j].fd = conn_fd[i];
214 conn_pollfd[j].events = POLLIN | POLLHUP | POLLNVAL;
215 conn_pollfd[j].revents = 0;
216 j++;
217 }
218
219 res = poll(conn_pollfd, j, 0 /* return immediately. */ );
220
221 if (res < 0) {
222 perror("poll(main) failed");
223 return ERROR;
224 }
225
226 /* nothing happened. go round again. */
227 if (res == 0) {
228 continue;
229 }
230
231 /* inspect the fds. */
232 for (i = 0; i < j; i++) {
233
234 if ((conn_pollfd[i].revents & POLLHUP)
235 || (conn_pollfd[i].revents & POLLNVAL)) {
236 /* this fd has been closed or otherwise gone bad; forget about
237 it. */
238 closed:
239 for (k = 0; k < MAX_CONNS; k++)
240 if (conn_fd[k] == conn_pollfd[i].fd) break;
241 assert(k < MAX_CONNS);
242 conn_fd[k] = 0;
243 conn_count--;
244 printf("\n(%d) ------------------- DISCONNECT "
245 "-------------------\n(%d)\n(%d) ",
246 conn_count, conn_count, conn_count);
247 }
248 else
249 if (conn_pollfd[i].revents & POLLIN) {
250 /* data is available on this fd */
251 res = read_from_sd(conn_pollfd[i].fd);
252 if (res == 0) goto closed;
253 }
254
255 } /* for (i = 0; i < j; i++) */
256
257
258
259 } /* while (1) */
260
261}
262
263
264/*--------------------------------------------------------------------*/
265/*--- end valgrind-listener.c ---*/
266/*--------------------------------------------------------------------*/