--- gvpe/src/vpn_tcp.C 2003/04/07 01:40:54 1.6 +++ gvpe/src/vpn_tcp.C 2007/11/13 02:12:08 1.19 @@ -1,7 +1,10 @@ /* vpn_tcp.C -- handle the tcp part of the protocol. + Copyright (C) 2003-2007 Marc Lehmann - This program is free software; you can redistribute it and/or modify + This file is part of GVPE. + + GVPE is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -12,36 +15,33 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + along with gvpe; if not, write to the Free Software + Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "config.h" #if ENABLE_TCP -// tcp processing is extremely ugly, since the vpe protocol is simply +// tcp processing is extremely ugly, since the gvpe protocol is simply // designed for unreliable datagram networks. tcp is implemented by // multiplexing packets over tcp. errors are completely ignored, as we -// rely on the higher level protocol to time out and reconnect. +// rely on the higher level layers to time out and reconnect. #include #include #include -#include #include -#include #include -#include #include #include #include +#include #include -#include -#include -#include + +#include "netcompat.h" #include "vpn.h" @@ -60,16 +60,17 @@ }; struct tcp_si_map : public map { - void cleaner_cb (time_watcher &w); time_watcher cleaner; + void cleaner_cb (ev::timer &w, int revents); ev::timer cleaner; tcp_si_map () - : cleaner(this, &tcp_si_map::cleaner_cb) - { - cleaner.start (0); - } + : cleaner(this, &tcp_si_map::cleaner_cb) + { + cleaner.start (::conf.keepalive / 2, ::conf.keepalive / 2); + } + } tcp_si; -struct tcp_connection : io_watcher { +struct tcp_connection : ev::io { tstamp last_activity; const sockinfo si; vpn &v; @@ -87,7 +88,7 @@ int proxy_req_len; #endif - void tcpv4_ev (io_watcher &w, short revents); + void tcpv4_ev (ev::io &w, int revents); bool send_packet (vpn_packet *pkt, int tos); bool write_packet (); @@ -95,33 +96,33 @@ void error (); // abort conenction && cleanup operator tcp_si_map::value_type() - { - return tcp_si_map::value_type (&si, this); - } + { + return tcp_si_map::value_type (&si, this); + } tcp_connection (int fd_, const sockinfo &si_, vpn &v_); ~tcp_connection (); }; -void tcp_si_map::cleaner_cb (time_watcher &w) +void tcp_si_map::cleaner_cb (ev::timer &w, int revents) { - w.at = NOW + 600; - tstamp to = NOW - ::conf.keepalive - 30 - 60; + tstamp to = ev::ev_now () - ::conf.keepalive - 30 - 60; for (iterator i = begin (); i != end(); ) if (i->second->last_activity >= to) ++i; else { + delete i->second; erase (i); i = begin (); } } void -vpn::tcpv4_ev (io_watcher &w, short revents) +vpn::tcpv4_ev (ev::io &w, int revents) { - if (revents & (POLLIN | POLLERR)) + if (revents & EV_READ) { struct sockaddr_in sa; socklen_t sa_len = sizeof (sa); @@ -131,12 +132,13 @@ if (fd >= 0) { + fcntl (fd, F_SETFL, O_NONBLOCK); + fcntl (fd, F_SETFD, FD_CLOEXEC); + sockinfo si(sa, PROT_TCPv4); slog (L_DEBUG, _("%s: accepted tcp connection"), (const char *)si);//D - fcntl (fd, F_SETFL, O_NONBLOCK); - tcp_connection *i = new tcp_connection (fd, si, *this); tcp_si.insert (*i); } @@ -171,9 +173,10 @@ u16 plen = htons (w_pkt->len); iovec vec[2]; - vec[0].iov_base = ((u8 *)&plen) + w_ofs; + //TODO: char* is the right type? hardly... + vec[0].iov_base = (char *)((u8 *)&plen) + w_ofs; vec[0].iov_len = 2 - w_ofs; - vec[1].iov_base = &((*w_pkt)[0]); + vec[1].iov_base = (char *)&((*w_pkt)[0]); vec[1].iov_len = w_len - 2; len = writev (fd, vec, 2); @@ -198,27 +201,27 @@ } void -tcp_connection::tcpv4_ev (io_watcher &w, short revents) +tcp_connection::tcpv4_ev (ev::io &w, int revents) { - last_activity = NOW; - - if (revents & (POLLERR | POLLHUP)) - { - error (); - return; - } + last_activity = ev::ev_now (); - if (revents & POLLOUT) + if (revents & EV_WRITE) { if (state == CONNECTING) { state = ESTABLISHED; - set (POLLIN); + set (EV_READ); #if ENABLE_HTTP_PROXY if (::conf.proxy_host && ::conf.proxy_port) { state = CONNECTING_PROXY; - write (fd, proxy_req, proxy_req_len); + + if (write (fd, proxy_req, proxy_req_len) == 0) + { + error (); + return; + } + free (proxy_req); proxy_req = 0; } #endif @@ -231,17 +234,17 @@ { delete w_pkt; w_pkt = 0; - set (POLLIN); + set (EV_READ); } } else - set (POLLIN); + set (EV_READ); } else - set (POLLIN); + set (EV_READ); } - if (revents & POLLIN) + if (revents & EV_READ) { if (state == ESTABLISHED) for (;;) @@ -285,6 +288,7 @@ else if (len < 0 && (errno == EINTR || errno == EAGAIN)) break; + // len == 0 <-> EOF error (); break; } @@ -344,7 +348,7 @@ bool tcp_connection::send_packet (vpn_packet *pkt, int tos) { - last_activity = NOW; + last_activity = ev::ev_now (); if (state == IDLE) { @@ -388,8 +392,11 @@ if (connect (fd, csi->sav4 (), csi->salenv4 ()) >= 0 || errno == EINPROGRESS) { + fcntl (fd, F_SETFL, O_NONBLOCK); + fcntl (fd, F_SETFD, FD_CLOEXEC); + state = CONNECTING; - start (fd, POLLOUT); + start (fd, EV_WRITE); } else close (fd); @@ -403,7 +410,9 @@ { // how this maps to the underlying tcp packets we don't know // and we don't care. at least we tried ;) +#if defined(SOL_IP) && defined(IP_TOS) setsockopt (fd, SOL_IP, IP_TOS, &tos, sizeof tos); +#endif w_pkt = pkt; w_ofs = 0; @@ -416,7 +425,7 @@ w_pkt = new vpn_packet; w_pkt->set (*pkt); - set (POLLIN | POLLOUT); + set (EV_READ | EV_WRITE); } } } @@ -426,6 +435,8 @@ void tcp_connection::error () { + stop (); + if (fd >= 0) { close (fd); @@ -438,14 +449,13 @@ free (proxy_req); proxy_req = 0; #endif - stop (); state = active ? IDLE : ERROR; } tcp_connection::tcp_connection (int fd_, const sockinfo &si_, vpn &v_) -: v(v_), si(si_), io_watcher(this, &tcp_connection::tcpv4_ev) +: v(v_), si(si_), ev::io(this, &tcp_connection::tcpv4_ev) { - last_activity = NOW; + last_activity = ev::ev_now (); r_pkt = 0; w_pkt = 0; fd = fd_; @@ -462,7 +472,7 @@ { active = false; state = ESTABLISHED; - start (fd, POLLIN); + start (fd, EV_READ); } }