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

Comparing gvpe/src/connection.C (file contents):
Revision 1.63 by pcg, Sun Dec 2 00:45:41 2007 UTC vs.
Revision 1.69 by pcg, Thu Aug 7 17:54:26 2008 UTC

1/* 1/*
2 connection.C -- manage a single connection 2 connection.C -- manage a single connection
3 Copyright (C) 2003-2005 Marc Lehmann <gvpe@schmorp.de> 3 Copyright (C) 2003-2008 Marc Lehmann <gvpe@schmorp.de>
4 4
5 This file is part of GVPE. 5 This file is part of GVPE.
6 6
7 GVPE is free software; you can redistribute it and/or modify 7 GVPE is free software; you can redistribute it and/or modify it
8 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
9 the Free Software Foundation; either version 2 of the License, or 9 Free Software Foundation; either version 3 of the License, or (at your
10 (at your option) any later version. 10 option) any later version.
11 11
12 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
13 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
15 GNU General Public License for more details. 15 Public License for more details.
16 16
17 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
18 along with gvpe; if not, write to the Free Software 18 with this program; if not, see <http://www.gnu.org/licenses/>.
19 Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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.
20*/ 30*/
21 31
22#include "config.h" 32#include "config.h"
23 33
24#include <list> 34#include <list>
91 rsachallenge chg; 101 rsachallenge chg;
92}; 102};
93 103
94struct rsa_cache : list<rsa_entry> 104struct rsa_cache : list<rsa_entry>
95{ 105{
96 void cleaner_cb (ev::timer &w, int revents); ev::timer cleaner; 106 inline void cleaner_cb (ev::timer &w, int revents); ev::timer cleaner;
97 107
98 bool find (const rsaid &id, rsachallenge &chg) 108 bool find (const rsaid &id, rsachallenge &chg)
99 { 109 {
100 for (iterator i = begin (); i != end (); ++i) 110 for (iterator i = begin (); i != end (); ++i)
101 { 111 {
130 if (!cleaner.is_active ()) 140 if (!cleaner.is_active ())
131 cleaner.again (); 141 cleaner.again ();
132 } 142 }
133 143
134 rsa_cache () 144 rsa_cache ()
135 : cleaner (this, &rsa_cache::cleaner_cb)
136 { 145 {
146 cleaner.set<rsa_cache, &rsa_cache::cleaner_cb> (this);
137 cleaner.set (RSA_TTL, RSA_TTL); 147 cleaner.set (RSA_TTL, RSA_TTL);
138 } 148 }
139 149
140} rsa_cache; 150} rsa_cache;
141 151
153 } 163 }
154} 164}
155 165
156////////////////////////////////////////////////////////////////////////////// 166//////////////////////////////////////////////////////////////////////////////
157 167
158void pkt_queue::put (net_packet *p) 168pkt_queue::pkt_queue (double max_ttl, int max_queue)
169: max_ttl (max_ttl), max_queue (max_queue)
159{ 170{
160 if (queue[i]) 171 queue = new pkt [max_queue];
161 {
162 delete queue[i];
163 j = (j + 1) % QUEUEDEPTH;
164 }
165 172
166 queue[i] = p;
167
168 i = (i + 1) % QUEUEDEPTH;
169}
170
171net_packet *pkt_queue::get ()
172{
173 net_packet *p = queue[j];
174
175 if (p)
176 {
177 queue[j] = 0;
178 j = (j + 1) % QUEUEDEPTH;
179 }
180
181 return p;
182}
183
184pkt_queue::pkt_queue ()
185{
186 memset (queue, 0, sizeof (queue));
187 i = 0; 173 i = 0;
188 j = 0; 174 j = 0;
175
176 expire.set<pkt_queue, &pkt_queue::expire_cb> (this);
189} 177}
190 178
191pkt_queue::~pkt_queue () 179pkt_queue::~pkt_queue ()
192{ 180{
193 for (i = QUEUEDEPTH; --i > 0; ) 181 while (net_packet *p = get ())
182 delete p;
183
194 delete queue[i]; 184 delete [] queue;
185}
186
187void pkt_queue::expire_cb (ev::timer &w, int revents)
188{
189 ev_tstamp expire = ev_now () - max_ttl;
190
191 for (;;)
192 {
193 if (empty ())
194 break;
195
196 double diff = queue[j].tstamp - expire;
197
198 if (diff >= 0.)
199 {
200 w.start (diff > 0.5 ? diff : 0.5);
201 break;
202 }
203
204 delete get ();
205 }
206}
207
208void pkt_queue::put (net_packet *p)
209{
210 ev_tstamp now = ev_now ();
211
212 // start expiry timer
213 if (empty ())
214 expire.start (max_ttl);
215
216 int ni = i + 1 == max_queue ? 0 : i + 1;
217
218 if (ni == j)
219 delete get ();
220
221 queue[i].pkt = p;
222 queue[i].tstamp = now;
223
224 i = ni;
225}
226
227net_packet *pkt_queue::get ()
228{
229 if (empty ())
230 return 0;
231
232 net_packet *p = queue[j].pkt;
233 queue[j].pkt = 0;
234
235 j = j + 1 == max_queue ? 0 : j + 1;
236
237 return p;
195} 238}
196 239
197struct net_rateinfo 240struct net_rateinfo
198{ 241{
199 u32 host; 242 u32 host;
590{ 633{
591 slog (L_TRACE, _("%s: possible connection establish (ictx %d, octx %d)"), conf->nodename, !!ictx, !!octx); 634 slog (L_TRACE, _("%s: possible connection establish (ictx %d, octx %d)"), conf->nodename, !!ictx, !!octx);
592 635
593 if (ictx && octx) 636 if (ictx && octx)
594 { 637 {
595 connectmode = conf->connectmode;
596
597 // make sure rekeying timeouts are slightly asymmetric 638 // make sure rekeying timeouts are slightly asymmetric
598 ev::tstamp rekey_interval = ::conf.rekey + (conf->id > THISNODE->id ? 10 : 0); 639 ev::tstamp rekey_interval = ::conf.rekey + (conf->id > THISNODE->id ? 10 : 0);
599 rekey.start (rekey_interval, rekey_interval); 640 rekey.start (rekey_interval, rekey_interval);
600 keepalive.start (::conf.keepalive); 641 keepalive.start (::conf.keepalive);
601 642
602 // send queued packets 643 // send queued packets
603 if (ictx && octx) 644 if (ictx && octx)
604 { 645 {
605 while (tap_packet *p = (tap_packet *)data_queue.get ()) 646 while (tap_packet *p = (tap_packet *)data_queue.get ())
606 { 647 {
607 send_data_packet (p); 648 if (p->len) send_data_packet (p);
608 delete p; 649 delete p;
609 } 650 }
610 651
611 while (vpn_packet *p = (vpn_packet *)vpn_queue.get ()) 652 while (vpn_packet *p = (vpn_packet *)vpn_queue.get ())
612 { 653 {
613 send_vpn_packet (p, si, IPTOS_RELIABILITY); 654 if (p->len) send_vpn_packet (p, si, IPTOS_RELIABILITY);
614 delete p; 655 delete p;
615 } 656 }
616 } 657 }
617 } 658 }
618 else 659 else
745 send_vpn_packet (r, si); 786 send_vpn_packet (r, si);
746 787
747 delete r; 788 delete r;
748} 789}
749 790
750void 791inline void
751connection::establish_connection_cb (ev::timer &w, int revents) 792connection::establish_connection_cb (ev::timer &w, int revents)
752{ 793{
753 if (!ictx 794 if (!ictx
754 && conf != THISNODE 795 && conf != THISNODE
755 && connectmode != conf_node::C_NEVER 796 && connectmode != conf_node::C_NEVER
756 && connectmode != conf_node::C_DISABLED 797 && connectmode != conf_node::C_DISABLED
757 && !w.is_active ()) 798 && !w.is_active ())
758 { 799 {
800 // a bit hacky, if ondemand, and packets are no longer queued, then reset the connection
801 // and stop trying. should probably be handled by a per-connection expire handler.
802 if (connectmode == conf_node::C_ONDEMAND && vpn_queue.empty () && data_queue.empty ())
803 {
804 reset_connection ();
805 return;
806 }
807
808 last_establish_attempt = ev_now ();
809
759 ev::tstamp retry_int = ev::tstamp (retry_cnt & 3 810 ev::tstamp retry_int = ev::tstamp (retry_cnt & 3
760 ? (retry_cnt & 3) + 1 811 ? (retry_cnt & 3) + 1
761 : 1 << (retry_cnt >> 2)); 812 : 1 << (retry_cnt >> 2));
762 813
763 reset_si (); 814 reset_si ();
786 else 837 else
787 send_ping (dsi, 0); 838 send_ping (dsi, 0);
788 } 839 }
789 } 840 }
790 841
791 retry_int *= slow ? 8. : 0.7; 842 retry_int *= slow ? 8. : 0.9;
792 843
793 if (retry_int < conf->max_retry) 844 if (retry_int < conf->max_retry)
794 retry_cnt++; 845 retry_cnt++;
795 else 846 else
796 retry_int = conf->max_retry; 847 retry_int = conf->max_retry;
806 { 857 {
807 slog (L_INFO, _("%s(%s): connection lost"), 858 slog (L_INFO, _("%s(%s): connection lost"),
808 conf->nodename, (const char *)si); 859 conf->nodename, (const char *)si);
809 860
810 if (::conf.script_node_down) 861 if (::conf.script_node_down)
811 if (!run_script (run_script_cb (this, &connection::script_node_down), false)) 862 {
863 run_script_cb cb;
864 cb.set<connection, &connection::script_node_down> (this);
865 if (!run_script (cb, false))
812 slog (L_WARN, _("node-down command execution failed, continuing.")); 866 slog (L_WARN, _("node-down command execution failed, continuing."));
867 }
813 } 868 }
814 869
815 delete ictx; ictx = 0; 870 delete ictx; ictx = 0;
816 delete octx; octx = 0; 871 delete octx; octx = 0;
817#if ENABLE_DNS 872#if ENABLE_DNS
835 send_reset (si); 890 send_reset (si);
836 891
837 reset_connection (); 892 reset_connection ();
838} 893}
839 894
840void 895inline void
841connection::rekey_cb (ev::timer &w, int revents) 896connection::rekey_cb (ev::timer &w, int revents)
842{ 897{
843 reset_connection (); 898 reset_connection ();
844 establish_connection (); 899 establish_connection ();
845} 900}
862 if (oseqno > MAX_SEQNO) 917 if (oseqno > MAX_SEQNO)
863 rekey (); 918 rekey ();
864} 919}
865 920
866void 921void
922connection::post_inject_queue ()
923{
924 // force a connection every now and when when packets are sent (max 1/s)
925 if (ev_now () - last_establish_attempt >= 0.95) // arbitrary
926 establish_connection.stop ();
927
928 establish_connection ();
929}
930
931void
867connection::inject_data_packet (tap_packet *pkt, bool broadcast/*TODO DDD*/) 932connection::inject_data_packet (tap_packet *pkt)
868{ 933{
869 if (ictx && octx) 934 if (ictx && octx)
870 send_data_packet (pkt); 935 send_data_packet (pkt);
871 else 936 else
872 { 937 {
873 if (!broadcast)
874 data_queue.put (new tap_packet (*pkt)); 938 data_queue.put (new tap_packet (*pkt));
875 939 post_inject_queue ();
876 establish_connection ();
877 } 940 }
878} 941}
879 942
880void connection::inject_vpn_packet (vpn_packet *pkt, int tos) 943void connection::inject_vpn_packet (vpn_packet *pkt, int tos)
881{ 944{
882 if (ictx && octx) 945 if (ictx && octx)
883 send_vpn_packet (pkt, si, tos); 946 send_vpn_packet (pkt, si, tos);
884 else 947 else
885 { 948 {
886 vpn_queue.put ((vpn_packet *)new data_packet (*(data_packet *)pkt)); 949 vpn_queue.put ((vpn_packet *)new data_packet (*(data_packet *)pkt));
887 950 post_inject_queue ();
888 establish_connection ();
889 } 951 }
890} 952}
891 953
892void 954void
893connection::recv_vpn_packet (vpn_packet *pkt, const sockinfo &rsi) 955connection::recv_vpn_packet (vpn_packet *pkt, const sockinfo &rsi)
1041 slog (L_INFO, _("%s(%s): connection established, protocol version %d.%d"), 1103 slog (L_INFO, _("%s(%s): connection established, protocol version %d.%d"),
1042 conf->nodename, (const char *)rsi, 1104 conf->nodename, (const char *)rsi,
1043 p->prot_major, p->prot_minor); 1105 p->prot_major, p->prot_minor);
1044 1106
1045 if (::conf.script_node_up) 1107 if (::conf.script_node_up)
1046 if (!run_script (run_script_cb (this, &connection::script_node_up), false)) 1108 {
1109 run_script_cb cb;
1110 cb.set<connection, &connection::script_node_up> (this);
1111 if (!run_script (cb, false))
1047 slog (L_WARN, _("node-up command execution failed, continuing.")); 1112 slog (L_WARN, _("node-up command execution failed, continuing."));
1113 }
1048 1114
1049 break; 1115 break;
1050 } 1116 }
1051 else 1117 else
1052 slog (L_ERR, _("%s(%s): sent and received challenge do not match"), 1118 slog (L_ERR, _("%s(%s): sent and received challenge do not match"),
1168 send_reset (rsi); 1234 send_reset (rsi);
1169 break; 1235 break;
1170 } 1236 }
1171} 1237}
1172 1238
1239inline void
1173void connection::keepalive_cb (ev::timer &w, int revents) 1240connection::keepalive_cb (ev::timer &w, int revents)
1174{ 1241{
1175 if (ev_now () >= last_activity + ::conf.keepalive + 30) 1242 if (ev_now () >= last_activity + ::conf.keepalive + 30)
1176 { 1243 {
1177 reset_connection (); 1244 reset_connection ();
1178 establish_connection (); 1245 establish_connection ();
1223 asprintf (&env, "DESTNODE=%s", conf->nodename); putenv (env); 1290 asprintf (&env, "DESTNODE=%s", conf->nodename); putenv (env);
1224 asprintf (&env, "DESTIP=%s", si.ntoa ()); putenv (env); 1291 asprintf (&env, "DESTIP=%s", si.ntoa ()); putenv (env);
1225 asprintf (&env, "DESTPORT=%d", ntohs (si.port)); putenv (env); 1292 asprintf (&env, "DESTPORT=%d", ntohs (si.port)); putenv (env);
1226} 1293}
1227 1294
1295inline const char *
1228const char *connection::script_node_up () 1296connection::script_node_up ()
1229{ 1297{
1230 script_init_connect_env (); 1298 script_init_connect_env ();
1231 1299
1232 putenv ((char *)"STATE=up"); 1300 putenv ((char *)"STATE=up");
1233 1301
1238 ::conf.script_node_up ? ::conf.script_node_up : "node-up"); 1306 ::conf.script_node_up ? ::conf.script_node_up : "node-up");
1239 1307
1240 return filename; 1308 return filename;
1241} 1309}
1242 1310
1311inline const char *
1243const char *connection::script_node_down () 1312connection::script_node_down ()
1244{ 1313{
1245 script_init_connect_env (); 1314 script_init_connect_env ();
1246 1315
1247 putenv ((char *)"STATE=down"); 1316 putenv ((char *)"STATE=down");
1248 1317
1254 1323
1255 return filename; 1324 return filename;
1256} 1325}
1257 1326
1258connection::connection (struct vpn *vpn, conf_node *conf) 1327connection::connection (struct vpn *vpn, conf_node *conf)
1259: vpn(vpn), conf(conf) 1328: vpn(vpn), conf(conf),
1260, rekey (this, &connection::rekey_cb)
1261, keepalive (this, &connection::keepalive_cb)
1262, establish_connection (this, &connection::establish_connection_cb)
1263#if ENABLE_DNS 1329#if ENABLE_DNS
1264, dns (0) 1330 dns (0),
1265#endif 1331#endif
1332 data_queue(conf->max_ttl, conf->max_queue),
1333 vpn_queue(conf->max_ttl, conf->max_queue)
1266{ 1334{
1335 rekey .set<connection, &connection::rekey_cb > (this);
1336 keepalive .set<connection, &connection::keepalive_cb > (this);
1337 establish_connection.set<connection, &connection::establish_connection_cb> (this);
1338
1339 last_establish_attempt = 0.;
1267 octx = ictx = 0; 1340 octx = ictx = 0;
1268 retry_cnt = 0;
1269 1341
1270 if (!conf->protocols) // make sure some protocol is enabled 1342 if (!conf->protocols) // make sure some protocol is enabled
1271 conf->protocols = PROT_UDPv4; 1343 conf->protocols = PROT_UDPv4;
1272 1344
1273 connectmode = conf_node::C_ALWAYS; // initial setting 1345 connectmode = conf->connectmode;
1346
1347 // queue a dummy packet to force an initial connection attempt
1348 if (connectmode != conf_node::C_ALWAYS && connectmode != conf_node::C_DISABLED)
1349 vpn_queue.put (new net_packet);
1350
1274 reset_connection (); 1351 reset_connection ();
1275} 1352}
1276 1353
1277connection::~connection () 1354connection::~connection ()
1278{ 1355{

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines