~ubuntu-branches/ubuntu/gutsy/tcpreen/gutsy

« back to all changes in this revision

Viewing changes to src/bridge.cc

  • Committer: Bazaar Package Importer
  • Author(s): Oliver Kurth
  • Date: 2003-03-04 23:19:35 UTC
  • Revision ID: james.westby@ubuntu.com-20030304231935-rlvnd0mv4be1n8rn
Tags: upstream-1.2.2
Import upstream version 1.2.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * bridge.cc - Monitored file (socket, pipe...) bridge
 
3
 * $Id: bridge.cc,v 1.8 2003/01/26 09:09:07 rdenisc Exp $
 
4
 */
 
5
 
 
6
/***********************************************************************
 
7
 *  Copyright (C) 2002-2003 R�mi Denis-Courmont.                       *
 
8
 *  This program is free software; you can redistribute and/or modify  *
 
9
 *  it under the terms of the GNU General Public License as published  *
 
10
 *  by the Free Software Foundation; version 2 of the license.         *
 
11
 *                                                                     *
 
12
 *  This program is distributed in the hope that it will be useful,    *
 
13
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of     *
 
14
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.               *
 
15
 *  See the GNU General Public License for more details.               *
 
16
 *                                                                     *
 
17
 *  You should have received a copy of the GNU General Pulic License   *
 
18
 *  along with this program; if not, you can get it from:              *
 
19
 *  http://www.gnu.org/copyleft/gpl.html                               *
 
20
 ***********************************************************************/
 
21
 
 
22
#ifdef HAVE_CONFIG_H
 
23
# include <config.h>
 
24
#endif
 
25
 
 
26
#include <stdio.h>
 
27
#include <string.h> /* memcpy() */
 
28
#ifdef HAVE_LIMITS_H
 
29
# include <limits.h> /* SHRT_MAX */
 
30
#endif
 
31
#ifdef HAVE_UNISTD_H
 
32
# include <sys/time.h> /* struct timeval (unused, but needed for select) */
 
33
# include <unistd.h> /* close(), select(), read(), write() */
 
34
#endif
 
35
#ifdef HAVE_SYS_SOCKET_H
 
36
# include <sys/socket.h> /* shutdown() */
 
37
#endif
 
38
 
 
39
#include "log.h"
 
40
#include "bridge.h"
 
41
 
 
42
/*
 
43
 * Finds a pair of fds (one for reading, one for writing) in fd vectors
 
44
 * readfds and writefds, both of length <len>.
 
45
 *
 
46
 * Loops for ever if len is nul (that's not a bug, that's logic).
 
47
 * Returns a non-negative value (`val') on success, -1 on select() error.
 
48
 *
 
49
 * On return, readfds[index] is readable, writefds[index] is writeable,
 
50
 * exceptflag is true if an exceptionnal condition occured on
 
51
 * readfds[index] rather than a readability event.
 
52
 *
 
53
 * Function undefined if len is negative or exceeds MAXFILE.
 
54
 */
 
55
inline int
 
56
select_fd_pair (const int *readfds, const int *writefds, int len,
 
57
                int *exceptflag)
 
58
{
 
59
        while (1)
 
60
        {
 
61
                fd_set readset, writeset, exceptset;
 
62
                int maxreadfd = -1, maxwritefd = -1, i, s2;
 
63
 
 
64
                FD_ZERO (&readset);
 
65
                FD_ZERO (&writeset);
 
66
 
 
67
                for (i = 0; i < len; i++)
 
68
                {
 
69
                        int fd;
 
70
 
 
71
                        fd = readfds[i];
 
72
                        if (fd != -1)
 
73
                        {
 
74
                                FD_SET (fd, &readset);
 
75
                                if (maxreadfd < fd)
 
76
                                        maxreadfd = fd;
 
77
                        }
 
78
 
 
79
                        fd = writefds[i];
 
80
                        if (fd != -1) {
 
81
                                FD_SET (fd, &writeset);
 
82
                                if (maxwritefd < fd)
 
83
                                        maxwritefd = fd;
 
84
                        }
 
85
                }
 
86
                memcpy (&exceptset, &readset, sizeof(exceptset));
 
87
 
 
88
 
 
89
                //  Finds readable stream(s)...
 
90
                if ((select (++maxreadfd, &readset, NULL, &exceptset, NULL)
 
91
                        == -1)
 
92
                // ...and then writeable stream(s). 
 
93
                 || ((s2 = select (++maxwritefd, NULL, &writeset, NULL, NULL))
 
94
                         == -1))
 
95
                        return -1;
 
96
 
 
97
                for (i = 0; s2 > 0; i++)
 
98
                {
 
99
                        int fd;
 
100
 
 
101
                        fd = writefds[i];
 
102
                        if (fd != -1)
 
103
                                if (FD_ISSET (fd, &writeset))
 
104
                                {
 
105
                                        s2--;
 
106
                                        fd = readfds[i];
 
107
                                        if (FD_ISSET (fd, &exceptset))
 
108
                                        {
 
109
                                                *exceptflag = 1;
 
110
                                                return i;
 
111
                                        }
 
112
                                        else if (FD_ISSET (fd, &readset))
 
113
                                        {
 
114
                                                *exceptflag = 0;
 
115
                                                return i;
 
116
                                        }
 
117
                                }
 
118
                }
 
119
        }
 
120
}
 
