--- gvpe/src/connection.C 2007/12/04 15:01:12 1.64 +++ gvpe/src/connection.C 2008/08/07 16:34:21 1.67 @@ -93,7 +93,7 @@ struct rsa_cache : list { - void cleaner_cb (ev::timer &w, int revents); ev::timer cleaner; + inline void cleaner_cb (ev::timer &w, int revents); ev::timer cleaner; bool find (const rsaid &id, rsachallenge &chg) { @@ -132,8 +132,8 @@ } rsa_cache () - : cleaner (this, &rsa_cache::cleaner_cb) { + cleaner.set (this); cleaner.set (RSA_TTL, RSA_TTL); } @@ -155,43 +155,76 @@ ////////////////////////////////////////////////////////////////////////////// -void pkt_queue::put (net_packet *p) +pkt_queue::pkt_queue (double max_ttl, int max_queue) +: max_ttl (max_ttl), max_queue (max_queue) { - if (queue[i]) - { - delete queue[i]; - j = (j + 1) % QUEUEDEPTH; - } + queue = new pkt [max_queue]; - queue[i] = p; + i = 0; + j = 0; - i = (i + 1) % QUEUEDEPTH; + expire.set (this); } -net_packet *pkt_queue::get () +pkt_queue::~pkt_queue () +{ + while (net_packet *p = get ()) + delete p; + + delete [] queue; +} + +void pkt_queue::expire_cb (ev::timer &w, int revents) { - net_packet *p = queue[j]; + ev_tstamp expire = ev_now () - max_ttl; - if (p) + for (;;) { - queue[j] = 0; - j = (j + 1) % QUEUEDEPTH; - } + if (empty ()) + break; - return p; + double diff = queue[j].tstamp - expire; + + if (diff >= 0.) + { + w.start (diff > 0.5 ? diff : 0.5); + break; + } + + delete get (); + } } -pkt_queue::pkt_queue () +void pkt_queue::put (net_packet *p) { - memset (queue, 0, sizeof (queue)); - i = 0; - j = 0; + ev_tstamp now = ev_now (); + + // start expiry timer + if (empty ()) + expire.start (max_ttl); + + int ni = i + 1 == max_queue ? 0 : i + 1; + + if (ni == j) + delete get (); + + queue[i].pkt = p; + queue[i].tstamp = now; + + i = ni; } -pkt_queue::~pkt_queue () +net_packet *pkt_queue::get () { - for (i = QUEUEDEPTH; --i > 0; ) - delete queue[i]; + if (empty ()) + return 0; + + net_packet *p = queue[j].pkt; + queue[j].pkt = 0; + + j = j + 1 == max_queue ? 0 : j + 1; + + return p; } struct net_rateinfo @@ -592,8 +625,6 @@ if (ictx && octx) { - connectmode = conf->connectmode; - // make sure rekeying timeouts are slightly asymmetric ev::tstamp rekey_interval = ::conf.rekey + (conf->id > THISNODE->id ? 10 : 0); rekey.start (rekey_interval, rekey_interval); @@ -604,13 +635,13 @@ { while (tap_packet *p = (tap_packet *)data_queue.get ()) { - send_data_packet (p); + if (p->len) send_data_packet (p); delete p; } while (vpn_packet *p = (vpn_packet *)vpn_queue.get ()) { - send_vpn_packet (p, si, IPTOS_RELIABILITY); + if (p->len) send_vpn_packet (p, si, IPTOS_RELIABILITY); delete p; } } @@ -747,7 +778,7 @@ delete r; } -void +inline void connection::establish_connection_cb (ev::timer &w, int revents) { if (!ictx @@ -756,6 +787,14 @@ && connectmode != conf_node::C_DISABLED && !w.is_active ()) { + // a bit hacky, if ondemand, and packets are no longer queued, then reset the connection + // and stop trying. should probably be handled by a per-connection expire handler. + if (connectmode == conf_node::C_ONDEMAND && vpn_queue.empty () && data_queue.empty ()) + { + reset_connection (); + return; + } + ev::tstamp retry_int = ev::tstamp (retry_cnt & 3 ? (retry_cnt & 3) + 1 : 1 << (retry_cnt >> 2)); @@ -810,7 +849,7 @@ if (::conf.script_node_down) { run_script_cb cb; - callback_set (cb, this, connection, script_node_down); + cb.set (this); if (!run_script (cb, false)) slog (L_WARN, _("node-down command execution failed, continuing.")); } @@ -841,7 +880,7 @@ reset_connection (); } -void +inline void connection::rekey_cb (ev::timer &w, int revents) { reset_connection (); @@ -1049,7 +1088,7 @@ if (::conf.script_node_up) { run_script_cb cb; - callback_set (cb, this, connection, script_node_up); + cb.set (this); if (!run_script (cb, false)) slog (L_WARN, _("node-up command execution failed, continuing.")); } @@ -1178,7 +1217,8 @@ } } -void connection::keepalive_cb (ev::timer &w, int revents) +inline void +connection::keepalive_cb (ev::timer &w, int revents) { if (ev_now () >= last_activity + ::conf.keepalive + 30) { @@ -1233,7 +1273,8 @@ asprintf (&env, "DESTPORT=%d", ntohs (si.port)); putenv (env); } -const char *connection::script_node_up () +inline const char * +connection::script_node_up () { script_init_connect_env (); @@ -1248,7 +1289,8 @@ return filename; } -const char *connection::script_node_down () +inline const char * +connection::script_node_down () { script_init_connect_env (); @@ -1264,21 +1306,33 @@ } connection::connection (struct vpn *vpn, conf_node *conf) -: vpn(vpn), conf(conf) -, rekey (this, &connection::rekey_cb) -, keepalive (this, &connection::keepalive_cb) -, establish_connection (this, &connection::establish_connection_cb) +: vpn(vpn), conf(conf), #if ENABLE_DNS -, dns (0) + dns (0), #endif + data_queue(conf->max_ttl, conf->max_queue), + vpn_queue(conf->max_ttl, conf->max_queue) { + rekey .set (this); + keepalive .set (this); + establish_connection.set (this); + octx = ictx = 0; retry_cnt = 0; if (!conf->protocols) // make sure some protocol is enabled conf->protocols = PROT_UDPv4; - connectmode = conf_node::C_ALWAYS; // initial setting + connectmode = conf->connectmode; + + // queue a dummy packet to force an initial connection attempt + if (connectmode != conf_node::C_ALWAYS && connectmode != conf_node::C_DISABLED) + { + net_packet *p = new net_packet; + p->len = 0; + vpn_queue.put (p); + } + reset_connection (); }