view src/message/ping.c @ 0:d39e1d0d75b6

initial add
author paulo@hit-nxdomain.opendns.com
date Sat, 20 Feb 2010 21:18:28 -0800
parents
children
line source
1 /*
2 * $Id: ping.c,v 1.4 2004/03/05 17:49:40 hipnod Exp $
3 *
4 * Copyright (C) 2001-2003 giFT project (gift.sourceforge.net)
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 */
17 #include "gt_gnutella.h"
18 #include "message/msg_handler.h"
20 #include "gt_node_list.h"
21 #include "gt_bind.h"
22 #include "gt_netorg.h"
24 #include "gt_stats.h"
25 #include "gt_share.h"
27 /******************************************************************************/
29 BOOL gt_is_pow2 (uint32_t num)
30 {
31 return BOOL_EXPR (num > 0 && (num & (num-1)) == 0);
32 }
34 static uint32_t get_shared_size (unsigned long size_mb)
35 {
36 uint32_t size_kb;
38 size_kb = size_mb * 1024;
40 if (GT_SELF->klass & GT_NODE_ULTRA)
41 /* TODO: round up to nearest power of two >= 8 here */;
42 else if (gt_is_pow2 (size_kb))
43 size_kb += 5; /* unmakes all powers of two, including 1 */
45 return size_kb;
46 }
48 /* reply to a ping packet */
49 static void ping_reply_self (GtPacket *packet, TCPC *c)
50 {
51 unsigned long files, size_kb;
52 double size_mb;
53 GtPacket *reply;
55 share_index (&files, &size_mb);
56 size_kb = get_shared_size (size_mb);
58 if (!(reply = gt_packet_reply (packet, GT_MSG_PING_REPLY)))
59 return;
61 gt_packet_put_port (reply, GT_SELF->gt_port);
62 gt_packet_put_ip (reply, GT_NODE(c)->my_ip);
63 gt_packet_put_uint32 (reply, (uint32_t)files);
64 gt_packet_put_uint32 (reply, (uint32_t)size_kb);
66 if (gt_packet_error (reply))
67 {
68 gt_packet_free (reply);
69 return;
70 }
72 gt_packet_send (c, reply);
73 gt_packet_free (reply);
74 }
76 /* send info about node dst to node c */
77 static TCPC *send_status (TCPC *c, GtNode *node, void **data)
78 {
79 GtPacket *pkt = (GtPacket *) data[0];
80 TCPC *dst = (TCPC *) data[1];
81 GtPacket *reply;
83 /* don't send a ping for the node itself */
84 if (c == dst)
85 return NULL;
87 if (!(reply = gt_packet_reply (pkt, GT_MSG_PING_REPLY)))
88 return NULL;
90 gt_packet_put_port (reply, node->gt_port);
91 gt_packet_put_ip (reply, node->ip);
92 gt_packet_put_uint32 (reply, node->files);
93 gt_packet_put_uint32 (reply, node->size_kb);
95 /* set the number of hops travelled to 1 */
96 gt_packet_set_hops (reply, 1);
98 if (gt_packet_error (reply))
99 {
100 gt_packet_free (reply);
101 return NULL;
102 }
104 gt_packet_send (dst, reply);
105 gt_packet_free (reply);
107 return NULL;
108 }
110 static void handle_crawler_ping (GtPacket *packet, TCPC *c)
111 {
112 void *data[2];
114 data[0] = packet;
115 data[1] = c;
117 /* reply ourselves */
118 ping_reply_self (packet, c);
120 /* send pings from connected hosts */
121 gt_conn_foreach (GT_CONN_FOREACH(send_status), data,
122 GT_NODE_NONE, GT_NODE_CONNECTED, 0);
123 }
125 static BOOL need_connections (void)
126 {
127 BOOL am_ultrapeer;
129 am_ultrapeer = GT_SELF->klass & GT_NODE_ULTRA;
131 /* send a pong if we need connections, but do this
132 * only if this is a search node: leaves shouldnt send pongs */
133 if (gt_conn_need_connections (GT_NODE_ULTRA) > 0 && am_ultrapeer)
134 return TRUE;
136 /* pretend we need connections temporarily even if we don't in order to
137 * figure out whether we are firewalled or not */
138 if (gt_uptime () < 10 * EMINUTES && GT_SELF->firewalled)
139 return TRUE;
141 return FALSE;
142 }
144 GT_MSG_HANDLER(gt_msg_ping)
145 {
146 time_t last_ping_time, now;
147 uint8_t ttl, hops;
149 now = time (NULL);
151 ttl = gt_packet_ttl (packet);
152 hops = gt_packet_hops (packet);
154 last_ping_time = GT_NODE(c)->last_ping_time;
155 GT_NODE(c)->last_ping_time = now;
157 if ((ttl == 1 && (hops == 0 || hops == 1)) /* tests if host is up */
158 || GT_NODE(c)->state == GT_NODE_CONNECTING_2 /* need to reply */
159 || need_connections ()) /* we need connections */
160 {
161 ping_reply_self (packet, c);
163 if (ttl == 1)
164 return;
165 }
166 else if (ttl == 2 && hops == 0)
167 {
168 /* crawler ping: respond with all connected nodes */
169 handle_crawler_ping (packet, c);
170 return;
171 }
173 /* dont re-broadcast pings from search nodes if we are not one */
174 if ((GT_NODE(c)->klass & GT_NODE_ULTRA) && !(GT_SELF->klass & GT_NODE_ULTRA))
175 return;
177 #if 0
178 /* notify this host when the pong cache gets full */
179 pong_cache_waiter_add (c, packet);
180 #endif
182 /* dont accept pings too often */
183 if (now - last_ping_time < 30 * ESECONDS)
184 return;
186 #if 0
187 if (!pong_cache_reply (c, packet))
188 {
189 /* refill the pong cache */
190 pong_cache_refill ();
191 return;
192 }
194 pong_cache_waiter_remove (c);
195 #endif
196 }