121
 
 
122
static int
 
123
times_in_array(int *array, int len, int elem)
 
124
{
 
125
        int c = 0, i;
 
126
 
 
127
        for (i = 0; i < len; i++)
 
128
                if (array[i] == elem)
 
129
                        c++;
 
130
        return c;
 
131
}
 
132
 
 
133
static int
 
134
spare_close(int *readfds, int *writefds, int len, int fd, int how)
 
135
{
 
136
        if (times_in_array (how ? writefds : readfds, len, fd) == 1) {
 
137
                if (times_in_array (how ? readfds : writefds, len, fd) == 0)
 
138
                        return close(fd);
 
139
                else
 
140
                        return shutdown (fd, how);
 
141
        }
 
142
        return 0;
 
143
}
 
144
 
 
145
 
 
146
#define MAX_PACKET_SIZE (SHRT_MAX > 65535) ? 65535 : SHRT_MAX /* (bytes) */
 
147
 
 
148
/*
 
149
 * Operates a bridge between fd[0](input)/fd[2](output) and another
 
150
 * between fd[1](input)/fd[3](output) and display any transmitted data
 
151
 * to each streams in the NULL-terminated stream list <logs>.
 
152
 *
 
153
 * Note: no assumption is made about the transport protocol used,
 
154
 * but the use of shutdown() assumes we work with sockets
 
155
 * (shutdown() will otherwise silently fail -- not a big problem).
 
156
 *
 
157
 * fd is modified: closed descriptors are replaced by (-1).
 
158
 * In case of error, some of them might not have been closed.
 
159
 * Do it yourself.
 
160
 */
 
161
 
 
162
#define blen 2 /* number of half-duplex bridges */
 
163
#define readfds fds
 
164
#define writefds (fds+blen)
 
165
int
 
166
monitor_bridge(int fds[4], DataLogList *logs, long limit)
 
167
{
 
168
        long totalcount = 0;
 
169
        int bcount = blen;
 
170
 
 
171
        do
 
172
        {
 
173
                int oob;
 
174
 
 
175
                // What should we do?
 
176
                int index = select_fd_pair (readfds, writefds, blen, &oob);
 
177
                if (index < 0)
 
178
                        return 0; // most likely: errno = EINTR
 
179
        
 
180
                // Processes data
 
181
                char buf[MAX_PACKET_SIZE];
 
182
                        
 
183
                // Reads data
 
184
                int rfd = readfds[index];
 
185
                int len = (oob)
 
186
                        ? recv (rfd, buf, sizeof(buf), MSG_OOB)
 
187
                        : read (rfd, buf, sizeof(buf));
 
188
                        
 
189
                switch (len)
 
190
                {
 
191
                        case -1:// usually: EINTR or ETIMEDOUT
 
192
                        case 0: // end-of-file
 
193
                                spare_close (readfds, writefds, blen, rfd, 0);
 
194
                                readfds[index] = -1;
 
195
                                spare_close (readfds, writefds, blen,
 
196
                                                writefds[index], 1);
 
197
                                writefds[index] = -1;
 
198
                                bcount--;
 
199
 
 
200
                                if (index & 1)
 
201
                                        logs->ShutdownServer ();
 
202
                                else
 
203
                                        logs->ShutdownClient ();
 
204
                                break;
 
205
 
 
206
                        default:
 
207
                                if (index & 1)
 
208
                                        logs->WriteServerData (buf, len, oob);
 
209
                                else
 
210
                                        logs->WriteClientData (buf, len, oob);
 
211
 
 
212
                                totalcount += len;
 
213
                                if (totalcount < 0)
 
214
                                        totalcount = LONG_MAX;
 
215
                                        
 
216
                                /* Sends data to the real destination */
 
217
                                int check = (oob)
 
218
                                        ? send (writefds[index], buf, len,
 
219
                                                MSG_OOB)
 
220
                                        : write (writefds[index], buf, len);
 
221
                                if (check != len)
 
222
                                {
 
223
                                        // usually either EINTR or ETIMEDOUT
 
224
                                        spare_close (readfds, writefds, blen,
 
225
                                                        rfd, 0);
 
226
                                        readfds[index] = -1;
 
227
                                        spare_close (readfds, writefds, blen,
 
228
                                                        writefds[index], 1);
 
229
                                        writefds[index] = -1;
 
230
                                        bcount--;
 
231
                                }
 
232
                }
 
233
        }
 
234
        while (bcount && ((limit == -1) || (limit > totalcount)));
 
235
 
 
236
        return 0;
 
237
}
 
238