annotate src/gt_netorg.c @ 0:d39e1d0d75b6

initial add
author paulo@hit-nxdomain.opendns.com
date Sat, 20 Feb 2010 21:18:28 -0800
parents
children
rev   line source
paulo@0 1 /*
paulo@0 2 * $Id: gt_netorg.c,v 1.47 2005/01/04 15:00:51 mkern Exp $
paulo@0 3 *
paulo@0 4 * Copyright (C) 2001-2003 giFT project (gift.sourceforge.net)
paulo@0 5 *
paulo@0 6 * This program is free software; you can redistribute it and/or modify it
paulo@0 7 * under the terms of the GNU General Public License as published by the
paulo@0 8 * Free Software Foundation; either version 2, or (at your option) any
paulo@0 9 * later version.
paulo@0 10 *
paulo@0 11 * This program is distributed in the hope that it will be useful, but
paulo@0 12 * WITHOUT ANY WARRANTY; without even the implied warranty of
paulo@0 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
paulo@0 14 * General Public License for more details.
paulo@0 15 */
paulo@0 16
paulo@0 17 #include "gt_gnutella.h"
paulo@0 18
paulo@0 19 #include "gt_node.h"
paulo@0 20 #include "gt_node_list.h"
paulo@0 21 #include "gt_netorg.h"
paulo@0 22
paulo@0 23 #include "gt_connect.h"
paulo@0 24 #include "gt_accept.h"
paulo@0 25
paulo@0 26 #include "gt_packet.h"
paulo@0 27
paulo@0 28 #include "gt_node_cache.h"
paulo@0 29 #include "gt_web_cache.h"
paulo@0 30
paulo@0 31 /*****************************************************************************/
paulo@0 32
paulo@0 33 /* how often we check the network's condition */
paulo@0 34 #define MAINTAIN_INTERVAL (10 * SECONDS)
paulo@0 35
paulo@0 36 /* how often to check to disconnect idle nodes */
paulo@0 37 #define IDLE_DISCONNECT_INTERVAL (2 * MINUTES)
paulo@0 38
paulo@0 39 /* how often to trim the node list */
paulo@0 40 #define CLEANUP_INTERVAL (15 * MINUTES)
paulo@0 41
paulo@0 42 /* how often to clear indications of connecting to nodes */
paulo@0 43 #define RETRY_ALL_INTERVAL (60 * MINUTES)
paulo@0 44
paulo@0 45 /* maximum number of unreplied pings before disconnecting from a node */
paulo@0 46 #define MAX_UNREPLIED_PINGS 10
paulo@0 47
paulo@0 48 /* how many connections attempts each maintain loop for nodes previously
paulo@0 49 * registered */
paulo@0 50 #define TRY_CONNECT_NODE_LIST gt_config_get_int("connect/node_list=3")
paulo@0 51
paulo@0 52 /* how many connection attempts for nodes in the pong cache */
paulo@0 53 #define TRY_CONNECT_NODE_CACHE gt_config_get_int("connect/node_cache=7")
paulo@0 54
paulo@0 55 /*****************************************************************************/
paulo@0 56
paulo@0 57 /* timer for initiating/closing connections */
paulo@0 58 static timer_id maintain_timer;
paulo@0 59
paulo@0 60 /* timer for disconnecting connections */
paulo@0 61 static timer_id disconnect_timer;
paulo@0 62
paulo@0 63 /* timer for disconnecting idle nodes */
paulo@0 64 static timer_id idle_disconnect_timer;
paulo@0 65
paulo@0 66 /* timer for cleaning up the node list */
paulo@0 67 static timer_id cleanup_timer;
paulo@0 68
paulo@0 69 /* timer to clear 'tried' indicators to retry connecting */
paulo@0 70 static timer_id retry_all_timer;
paulo@0 71
paulo@0 72 /*****************************************************************************/
paulo@0 73
paulo@0 74 static GtNode *node_disconnect_one (TCPC *c, GtNode *node, void *udata)
paulo@0 75 {
paulo@0 76 GT->DBGFN (GT, "[%s]: disconnecting", net_ip_str (GT_NODE(c)->ip));
paulo@0 77 gt_node_disconnect (c);
paulo@0 78 return NULL;
paulo@0 79 }
paulo@0 80
paulo@0 81 static GtNode *node_ping (TCPC *c, GtNode *node, GtPacket *packet)
paulo@0 82 {
paulo@0 83 gt_packet_send (c, packet);
paulo@0 84
paulo@0 85 /* ->pings_with_noreply gets set to zero when the node sends a pong */
paulo@0 86 if (gt_packet_ttl (packet) == 1)
paulo@0 87 node->pings_with_noreply++;
paulo@0 88
paulo@0 89 return NULL;
paulo@0 90 }
paulo@0 91
paulo@0 92 static void ping_hosts_ttl (uint8_t ttl)
paulo@0 93 {
paulo@0 94 GtPacket *packet;
paulo@0 95
paulo@0 96 if (!(packet = gt_packet_new (GT_MSG_PING, ttl, NULL)))
paulo@0 97 return;
paulo@0 98
paulo@0 99 gt_conn_foreach (GT_CONN_FOREACH(node_ping), packet,
paulo@0 100 GT_NODE_NONE, GT_NODE_CONNECTED, 0);
paulo@0 101
paulo@0 102 gt_packet_free (packet);
paulo@0 103 }
paulo@0 104
paulo@0 105 static void ping_hosts (time_t now)
paulo@0 106 {
paulo@0 107 static time_t last_ping;
paulo@0 108 static time_t last_keep_alive;
paulo@0 109 BOOL need_connections;
paulo@0 110 uint8_t ttl;
paulo@0 111
paulo@0 112 need_connections = gt_conn_need_connections (GT_NODE_ULTRA);
paulo@0 113
paulo@0 114 if (now - last_ping < 30 * SECONDS && !need_connections)
paulo@0 115 return;
paulo@0 116
paulo@0 117 last_ping = now;
paulo@0 118
paulo@0 119 /* ping to get more hosts if we need connections */
paulo@0 120 if (now - last_keep_alive >= 1 * MINUTES)
paulo@0 121 {
paulo@0 122 /* do a keepalive */
paulo@0 123 ttl = 1;
paulo@0 124 last_keep_alive = now;
paulo@0 125 }
paulo@0 126 else
paulo@0 127 {
paulo@0 128 /* get more hosts */
paulo@0 129 ttl = 7;
paulo@0 130 }
paulo@0 131
paulo@0 132 ping_hosts_ttl (ttl);
paulo@0 133 }
paulo@0 134
paulo@0 135 /*****************************************************************************/
paulo@0 136
paulo@0 137 static void disconnect_no_query_route (void)
paulo@0 138 {
paulo@0 139 int nr_supernodes;
paulo@0 140
paulo@0 141 /* only disconnect if theres other nodes to fallback on */
paulo@0 142 nr_supernodes = gt_conn_length (GT_NODE_ULTRA, GT_NODE_CONNECTED);
paulo@0 143
paulo@0 144 if (nr_supernodes > 0)
paulo@0 145 {
paulo@0 146 gt_conn_foreach (node_disconnect_one, NULL,
paulo@0 147 GT_NODE_LEAF, GT_NODE_CONNECTED, 0);
paulo@0 148 }
paulo@0 149 }
paulo@0 150
paulo@0 151 static void report_connected_leaf (int connected)
paulo@0 152 {
paulo@0 153 static int last_connected = 0;
paulo@0 154
paulo@0 155 if (connected != last_connected)
paulo@0 156 {
paulo@0 157 GT->DBGFN (GT, "connected=%d nodes=%d", connected,
paulo@0 158 gt_conn_length (GT_NODE_NONE, GT_NODE_ANY));
paulo@0 159 last_connected = connected;
paulo@0 160 }
paulo@0 161 }
paulo@0 162
paulo@0 163 static int get_need_as_ultra (gt_node_class_t klass)
paulo@0 164 {
paulo@0 165 switch (klass)
paulo@0 166 {
paulo@0 167 case GT_NODE_ULTRA: return GT_PEER_CONNECTIONS;
paulo@0 168 case GT_NODE_LEAF: return GT_LEAF_CONNECTIONS;
paulo@0 169 default: return 0;
paulo@0 170 }
paulo@0 171 }
paulo@0 172
paulo@0 173 static int get_need_as_leaf (gt_node_class_t klass)
paulo@0 174 {
paulo@0 175 switch (klass)
paulo@0 176 {
paulo@0 177 case GT_NODE_ULTRA: return GT_SHIELDED_CONNECTIONS;
paulo@0 178 case GT_NODE_LEAF: return 0; /* no leaf<->leaf connections allowed */
paulo@0 179 default: return 0;
paulo@0 180 }
paulo@0 181 }
paulo@0 182
paulo@0 183 int gt_conn_need_connections (gt_node_class_t klass)
paulo@0 184 {
paulo@0 185 int connected;
paulo@0 186 int desired;
paulo@0 187
paulo@0 188 connected = gt_conn_length (klass, GT_NODE_CONNECTED);
paulo@0 189
paulo@0 190 /* don't call this with multiple classes -- the need of one
paulo@0 191 * class could cancel a surplus of the other */
paulo@0 192 assert (klass == GT_NODE_ULTRA || klass == GT_NODE_LEAF);
paulo@0 193
paulo@0 194 if (GT_SELF->klass & GT_NODE_ULTRA)
paulo@0 195 desired = get_need_as_ultra (klass);
paulo@0 196 else
paulo@0 197 desired = get_need_as_leaf (klass);
paulo@0 198
paulo@0 199 return desired - connected;
paulo@0 200 }
paulo@0 201
paulo@0 202 static void disconnect_hosts (gt_node_class_t klass, int excess)
paulo@0 203 {
paulo@0 204 int connected;
paulo@0 205
paulo@0 206 connected = gt_conn_length (klass, GT_NODE_CONNECTED);
paulo@0 207
paulo@0 208 GT->DBGFN (GT, "too many connections (%d)[%s], disconnecting %d",
paulo@0 209 connected, gt_node_class_str (klass), excess);
paulo@0 210
paulo@0 211 while (excess-- > 0)
paulo@0 212 {
paulo@0 213 GtNode *node = gt_conn_random (klass, GT_NODE_CONNECTED);
paulo@0 214
paulo@0 215 /* TODO: send BYE message here */
paulo@0 216
paulo@0 217 assert (GT_CONN(node) != NULL);
paulo@0 218 gt_node_disconnect (GT_CONN(node));
paulo@0 219 }
paulo@0 220 }
paulo@0 221
paulo@0 222 static BOOL disconnect_excess_timer (void *udata)
paulo@0 223 {
paulo@0 224 int leaf_excess;
paulo@0 225 int ultra_excess;
paulo@0 226
paulo@0 227 leaf_excess = gt_conn_need_connections (GT_NODE_LEAF);
paulo@0 228 ultra_excess = gt_conn_need_connections (GT_NODE_ULTRA);
paulo@0 229
paulo@0 230 if (leaf_excess < 0)
paulo@0 231 disconnect_hosts (GT_NODE_LEAF, -leaf_excess);
paulo@0 232
paulo@0 233 if (ultra_excess < 0)
paulo@0 234 disconnect_hosts (GT_NODE_ULTRA, -ultra_excess);
paulo@0 235
paulo@0 236 disconnect_timer = 0;
paulo@0 237 return FALSE;
paulo@0 238 }
paulo@0 239
paulo@0 240 static GtNode *collect_each_node (TCPC *c, GtNode *node, List **nodes)
paulo@0 241 {
paulo@0 242 if (node->tried_connect)
paulo@0 243 return NULL;
paulo@0 244
paulo@0 245 if (!node->gt_port)
paulo@0 246 return NULL;
paulo@0 247
paulo@0 248 /* mark having tried to to connect to this node already */
paulo@0 249 node->tried_connect = TRUE;
paulo@0 250
paulo@0 251 *nodes = list_append (*nodes, node);
paulo@0 252
paulo@0 253 /* stop iterating if we have enough nodes */
paulo@0 254 if (list_length (*nodes) >= TRY_CONNECT_NODE_LIST)
paulo@0 255 return node;
paulo@0 256
paulo@0 257 return NULL;
paulo@0 258 }
paulo@0 259
paulo@0 260 static GtNode *clear_try_bit (TCPC *c, GtNode *node, void *udata)
paulo@0 261 {
paulo@0 262 node->tried_connect = FALSE;
paulo@0 263 return NULL;
paulo@0 264 }
paulo@0 265
paulo@0 266 static BOOL prune_registered (struct cached_node *cached, void *udata)
paulo@0 267 {
paulo@0 268 if (gt_node_lookup (cached->addr.ip, cached->addr.port))
paulo@0 269 {
paulo@0 270 GT->DBGFN (GT, "pruning %s (already registered)",
paulo@0 271 net_ip_str (cached->addr.ip), cached->addr.port);
paulo@0 272 free (cached);
paulo@0 273 return TRUE;
paulo@0 274 }
paulo@0 275
paulo@0 276 return FALSE;
paulo@0 277 }
paulo@0 278
paulo@0 279 static BOOL register_cached (struct cached_node *cached, void *udata)
paulo@0 280 {
paulo@0 281 GtNode *node;
paulo@0 282
paulo@0 283 node = gt_node_lookup (cached->addr.ip, cached->addr.port);
paulo@0 284
paulo@0 285 if (node)
paulo@0 286 {
paulo@0 287 /*
paulo@0 288 * Argh, gt_node_lookup only matches by IP
paulo@0 289 * This should be assert (0)
paulo@0 290 */
paulo@0 291 assert (node->gt_port != cached->addr.port);
paulo@0 292
paulo@0 293 free (cached);
paulo@0 294 return TRUE;
paulo@0 295 }
paulo@0 296
paulo@0 297 node = gt_node_register (cached->addr.ip, cached->addr.port,
paulo@0 298 cached->klass);
paulo@0 299
paulo@0 300 /* we've got to free the node, Jim */
paulo@0 301 free (cached);
paulo@0 302
paulo@0 303 /* this happens if the address is invalid or a mem failure */
paulo@0 304 if (!node)
paulo@0 305 return TRUE;
paulo@0 306
paulo@0 307 gt_connect (node);
paulo@0 308 node->tried_connect = TRUE;
paulo@0 309
paulo@0 310 return TRUE;
paulo@0 311 }
paulo@0 312
paulo@0 313 static BOOL connect_each (GtNode *node, void *udata)
paulo@0 314 {
paulo@0 315 if (gt_connect (node) < 0)
paulo@0 316 {
paulo@0 317 GT->err (GT, "Failed to connect to node %s:%hu: %s",
paulo@0 318 net_ip_str (node->ip), node->gt_port, GIFT_NETERROR());
paulo@0 319 return TRUE;
paulo@0 320 }
paulo@0 321
paulo@0 322 return TRUE;
paulo@0 323 }
paulo@0 324
paulo@0 325 /*****************************************************************************/
paulo@0 326
paulo@0 327 /* returns number of nodes we will try to connect to */
paulo@0 328 static size_t try_some_nodes (time_t now)
paulo@0 329 {
paulo@0 330 List *nodes = NULL;
paulo@0 331 List *cached = NULL;
paulo@0 332 size_t total = 0;
paulo@0 333 size_t nr;
paulo@0 334 size_t len;
paulo@0 335 size_t count;
paulo@0 336
paulo@0 337 /* the total amount of nodes we should try */
paulo@0 338 nr = TRY_CONNECT_NODE_LIST + TRY_CONNECT_NODE_CACHE;
paulo@0 339
paulo@0 340 /*
paulo@0 341 * Iterate the node (pong) cache and node list until we
paulo@0 342 * have seen 'nr' nodes or there are no more hosts to try.
paulo@0 343 */
paulo@0 344
paulo@0 345 while (total < nr)
paulo@0 346 {
paulo@0 347 gt_conn_foreach (GT_CONN_FOREACH(collect_each_node), &nodes,
paulo@0 348 GT_NODE_NONE, GT_NODE_DISCONNECTED, 0);
paulo@0 349
paulo@0 350 /* grab at most nr - total nodes (still need to fix the preceeding
paulo@0 351 * call to gt_conn_foreach() to respect 'total') */
paulo@0 352 count = MIN (nr - total, TRY_CONNECT_NODE_CACHE);
paulo@0 353 assert (count >= 0);
paulo@0 354
paulo@0 355 cached = gt_node_cache_get_remove (count);
paulo@0 356
paulo@0 357 /* registered nodes can still slip into our node cache, argh */
paulo@0 358 cached = list_foreach_remove (cached,
paulo@0 359 (ListForeachFunc)prune_registered,
paulo@0 360 NULL);
paulo@0 361
paulo@0 362 len = list_length (nodes) + list_length (cached);
paulo@0 363
paulo@0 364 total += len;
paulo@0 365
paulo@0 366 if (len == 0)
paulo@0 367 break;
paulo@0 368
paulo@0 369 nodes = list_foreach_remove (nodes, (ListForeachFunc)connect_each,
paulo@0 370 NULL);
paulo@0 371 assert (nodes == NULL);
paulo@0 372
paulo@0 373 cached = list_foreach_remove (cached, (ListForeachFunc)register_cached,
paulo@0 374 NULL);
paulo@0 375 assert (cached == NULL);
paulo@0 376 }
paulo@0 377
paulo@0 378 return total;
paulo@0 379 }
paulo@0 380
paulo@0 381 static void maintain_class (gt_node_class_t klass, time_t now)
paulo@0 382 {
paulo@0 383 int connected;
paulo@0 384 int need;
paulo@0 385
paulo@0 386 connected = gt_conn_length (klass, GT_NODE_CONNECTED);
paulo@0 387 need = gt_conn_need_connections (klass);
paulo@0 388
paulo@0 389 /*
paulo@0 390 * print the number of nodes connected if it has changed
paulo@0 391 * XXX: print leaves from ultrapeers and leaves too.
paulo@0 392 * damn static variables to hell
paulo@0 393 */
paulo@0 394 if (klass == GT_NODE_ULTRA)
paulo@0 395 report_connected_leaf (connected);
paulo@0 396
paulo@0 397 /* 0 == perfection */
paulo@0 398 if (need == 0)
paulo@0 399 return;
paulo@0 400
paulo@0 401 /* disconnect some nodes */
paulo@0 402 if (need < 0)
paulo@0 403 {
paulo@0 404 if (disconnect_timer)
paulo@0 405 return;
paulo@0 406
paulo@0 407 /*
paulo@0 408 * Disconnect the node soon, because it could happen that
paulo@0 409 * someone will disconnect from us first, causing cascading
paulo@0 410 * disconnects.
paulo@0 411 */
paulo@0 412 GT->DBGFN (GT, "starting disconnect timer...");
paulo@0 413 disconnect_timer = timer_add (4 * SECONDS,
paulo@0 414 (TimerCallback)disconnect_excess_timer,
paulo@0 415 NULL);
paulo@0 416 return;
paulo@0 417 }
paulo@0 418
paulo@0 419 /*
paulo@0 420 * If try_some_nodes() returns 0, then there are no nodes in the node
paulo@0 421 * cache nor any on the node list that we haven't tried yet. In that case,
paulo@0 422 * we need to contact the gwebcaches and hope a fresh infusion of nodes
paulo@0 423 * will help. While we wait, we retry all the nodes we already tried by
paulo@0 424 * clearing node->tried_connect for each node, which otherwise prevents
paulo@0 425 * from recontacting the nodes.
paulo@0 426 *
paulo@0 427 * We will "block" on the gwebcaches if the bandwidth is completely
paulo@0 428 * saturated and we can't get a reply from anyone, or if there are no
paulo@0 429 * ultrapeers with connection slots available. The gwebcache subsystem
paulo@0 430 * imposes its own limits on how often it will contact gwebcaches, so if
paulo@0 431 * we do end up in this situation, hopefully we will simply spend most of
paulo@0 432 * the time unconnected rather than hammering the gwebcaches.
paulo@0 433 */
paulo@0 434 if (try_some_nodes (now) == 0)
paulo@0 435 {
paulo@0 436 size_t len;
paulo@0 437
paulo@0 438 len = gt_conn_length (GT_NODE_NONE, GT_NODE_ANY);
paulo@0 439 GT->dbg (GT, "try_some_nodes() returned 0. node list len=%u", len);
paulo@0 440
paulo@0 441 if (connected == 0 || len < 20)
paulo@0 442 {
paulo@0 443 /* try to get more hosts */
paulo@0 444 GT->dbg (GT, "No hosts to try. Looking in gwebcaches...");
paulo@0 445 gt_web_cache_update ();
paulo@0 446 }
paulo@0 447
paulo@0 448 GT->dbg (GT, "Retrying to connect to nodes...");
paulo@0 449
paulo@0 450 /* while we are waiting for the gwebcaches, try each node again */
paulo@0 451 gt_conn_foreach (GT_CONN_FOREACH(clear_try_bit), NULL,
paulo@0 452 GT_NODE_NONE, GT_NODE_ANY, 0);
paulo@0 453
paulo@0 454 return;
paulo@0 455 }
paulo@0 456 }
paulo@0 457
paulo@0 458 static GtNode *disconnect_no_ping_replies (TCPC *c, GtNode *node, void *udata)
paulo@0 459 {
paulo@0 460 if (node->pings_with_noreply < MAX_UNREPLIED_PINGS)
paulo@0 461 return NULL;
paulo@0 462
paulo@0 463 GT->DBGSOCK (GT, node->c, "%d unreplied pings. disconnecting",
paulo@0 464 node->pings_with_noreply);
paulo@0 465
paulo@0 466 gt_node_disconnect (c);
paulo@0 467 return NULL;
paulo@0 468 }
paulo@0 469
paulo@0 470 /*****************************************************************************/
paulo@0 471
paulo@0 472 /*
paulo@0 473 * This is the main network maintainence function. All connections to the
paulo@0 474 * network are initiated from here.
paulo@0 475 */
paulo@0 476 static BOOL maintain (void *udata)
paulo@0 477 {
paulo@0 478 time_t now;
paulo@0 479
paulo@0 480 now = time (NULL);
paulo@0 481
paulo@0 482 /* disconnect nodes without query routing if we are not a supernode */
paulo@0 483 if (!(GT_SELF->klass & GT_NODE_ULTRA))
paulo@0 484 disconnect_no_query_route ();
paulo@0 485
paulo@0 486 #if 0
paulo@0 487 trace_list (connections);
paulo@0 488 #endif
paulo@0 489
paulo@0 490 /*
paulo@0 491 * Send pings to all connected nodes. We used to do this only every
paulo@0 492 * minute, but because some nodes have short timeouts if they receive
paulo@0 493 * nothing from you, we now do it every MAINTAIN_INTERVAL.
paulo@0 494 */
paulo@0 495 ping_hosts (now);
paulo@0 496
paulo@0 497 maintain_class (GT_NODE_ULTRA, now);
paulo@0 498 maintain_class (GT_NODE_LEAF, now);
paulo@0 499
paulo@0 500 return TRUE;
paulo@0 501 }
paulo@0 502
paulo@0 503 static BOOL idle_disconnect (void *udata)
paulo@0 504 {
paulo@0 505 gt_conn_foreach (GT_CONN_FOREACH(disconnect_no_ping_replies), NULL,
paulo@0 506 GT_NODE_NONE, GT_NODE_CONNECTED, 0);
paulo@0 507 return TRUE;
paulo@0 508 }
paulo@0 509
paulo@0 510 static BOOL cleanup (void *udata)
paulo@0 511 {
paulo@0 512 /* trim excess nodes */
paulo@0 513 gt_conn_trim ();
paulo@0 514
paulo@0 515 /* save to disk important nodes from the node list */
paulo@0 516 gt_node_list_save ();
paulo@0 517
paulo@0 518 /* save to disk important nodes from the node cache */
paulo@0 519 gt_node_cache_save ();
paulo@0 520
paulo@0 521 return TRUE;
paulo@0 522 }
paulo@0 523
paulo@0 524 static BOOL retry_all (void *udata)
paulo@0 525 {
paulo@0 526 /*
paulo@0 527 * Clear the 'tried' bit for all nodes, so if we start looking for nodes
paulo@0 528 * we try reconnecting to the ones we know about instead of contacting the
paulo@0 529 * gwebcaches.
paulo@0 530 *
paulo@0 531 * NOTE: should all the nodes be possibly retried (GT_NODE_ANY) or
paulo@0 532 * only those that are disconnected (GT_NODE_DISCONNECTED)?
paulo@0 533 */
paulo@0 534 gt_conn_foreach (GT_CONN_FOREACH(clear_try_bit), NULL,
paulo@0 535 GT_NODE_NONE, GT_NODE_ANY, 0);
paulo@0 536
paulo@0 537 return TRUE;
paulo@0 538 }
paulo@0 539 /*****************************************************************************/
paulo@0 540
paulo@0 541 void gt_netorg_init (void)
paulo@0 542 {
paulo@0 543 if (maintain_timer != 0)
paulo@0 544 return;
paulo@0 545
paulo@0 546 /* load the node cache */
paulo@0 547 gt_node_cache_init ();
paulo@0 548
paulo@0 549 /* setup the links maintain timer */
paulo@0 550 maintain_timer = timer_add (MAINTAIN_INTERVAL,
paulo@0 551 maintain, NULL);
paulo@0 552
paulo@0 553 idle_disconnect_timer = timer_add (IDLE_DISCONNECT_INTERVAL,
paulo@0 554 idle_disconnect, NULL);
paulo@0 555
paulo@0 556 cleanup_timer = timer_add (CLEANUP_INTERVAL,
paulo@0 557 cleanup, NULL);
paulo@0 558
paulo@0 559 retry_all_timer = timer_add (RETRY_ALL_INTERVAL,
paulo@0 560 retry_all, NULL);
paulo@0 561
paulo@0 562 /* call it now so we don't have to wait the first time */
paulo@0 563 maintain (NULL);
paulo@0 564 }
paulo@0 565
paulo@0 566 void gt_netorg_cleanup (void)
paulo@0 567 {
paulo@0 568 /* save the node cache */
paulo@0 569 gt_node_cache_cleanup ();
paulo@0 570
paulo@0 571 timer_remove_zero (&disconnect_timer);
paulo@0 572
paulo@0 573 timer_remove_zero (&maintain_timer);
paulo@0 574 timer_remove_zero (&idle_disconnect_timer);
paulo@0 575 timer_remove_zero (&cleanup_timer);
paulo@0 576 timer_remove_zero (&retry_all_timer);
paulo@0 577 }