Exemplo n.º 1
0
/**
 * Record activity on the node.
 */
void
stable_record_activity(const knode_t *kn)
{
    struct lifedata *ld;
    struct lifedata new_ld;

    knode_check(kn);
    g_assert(kn->flags & KNODE_F_ALIVE);

    ld = get_lifedata(kn->id);

    if (NULL == ld) {
        ld = &new_ld;

        new_ld.version = LIFEDATA_STRUCT_VERSION;
        new_ld.first_seen = kn->first_seen;
        new_ld.last_seen = kn->last_seen;

        gnet_stats_count_general(GNR_DHT_STABLE_NODES_HELD, +1);
    } else {
        if (kn->last_seen <= ld->last_seen)
            return;
        ld->last_seen = kn->last_seen;
    }

    dbmw_write(db_lifedata, kn->id->v, ld, sizeof *ld);
}
Exemplo n.º 2
0
/**
 * Notification from the socket layer that we got a new datagram.
 *
 * @param s				the receiving socket (with s->addr and s->port set)
 * @param data			start of received data (not necessarily s->buf)
 * @param len			length of received data (not necessarily s->pos)
 * @param truncated		whether received datagram was truncated
 *
 * If `truncated' is true, then the message was too large for the
 * socket buffer.
 */
void
udp_received(const gnutella_socket_t *s,
	const void *data, size_t len, bool truncated)
{
	gnutella_node_t *n;
	bool bogus = FALSE;
	bool dht = FALSE;
	bool rudp = FALSE;

	/*
	 * This must be regular Gnutella / DHT traffic.
	 */

	inet_udp_got_incoming(s->addr);

	/*
	 * We need to identify semi-reliable UDP traffic early, because that
	 * traffic needs to go through the RX stack to reassemble the final
	 * payload out of the many fragments, or to process the acknowledgments.
	 *
	 * We have to apply heuristics however because the leading 8 bytes could
	 * be just a part of gnutella message (the first 8 bytes of a GUID).
	 * One thing is certain though: if the size is less than that of a a
	 * Gnutella header, it has to be semi-reliable UDP traffic...
	 *
	 * Because semi-reliable UDP uses small payloads, much smaller than our
	 * socket buffer, the datagram cannot be truncated.
	 */

	if (!truncated) {
		enum udp_traffic utp;
		rxdrv_t *rx;

		utp = udp_intuit_traffic_type(s, data, len);

		switch (utp) {
		case GNUTELLA:
			goto unreliable;
		case RUDP:
			rudp = TRUE;
			gnet_stats_count_general(GNR_RUDP_RX_BYTES, len);
			goto rudp;		/* Don't account this message in UDP statistics */
		case DHT:
			dht = TRUE;
			goto unreliable;
		case UNKNOWN:
			goto unknown;
		case SEMI_RELIABLE_GTA:
		case SEMI_RELIABLE_GND:
			break;
		}

		/*
		 * We are going to treat this message a a semi-reliable UDP fragment.
		 *
		 * Account the size of the payload for traffic purposes, then redirect
		 * the message to the RX layer that reassembles and dispatches these
		 * messages.
		 */

		bws_udp_count_read(len, FALSE);	/* We know it's not DHT traffic */

		rx = udp_get_rx_semi_reliable(utp, s->addr, len);

		if (rx != NULL) {
			gnet_host_t from;

			gnet_host_set(&from, s->addr, s->port);
			ut_got_message(rx, data, len, &from);
		}

		return;
	}

unknown:
	/*
	 * Discriminate between Gnutella UDP and DHT messages, so that we
	 * can account received data with the proper bandwidth scheduler.
	 */

	if (len >= GTA_HEADER_SIZE)
		dht = GTA_MSG_DHT == gnutella_header_get_function(data);

	/* FALL THROUGH */

unreliable:
	/*
	 * Account for Gnutella / DHT incoming UDP traffic.
	 */

	bws_udp_count_read(len, dht);

	/* FALL THROUGH */

rudp:
	/*
	 * The RUDP layer is used to implement firewalled-to-firewalled transfers
	 * via a mini TCP-like layer built on top of UDP.  Therefore, it is used
	 * as the basis for higher-level connections (HTTP) and will have to be
	 * accounted for once the type of traffic is known, by upper layers, as
	 * part of the upload/download traffic.
	 *
	 * Of course, the higher levels will never see all the bytes that pass
	 * through, such as acknowledgments or retransmissions, but that is also
	 * the case for TCP-based sockets.
	 *		--RAM, 2012-11-02.
	 */

	/*
	 * If we get traffic from a bogus IP (unroutable), warn, for now.
	 */

	if (bogons_check(s->addr)) {
		bogus = TRUE;

		if (GNET_PROPERTY(udp_debug)) {
			g_warning("UDP %sdatagram (%zu byte%s) received from bogus IP %s",
				truncated ? "truncated " : "",
				len, 1 == len ? "" : "s",
				host_addr_to_string(s->addr));
		}
		gnet_stats_inc_general(GNR_UDP_BOGUS_SOURCE_IP);
	}

	/*
	 * Get proper pseudo-node.
	 *
	 * These routines can return NULL if the address/port combination is
	 * not correct, but this will be handled by udp_is_valid_gnet().
	 */

	n = dht ? node_dht_get_addr_port(s->addr, s->port) :
		node_udp_get_addr_port(s->addr, s->port);

	if (!udp_is_valid_gnet(n, s, truncated, data, len))
		return;

	/*
	 * RUDP traffic does not go to the upper Gnutella processing layers.
	 */

	if (rudp) {
		/* Not ready for prime time */
#if 0
		rudp_handle_packet(s->addr, s->port. data, len);
#endif
		return;
	}

	/*
	 * Process message as if it had been received from regular Gnet by
	 * another node, only we'll use a special "pseudo UDP node" as origin.
	 */

	if (GNET_PROPERTY(udp_debug) > 19 || (bogus && GNET_PROPERTY(udp_debug)))
		g_debug("UDP got %s from %s%s", gmsg_infostr_full(data, len),
			bogus ? "BOGUS " : "", host_addr_port_to_string(s->addr, s->port));

	node_udp_process(n, s, data, len);
}
Exemplo n.º 3
0
/**
 * Fill supplied value vector with the DHT values we have under the key that
 * match the specifications: among those bearing the specified secondary keys
 * (or all of them if no secondary keys are supplied), return only those with
 * the proper DHT value type.
 *
 * @param id				the primary key of the value
 * @param type				type of DHT value they want
 * @param secondary			optional secondary keys
 * @param secondary_count	amount of secondary keys supplied
 * @param valvec			value vector where results are stored
 * @param valcnt			size of value vector
 * @param loadptr			where to write the average request load for key
 * @param cached			if non-NULL, filled with whether key was cached
 *
 * @return amount of values filled into valvec.  The values are dynamically
 * created and must be freed by caller through dht_value_free().
 */
