1 /* Proxytunnel - (C) 2001-2008 Jos Visser / Mark Janssen */
2 /* Contact: josv@osp.nl / maniac@maniac.nl */
3
4 /*
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20 /* io.c */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <sys/types.h>
27 #include <sys/socket.h>
28
29 #include "proxytunnel.h"
30 #include "io.h"
31
32 #define ACTIVE 1
33 #define CLOSED 0
34
35 /*
36 * Read one line of data from the tunnel. Line is terminated by a
37 * newline character. Result is stored in buf.
38 */
readline(PTSTREAM * pts)39 int readline(PTSTREAM *pts) {
40 char *p = buf;
41 char c = 0;
42 int i = 0;
43
44 /* Read one character at a time into buf, until a newline is encountered. */
45 while ( c != 10 && ( i < SIZE - 1 ) ) {
46 if( stream_read( pts, &c ,1) <= 0) {
47 my_perror( "Socket read error" );
48 exit( 1 );
49 }
50
51 *p = c;
52 p++;
53 i++;
54 }
55
56 *p = 0;
57
58 if( args_info.verbose_flag ) {
59 /* Copy line of data into dstr without trailing newline */
60 char *dstr = malloc(strlen(buf) + 1);
61 strncpy( dstr, buf, strlen(buf));
62 if (strcmp(dstr, ""))
63 message( " <- %s\n", dstr );
64 }
65 return strlen( buf );
66 }
67
68 /*
69 * Bond stream1 and stream2 together; any data received in stream1 is relayed
70 * to stream2, and vice-versa.
71 */
cpio(PTSTREAM * stream1,PTSTREAM * stream2)72 void cpio(PTSTREAM *stream1, PTSTREAM *stream2) {
73 fd_set readfds;
74 fd_set writefds;
75 fd_set exceptfds;
76 int in_max_fd, out_max_fd, max_fd;
77
78 /* Find the biggest file descriptor for select() */
79 in_max_fd = MAX(stream_get_incoming_fd(stream1), stream_get_incoming_fd(stream2));
80 out_max_fd = MAX(stream_get_outgoing_fd(stream1), stream_get_outgoing_fd(stream2));
81 max_fd = MAX(in_max_fd, out_max_fd);
82
83 /* We are never interested in sockets being available for write */
84 FD_ZERO( &writefds );
85
86
87 /* experimental timeout */
88 struct timeval select_timeout;
89 select_timeout.tv_sec = 30; /* should be fine */
90 select_timeout.tv_usec = 0;
91
92 if( args_info.verbose_flag )
93 message( "\nTunnel established.\n" );
94
95 int stream_status = ACTIVE;
96 while( stream_status == ACTIVE ) {
97 /* Clear the interesting socket sets */
98 FD_ZERO( &readfds );
99 FD_ZERO( &exceptfds );
100
101 /* We want to know whether stream1 or stream2 is ready for reading */
102 FD_SET( stream_get_incoming_fd(stream1), &readfds );
103 FD_SET( stream_get_incoming_fd(stream2), &readfds );
104
105 /* And we want to know about exceptional conditions on either stream */
106 FD_SET( stream_get_incoming_fd(stream1), &exceptfds );
107 FD_SET( stream_get_outgoing_fd(stream1), &exceptfds );
108 FD_SET( stream_get_incoming_fd(stream2), &exceptfds );
109 FD_SET( stream_get_outgoing_fd(stream2), &exceptfds );
110
111 /* reset the timeout, since select() does modify this struct! */
112 select_timeout.tv_sec = 30;
113 select_timeout.tv_usec = 0;
114
115 /* Wait/timeout something happens on the registered sockets/files */
116 int number_of_fds_ready;
117 number_of_fds_ready = select( max_fd + 1, &readfds, &writefds, &exceptfds, &select_timeout );
118 if ( number_of_fds_ready < 0 ) {
119 perror("select error");
120 exit(1);
121 }
122
123 if (number_of_fds_ready > 0) {
124 /* Is stream1 ready for read? If so, copy a block of data
125 * from stream1 to stream2. Or else if stream2
126 * is ready for read, copy a block of data from the
127 * stream2 to stream1. Otherwise an exceptional condition
128 * is flagged and the program is terminated.
129 */
130 if ( FD_ISSET( stream_get_incoming_fd(stream1), &readfds ) ) {
131 if ( stream_copy(stream1, stream2 ) )
132 stream_status = CLOSED;
133 } else if( FD_ISSET( stream_get_incoming_fd(stream2), &readfds ) ) {
134 if( stream_copy(stream2, stream1 ) )
135 stream_status = CLOSED;
136 } else {
137 my_perror( "Exceptional condition" );
138 stream_status = CLOSED;
139 }
140 }
141 }
142 closeall();
143 }
144