rev |
line source |
paulo@0
|
1 /*
|
paulo@0
|
2 * $Id: ping.c,v 1.4 2004/03/05 17:49:40 hipnod 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 #include "message/msg_handler.h"
|
paulo@0
|
19
|
paulo@0
|
20 #include "gt_node_list.h"
|
paulo@0
|
21 #include "gt_bind.h"
|
paulo@0
|
22 #include "gt_netorg.h"
|
paulo@0
|
23
|
paulo@0
|
24 #include "gt_stats.h"
|
paulo@0
|
25 #include "gt_share.h"
|
paulo@0
|
26
|
paulo@0
|
27 /******************************************************************************/
|
paulo@0
|
28
|
paulo@0
|
29 BOOL gt_is_pow2 (uint32_t num)
|
paulo@0
|
30 {
|
paulo@0
|
31 return BOOL_EXPR (num > 0 && (num & (num-1)) == 0);
|
paulo@0
|
32 }
|
paulo@0
|
33
|
paulo@0
|
34 static uint32_t get_shared_size (unsigned long size_mb)
|
paulo@0
|
35 {
|
paulo@0
|
36 uint32_t size_kb;
|
paulo@0
|
37
|
paulo@0
|
38 size_kb = size_mb * 1024;
|
paulo@0
|
39
|
paulo@0
|
40 if (GT_SELF->klass & GT_NODE_ULTRA)
|
paulo@0
|
41 /* TODO: round up to nearest power of two >= 8 here */;
|
paulo@0
|
42 else if (gt_is_pow2 (size_kb))
|
paulo@0
|
43 size_kb += 5; /* unmakes all powers of two, including 1 */
|
paulo@0
|
44
|
paulo@0
|
45 return size_kb;
|
paulo@0
|
46 }
|
paulo@0
|
47
|
paulo@0
|
48 /* reply to a ping packet */
|
paulo@0
|
49 static void ping_reply_self (GtPacket *packet, TCPC *c)
|
paulo@0
|
50 {
|
paulo@0
|
51 unsigned long files, size_kb;
|
paulo@0
|
52 double size_mb;
|
paulo@0
|
53 GtPacket *reply;
|
paulo@0
|
54
|
paulo@0
|
55 share_index (&files, &size_mb);
|
paulo@0
|
56 size_kb = get_shared_size (size_mb);
|
paulo@0
|
57
|
paulo@0
|
58 if (!(reply = gt_packet_reply (packet, GT_MSG_PING_REPLY)))
|
paulo@0
|
59 return;
|
paulo@0
|
60
|
paulo@0
|
61 gt_packet_put_port (reply, GT_SELF->gt_port);
|
paulo@0
|
62 gt_packet_put_ip (reply, GT_NODE(c)->my_ip);
|
paulo@0
|
63 gt_packet_put_uint32 (reply, (uint32_t)files);
|
paulo@0
|
64 gt_packet_put_uint32 (reply, (uint32_t)size_kb);
|
paulo@0
|
65
|
paulo@0
|
66 if (gt_packet_error (reply))
|
paulo@0
|
67 {
|
paulo@0
|
68 gt_packet_free (reply);
|
paulo@0
|
69 return;
|
paulo@0
|
70 }
|
paulo@0
|
71
|
paulo@0
|
72 gt_packet_send (c, reply);
|
paulo@0
|
73 gt_packet_free (reply);
|
paulo@0
|
74 }
|
paulo@0
|
75
|
paulo@0
|
76 /* send info about node dst to node c */
|
paulo@0
|
77 static TCPC *send_status (TCPC *c, GtNode *node, void **data)
|
paulo@0
|
78 {
|
paulo@0
|
79 GtPacket *pkt = (GtPacket *) data[0];
|
paulo@0
|
80 TCPC *dst = (TCPC *) data[1];
|
paulo@0
|
81 GtPacket *reply;
|
paulo@0
|
82
|
paulo@0
|
83 /* don't send a ping for the node itself */
|
paulo@0
|
84 if (c == dst)
|
paulo@0
|
85 return NULL;
|
paulo@0
|
86
|
paulo@0
|
87 if (!(reply = gt_packet_reply (pkt, GT_MSG_PING_REPLY)))
|
paulo@0
|
88 return NULL;
|
paulo@0
|
89
|
paulo@0
|
90 gt_packet_put_port (reply, node->gt_port);
|
paulo@0
|
91 gt_packet_put_ip (reply, node->ip);
|
paulo@0
|
92 gt_packet_put_uint32 (reply, node->files);
|
paulo@0
|
93 gt_packet_put_uint32 (reply, node->size_kb);
|
paulo@0
|
94
|
paulo@0
|
95 /* set the number of hops travelled to 1 */
|
paulo@0
|
96 gt_packet_set_hops (reply, 1);
|
paulo@0
|
97
|
paulo@0
|
98 if (gt_packet_error (reply))
|
paulo@0
|
99 {
|
paulo@0
|
100 gt_packet_free (reply);
|
paulo@0
|
101 return NULL;
|
paulo@0
|
102 }
|
paulo@0
|
103
|
paulo@0
|
104 gt_packet_send (dst, reply);
|
paulo@0
|
105 gt_packet_free (reply);
|
paulo@0
|
106
|
paulo@0
|
107 return NULL;
|
paulo@0
|
108 }
|
paulo@0
|
109
|
paulo@0
|
110 static void handle_crawler_ping (GtPacket *packet, TCPC *c)
|
paulo@0
|
111 {
|
paulo@0
|
112 void *data[2];
|
paulo@0
|
113
|
paulo@0
|
114 data[0] = packet;
|
paulo@0
|
115 data[1] = c;
|
paulo@0
|
116
|
paulo@0
|
117 /* reply ourselves */
|
paulo@0
|
118 ping_reply_self (packet, c);
|
paulo@0
|
119
|
paulo@0
|
120 /* send pings from connected hosts */
|
paulo@0
|
121 gt_conn_foreach (GT_CONN_FOREACH(send_status), data,
|
paulo@0
|
122 GT_NODE_NONE, GT_NODE_CONNECTED, 0);
|
paulo@0
|
123 }
|
paulo@0
|
124
|
paulo@0
|
125 static BOOL need_connections (void)
|
paulo@0
|
126 {
|
paulo@0
|
127 BOOL am_ultrapeer;
|
paulo@0
|
128
|
paulo@0
|
129 am_ultrapeer = GT_SELF->klass & GT_NODE_ULTRA;
|
paulo@0
|
130
|
paulo@0
|
131 /* send a pong if we need connections, but do this
|
paulo@0
|
132 * only if this is a search node: leaves shouldnt send pongs */
|
paulo@0
|
133 if (gt_conn_need_connections (GT_NODE_ULTRA) > 0 && am_ultrapeer)
|
paulo@0
|
134 return TRUE;
|
paulo@0
|
135
|
paulo@0
|
136 /* pretend we need connections temporarily even if we don't in order to
|
paulo@0
|
137 * figure out whether we are firewalled or not */
|
paulo@0
|
138 if (gt_uptime () < 10 * EMINUTES && GT_SELF->firewalled)
|
paulo@0
|
139 return TRUE;
|
paulo@0
|
140
|
paulo@0
|
141 return FALSE;
|
paulo@0
|
142 }
|
paulo@0
|
143
|
paulo@0
|
144 GT_MSG_HANDLER(gt_msg_ping)
|
paulo@0
|
145 {
|
paulo@0
|
146 time_t last_ping_time, now;
|
paulo@0
|
147 uint8_t ttl, hops;
|
paulo@0
|
148
|
paulo@0
|
149 now = time (NULL);
|
paulo@0
|
150
|
paulo@0
|
151 ttl = gt_packet_ttl (packet);
|
paulo@0
|
152 hops = gt_packet_hops (packet);
|
paulo@0
|
153
|
paulo@0
|
154 last_ping_time = GT_NODE(c)->last_ping_time;
|
paulo@0
|
155 GT_NODE(c)->last_ping_time = now;
|
paulo@0
|
156
|
paulo@0
|
157 if ((ttl == 1 && (hops == 0 || hops == 1)) /* tests if host is up */
|
paulo@0
|
158 || GT_NODE(c)->state == GT_NODE_CONNECTING_2 /* need to reply */
|
paulo@0
|
159 || need_connections ()) /* we need connections */
|
paulo@0
|
160 {
|
paulo@0
|
161 ping_reply_self (packet, c);
|
paulo@0
|
162
|
paulo@0
|
163 if (ttl == 1)
|
paulo@0
|
164 return;
|
paulo@0
|
165 }
|
paulo@0
|
166 else if (ttl == 2 && hops == 0)
|
paulo@0
|
167 {
|
paulo@0
|
168 /* crawler ping: respond with all connected nodes */
|
paulo@0
|
169 handle_crawler_ping (packet, c);
|
paulo@0
|
170 return;
|
paulo@0
|
171 }
|
paulo@0
|
172
|
paulo@0
|
173 /* dont re-broadcast pings from search nodes if we are not one */
|
paulo@0
|
174 if ((GT_NODE(c)->klass & GT_NODE_ULTRA) && !(GT_SELF->klass & GT_NODE_ULTRA))
|
paulo@0
|
175 return;
|
paulo@0
|
176
|
paulo@0
|
177 #if 0
|
paulo@0
|
178 /* notify this host when the pong cache gets full */
|
paulo@0
|
179 pong_cache_waiter_add (c, packet);
|
paulo@0
|
180 #endif
|
paulo@0
|
181
|
paulo@0
|
182 /* dont accept pings too often */
|
paulo@0
|
183 if (now - last_ping_time < 30 * ESECONDS)
|
paulo@0
|
184 return;
|
paulo@0
|
185
|
paulo@0
|
186 #if 0
|
paulo@0
|
187 if (!pong_cache_reply (c, packet))
|
paulo@0
|
188 {
|
paulo@0
|
189 /* refill the pong cache */
|
paulo@0
|
190 pong_cache_refill ();
|
paulo@0
|
191 return;
|
paulo@0
|
192 }
|
paulo@0
|
193
|
paulo@0
|
194 pong_cache_waiter_remove (c);
|
paulo@0
|
195 #endif
|
paulo@0
|
196 }
|