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