ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/gvpe/src/vpn_tcp.C
(Generate patch)

Comparing gvpe/src/vpn_tcp.C (file contents):
Revision 1.5 by pcg, Mon Apr 7 01:28:56 2003 UTC vs.
Revision 1.26 by pcg, Thu Aug 7 17:54:27 2008 UTC

1/* 1/*
2 vpn_tcp.C -- handle the tcp part of the protocol. 2 vpn_tcp.C -- handle the tcp part of the protocol.
3 Copyright (C) 2003-2008 Marc Lehmann <gvpe@schmorp.de>
3 4
5 This file is part of GVPE.
6
4 This program is free software; you can redistribute it and/or modify 7 GVPE is free software; you can redistribute it and/or modify it
5 it under the terms of the GNU General Public License as published by 8 under the terms of the GNU General Public License as published by the
6 the Free Software Foundation; either version 2 of the License, or 9 Free Software Foundation; either version 3 of the License, or (at your
7 (at your option) any later version. 10 option) any later version.
8 11
9 This program is distributed in the hope that it will be useful, 12 This program is distributed in the hope that it will be useful, but
10 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
12 GNU General Public License for more details. 15 Public License for more details.
13 16
14 You should have received a copy of the GNU General Public License 17 You should have received a copy of the GNU General Public License along
15 along with this program; if not, write to the Free Software 18 with this program; if not, see <http://www.gnu.org/licenses/>.
16 Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19
20 Additional permission under GNU GPL version 3 section 7
21
22 If you modify this Program, or any covered work, by linking or
23 combining it with the OpenSSL project's OpenSSL library (or a modified
24 version of that library), containing parts covered by the terms of the
25 OpenSSL or SSLeay licenses, the licensors of this Program grant you
26 additional permission to convey the resulting work. Corresponding
27 Source for a non-source form of such a combination shall include the
28 source code for the parts of OpenSSL used as well as that of the
29 covered work.
17*/ 30*/
18 31
19#include "config.h" 32#include "config.h"
20 33
21#if ENABLE_TCP 34#if ENABLE_TCP
22 35
23// tcp processing is extremely ugly, since the vpe protocol is simply 36// tcp processing is extremely ugly, since the gvpe protocol is simply
24// designed for unreliable datagram networks. tcp is implemented by 37// designed for unreliable datagram networks. tcp is implemented by
25// multiplexing packets over tcp. errors are completely ignored, as we 38// multiplexing packets over tcp. errors are completely ignored, as we
26// rely on the higher level protocol to time out and reconnect. 39// rely on the higher level layers to time out and reconnect.
27 40
28#include <cstring> 41#include <cstring>
29 42
30#include <sys/types.h> 43#include <sys/types.h>
31#include <sys/socket.h> 44#include <sys/socket.h>
32#include <sys/poll.h>
33#include <sys/wait.h> 45#include <sys/wait.h>
34#include <netinet/in.h>
35#include <sys/uio.h> 46#include <sys/uio.h>
36#include <arpa/inet.h>
37#include <errno.h> 47#include <errno.h>
38#include <time.h> 48#include <time.h>
39#include <unistd.h> 49#include <unistd.h>
50#include <fcntl.h>
40 51
41#include <map> 52#include <map>
42#include <unistd.h> 53
43#include <fcntl.h> 54#include "netcompat.h"
44#include <sys/poll.h>
45 55
46#include "vpn.h" 56#include "vpn.h"
47 57
48#if ENABLE_HTTP_PROXY 58#if ENABLE_HTTP_PROXY
49# include "conf.h" 59# include "conf.h"
57 { 67 {
58 return *a < *b; 68 return *a < *b;
59 } 69 }
60}; 70};
61 71
62struct tcp_si_map : public map<const sockinfo *, tcp_connection *, lt_sockinfo> { 72struct tcp_si_map : public map<const sockinfo *, tcp_connection *, lt_sockinfo>
63 void cleaner_cb (time_watcher &w); time_watcher cleaner; 73{
74 inline void cleaner_cb (ev::timer &w, int revents); ev::timer cleaner;
64 75
65 tcp_si_map () 76 tcp_si_map ()
66 : cleaner(this, &tcp_si_map::cleaner_cb)
67 { 77 {
68 cleaner.start (0); 78 ev_default_loop (0);
79 cleaner.set<tcp_si_map, &tcp_si_map::cleaner_cb> (this);
80 cleaner.start (::conf.keepalive / 2, ::conf.keepalive / 2);
69 } 81 }
82
70} tcp_si; 83} tcp_si;
71 84
72struct tcp_connection : io_watcher { 85struct tcp_connection : ev::io
86{
87 int tos;
73 tstamp last_activity; 88 tstamp last_activity;
74 const sockinfo si; 89 const sockinfo si;
75 vpn &v; 90 vpn &v;
76 bool active; // this connection has been actively established 91 bool active; // this connection has been actively established
77 enum { ERROR, IDLE, CONNECTING, CONNECTING_PROXY, ESTABLISHED } state; 92 enum { ERROR, IDLE, CONNECTING, CONNECTING_PROXY, ESTABLISHED } state;
85#if ENABLE_HTTP_PROXY 100#if ENABLE_HTTP_PROXY
86 char *proxy_req; 101 char *proxy_req;
87 int proxy_req_len; 102 int proxy_req_len;
88#endif 103#endif
89 104
90 void tcpv4_ev (io_watcher &w, short revents); 105 inline void tcpv4_ev (ev::io &w, int revents);
91 106
92 bool send_packet (vpn_packet *pkt, int tos); 107 bool send_packet (vpn_packet *pkt, int tos);
93 bool write_packet (); 108 bool write_packet ();
94 109
95 void error (); // abort conenction && cleanup 110 void error (); // abort conenction && cleanup
96 111
97 operator tcp_si_map::value_type() 112 operator tcp_si_map::value_type()
98 { 113 {
99 return tcp_si_map::value_type (&si, this); 114 return tcp_si_map::value_type (&si, this);
100 } 115 }
101 116
102 tcp_connection (int fd_, const sockinfo &si_, vpn &v_); 117 tcp_connection (int fd_, const sockinfo &si_, vpn &v_);
103 ~tcp_connection (); 118 ~tcp_connection ();
104}; 119};
105 120
106void tcp_si_map::cleaner_cb (time_watcher &w) 121void tcp_si_map::cleaner_cb (ev::timer &w, int revents)
107{ 122{
108 w.at = NOW + 600;
109 tstamp to = NOW - ::conf.keepalive - 30 - 60; 123 tstamp to = ev_now () - ::conf.keepalive - 30 - 60;
110 124
111 for (iterator i = begin (); i != end(); ) 125 for (iterator i = begin (); i != end(); )
112 if (i->second->last_activity >= to) 126 if (i->second->last_activity >= to)
113 ++i; 127 ++i;
114 else 128 else
115 { 129 {
130 delete i->second;
116 erase (i); 131 erase (i);
117 i = begin (); 132 i = begin ();
118 } 133 }
119} 134}
120 135
121void 136void
122vpn::tcpv4_ev (io_watcher &w, short revents) 137vpn::tcpv4_ev (ev::io &w, int revents)
123{ 138{
124 if (revents & (POLLIN | POLLERR)) 139 if (revents & EV_READ)
125 { 140 {
126 struct sockaddr_in sa; 141 struct sockaddr_in sa;
127 socklen_t sa_len = sizeof (sa); 142 socklen_t sa_len = sizeof (sa);
128 int len; 143 int len;
129 144
130 int fd = accept (w.fd, (sockaddr *)&sa, &sa_len); 145 int fd = accept (w.fd, (sockaddr *)&sa, &sa_len);
131 146
132 if (fd >= 0) 147 if (fd >= 0)
133 { 148 {
149 fcntl (fd, F_SETFL, O_NONBLOCK);
150 fcntl (fd, F_SETFD, FD_CLOEXEC);
151
134 sockinfo si(sa, PROT_TCPv4); 152 sockinfo si(sa, PROT_TCPv4);
135 153
136 slog (L_DEBUG, _("%s: accepted tcp connection"), (const char *)si);//D 154 slog (L_DEBUG, _("%s: accepted tcp connection"), (const char *)si);//D
137
138 fcntl (fd, F_SETFL, O_NONBLOCK);
139 155
140 tcp_connection *i = new tcp_connection (fd, si, *this); 156 tcp_connection *i = new tcp_connection (fd, si, *this);
141 tcp_si.insert (*i); 157 tcp_si.insert (*i);
142 } 158 }
143 } 159 }
169 if (w_ofs < 2) 185 if (w_ofs < 2)
170 { 186 {
171 u16 plen = htons (w_pkt->len); 187 u16 plen = htons (w_pkt->len);
172 188
173 iovec vec[2]; 189 iovec vec[2];
190 //TODO: char* is the right type? hardly...
174 vec[0].iov_base = ((u8 *)&plen) + w_ofs; 191 vec[0].iov_base = (char *)((u8 *)&plen) + w_ofs;
175 vec[0].iov_len = 2 - w_ofs; 192 vec[0].iov_len = 2 - w_ofs;
176 vec[1].iov_base = &((*w_pkt)[0]); 193 vec[1].iov_base = (char *)&((*w_pkt)[0]);
177 vec[1].iov_len = w_len - 2; 194 vec[1].iov_len = w_len - 2;
178 195
179 len = writev (fd, vec, 2); 196 len = writev (fd, vec, 2);
180 } 197 }
181 else 198 else
196 return false; 213 return false;
197 } 214 }
198} 215}
199 216
200void 217void
201tcp_connection::tcpv4_ev (io_watcher &w, short revents) 218tcp_connection::tcpv4_ev (ev::io &w, int revents)
202{ 219{
203 last_activity = NOW; 220 last_activity = ev_now ();
204 221
205 if (revents & (POLLERR | POLLHUP)) 222 if (revents & EV_WRITE)
206 {
207 error ();
208 return;
209 }
210
211 if (revents & POLLOUT)
212 { 223 {
213 if (state == CONNECTING) 224 if (state == CONNECTING)
214 { 225 {
215 state = ESTABLISHED; 226 state = ESTABLISHED;
216 set (POLLIN); 227 set (EV_READ);
217#if ENABLE_HTTP_PROXY 228#if ENABLE_HTTP_PROXY
218 if (::conf.proxy_host && ::conf.proxy_port) 229 if (::conf.proxy_host && ::conf.proxy_port)
219 { 230 {
220 state = CONNECTING_PROXY; 231 state = CONNECTING_PROXY;
232
221 write (fd, proxy_req, proxy_req_len); 233 if (write (fd, proxy_req, proxy_req_len) == 0)
234 {
235 error ();
236 return;
237 }
238
222 free (proxy_req); proxy_req = 0; 239 free (proxy_req); proxy_req = 0;
223 } 240 }
224#endif 241#endif
225 } 242 }
226 else if (state == ESTABLISHED) 243 else if (state == ESTABLISHED)
229 { 246 {
230 if (write_packet ()) 247 if (write_packet ())
231 { 248 {
232 delete w_pkt; w_pkt = 0; 249 delete w_pkt; w_pkt = 0;
233 250
234 set (POLLIN); 251 set (EV_READ);
235 } 252 }
236 } 253 }
237 else 254 else
238 set (POLLIN); 255 set (EV_READ);
239 } 256 }
240 else 257 else
241 set (POLLIN); 258 set (EV_READ);
242 } 259 }
243 260
244 if (revents & POLLIN) 261 if (revents & EV_READ)
245 { 262 {
246 if (state == ESTABLISHED) 263 if (state == ESTABLISHED)
247 for (;;) 264 for (;;)
248 { 265 {
249 if (!r_pkt) 266 if (!r_pkt)
283 break; 300 break;
284 } 301 }
285 else if (len < 0 && (errno == EINTR || errno == EAGAIN)) 302 else if (len < 0 && (errno == EINTR || errno == EAGAIN))
286 break; 303 break;
287 304
305 // len == 0 <-> EOF
288 error (); 306 error ();
289 break; 307 break;
290 } 308 }
291#if ENABLE_HTTP_PROXY 309#if ENABLE_HTTP_PROXY
292 else if (state == CONNECTING_PROXY) 310 else if (state == CONNECTING_PROXY)
320 338
321 fcntl (fd, F_SETFL, O_NONBLOCK); 339 fcntl (fd, F_SETFL, O_NONBLOCK);
322 340
323 if (i < 12) 341 if (i < 12)
324 { 342 {
325 slog (L_ERR, _("%s: unable to do proxy-forwarding, short response"), 343 slog (L_ERR, _("(%s): unable to do proxy-forwarding, short response"),
326 (const char *)si); 344 (const char *)si);
327 error (); 345 error ();
328 } 346 }
329 else if (r[0] != 'H' || r[1] != 'T' || r[2] != 'T' || r[3] != 'P' || r[4] != '/' 347 else if (r[0] != 'H' || r[1] != 'T' || r[2] != 'T' || r[3] != 'P' || r[4] != '/'
330 || r[5] != '1' // http-major 348 || r[5] != '1' // http-major
331 || r[9] != '2') // response 349 || r[9] != '2') // response
332 { 350 {
333 slog (L_ERR, _("%s: malformed or unexpected proxy response (%.12s)"), 351 slog (L_ERR, _("(%s): malformed or unexpected proxy response (%.12s)"),
334 (const char *)si, r); 352 (const char *)si, r);
335 error (); 353 error ();
336 } 354 }
337 else 355 else
338 state = ESTABLISHED; 356 state = ESTABLISHED;
342} 360}
343 361
344bool 362bool
345tcp_connection::send_packet (vpn_packet *pkt, int tos) 363tcp_connection::send_packet (vpn_packet *pkt, int tos)
346{ 364{
347 last_activity = NOW; 365 last_activity = ev_now ();
348 366
349 if (state == IDLE) 367 if (state == IDLE)
350 { 368 {
351 // woaw, the first lost packet ;) 369 // woaw, the first lost packet ;)
352 fd = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP); 370 fd = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
386 fcntl (fd, F_SETFL, O_NONBLOCK); 404 fcntl (fd, F_SETFL, O_NONBLOCK);
387 405
388 if (connect (fd, csi->sav4 (), csi->salenv4 ()) >= 0 406 if (connect (fd, csi->sav4 (), csi->salenv4 ()) >= 0
389 || errno == EINPROGRESS) 407 || errno == EINPROGRESS)
390 { 408 {
409 fcntl (fd, F_SETFL, O_NONBLOCK);
410 fcntl (fd, F_SETFD, FD_CLOEXEC);
411
391 state = CONNECTING; 412 state = CONNECTING;
392 start (fd, POLLOUT); 413 start (fd, EV_WRITE);
393 } 414 }
394 else 415 else
395 close (fd); 416 close (fd);
396 } 417 }
397 } 418 }
401 // right thing to do, not using tcp *is* the right thing to do. 422 // right thing to do, not using tcp *is* the right thing to do.
402 if (!w_pkt) 423 if (!w_pkt)
403 { 424 {
404 // how this maps to the underlying tcp packets we don't know 425 // how this maps to the underlying tcp packets we don't know
405 // and we don't care. at least we tried ;) 426 // and we don't care. at least we tried ;)
427#if defined(SOL_IP) && defined(IP_TOS)
428 if (tos != this->tos)
429 {
430 this->tos = tos;
406 setsockopt (fd, SOL_IP, IP_TOS, &tos, sizeof tos); 431 setsockopt (fd, SOL_IP, IP_TOS, &tos, sizeof tos);
432 }
433#endif
407 434
408 w_pkt = pkt; 435 w_pkt = pkt;
409 w_ofs = 0; 436 w_ofs = 0;
410 w_len = pkt->len + 2; // length + size header 437 w_len = pkt->len + 2; // length + size header
411 438
414 else 441 else
415 { 442 {
416 w_pkt = new vpn_packet; 443 w_pkt = new vpn_packet;
417 w_pkt->set (*pkt); 444 w_pkt->set (*pkt);
418 445
419 set (POLLIN | POLLOUT); 446 set (EV_READ | EV_WRITE);
420 } 447 }
421 } 448 }
422 } 449 }
423 450
424 return state != ERROR; 451 return state != ERROR;
425} 452}
426 453
427void tcp_connection::error () 454void tcp_connection::error ()
428{ 455{
456 stop ();
457
429 if (fd >= 0) 458 if (fd >= 0)
430 { 459 {
431 close (fd); 460 close (fd);
461 tos = -1;
432 fd = -1; 462 fd = -1;
433 } 463 }
434 464
435 delete r_pkt; r_pkt = 0; 465 delete r_pkt; r_pkt = 0;
436 delete w_pkt; w_pkt = 0; 466 delete w_pkt; w_pkt = 0;
437#if ENABLE_HTTP_PROXY 467#if ENABLE_HTTP_PROXY
438 free (proxy_req); proxy_req = 0; 468 free (proxy_req); proxy_req = 0;
439#endif 469#endif
440 470
441 stop ();
442 state = active ? IDLE : ERROR; 471 state = active ? IDLE : ERROR;
443} 472}
444 473
445tcp_connection::tcp_connection (int fd_, const sockinfo &si_, vpn &v_) 474tcp_connection::tcp_connection (int fd_, const sockinfo &si_, vpn &v_)
446: v(v_), si(si_), io_watcher(this, &tcp_connection::tcpv4_ev) 475: v(v_), si(si_)
447{ 476{
477 set<tcp_connection, &tcp_connection::tcpv4_ev> (this);
478
448 last_activity = NOW; 479 last_activity = ev_now ();
449 r_pkt = 0; 480 r_pkt = 0;
450 w_pkt = 0; 481 w_pkt = 0;
482 tos = -1;
451 fd = fd_; 483 fd = fd_;
452#if ENABLE_HTTP_PROXY 484#if ENABLE_HTTP_PROXY
453 proxy_req = 0; 485 proxy_req = 0;
454#endif 486#endif
455 487
460 } 492 }
461 else 493 else
462 { 494 {
463 active = false; 495 active = false;
464 state = ESTABLISHED; 496 state = ESTABLISHED;
465 start (fd, POLLIN); 497 start (fd, EV_READ);
466 } 498 }
467} 499}
468 500
469tcp_connection::~tcp_connection () 501tcp_connection::~tcp_connection ()
470{ 502{

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines