ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/gvpe/src/vpn_tcp.C
Revision: 1.14
Committed: Tue Apr 26 00:55:56 2005 UTC (19 years, 1 month ago) by pcg
Content type: text/plain
Branch: MAIN
Changes since 1.13: +1 -1 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 pcg 1.1 /*
2     vpn_tcp.C -- handle the tcp part of the protocol.
3 pcg 1.12 Copyright (C) 2003-2005 Marc Lehmann <gvpe@schmorp.de>
4 pcg 1.1
5 pcg 1.12 This file is part of GVPE.
6    
7     GVPE is free software; you can redistribute it and/or modify
8 pcg 1.1 it under the terms of the GNU General Public License as published by
9     the Free Software Foundation; either version 2 of the License, or
10     (at your option) any later version.
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. See the
15     GNU General Public License for more details.
16    
17     You should have received a copy of the GNU General Public License
18 pcg 1.12 along with gvpe; if not, write to the Free Software
19 pcg 1.14 Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 pcg 1.1 */
21    
22     #include "config.h"
23    
24     #if ENABLE_TCP
25    
26     // tcp processing is extremely ugly, since the vpe protocol is simply
27     // designed for unreliable datagram networks. tcp is implemented by
28     // multiplexing packets over tcp. errors are completely ignored, as we
29     // rely on the higher level protocol to time out and reconnect.
30    
31     #include <cstring>
32    
33     #include <sys/types.h>
34     #include <sys/socket.h>
35     #include <sys/wait.h>
36     #include <sys/uio.h>
37     #include <errno.h>
38     #include <time.h>
39     #include <unistd.h>
40 pcg 1.9 #include <fcntl.h>
41 pcg 1.1
42     #include <map>
43 pcg 1.8
44     #include "netcompat.h"
45 pcg 1.1
46     #include "vpn.h"
47    
48 pcg 1.4 #if ENABLE_HTTP_PROXY
49     # include "conf.h"
50     #endif
51    
52 pcg 1.1 struct tcp_connection;
53    
54     struct lt_sockinfo
55     {
56     bool operator()(const sockinfo *a, const sockinfo *b) const
57     {
58     return *a < *b;
59     }
60     };
61    
62     struct tcp_si_map : public map<const sockinfo *, tcp_connection *, lt_sockinfo> {
63     void cleaner_cb (time_watcher &w); time_watcher cleaner;
64    
65     tcp_si_map ()
66 pcg 1.13 : cleaner(this, &tcp_si_map::cleaner_cb)
67     { }
68    
69 pcg 1.1 } tcp_si;
70    
71     struct tcp_connection : io_watcher {
72     tstamp last_activity;
73     const sockinfo si;
74     vpn &v;
75     bool active; // this connection has been actively established
76 pcg 1.4 enum { ERROR, IDLE, CONNECTING, CONNECTING_PROXY, ESTABLISHED } state;
77 pcg 1.1
78     vpn_packet *r_pkt;
79     u32 r_len, r_ofs;
80    
81 pcg 1.3 vpn_packet *w_pkt;
82     u32 w_len, w_ofs;
83    
84 pcg 1.4 #if ENABLE_HTTP_PROXY
85     char *proxy_req;
86     int proxy_req_len;
87     #endif
88    
89 pcg 1.1 void tcpv4_ev (io_watcher &w, short revents);
90    
91 pcg 1.2 bool send_packet (vpn_packet *pkt, int tos);
92 pcg 1.3 bool write_packet ();
93 pcg 1.1
94     void error (); // abort conenction && cleanup
95    
96     operator tcp_si_map::value_type()
97 pcg 1.13 {
98     return tcp_si_map::value_type (&si, this);
99     }
100 pcg 1.1
101     tcp_connection (int fd_, const sockinfo &si_, vpn &v_);
102     ~tcp_connection ();
103     };
104    
105     void tcp_si_map::cleaner_cb (time_watcher &w)
106     {
107 pcg 1.11 w.start (NOW + 600);
108    
109 pcg 1.1 tstamp to = NOW - ::conf.keepalive - 30 - 60;
110    
111     for (iterator i = begin (); i != end(); )
112     if (i->second->last_activity >= to)
113     ++i;
114     else
115     {
116     erase (i);
117     i = begin ();
118     }
119     }
120    
121     void
122     vpn::tcpv4_ev (io_watcher &w, short revents)
123     {
124 pcg 1.11 if (revents & EVENT_READ)
125 pcg 1.1 {
126     struct sockaddr_in sa;
127     socklen_t sa_len = sizeof (sa);
128     int len;
129    
130     int fd = accept (w.fd, (sockaddr *)&sa, &sa_len);
131    
132     if (fd >= 0)
133     {
134     sockinfo si(sa, PROT_TCPv4);
135    
136     slog (L_DEBUG, _("%s: accepted tcp connection"), (const char *)si);//D
137    
138     fcntl (fd, F_SETFL, O_NONBLOCK);
139    
140     tcp_connection *i = new tcp_connection (fd, si, *this);
141     tcp_si.insert (*i);
142     }
143     }
144     }
145    
146 pcg 1.2 bool
147 pcg 1.1 vpn::send_tcpv4_packet (vpn_packet *pkt, const sockinfo &si, int tos)
148     {
149     tcp_si_map::iterator info = tcp_si.find (&si);
150    
151     tcp_connection *i;
152    
153     if (info == tcp_si.end ())
154     {
155     i = new tcp_connection (-1, si, *this);
156     tcp_si.insert (*i);
157     }
158     else
159     i = info->second;
160    
161 pcg 1.2 return i->send_packet (pkt, tos);
162 pcg 1.1 }
163    
164 pcg 1.3 bool
165     tcp_connection::write_packet ()
166     {
167     ssize_t len;
168    
169     if (w_ofs < 2)
170     {
171     u16 plen = htons (w_pkt->len);
172    
173     iovec vec[2];
174 pcg 1.7 //TODO: char* is the right type? hardly...
175     vec[0].iov_base = (char *)((u8 *)&plen) + w_ofs;
176 pcg 1.3 vec[0].iov_len = 2 - w_ofs;
177 pcg 1.7 vec[1].iov_base = (char *)&((*w_pkt)[0]);
178 pcg 1.3 vec[1].iov_len = w_len - 2;
179    
180     len = writev (fd, vec, 2);
181     }
182     else
183     len = write (fd, &((*w_pkt)[w_ofs - 2]), w_len);
184    
185     if (len > 0)
186     {
187     w_ofs += len;
188     w_len -= len;
189    
190     return w_len == 0;
191     }
192     else if (len < 0 && (errno == EAGAIN || errno == EINTR))
193     return false;
194     else
195     {
196     error ();
197     return false;
198     }
199     }
200    
201 pcg 1.1 void
202     tcp_connection::tcpv4_ev (io_watcher &w, short revents)
203     {
204     last_activity = NOW;
205    
206 pcg 1.11 if (revents & EVENT_WRITE)
207 pcg 1.3 {
208     if (state == CONNECTING)
209     {
210     state = ESTABLISHED;
211 pcg 1.11 set (EVENT_READ);
212 pcg 1.4 #if ENABLE_HTTP_PROXY
213     if (::conf.proxy_host && ::conf.proxy_port)
214     {
215     state = CONNECTING_PROXY;
216 pcg 1.11
217     if (write (fd, proxy_req, proxy_req_len) == 0)
218     {
219     error ();
220     return;
221     }
222    
223 pcg 1.4 free (proxy_req); proxy_req = 0;
224     }
225     #endif
226 pcg 1.3 }
227     else if (state == ESTABLISHED)
228     {
229     if (w_pkt)
230     {
231     if (write_packet ())
232     {
233     delete w_pkt; w_pkt = 0;
234    
235 pcg 1.11 set (EVENT_READ);
236 pcg 1.3 }
237     }
238     else
239 pcg 1.11 set (EVENT_READ);
240 pcg 1.3 }
241     else
242 pcg 1.11 set (EVENT_READ);
243 pcg 1.3 }
244    
245 pcg 1.11 if (revents & EVENT_READ)
246 pcg 1.1 {
247 pcg 1.4 if (state == ESTABLISHED)
248     for (;;)
249     {
250     if (!r_pkt)
251     {
252     r_pkt = new vpn_packet;
253     r_ofs = 0;
254     r_len = 2; // header
255     }
256    
257     ssize_t len = read (fd, &((*r_pkt)[r_ofs < 2 ? r_ofs : r_ofs - 2]), r_len);
258    
259     if (len > 0)
260     {
261     r_len -= len;
262     r_ofs += len;
263    
264     if (r_len == 0)
265     {
266     if (r_ofs == 2)
267     {
268     r_len = ntohs (*(u16 *)&((*r_pkt)[0]));
269     r_pkt->len = r_len;
270    
271     if (r_len > 0 && r_len < MAXSIZE)
272     continue;
273     }
274     else
275     {
276     v.recv_vpn_packet (r_pkt, si);
277     delete r_pkt;
278     r_pkt = 0;
279    
280     continue;
281     }
282     }
283     else
284     break;
285     }
286     else if (len < 0 && (errno == EINTR || errno == EAGAIN))
287     break;
288    
289 pcg 1.11 // len == 0 <-> EOF
290 pcg 1.4 error ();
291     break;
292     }
293     #if ENABLE_HTTP_PROXY
294     else if (state == CONNECTING_PROXY)
295 pcg 1.1 {
296 pcg 1.4 fcntl (fd, F_SETFL, 0);
297     char r[1024];
298     int i;
299     bool emptyline = false;
300 pcg 1.1
301 pcg 1.4 // we do a blocking read of the response, to hell with it
302     for (i = 0; i < 1023; i++)
303 pcg 1.1 {
304 pcg 1.4 int l = read (fd, &r[i], 1);
305 pcg 1.1
306 pcg 1.4 if (l <= 0)
307 pcg 1.1 {
308 pcg 1.4 error ();
309     return;
310     }
311 pcg 1.1
312 pcg 1.4 if (r[i] == '\012')
313     {
314     if (emptyline)
315     break;
316 pcg 1.1 else
317 pcg 1.4 emptyline = true;
318 pcg 1.1 }
319 pcg 1.4 else if (r[i] != '\015')
320     emptyline = false;
321 pcg 1.1 }
322    
323 pcg 1.4 fcntl (fd, F_SETFL, O_NONBLOCK);
324    
325     if (i < 12)
326     {
327 pcg 1.6 slog (L_ERR, _("(%s): unable to do proxy-forwarding, short response"),
328 pcg 1.5 (const char *)si);
329 pcg 1.4 error ();
330     }
331     else if (r[0] != 'H' || r[1] != 'T' || r[2] != 'T' || r[3] != 'P' || r[4] != '/'
332     || r[5] != '1' // http-major
333     || r[9] != '2') // response
334     {
335 pcg 1.6 slog (L_ERR, _("(%s): malformed or unexpected proxy response (%.12s)"),
336 pcg 1.5 (const char *)si, r);
337 pcg 1.4 error ();
338     }
339     else
340     state = ESTABLISHED;
341 pcg 1.1 }
342 pcg 1.4 #endif
343 pcg 1.1 }
344     }
345    
346 pcg 1.2 bool
347 pcg 1.1 tcp_connection::send_packet (vpn_packet *pkt, int tos)
348     {
349     last_activity = NOW;
350    
351     if (state == IDLE)
352     {
353     // woaw, the first lost packet ;)
354     fd = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
355    
356     if (fd >= 0)
357     {
358 pcg 1.4 const sockinfo *csi = &si;
359    
360     #if ENABLE_HTTP_PROXY
361     sockinfo psi;
362    
363     if (::conf.proxy_host && ::conf.proxy_port)
364     {
365     psi.set (::conf.proxy_host, ::conf.proxy_port, PROT_TCPv4);
366    
367     if (psi.valid ())
368     {
369     csi = &psi;
370    
371     proxy_req_len = asprintf (&proxy_req,
372     "CONNECT %s:%d HTTP/1.0\015\012"
373     "%s%s%s" // optional proxy-auth
374     "\015\012",
375     si.ntoa (),
376     ntohs (si.port),
377     ::conf.proxy_auth ? "Proxy-Authorization: Basic " : "",
378     ::conf.proxy_auth ? ::conf.proxy_auth : "",
379     ::conf.proxy_auth ? "\015\012" : "");
380    
381     }
382     else
383     slog (L_ERR, _("unable to resolve http proxy hostname '%s', trying direct"),
384     ::conf.proxy_host);
385     }
386     #endif
387    
388 pcg 1.1 fcntl (fd, F_SETFL, O_NONBLOCK);
389 pcg 1.4
390     if (connect (fd, csi->sav4 (), csi->salenv4 ()) >= 0
391 pcg 1.1 || errno == EINPROGRESS)
392     {
393     state = CONNECTING;
394 pcg 1.11 start (fd, EVENT_WRITE);
395 pcg 1.1 }
396     else
397     close (fd);
398     }
399     }
400     else if (state == ESTABLISHED)
401     {
402 pcg 1.3 // drop packet if the tcp write buffer is full. this *is* the
403     // right thing to do, not using tcp *is* the right thing to do.
404     if (!w_pkt)
405     {
406     // how this maps to the underlying tcp packets we don't know
407     // and we don't care. at least we tried ;)
408 pcg 1.7 #if defined(SOL_IP) && defined(IP_TOS)
409 pcg 1.3 setsockopt (fd, SOL_IP, IP_TOS, &tos, sizeof tos);
410 pcg 1.7 #endif
411 pcg 1.3
412     w_pkt = pkt;
413     w_ofs = 0;
414     w_len = pkt->len + 2; // length + size header
415    
416     if (write_packet ())
417     w_pkt = 0;
418     else
419     {
420     w_pkt = new vpn_packet;
421     w_pkt->set (*pkt);
422 pcg 1.1
423 pcg 1.11 set (EVENT_READ | EVENT_WRITE);
424 pcg 1.3 }
425     }
426 pcg 1.1 }
427 pcg 1.2
428     return state != ERROR;
429 pcg 1.1 }
430    
431 pcg 1.4 void tcp_connection::error ()
432     {
433     if (fd >= 0)
434     {
435     close (fd);
436     fd = -1;
437     }
438    
439     delete r_pkt; r_pkt = 0;
440     delete w_pkt; w_pkt = 0;
441     #if ENABLE_HTTP_PROXY
442     free (proxy_req); proxy_req = 0;
443     #endif
444    
445     stop ();
446     state = active ? IDLE : ERROR;
447     }
448    
449 pcg 1.1 tcp_connection::tcp_connection (int fd_, const sockinfo &si_, vpn &v_)
450     : v(v_), si(si_), io_watcher(this, &tcp_connection::tcpv4_ev)
451     {
452 pcg 1.13 if (!tcp_si.cleaner.active)
453     tcp_si.cleaner.start (0);
454    
455 pcg 1.1 last_activity = NOW;
456     r_pkt = 0;
457 pcg 1.3 w_pkt = 0;
458 pcg 1.1 fd = fd_;
459 pcg 1.4 #if ENABLE_HTTP_PROXY
460     proxy_req = 0;
461     #endif
462 pcg 1.1
463     if (fd < 0)
464     {
465     active = true;
466     state = IDLE;
467     }
468     else
469     {
470     active = false;
471     state = ESTABLISHED;
472 pcg 1.11 start (fd, EVENT_READ);
473 pcg 1.1 }
474     }
475    
476     tcp_connection::~tcp_connection ()
477     {
478     error ();
479     }
480    
481     #endif
482