int
keys_get(const kuid_t *id, dht_value_type_t type,
	kuid_t **secondary, int secondary_count, dht_value_t **valvec, int valcnt,
	float *loadptr, bool *cached)
{
	struct keyinfo *ki;
	struct keydata *kd;
	int i;
	int vcnt = valcnt;
	dht_value_t **vvec = valvec;

	g_assert(secondary_count == 0 || secondary != NULL);
	g_assert(valvec);
	g_assert(valcnt > 0);
	g_assert(loadptr);

	ki = hikset_lookup(keys, id);

	g_assert(ki);	/* If called, we know the key exists */

	if (GNET_PROPERTY(dht_storage_debug) > 5)
		g_debug("DHT FETCH key %s (load = %g, current reqs = %u) type %s"
			" with %d secondary key%s",
			kuid_to_hex_string(id), ki->get_req_load, ki->get_requests,
			dht_value_type_to_string(type),
			secondary_count, plural(secondary_count));

	*loadptr = ki->get_req_load;
	ki->get_requests++;

	kd = get_keydata(id);
	if (kd == NULL)				/* DB failure */
		return 0;

	/*
	 * If secondary keys were requested, lookup them up and make sure
	 * they have the right DHT type (or skip them).
	 */

	for (i = 0; i < secondary_count && vcnt > 0; i++) {
		uint64 dbkey = lookup_secondary(kd, secondary[i]);
		dht_value_t *v;

		if (0 == dbkey)
			continue;

		v = values_get(dbkey, type);
		if (v == NULL)
			continue;

		g_assert(kuid_eq(dht_value_key(v), id));

		if (GNET_PROPERTY(dht_storage_debug) > 5)
			g_debug("DHT FETCH key %s via secondary key %s has matching %s",
				kuid_to_hex_string(id), kuid_to_hex_string2(secondary[i]),
				dht_value_to_string(v));

		*vvec++ = v;
		vcnt--;
	}

	/*
	 * Don't count secondary-key fetches in the local hit stats: in order to
	 * be able to get these fetches, we must have initially provided the
	 * list of these keys, and thus we have already traversed the code below
	 * for that fetch, which accounted the hit already.
	 */

	if (secondary_count) {
		int n = vvec - valvec;		/* Amount of entries filled */

		gnet_stats_count_general(GNR_DHT_CLAIMED_SECONDARY_KEYS, n);
		if (ki->flags & DHT_KEY_F_CACHED)
			gnet_stats_count_general(GNR_DHT_CLAIMED_CACHED_SECONDARY_KEYS, n);

		goto done;
	}

	/*
	 * No secondary keys specified.  Look them all up.
	 */

	for (i = 0; i < kd->values && vcnt > 0; i++) {
		uint64 dbkey = kd->dbkeys[i];
		dht_value_t *v;

		g_assert(0 != dbkey);

		v = values_get(dbkey, type);
		if (v == NULL)
			continue;

		g_assert(kuid_eq(dht_value_key(v), id));

		if (GNET_PROPERTY(dht_storage_debug) > 5)
			g_debug("DHT FETCH key %s has matching %s",
				kuid_to_hex_string(id), dht_value_to_string(v));

		*vvec++ = v;
		vcnt--;
	}

	/*
	 * Stats update: we count all the hits, plus successful hits on keys
	 * that do not fall within our k-ball, i.e. keys for which we act as
	 * a "cache".  Note that our k-ball frontier can evolve through time,
	 * so we rely on the DHT_KEY_F_CACHED flag, positionned at creation time.
	 */

	if (vvec != valvec) {
		gnet_stats_inc_general(GNR_DHT_FETCH_LOCAL_HITS);
		if (ki->flags & DHT_KEY_F_CACHED)
			gnet_stats_inc_general(GNR_DHT_FETCH_LOCAL_CACHED_HITS);
	}

done:

	if (cached)
		*cached = (ki->flags & DHT_KEY_F_CACHED) ? TRUE : FALSE;

	return vvec - valvec;		/* Amount of entries filled */
}