void gnet_stats_count_dropped(gnutella_node_t *n, msg_drop_reason_t reason) { uint32 size; uint type; gnet_stats_t *stats; g_assert(UNSIGNED(reason) < MSG_DROP_REASON_COUNT); g_assert(thread_is_main()); stats = NODE_USES_UDP(n) ? &gnet_udp_stats : &gnet_tcp_stats; if (NODE_TALKS_G2(n)) { int f = g2_msg_type(n->data, n->size); if (f != G2_MSG_MAX) { f += MSG_G2_BASE; } else { f = G_N_ELEMENTS(stats_lut) - 1; /* Last, holds MSG_UNKNOWN */ } type = stats_lut[f]; size = n->size; } else { type = stats_lut[gnutella_header_get_function(&n->header)]; size = n->size + sizeof(n->header); } entropy_harvest_small( VARLEN(n->addr), VARLEN(n->port), VARLEN(reason), VARLEN(type), VARLEN(size), NULL); DROP_STATS(stats, type, size); node_inc_rxdrop(n); switch (reason) { case MSG_DROP_HOSTILE_IP: n->n_hostile++; break; case MSG_DROP_SPAM: n->n_spam++; break; case MSG_DROP_EVIL: n->n_evil++; break; default: ; } if (NODE_TALKS_G2(n)) { if (GNET_PROPERTY(log_dropped_g2)) { g2_msg_log_dropped_data(n->data, n->size, "from %s: %s", node_infostr(n), gnet_stats_drop_reason_to_string(reason)); } } else { if (GNET_PROPERTY(log_dropped_gnutella)) { gmsg_log_split_dropped(&n->header, n->data, n->size, "from %s: %s", node_infostr(n), gnet_stats_drop_reason_to_string(reason)); } } }
void gnet_stats_count_sent(const gnutella_node_t *n, uint8 type, const void *base, uint32 size) { uint t = stats_lut[type]; gnet_stats_t *stats; uint8 hops; g_assert(t != MSG_UNKNOWN); g_assert(thread_is_main()); g_assert(!NODE_TALKS_G2(n)); stats = NODE_USES_UDP(n) ? &gnet_udp_stats : &gnet_tcp_stats; /* * Adjust for Kademlia messages. */ if (GTA_MSG_DHT == type && size >= KDA_HEADER_SIZE) { uint8 opcode = kademlia_header_get_function(base); if (UNSIGNED(opcode + MSG_DHT_BASE) < G_N_ELEMENTS(stats_lut)) { t = stats_lut[opcode + MSG_DHT_BASE]; } hops = 0; } else { hops = gnutella_header_get_hops(base); } gnet_stats_count_sent_internal(n, t, hops, size, stats); }
/** * Send a message to target node. * * @param n the G2 node to which message should be sent * @param mb the message to sent (ownership taken, will be freed later) */ void g2_node_send(const gnutella_node_t *n, pmsg_t *mb) { node_check(n); g_assert(NODE_TALKS_G2(n)); if (NODE_IS_UDP(n)) mq_udp_node_putq(n->outq, mb, n); else if (NODE_IS_WRITABLE(n)) mq_tcp_putq(n->outq, mb, NULL); else goto drop; if (GNET_PROPERTY(log_sending_g2)) { g_debug("%s(): sending %s to %s", G_STRFUNC, g2_msg_infostr_mb(mb), node_infostr(n)); } return; drop: if (GNET_PROPERTY(log_sending_g2)) { g_debug("%s(): aborting sending %s to %s", G_STRFUNC, g2_msg_infostr_mb(mb), node_infostr(n)); } pmsg_free(mb); /* Cannot send it, free it now */ }
void gnet_stats_g2_count_queued(const gnutella_node_t *n, const void *base, size_t len) { gnet_stats_t *stats; uint t; uint8 f; g_assert(thread_is_main()); g_assert(NODE_TALKS_G2(n)); stats = NODE_USES_UDP(n) ? &gnet_udp_stats : &gnet_tcp_stats; f = g2_msg_type(base, len); if (f != G2_MSG_MAX) { f += MSG_G2_BASE; } else { f = G_N_ELEMENTS(stats_lut) - 1; /* Last, holds MSG_UNKNOWN */ } t = stats_lut[f]; /* Leaf mode => hops = 0 */ gnet_stats_count_queued_internal(n, t, 0, len, stats); }
/** * Called when Gnutella header has been read. */ void gnet_stats_count_received_header(gnutella_node_t *n) { uint t = stats_lut[gnutella_header_get_function(&n->header)]; uint8 ttl, hops; g_assert(thread_is_main()); g_assert(!NODE_TALKS_G2(n)); ttl = gnutella_header_get_ttl(&n->header); hops = gnutella_header_get_hops(&n->header); gnet_stats_count_received_header_internal(n, GTA_HEADER_SIZE, t, ttl, hops); }
/** * Generate as many "NH" children to the root as we have neihbouring hubs, * when the node is firewalled. They can act as "push proxies", as in Gnutella. */ static void g2_build_add_neighbours(g2_tree_t *t) { if (GNET_PROPERTY(is_firewalled) || GNET_PROPERTY(is_udp_firewalled)) { const pslist_t *sl; PSLIST_FOREACH(node_all_g2_nodes(), sl) { const gnutella_node_t *n = sl->data; node_check(n); g_assert(NODE_TALKS_G2(n)); if (NODE_IS_ESTABLISHED(n) && node_address_known(n)) g2_build_add_host(t, "NH", n->gnet_addr, n->gnet_port); } } }
void gnet_stats_g2_count_sent(const gnutella_node_t *n, enum g2_msg type, uint32 size) { uint t; gnet_stats_t *stats; g_assert(thread_is_main()); g_assert((uint) type < UNSIGNED(G2_MSG_MAX)); g_assert(NODE_TALKS_G2(n)); stats = NODE_USES_UDP(n) ? &gnet_udp_stats : &gnet_tcp_stats; t = stats_lut[MSG_G2_BASE + type]; g_assert(t != MSG_UNKNOWN); /* Leaf mode => hops = 0 */ gnet_stats_count_sent_internal(n, t, 0, size, stats); }
void gnet_stats_count_expired(const gnutella_node_t *n) { uint32 size = n->size + sizeof(n->header); uint t = stats_lut[gnutella_header_get_function(&n->header)]; gnet_stats_t *stats; g_assert(thread_is_main()); g_assert(!NODE_TALKS_G2(n)); stats = NODE_USES_UDP(n) ? &gnet_udp_stats : &gnet_tcp_stats; gnet_stats.pkg.expired[MSG_TOTAL]++; gnet_stats.pkg.expired[t]++; gnet_stats.byte.expired[MSG_TOTAL] += size; gnet_stats.byte.expired[t] += size; stats->pkg.expired[MSG_TOTAL]++; stats->pkg.expired[t]++; stats->byte.expired[MSG_TOTAL] += size; stats->byte.expired[t] += size; }
/** * Called to transform Gnutella header counting into Kademlia header counting. * * @param n the node receiving the message * @param kt */ static void gnet_stats_count_kademlia_header(const gnutella_node_t *n, uint kt) { uint t = stats_lut[gnutella_header_get_function(&n->header)]; uint i; gnet_stats_t *stats; g_assert(thread_is_main()); g_assert(!NODE_TALKS_G2(n)); stats = NODE_USES_UDP(n) ? &gnet_udp_stats : &gnet_tcp_stats; gnet_stats.pkg.received[t]--; gnet_stats.pkg.received[kt]++; gnet_stats.byte.received[t] -= GTA_HEADER_SIZE; gnet_stats.byte.received[kt] += GTA_HEADER_SIZE; stats->pkg.received[t]--; stats->pkg.received[kt]++; stats->byte.received[t] -= GTA_HEADER_SIZE; stats->byte.received[kt] += GTA_HEADER_SIZE; i = MIN(gnutella_header_get_ttl(&n->header), STATS_RECV_COLUMNS - 1); stats->pkg.received_ttl[i][MSG_TOTAL]--; stats->pkg.received_ttl[i][t]--; i = MIN(gnutella_header_get_hops(&n->header), STATS_RECV_COLUMNS - 1); stats->pkg.received_hops[i][MSG_TOTAL]--; stats->pkg.received_hops[i][t]--; /* DHT messages have no hops nor ttl, use 0 */ stats->pkg.received_ttl[0][MSG_TOTAL]++; stats->pkg.received_ttl[0][kt]++; stats->pkg.received_hops[0][MSG_TOTAL]++; stats->pkg.received_hops[0][kt]++; }
void gnet_stats_count_dropped_nosize( const gnutella_node_t *n, msg_drop_reason_t reason) { uint type; gnet_stats_t *stats; g_assert(UNSIGNED(reason) < MSG_DROP_REASON_COUNT); g_assert(thread_is_main()); g_assert(!NODE_TALKS_G2(n)); type = stats_lut[gnutella_header_get_function(&n->header)]; stats = NODE_USES_UDP(n) ? &gnet_udp_stats : &gnet_tcp_stats; entropy_harvest_small(VARLEN(n->addr), VARLEN(n->port), NULL); /* Data part of message not read */ DROP_STATS(stats, type, sizeof(n->header)); if (GNET_PROPERTY(log_dropped_gnutella)) gmsg_log_split_dropped(&n->header, n->data, 0, "from %s: %s", node_infostr(n), gnet_stats_drop_reason_to_string(reason)); }
/** * Called when Gnutella payload has been read, or when a G2 messsage is read. * * The actual payload size (effectively read) is expected to be found * in n->size for Gnutella messages and G2 messages. * * @param n the node from which message was received * @param payload start of Gnutella payload, or head of G2 frame */ void gnet_stats_count_received_payload(const gnutella_node_t *n, const void *payload) { uint8 f; uint t; uint i; gnet_stats_t *stats; uint32 size; uint8 hops, ttl; g_assert(thread_is_main()); stats = NODE_USES_UDP(n) ? &gnet_udp_stats : &gnet_tcp_stats; size = n->size; /* * Size is NOT read in the Gnutella header but in n->size, which * reflects how much data we have in the payload, as opposed to the * size in the header which may be wrong, or have highest bits set * because they indicate flags. * * In particular, broken DHT messages often come with an invalid size in * the header. * --RAM, 2010-10-30 */ if (NODE_TALKS_G2(n)) { f = g2_msg_type(payload, size); if (f != G2_MSG_MAX) { f += MSG_G2_BASE; } else { f = G_N_ELEMENTS(stats_lut) - 1; /* Last, holds MSG_UNKNOWN */ } ttl = 1; hops = NODE_USES_UDP(n) ? 0 : 1; t = stats_lut[f]; /* * No header for G2, so count header reception now with a size of zero. * This is required to update the other packet reception statistics. */ gnet_stats_count_received_header_internal( deconstify_pointer(n), 0, t, ttl, hops); } else { f = gnutella_header_get_function(&n->header); hops = gnutella_header_get_hops(&n->header); ttl = gnutella_header_get_ttl(&n->header); t = stats_lut[f]; } gnet_stats_randomness(n, f, size); /* * If we're dealing with a Kademlia message, we need to do two things: * * We counted the Gnutella header for the GTA_MSG_DHT message, but we * now need to undo that and count it as a Kademlia message. * * To access the proper entry in the array, we need to offset the * Kademlia OpCode from the header with MSG_DHT_BASE to get the entry * in the statistics that are associated with that particular message. * --RAM, 2010-11-01 */ if (GTA_MSG_DHT == f && size + GTA_HEADER_SIZE >= KDA_HEADER_SIZE) { uint8 opcode = peek_u8(payload); /* Kademlia Opcode */ if (UNSIGNED(opcode + MSG_DHT_BASE) < G_N_ELEMENTS(stats_lut)) { t = stats_lut[opcode + MSG_DHT_BASE]; gnet_stats_count_kademlia_header(n, t); } } g_assert(t < MSG_TOTAL); gnet_stats.byte.received[MSG_TOTAL] += size; gnet_stats.byte.received[t] += size; stats->byte.received[MSG_TOTAL] += size; stats->byte.received[t] += size; i = MIN(ttl, STATS_RECV_COLUMNS - 1); stats->byte.received_ttl[i][MSG_TOTAL] += size; stats->byte.received_ttl[i][t] += size; i = MIN(hops, STATS_RECV_COLUMNS - 1); stats->byte.received_hops[i][MSG_TOTAL] += size; stats->byte.received_hops[i][t] += size; }
/** * Handle message coming from G2 node. */ void g2_node_handle(gnutella_node_t *n) { g2_tree_t *t; size_t plen; enum g2_msg type; node_check(n); g_assert(NODE_TALKS_G2(n)); t = g2_frame_deserialize(n->data, n->size, &plen, FALSE); if (NULL == t) { if (GNET_PROPERTY(g2_debug) > 0 || GNET_PROPERTY(log_bad_g2)) { g_warning("%s(): cannot deserialize /%s from %s", G_STRFUNC, g2_msg_raw_name(n->data, n->size), node_infostr(n)); } if (GNET_PROPERTY(log_bad_g2)) dump_hex(stderr, "G2 Packet", n->data, n->size); return; } else if (plen != n->size) { if (GNET_PROPERTY(g2_debug) > 0 || GNET_PROPERTY(log_bad_g2)) { g_warning("%s(): consumed %zu bytes but /%s from %s had %u", G_STRFUNC, plen, g2_msg_raw_name(n->data, n->size), node_infostr(n), n->size); } if (GNET_PROPERTY(log_bad_g2)) dump_hex(stderr, "G2 Packet", n->data, n->size); hostiles_dynamic_add(n->addr, "cannot parse incoming messages", HSTL_GIBBERISH); goto done; } else if (GNET_PROPERTY(g2_debug) > 19) { g_debug("%s(): received packet from %s", G_STRFUNC, node_infostr(n)); g2_tfmt_tree_dump(t, stderr, G2FMT_O_PAYLEN); } type = g2_msg_name_type(g2_tree_name(t)); switch (type) { case G2_MSG_PI: g2_node_handle_ping(n, t); break; case G2_MSG_PO: g2_node_handle_pong(n, t); break; case G2_MSG_LNI: g2_node_handle_lni(n, t); break; case G2_MSG_KHL: g2_node_handle_khl(t); break; case G2_MSG_PUSH: handle_push_request(n, t); break; case G2_MSG_Q2: g2_node_handle_q2(n, t); break; case G2_MSG_QA: case G2_MSG_QKA: g2_node_handle_rpc_answer(n, t, type); break; case G2_MSG_QH2: search_g2_results(n, t); break; default: g2_node_drop(G_STRFUNC, n, t, "default"); break; } done: g2_tree_free_null(&t); }