2
* bridge.cc - Monitored file (socket, pipe...) bridge
3
* $Id: bridge.cc,v 1.8 2003/01/26 09:09:07 rdenisc Exp $
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. *
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. *
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
***********************************************************************/
27
#include <string.h> /* memcpy() */
29
# include <limits.h> /* SHRT_MAX */
32
# include <sys/time.h> /* struct timeval (unused, but needed for select) */
33
# include <unistd.h> /* close(), select(), read(), write() */
35
#ifdef HAVE_SYS_SOCKET_H
36
# include <sys/socket.h> /* shutdown() */
43
* Finds a pair of fds (one for reading, one for writing) in fd vectors
44
* readfds and writefds, both of length <len>.
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.
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.
53
* Function undefined if len is negative or exceeds MAXFILE.
56
select_fd_pair (const int *readfds, const int *writefds, int len,
61
fd_set readset, writeset, exceptset;
62
int maxreadfd = -1, maxwritefd = -1, i, s2;
67
for (i = 0; i < len; i++)
74
FD_SET (fd, &readset);
81
FD_SET (fd, &writeset);
86
memcpy (&exceptset, &readset, sizeof(exceptset));
89
// Finds readable stream(s)...
90
if ((select (++maxreadfd, &readset, NULL, &exceptset, NULL)
92
// ...and then writeable stream(s).
93
|| ((s2 = select (++maxwritefd, NULL, &writeset, NULL, NULL))
97
for (i = 0; s2 > 0; i++)
103
if (FD_ISSET (fd, &writeset))
107
if (FD_ISSET (fd, &exceptset))
112
else if (FD_ISSET (fd, &readset))
123
times_in_array(int *array, int len, int elem)
127
for (i = 0; i < len; i++)
128
if (array[i] == elem)
134
spare_close(int *readfds, int *writefds, int len, int fd, int how)
136
if (times_in_array (how ? writefds : readfds, len, fd) == 1) {
137
if (times_in_array (how ? readfds : writefds, len, fd) == 0)
140
return shutdown (fd, how);
146
#define MAX_PACKET_SIZE (SHRT_MAX > 65535) ? 65535 : SHRT_MAX /* (bytes) */
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>.
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).
157
* fd is modified: closed descriptors are replaced by (-1).
158
* In case of error, some of them might not have been closed.
162
#define blen 2 /* number of half-duplex bridges */
164
#define writefds (fds+blen)
166
monitor_bridge(int fds[4], DataLogList *logs, long limit)
175
// What should we do?
176
int index = select_fd_pair (readfds, writefds, blen, &oob);
178
return 0; // most likely: errno = EINTR
181
char buf[MAX_PACKET_SIZE];
184
int rfd = readfds[index];
186
? recv (rfd, buf, sizeof(buf), MSG_OOB)
187
: read (rfd, buf, sizeof(buf));
191
case -1:// usually: EINTR or ETIMEDOUT
192
case 0: // end-of-file
193
spare_close (readfds, writefds, blen, rfd, 0);
195
spare_close (readfds, writefds, blen,
197
writefds[index] = -1;
201
logs->ShutdownServer ();
203
logs->ShutdownClient ();
208
logs->WriteServerData (buf, len, oob);
210
logs->WriteClientData (buf, len, oob);
214
totalcount = LONG_MAX;
216
/* Sends data to the real destination */
218
? send (writefds[index], buf, len,
220
: write (writefds[index], buf, len);
223
// usually either EINTR or ETIMEDOUT
224
spare_close (readfds, writefds, blen,
227
spare_close (readfds, writefds, blen,
229
writefds[index] = -1;
234
while (bcount && ((limit == -1) || (limit > totalcount)));