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 }
|