Code Search for Developers
 
 
  

nodes.c from Gtk-Gnutella at Krugle


Show nodes.c syntax highlighted

/*
 * $Id: nodes.c 14737 2007-09-02 00:32:36Z cbiere $
 *
 * Copyright (c) 2001-2004, Raphael Manfredi
 *
 *----------------------------------------------------------------------
 * This file is part of gtk-gnutella.
 *
 *  gtk-gnutella is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  gtk-gnutella is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with gtk-gnutella; if not, write to the Free Software
 *  Foundation, Inc.:
 *      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *----------------------------------------------------------------------
 */

/**
 * @ingroup core
 * @file
 *
 * Gnutella node management.
 *
 * @author Raphael Manfredi
 * @date 2001-2004
 */

#include "common.h"

RCSID("$Id: nodes.c 14737 2007-09-02 00:32:36Z cbiere $")

#include <zlib.h>	/* Z_DEFAULT_COMPRESSION, Z_OK */

#include "sockets.h"
#include "search.h"
#include "share.h"
#include "routing.h"
#include "hosts.h"
#include "nodes.h"
#include "gmsg.h"
#include "mq.h"
#include "mq_tcp.h"
#include "mq_udp.h"
#include "sq.h"
#include "tx.h"
#include "tx_link.h"
#include "tx_deflate.h"
#include "tx_dgram.h"
#include "rxbuf.h"
#include "rx.h"
#include "rx_link.h"
#include "rx_inflate.h"
#include "pmsg.h"
#include "pcache.h"
#include "bsched.h"
#include "http.h"
#include "version.h"
#include "alive.h"
#include "uploads.h"			/* For handle_push_request() */
#include "whitelist.h"
#include "gnet_stats.h"
#include "ban.h"
#include "hcache.h"
#include "qrp.h"
#include "vmsg.h"
#include "token.h"
#include "hostiles.h"
#include "clock.h"
#include "hsep.h"
#include "dq.h"
#include "dh.h"
#include "ioheader.h"
#include "settings.h"
#include "features.h"
#include "udp.h"
#include "tsync.h"
#include "geo_ip.h"
#include "extensions.h"
#include "bh_upload.h"
#include "tls_cache.h"

#include "lib/adns.h"
#include "lib/aging.h"
#include "lib/atoms.h"
#include "lib/cq.h"
#include "lib/dbus_util.h"
#include "lib/file.h"
#include "lib/getdate.h"
#include "lib/hashlist.h"
#include "lib/iovec.h"
#include "lib/endian.h"
#include "lib/getline.h"
#include "lib/glib-missing.h"
#include "lib/header.h"
#include "lib/listener.h"
#include "lib/misc.h"
#include "lib/tm.h"
#include "lib/utf8.h"
#include "lib/walloc.h"
#include "lib/zlib_util.h"

#include "if/gnet_property.h"
#include "if/gnet_property_priv.h"

#include "lib/override.h"		/* Must be the last header included */

#define CONNECT_PONGS_COUNT		10	  /**< Amoung of pongs to send */
#define CONNECT_PONGS_LOW		5	  /**< Amoung of pongs sent if saturated */
#define BYE_MAX_SIZE			4096  /**< Maximum size for the Bye message */
#define NODE_SEND_BUFSIZE		4096  /**< TCP send buffer size - 4K */
#define NODE_SEND_LEAF_BUFSIZE	1024  /**< TCP send buffer size for leaves */
#define MAX_GGEP_PAYLOAD		1536  /**< In ping, pong, push */
#define MAX_HOP_COUNT			255	  /**< Architecturally defined maximum */
#define NODE_LEGACY_DEGREE		8	  /**< Older node without X-Degree */
#define NODE_LEGACY_TTL			7	  /**< Older node without X-Max-TTL */
#define NODE_USELESS_GRACE		20	  /**< No kick if condition too recent */
#define NODE_UP_USELESS_GRACE	600	  /**< No kick if condition too recent */

#define SHUTDOWN_GRACE_DELAY	120	  /**< Grace time for shutdowning nodes */
#define BYE_GRACE_DELAY			30	  /**< Bye sent, give time to propagate */
#define MAX_WEIRD_MSG			5	  /**< End link after so much weirds */
#define MAX_TX_RX_RATIO			85	  /**< Max TX/RX ratio for shortage */
#define MIN_TX_FOR_RATIO		1000  /**< TX packets before enforcing ratio */
#define ALIVE_PERIOD			20	  /**< Seconds between each alive ping */
#define ALIVE_PERIOD_LEAF		120	  /**< Idem, for leaves <-> ultrapeers */
#define ALIVE_MAX_PENDING		6	  /**< Max unanswered pings in a row */
#define ALIVE_MAX_PENDING_LEAF	4 /**< Max unanswered pings in a row (leaves) */

#define NODE_MIN_UP_CONNECTIONS	25	   /**< Min 25 peer connections for UP */
#define NODE_MIN_UPTIME			3600   /**< Minumum uptime to become an UP */
#define NODE_MIN_AVG_UPTIME		10800  /**< Average uptime to become an UP */
#define NODE_AVG_LEAF_MEM		262144 /**< Average memory used by leaf */
#define NODE_CASUAL_FD			10	   /**< # of fds we might use casually */
#define NODE_UPLOAD_QUEUE_FD	5	   /**< # of fds/upload slot we can queue */

#define NODE_TX_BUFSIZ			1024	/**< Buffer size for TX deflation */
#define NODE_TX_FLUSH			16384	/**< Flush deflator every 16K */

#define NODE_AUTO_SWITCH_MIN	1800	/**< Don't switch too often UP - leaf */
#define NODE_AUTO_SWITCH_MAX	61200	/**< Max between switches (17 hours) */
#define NODE_UP_NO_LEAF_MAX		3600	/**< Don't remain UP if no leaves */

#define NODE_TSYNC_WAIT_MS		5000	/**< Wait time after connecting (5s) */
#define NODE_TSYNC_PERIOD_MS	300000	/**< Synchronize every 5 minutes */
#define NODE_TSYNC_CHECK		15		/**< 15 secs before a timeout */

#define TCP_CRAWLER_FREQ		300		/**< once every 5 minutes */
#define UDP_CRAWLER_FREQ		120		/**< once every 2 minutes */

const gchar *start_rfc822_date;			/**< RFC822 format of start_time */

static GSList *sl_nodes;
static GSList *sl_nodes_without_broken_gtkg;
static GHashTable *nodes_by_id;
static GHashTable *nodes_by_guid;
static gnutella_node_t *udp_node;
static gnutella_node_t *udp6_node;
static gnutella_node_t *browse_node;
static gchar *payload_inflate_buffer;
static gint payload_inflate_buffer_len;

/* These two contain connected and connectING(!) nodes. */
static GHashTable *ht_connected_nodes   = NULL;
static guint32     connected_node_count = 0;

#define NO_METADATA		GUINT_TO_POINTER(1)	/**< No metadata for host */

static GHashTable *unstable_servent = NULL;
static GSList *unstable_servents = NULL;

static struct aging *tcp_crawls;
static struct aging *udp_crawls;

typedef struct node_bad_client {
	const char *vendor;
	int	errors;
} node_bad_client_t;

static int node_error_threshold = 6;	/**< This requires an average uptime of
										     1 hour for an ultrapeer */
static time_t node_error_cleanup_timer = 6 * 3600;	/**< 6 hours */

static GSList *sl_proxies;	/* Our push proxies */

static guint32 shutdown_nodes;

static gboolean allow_gnet_connections = FALSE;

GHookList node_added_hook_list;

/**
 * For use by node_added_hook_list hooks, since we can't add a parameter
 * at list invoke time.
 */
struct gnutella_node *node_added;

/**
 * Structure used for asynchronous reaction to peer mode changes.
 */
static struct {
	gboolean changed;
	node_peer_t new;
} peermode = { FALSE, NODE_P_UNKNOWN };

/**
 * Types of bad nodes for node_is_bad().
 */
enum node_bad {
	NODE_BAD_OK = 0,		/**< Node is fine */
	NODE_BAD_IP,			/**< Node has a bad (unstable) IP */
	NODE_BAD_VENDOR,		/**< Node has a bad vendor string */
	NODE_BAD_NO_VENDOR		/**< Node has no vendor string */
};

static guint connected_node_cnt = 0;
static guint compressed_node_cnt = 0;
static guint compressed_leaf_cnt = 0;
static gint pending_byes = 0;			/* Used when shutdowning servent */
static gboolean in_shutdown = FALSE;
static guint32 leaf_to_up_switch = NODE_AUTO_SWITCH_MIN;
static time_t no_leaves_connected = 0;

static const gchar no_reason[] = "<no reason>"; /* Don't translate this */

static query_hashvec_t *query_hashvec;

static void node_disable_read(struct gnutella_node *n);
static gboolean node_data_ind(rxdrv_t *rx, pmsg_t *mb);
static void node_bye_sent(struct gnutella_node *n);
static void call_node_process_handshake_ack(gpointer obj, header_t *header);
static void node_send_qrt(struct gnutella_node *n,
				struct routing_table *query_table);
static void node_send_patch_step(struct gnutella_node *n);
static void node_bye_flags(guint32 mask, gint code, const gchar *message);
static void node_bye_all_but_one(struct gnutella_node *nskip,
				gint code, const gchar *message);
static void node_set_current_peermode(node_peer_t mode);
static enum node_bad node_is_bad(struct gnutella_node *n);
static gnutella_node_t *node_udp_create(enum net_type net);
static gnutella_node_t *node_browse_create(void);
static gboolean node_remove_useless_leaf(gboolean *is_gtkg);
static gboolean node_remove_useless_ultra(gboolean *is_gtkg);

/***
 *** Callbacks
 ***/

static listeners_t node_added_listeners   = NULL;
static listeners_t node_removed_listeners = NULL;
static listeners_t node_info_changed_listeners = NULL;
static listeners_t node_flags_changed_listeners = NULL;

void
node_add_node_added_listener(node_added_listener_t l)
{
    LISTENER_ADD(node_added, l);
}

void
node_remove_node_added_listener(node_added_listener_t l)
{
    LISTENER_REMOVE(node_added, l);
}

void
node_add_node_removed_listener(node_removed_listener_t l)
{
    LISTENER_ADD(node_removed, l);
}

void
node_remove_node_removed_listener(node_removed_listener_t l)
{
    LISTENER_REMOVE(node_removed, l);
}

void
node_add_node_info_changed_listener(node_info_changed_listener_t l)
{
    LISTENER_ADD(node_info_changed, l);
}

void
node_remove_node_info_changed_listener(node_info_changed_listener_t l)
{
    LISTENER_REMOVE(node_info_changed, l);
}

void
node_add_node_flags_changed_listener(node_flags_changed_listener_t l)
{
    LISTENER_ADD(node_flags_changed, l);
}

void
node_remove_node_flags_changed_listener(node_flags_changed_listener_t l)
{
    LISTENER_REMOVE(node_flags_changed, l);
}

static void
node_fire_node_added(gnutella_node_t *n)
{
    n->last_update = tm_time();
    LISTENER_EMIT(node_added, (NODE_ID(n)));
}

static void
node_fire_node_removed(gnutella_node_t *n)
{
    n->last_update = tm_time();
    LISTENER_EMIT(node_removed, (NODE_ID(n)));
}

static void
node_fire_node_info_changed(gnutella_node_t *n)
{
    LISTENER_EMIT(node_info_changed, (NODE_ID(n)));
}

static void
node_fire_node_flags_changed(gnutella_node_t *n)
{
    LISTENER_EMIT(node_flags_changed, (NODE_ID(n)));
}

/***
 *** Utilities
 ***/

/**
 * Free atom string key from hash table.
 */
static void
free_key(gpointer key, gpointer unused_val, gpointer unused_x)
{
	(void) unused_val;
	(void) unused_x;
	atom_str_free(key);
}

/**
 * Free atom string key from hash table and return TRUE.
 */
static gboolean
free_key_true(gpointer key, gpointer unused_val, gpointer unused_x)
{
	(void) unused_val;
	(void) unused_x;
	atom_str_free(key);
	return TRUE;
}

/**
 * Clear hash table whose keys are atoms and values ignored.
 */
static void
string_table_clear(GHashTable *ht)
{
	g_assert(ht != NULL);

	g_hash_table_foreach_remove(ht, free_key_true, NULL);
}

/**
 * Dispose of hash table whose keys are atoms and values ignored.
 */
static void
string_table_free(GHashTable **ht_ptr)
{
	g_assert(ht_ptr);
	if (*ht_ptr) {
		GHashTable *ht = *ht_ptr;

		g_hash_table_foreach(ht, free_key, NULL);
		g_hash_table_destroy(ht);
		*ht_ptr = NULL;
	}
}

/**
 * Sends a PING to the node over UDP (if enabled).
 */
static void
node_send_udp_ping(struct gnutella_node *n)
{
	udp_send_ping(NULL, n->addr, n->port, TRUE);	
}

/***
 *** Time Sync operations.
 ***/

/**
 * Send "Time Sync" via UDP if we know the remote IP:port, via TCP otherwise.
 */
static void
node_tsync_udp(cqueue_t *unused_cq, gpointer obj)
{
	gnutella_node_t *n = obj;
	gnutella_node_t *udp = NULL, *tn;

	(void) unused_cq;
	g_assert(!NODE_IS_UDP(n));
	g_assert(n->attrs & NODE_A_TIME_SYNC);

	n->tsync_ev = NULL;	/* has been freed before calling this function */

	/*
	 * If we did not get replies within the reasonable time period, we
	 * marked the node with NODE_F_TSYNC_TCP to use TCP instead of UDP.
	 */

	if (
		!(n->flags & NODE_F_TSYNC_TCP) &&
		is_host_addr(n->gnet_addr)
	)
		udp = node_udp_get_addr_port(n->gnet_addr, n->gnet_port);

	tn = udp ? udp : n;
	if (!host_is_valid(tn->addr, tn->port))
		return;

	tsync_send(tn, NODE_ID(n));

	/*
	 * Next sync will occur in NODE_TSYNC_PERIOD_MS milliseconds.
	 */

	n->tsync_ev =
		cq_insert(callout_queue, NODE_TSYNC_PERIOD_MS, node_tsync_udp, n);
}

/**
 * Invoked when we determined that the node supports Time Sync.
 */
void
node_can_tsync(gnutella_node_t *n)
{
	g_assert(!NODE_IS_UDP(n));

	if (n->attrs & NODE_A_TIME_SYNC)
		return;

	n->attrs |= NODE_A_TIME_SYNC;

	/*
	 * Schedule a time sync in NODE_TSYNC_WAIT_MS milliseconds.
	 */

	n->tsync_ev =
		cq_insert(callout_queue, NODE_TSYNC_WAIT_MS, node_tsync_udp, n);
}

/**
 * Sent "probe" time sync via TCP to the specified node to compute the RTT...
 */
static void
node_tsync_tcp(gnutella_node_t *n)
{
	g_assert(!NODE_IS_UDP(n));
	g_assert(n->attrs & NODE_A_TIME_SYNC);

	tsync_send(n, NODE_ID(n));
}

/***
 *** Private functions
 ***/

/**
 * Check whether we already have the host.
 */
static gboolean
node_ht_connected_nodes_has(const host_addr_t addr, guint16 port)
{
	gnet_host_t  host;

	gnet_host_set(&host, addr, port);
	return NULL != g_hash_table_lookup(ht_connected_nodes, &host);
}

/**
 * Check whether we already have the host.
 */
static gnet_host_t *
node_ht_connected_nodes_find(const host_addr_t addr, guint16 port)
{
	gnet_host_t  host;
    gboolean     found;
    gpointer	 orig_host, metadata;

	gnet_host_set(&host, addr, port);
	found = g_hash_table_lookup_extended(ht_connected_nodes, &host,
				&orig_host, &metadata);

    return found ? orig_host : NULL;
}

/**
 * Add host to the hash table host cache.
 */
static void
node_ht_connected_nodes_add(const host_addr_t addr, guint16 port)
{
    gnet_host_t *host;

    if (node_ht_connected_nodes_has(addr, port))
        return;

 	host = walloc(sizeof *host);
	gnet_host_set(host, addr, port);
	g_hash_table_insert(ht_connected_nodes, host, NO_METADATA);
	connected_node_count++;
}

/**
 * Remove host from the hash table host cache.
 */
static void
node_ht_connected_nodes_remove(const host_addr_t addr, guint16 port)
{
    gnet_host_t *orig_host;

    orig_host = node_ht_connected_nodes_find(addr, port);

    if (orig_host) {
		g_hash_table_remove(ht_connected_nodes, orig_host);
		g_assert(connected_node_count > 0);
		connected_node_count--;

		wfree(orig_host, sizeof *orig_host);
	}
}

/**
 * Dumps a gnutella message (debug).
 */
static void
message_dump(const struct gnutella_node *n)
{
	printf("Node %s: ", node_addr(n));
	printf("Func 0x%.2x ", gnutella_header_get_function(&n->header));
	printf("TTL = %u ", gnutella_header_get_ttl(&n->header));
	printf("hops = %u ", gnutella_header_get_hops(&n->header));

	printf(" data = %u", (guint) gmsg_size(&n->header));

	switch (gnutella_header_get_function(&n->header)) {
	case GTA_MSG_INIT_RESPONSE:
		{
			guint32 ip, count, total;
			guint16 port;

			port = peek_le16(n->data);
			ip = peek_be32(n->data + 2);
			count = peek_le32(n->data + 6);
			total = peek_le32(n->data + 10);

			printf(" Host = %s Port = %u Count = %u Total = %u",
					ip_to_string(ip), port, count, total);
		}
		break;
	case GTA_MSG_PUSH_REQUEST:
		{
			guint32 ip, idx;
			guint16 port;

			idx = peek_le32(n->data + 16);
			ip = peek_be32(n->data + 20);
			port = peek_le16(n->data + 24);

			printf(" Index = %u Host = %s Port = %u ", idx, ip_to_string(ip),
					port);
		}
		break;
	}

	printf("\n");
}

/**
 * Check whether node is a gtk-gnutella node.
 */
static inline gboolean
node_is_gtkg(const struct gnutella_node *n)
{
	return 0 != (NODE_F_GTKG & n->flags);
}

/**
 * Extract IP/port information out of the Query Hit into `ip' and `port'.
 */
static void
node_extract_host(const struct gnutella_node *n,
	host_addr_t *ha, guint16 *port)
{
	/* Read Query Hit info */

	*ha = host_addr_get_ipv4(gnutella_search_results_get_host_ip(n->data));
	*port = gnutella_search_results_get_host_port(n->data);
}

/**
 * Check the Ultrapeer requirements, returning TRUE if we can become an UP.
 */
static gboolean
can_become_ultra(time_t now)
{
	gboolean avg_servent_uptime;
	gboolean avg_ip_uptime;
	gboolean node_uptime;
	gboolean not_firewalled;
	gboolean good_udp_support;
	gboolean enough_conn;
	gboolean enough_fd;
	gboolean enough_mem;
	gboolean enough_bw;
	const gchar *ok = "** OK **";
	const gchar *no = "-- NO --";

	/* Uptime requirements */
	avg_servent_uptime = get_average_servent_uptime(now) >= NODE_MIN_AVG_UPTIME;
	avg_ip_uptime =
		get_average_ip_lifetime(now, NET_TYPE_IPV4) >= NODE_MIN_AVG_UPTIME ||
		get_average_ip_lifetime(now, NET_TYPE_IPV6) >= NODE_MIN_AVG_UPTIME;
	node_uptime = delta_time(now, GNET_PROPERTY(start_stamp)) > NODE_MIN_UPTIME;

	/* Connectivity requirements */
	not_firewalled = !GNET_PROPERTY(is_firewalled) &&
		!GNET_PROPERTY(is_udp_firewalled);

	/*
	 * Require proper UDP support to be enabled. An efficient UP must be
	 * able to perform OOB-proxying of queries from firewalled leaves, lest
	 * the query hits will have to be routed back on the Gnutella network.
	 *		--RAM, 2006-08-18
	 */

	good_udp_support = 
		GNET_PROPERTY(proxy_oob_queries) &&
		udp_active() && (
		 	host_is_valid(listen_addr(), socket_listen_port()) ||
			host_is_valid(listen_addr6(), socket_listen_port())
		);

	/*
	 * System requirements
	 *
	 * We don't count all the banned fd, since we can now steal the necessary
	 * descriptors out of the banned pool if we run short of fd.  We need to
	 * provision for possible PARQ active queuing, which is why we scale the
	 * `max_uploads' parameter.
	 *
	 * Likewise, we assume that at most 1/4th of the downloads will actually
	 * be active at one time (meaning one fd for the connection and one fd
	 * for the file being written to).  We count "max_uploads" twice because
	 * those have one also two fd (for the connection and the file).
	 */

	enough_fd = (GNET_PROPERTY(max_leaves) + GNET_PROPERTY(max_connections)
			+ GNET_PROPERTY(max_downloads) + (GNET_PROPERTY(max_downloads) / 4)
			+ (GNET_PROPERTY(max_uploads) * (1 + NODE_UPLOAD_QUEUE_FD))
		   	+ GNET_PROPERTY(max_uploads)
			+ (GNET_PROPERTY(max_banned_fd) / 10) + NODE_CASUAL_FD)
					< GNET_PROPERTY(sys_nofile);

	enough_mem = (GNET_PROPERTY(max_leaves) * NODE_AVG_LEAF_MEM +
		(GNET_PROPERTY(max_leaves) + GNET_PROPERTY(max_connections))
			* GNET_PROPERTY(node_sendqueue_size))
		< 1024 / 2 * GNET_PROPERTY(sys_physmem);

	/* Bandwidth requirements */
	enough_bw = bsched_enough_up_bandwidth();

	/* Connection requirements */
	enough_conn = GNET_PROPERTY(up_connections) >= NODE_MIN_UP_CONNECTIONS;

#define OK(b)	((b) ? ok : no)

	if (GNET_PROPERTY(node_debug) > 3) {
		g_message("Checking Ultrapeer criteria:");
		g_message("> Sufficient average uptime   : %s", OK(avg_servent_uptime));
		g_message("> Sufficient IP address uptime: %s", OK(avg_ip_uptime));
		g_message("> Sufficient node uptime      : %s", OK(node_uptime));
		g_message("> Node not firewalled         : %s", OK(not_firewalled));
		g_message("> Enough min peer connections : %s", OK(enough_conn));
		g_message("> Enough file descriptors     : %s", OK(enough_fd));
		g_message("> Enough physical memory      : %s", OK(enough_mem));
		g_message("> Enough available bandwidth  : %s", OK(enough_bw));
		g_message("> Good UDP support            : %s", OK(good_udp_support));
	}

#undef OK

	/*
	 * Let them see the results of our checks in the GUI.
	 */

	gnet_prop_set_boolean_val(PROP_UP_REQ_AVG_SERVENT_UPTIME,
                                                          avg_servent_uptime);
	gnet_prop_set_boolean_val(PROP_UP_REQ_AVG_IP_UPTIME,  avg_ip_uptime);
	gnet_prop_set_boolean_val(PROP_UP_REQ_NODE_UPTIME,    node_uptime);
	gnet_prop_set_boolean_val(PROP_UP_REQ_NOT_FIREWALLED, not_firewalled);
	gnet_prop_set_boolean_val(PROP_UP_REQ_ENOUGH_CONN,    enough_conn);
	gnet_prop_set_boolean_val(PROP_UP_REQ_ENOUGH_FD,      enough_fd);
	gnet_prop_set_boolean_val(PROP_UP_REQ_ENOUGH_MEM,     enough_mem);
	gnet_prop_set_boolean_val(PROP_UP_REQ_ENOUGH_BW,      enough_bw);
	gnet_prop_set_boolean_val(PROP_UP_REQ_GOOD_UDP,       good_udp_support);
	gnet_prop_set_timestamp_val(PROP_NODE_LAST_ULTRA_CHECK, now);

	return avg_servent_uptime && avg_ip_uptime && node_uptime &&
		not_firewalled && enough_fd && enough_mem && enough_bw &&
		good_udp_support &&
		!GNET_PROPERTY(ancient_version);
		/* Old versions don't become ultrapeers */
}

/**
 * Low frequency node timer.
 */
void
node_slow_timer(time_t now)
{
	
	if (udp_active()) {
		static time_t last_ping;

		/**
		 * Periodically emit an UHC ping to a random node to keep the cache
		 * fresh and diverse.
		 */

		if (!last_ping || delta_time(now, last_ping) > 120) {
			host_addr_t addr;
			guint16 port;
			
			last_ping = now;
			if (hcache_get_caught(HOST_ANY, &addr, &port)) {
				udp_send_ping(NULL, addr, port, TRUE);	
			}
		}
	}

	/*
	 * Clear `no_leaves_connected' if we have something connected, or
	 * record the first time at which we came here with no leaf connected.
	 */

	if (GNET_PROPERTY(current_peermode) == NODE_P_ULTRA) {
		if (GNET_PROPERTY(node_leaf_count))
			no_leaves_connected = 0;
		else if (no_leaves_connected == 0)
			no_leaves_connected = now;
	} else
		no_leaves_connected = 0;

	/*
	 * If we're in "auto" mode and we're still running as a leaf node,
	 * evaluate our ability to become an ultra node.
	 *
	 * NB: we test for configured_peermode == NODE_P_ULTRA because we
	 * can switch to leaf even when the user wants to be an ultra node
	 * when we make a very bad ultra peer and it is best for the network
	 * that we be a leaf node.
	 */

	if (
		(GNET_PROPERTY(configured_peermode) == NODE_P_AUTO ||
			GNET_PROPERTY(configured_peermode) == NODE_P_ULTRA) &&
		GNET_PROPERTY(current_peermode) == NODE_P_LEAF &&
		delta_time(now, GNET_PROPERTY(node_last_ultra_leaf_switch)) >
			(time_delta_t) leaf_to_up_switch &&
		can_become_ultra(now)
	) {
		g_warning("being promoted to Ultrapeer status");
		gnet_prop_set_guint32_val(PROP_CURRENT_PEERMODE, NODE_P_ULTRA);
		gnet_prop_set_timestamp_val(PROP_NODE_LAST_ULTRA_LEAF_SWITCH, now);
		return;
	}

	/*
	 * If we're in "auto" mode and we've been promoted to an ultra node,
	 * evaluate how good we are and whether we would not be better off
	 * running as a leaf node.
	 *
	 * We double the time we'll spend as a leaf node before switching
	 * again to UP mode to avoid endless switches between UP and leaf.
	 * We limit that doubling to NODE_AUTO_SWITCH_MAX, to ensure that if
	 * we can become one, then we should do so on a regular basis.
	 */

	if (
		GNET_PROPERTY(configured_peermode) == NODE_P_AUTO &&
		GNET_PROPERTY(current_peermode) == NODE_P_ULTRA &&
		delta_time(now, GNET_PROPERTY(node_last_ultra_leaf_switch))
			> NODE_AUTO_SWITCH_MIN &&
		!can_become_ultra(now)
	) {
		leaf_to_up_switch *= 2;
		leaf_to_up_switch = MIN(leaf_to_up_switch, NODE_AUTO_SWITCH_MAX);
		g_warning("being demoted from Ultrapeer status (for %u secs)",
			leaf_to_up_switch);
		gnet_prop_set_guint32_val(PROP_CURRENT_PEERMODE, NODE_P_LEAF);
		gnet_prop_set_timestamp_val(PROP_NODE_LAST_ULTRA_LEAF_SWITCH, now);
		return;
	}

	/*
	 * If we're running in ultra node and we are TCP-firewalled, then
	 * switch to leaf mode.
	 *
	 * We don't check whether they are firewalled if they asked to run as
	 * an ultranode here -- this will be caught by the check below when
	 * no leaf can connect.
	 */

	if (
		GNET_PROPERTY(configured_peermode) == NODE_P_AUTO &&
		GNET_PROPERTY(current_peermode) == NODE_P_ULTRA &&
		GNET_PROPERTY(is_firewalled)
	) {
		g_warning("firewalled node being demoted from Ultrapeer status");
		gnet_prop_set_guint32_val(PROP_CURRENT_PEERMODE, NODE_P_LEAF);
		gnet_prop_set_timestamp_val(PROP_NODE_LAST_ULTRA_LEAF_SWITCH, now);
		return;
	}

	/*
	 * If we're running as an ultra node (whether automaatically promoted
	 * or configured explicitly to run as such) and we have seen no leaf
	 * node connection for some time, then we're a bad node: we're taking
	 * an ultranode slot in a high outdegree network with a low TTL and
	 * are therefore harming the propagation of queries to leaf nodes,
	 * since we have none.
	 *
	 * Therefore, we'll be better off running as a leaf node.
	 */

	if (
		GNET_PROPERTY(current_peermode) == NODE_P_ULTRA &&
		no_leaves_connected != 0 &&
		delta_time(now, no_leaves_connected) > NODE_UP_NO_LEAF_MAX
	) {
		leaf_to_up_switch *= 2;
		leaf_to_up_switch = MIN(leaf_to_up_switch, NODE_AUTO_SWITCH_MAX);
		g_warning(
			"demoted from Ultrapeer status for %d secs due to missing leaves",
			leaf_to_up_switch);
		gnet_prop_set_guint32_val(PROP_CURRENT_PEERMODE, NODE_P_LEAF);
		gnet_prop_set_timestamp_val(PROP_NODE_LAST_ULTRA_LEAF_SWITCH, now);
		return;
	}
}

static inline void
node_error_cleanup(void)
{
	GSList *sl;
	GSList *to_remove = NULL;

	for (sl = unstable_servents; sl != NULL; sl = g_slist_next(sl)) {
		node_bad_client_t *bad_node = sl->data;

		g_assert(bad_node != NULL);

		if (--bad_node->errors == 0)
			to_remove = g_slist_prepend(to_remove, bad_node);
	}

	for (sl = to_remove; sl != NULL; sl = g_slist_next(sl)) {
		node_bad_client_t *bad_node = sl->data;

		g_assert(bad_node != NULL);
		g_assert(bad_node->vendor != NULL);

		if (GNET_PROPERTY(node_debug) > 1)
			g_warning("[nodes up] Unbanning client: %s", bad_node->vendor);

		g_hash_table_remove(unstable_servent, bad_node->vendor);
		unstable_servents = g_slist_remove(unstable_servents, bad_node);

		atom_str_free_null(&bad_node->vendor);
		wfree(bad_node, sizeof(*bad_node));
	}

	g_slist_free(to_remove);
}

static void
node_tls_refresh(struct gnutella_node *n)
{
	node_check(n);

	if (
		(n->flags & NODE_F_CAN_TLS) &&
		n->gnet_port &&
		is_host_addr(n->gnet_addr)
	) {
		time_t seen;
		
		seen = tls_cache_get_timestamp(n->gnet_addr, n->gnet_port);
		if (!seen || delta_time(tm_time(), seen) > 60) {
			tls_cache_insert(n->gnet_addr, n->gnet_port);
		}
	}
}

void
node_supports_tls(struct gnutella_node *n)
{
	node_check(n);
	
	n->flags |= NODE_F_CAN_TLS;
	node_tls_refresh(n);
}

/**
 * Periodic node heartbeat timer.
 */
void
node_timer(time_t now)
{
	const GSList *sl;

	if ((now % node_error_cleanup_timer) == 0)
		node_error_cleanup();

	/*
	 * Asynchronously react to current peermode change.
	 * See comment in node_set_current_peermode().
	 */

	if (peermode.changed) {
		peermode.changed = FALSE;
		node_set_current_peermode(peermode.new);
	}

	for (sl = sl_nodes; NULL != sl; /* empty */ ) {
		struct gnutella_node *n = sl->data;

		/*
		 * NB:	As the list `sl_nodes' might be modified, the next
		 * 		link has to be before any changes might apply!
		 */
 		sl = g_slist_next(sl);

		node_tls_refresh(n);

		/*
		 * If we're sending a BYE message, check whether the whole TX
		 * stack finally flushed.
		 */

		if (n->flags & NODE_F_BYE_SENT) {
			g_assert(n->outq);
			if (mq_pending(n->outq) == 0)
				node_bye_sent(n);
		}

		/*
		 * No timeout during shutdowns, or when `stop_host_get' is set.
		 */

		if (!(in_shutdown || GNET_PROPERTY(stop_host_get))) {
			if (n->status == GTA_NODE_REMOVING) {
				if (
					delta_time(now, n->last_update) >
						(time_delta_t) GNET_PROPERTY(entry_removal_timeout)
				) {
					node_real_remove(n);
					continue;
				}
			} else if (NODE_IS_CONNECTING(n)) {
				if (
					delta_time(now, n->last_update) >
						(time_delta_t) GNET_PROPERTY(node_connecting_timeout)
				) {
					node_send_udp_ping(n);
					node_remove(n, _("Timeout"));
                    hcache_add(HCACHE_TIMEOUT, n->addr, 0, "timeout");
				}
			} else if (n->status == GTA_NODE_SHUTDOWN) {
				if (delta_time(now, n->shutdown_date) > n->shutdown_delay) {
					gchar reason[1024];

					g_strlcpy(reason, n->error_str, sizeof reason);
					node_remove(n, _("Shutdown (%s)"), reason);
				}
			} else if (
				GNET_PROPERTY(current_peermode) == NODE_P_ULTRA &&
				NODE_IS_ULTRA(n)
			) {
				time_delta_t quiet = delta_time(now, n->last_tx);

				/*
				 * Ultra node connected to another ultra node.
				 *
				 * There is no longer any flow-control or activity
				 * timeout between an ultra node and a leaf, as long
				 * as they reply to eachother alive pings.
				 *		--RAM, 11/12/2003
				 */

				if (
					quiet >
						(time_delta_t) GNET_PROPERTY(node_connected_timeout) &&
					NODE_MQUEUE_COUNT(n)
				) {
                    hcache_add(HCACHE_TIMEOUT, n->addr, 0,
                        "activity timeout");
					node_bye_if_writable(n, 405, "Activity timeout");
				} else if (
					NODE_IN_TX_FLOW_CONTROL(n) &&
					delta_time(now, n->tx_flowc_date) >
						(time_delta_t) GNET_PROPERTY(node_tx_flowc_timeout)
				) {
                    hcache_add(HCACHE_UNSTABLE, n->addr, 0,
                        "flow-controlled too long");
					node_bye(n, 405, "Flow-controlled for too long (%d sec%s)",
						GNET_PROPERTY(node_tx_flowc_timeout),
						GNET_PROPERTY(node_tx_flowc_timeout) == 1 ? "" : "s");
				}
			}
		}

		if (n->searchq != NULL)
			sq_process(n->searchq, now);

		/*
		 * Sanity checks for connected nodes.
		 */

		if (n->status == GTA_NODE_CONNECTED) {
			time_delta_t tx_quiet = delta_time(now, n->last_tx);
			time_delta_t rx_quiet = delta_time(now, n->last_rx);

			if (n->n_weird >= MAX_WEIRD_MSG) {
				g_message("Removing %s <%s> due to security violation",
					node_addr(n), node_vendor(n));
				node_bye_if_writable(n, 412, "Security violation");
				return;
			}

#if 0
			/* FIXME: Disabled because it's nonsense. The ratio sent:received
			 * can be very high due to OOB reply indications for example and
			 * indicates no bad condition for this peer at all.
			 */
			if (
				!NODE_IS_LEAF(n) &&
				n->sent > MIN_TX_FOR_RATIO &&
				(n->received == 0 || n->sent / n->received > MAX_TX_RX_RATIO)
			) {
				node_bye_if_writable(n, 405, "Reception shortage");
				return;
			}
#endif

			/*
			 * If quiet period is nearing timeout and node supports
			 * time-sync, send them one if none is pending.
			 */

			if (
				GNET_PROPERTY(node_connected_timeout) > 2*NODE_TSYNC_CHECK &&
				MAX(tx_quiet, rx_quiet) >
					(time_delta_t) GNET_PROPERTY(node_connected_timeout) -
									NODE_TSYNC_CHECK &&
				(n->attrs & NODE_A_TIME_SYNC) &&
				!(n->flags & NODE_F_TSYNC_WAIT)
			) {
				node_tsync_tcp(n);
				n->flags |= NODE_F_TSYNC_WAIT;
			}

			/*
			 * Only send "alive" pings if we have not received anything
			 * for a while and if some time has elapsed since our last
			 * attempt to send such a ping.
			 *		--RAM, 01/11/2003
			 */

			if (
				NODE_IS_ESTABLISHED(n) &&
				delta_time(now, n->last_rx) > n->alive_period
			) {
				guint32 last;
				guint32 avg;
				time_delta_t period;

				/*
				 * Take the round-trip time of the ping/pongs as a base for
				 * computing the time we should space our pings.  Indeed,
				 * if the round-trip is 90s (taking an extreme example) due
				 * to queuing and TCP/IP clogging and we send pings every 20
				 * seconds, we will have sent 4 before getting a chance to see
				 * any reply back!
				 *		-RAM, 01/11/2003
				 */

				alive_get_roundtrip_ms(n->alive_pings, &avg, &last);
				last = MAX(avg, last) / 1000;	/* Convert ms to seconds */
				period = MAX(n->alive_period, (time_delta_t) last);

				if (
					delta_time(now, n->last_alive_ping) > period &&
					!alive_send_ping(n->alive_pings)
				) {
					node_bye(n, 406, "No reply to alive pings");
					return;
				}
			}

			/*
			 * Check whether we need to send more QRT patch updates.
			 */

			if (n->qrt_update != NULL) {
				g_assert(NODE_IS_CONNECTED(n));
				node_send_patch_step(n);
				if (!NODE_IS_CONNECTED(n))
					return;
			}

			/*
			 * Check RX flow control.
			 */

			if (n->rxfc != NULL) {
				struct node_rxfc_mon *rxfc = n->rxfc;

				if (
					delta_time(now, rxfc->start_half_period)
						> NODE_RX_FC_HALF_PERIOD
				) {
					time_t total;
					gdouble fc_ratio;
					guint32 max_ratio;

					/*
					 * If we're a leaf node, we allow the ultrapeer to flow
					 * control our incoming connection for 95% of the time.
					 * Being flow controlled means we're not getting that much
					 * queries, and we can't send ours, but as long as we have
					 * a non-null window to send our queries, that's fine.
					 */

					max_ratio = GNET_PROPERTY(current_peermode) == NODE_P_LEAF
								? 95
								: GNET_PROPERTY(node_rx_flowc_ratio);

					if (rxfc->fc_start) {		/* In flow control */
						rxfc->fc_accumulator += delta_time(now, rxfc->fc_start);
						rxfc->fc_start = now;
					}

					total = rxfc->fc_accumulator + rxfc->fc_last_half;

					/* New period begins */
					rxfc->fc_last_half = rxfc->fc_accumulator;
					rxfc->fc_accumulator = 0;
					rxfc->start_half_period = now;

					fc_ratio = (gdouble) total / (2.0 * NODE_RX_FC_HALF_PERIOD);
					fc_ratio *= 100.0;

					if ((guint32) fc_ratio > max_ratio) {
						node_bye(n, 405,
							"Remotely flow-controlled too often "
							"(%.2f%% > %d%% of time)", fc_ratio, max_ratio);
						return;
					}

					/* Dispose of monitoring if we're not flow-controlled */
					if (total == 0) {
						wfree(n->rxfc, sizeof(*n->rxfc));
						n->rxfc = NULL;
					}
				}
			}
		}

		/*
		 * Rotate `qrelayed' on a regular basis into `qrelayed_old' and
		 * dispose of previous `qrelayed_old'.
		 */

		if (
			n->qrelayed != NULL &&
			delta_time(now, n->qrelayed_created) >=
				(time_delta_t) GNET_PROPERTY(node_queries_half_life)
		) {
			GHashTable *new;

			if (n->qrelayed_old != NULL) {
				new = n->qrelayed_old;
				string_table_clear(new);
			} else
				new = g_hash_table_new(g_str_hash, g_str_equal);

			n->qrelayed_old = n->qrelayed;
			n->qrelayed = new;
			n->qrelayed_created = now;
		}
	}

	sq_process(sq_global_queue(), now);
}

struct node_id {
	guint64 value;
};

static inline guint64
node_id_value(const node_id_t node_id)
{
	return node_id->value;
}
	
gboolean
node_id_self(const node_id_t node_id)
{
	return 0 == node_id_value(node_id);
}

node_id_t
node_id_get_self(void)
{
	static const struct node_id NODE_SELF_ID;
	return &NODE_SELF_ID;
}

guint
node_id_hash(gconstpointer key)
{
	node_id_t p = key;
	return uint64_hash(p);
}

gboolean
node_id_eq(const node_id_t p, const node_id_t q)
{
	guint64 a = node_id_value(p), b = node_id_value(q);
	return uint64_eq(&a, &b);
}

const gchar *
node_id_to_string(const node_id_t node_id)
{
	static gchar buf[UINT64_DEC_BUFLEN];
	uint64_to_string_buf(node_id_value(node_id), buf, sizeof buf);
	return buf; 
}

node_id_t
node_id_ref(const node_id_t node_id)
{
	return (node_id_t) atom_uint64_get(&node_id->value);
}

void
node_id_unref(const node_id_t node_id)
{
	g_assert(node_id);
	g_assert(node_id != node_id_get_self());
	atom_uint64_free(&node_id->value);
}

static node_id_t
node_id_new(const struct gnutella_node *n)
{
	static struct node_id counter;
	node_id_t node_id;

	node_check(n);
	counter.value++;
	node_id = node_id_ref(&counter);
	gm_hash_table_insert_const(nodes_by_id, node_id, n);
	return node_id;
}

/**
 * Network init.
 */
void
node_init(void)
{
	time_t now = clock_loc2gmt(tm_time());

	rxbuf_init();

	g_assert(23 == sizeof(gnutella_header_t));

	header_features_add(FEATURES_CONNECTIONS, "browse",
		BH_VERSION_MAJOR, BH_VERSION_MINOR);

	g_hook_list_init(&node_added_hook_list, sizeof(GHook));
	node_added_hook_list.seq_id = 1;
	node_added = NULL;

	/* Max: 128 unique words / URNs! */
	query_hashvec = qhvec_alloc(QRP_HVEC_MAX);

	unstable_servent   = g_hash_table_new(NULL, NULL);
    ht_connected_nodes = g_hash_table_new(host_hash, host_eq);
	nodes_by_id        = g_hash_table_new(node_id_hash, node_id_eq_func);
	nodes_by_guid      = g_hash_table_new(guid_hash, guid_eq);

	start_rfc822_date = atom_str_get(timestamp_rfc822_to_string(now));
	gnet_prop_set_timestamp_val(PROP_START_STAMP, now);

	udp_node = node_udp_create(NET_TYPE_IPV4);
	udp6_node = node_udp_create(NET_TYPE_IPV6);
	browse_node = node_browse_create();

	payload_inflate_buffer_len = settings_max_msg_size();
	payload_inflate_buffer = g_malloc(payload_inflate_buffer_len);

	/*
	 * Limit replies to TCP/UDP crawls from a single IP.
	 */

	tcp_crawls = aging_make(TCP_CRAWLER_FREQ,
		host_addr_hash_func, host_addr_eq_func, wfree_host_addr);

	udp_crawls = aging_make(UDP_CRAWLER_FREQ,
		host_addr_hash_func, host_addr_eq_func, wfree_host_addr);

	/*
	 * Signal we support flags in the size header via "sflag/0.1"
	 */

	header_features_add(FEATURES_CONNECTIONS, "sflag", 0, 1);
}

/**
 * Change the socket RX buffer size for all the currently connected nodes.
 */
void
node_set_socket_rx_size(gint rx_size)
{
	GSList *sl;

	g_assert(rx_size > 0);

	for (sl = sl_nodes; sl != NULL; sl = g_slist_next(sl)) {
		struct gnutella_node *n = sl->data;

		if (n->socket) {
			socket_check(n->socket);
			socket_recv_buf(n->socket, rx_size, TRUE);
		}
	}
}

/*
 * Nodes
 */

guint
connected_nodes(void)
{
	return connected_node_cnt;
}

guint
node_count(void)
{
	return connected_node_count - shutdown_nodes -
			GNET_PROPERTY(node_leaf_count);
}

/**
 * Amount of node connections we would like to keep.
 *
 * @return 0 if none.
 */
guint
node_keep_missing(void)
{
	gint missing;

	switch ((node_peer_t) GNET_PROPERTY(current_peermode)) {
	case NODE_P_LEAF:
		missing = GNET_PROPERTY(max_ultrapeers)
					- GNET_PROPERTY(node_ultra_count);
		return MAX(0, missing);
	case NODE_P_NORMAL:
	case NODE_P_ULTRA:
		missing = GNET_PROPERTY(up_connections)
					- (GNET_PROPERTY(node_ultra_count)
							+ GNET_PROPERTY(node_normal_count));
		return MAX(0, missing);
	case NODE_P_AUTO:
	case NODE_P_CRAWLER:
	case NODE_P_UDP:
	case NODE_P_UNKNOWN:
		break;
	}

	g_assert_not_reached();
	return 0;
}

/**
 * Amount of node connections we would like to have.
 *
 * @return 0 if none.
 */
guint
node_missing(void)
{
	gint missing;

	switch ((node_peer_t) GNET_PROPERTY(current_peermode)) {
	case NODE_P_LEAF:
		missing = GNET_PROPERTY(max_ultrapeers)
					- GNET_PROPERTY(node_ultra_count);
		return MAX(0, missing);
	case NODE_P_NORMAL:
	case NODE_P_ULTRA:
		missing = GNET_PROPERTY(max_connections)
					- (GNET_PROPERTY(node_ultra_count)
							+ GNET_PROPERTY(node_normal_count));
		return MAX(0, missing);
	case NODE_P_AUTO:
	case NODE_P_CRAWLER:
	case NODE_P_UDP:
	case NODE_P_UNKNOWN:
		break;
	}

	g_assert_not_reached();
	return 0;
}

/**
 * Amount of leaves we're missing (0 if not in ultra mode).
 */
guint
node_leaves_missing(void)
{
	gint missing;

	if (GNET_PROPERTY(current_peermode) != NODE_P_ULTRA)
		return 0;

	missing = GNET_PROPERTY(max_leaves) - GNET_PROPERTY(node_leaf_count);

	return MAX(0, missing);
}

/**
 * @return this node's outdegree, i.e. the maximum amount of peer connections
 * that we can support.
 */
guint
node_outdegree(void)
{
	switch ((node_peer_t) GNET_PROPERTY(current_peermode)) {
	case NODE_P_LEAF:
		return GNET_PROPERTY(max_ultrapeers);
	case NODE_P_NORMAL:
	case NODE_P_ULTRA:
		return GNET_PROPERTY(max_connections);
	case NODE_P_AUTO:
	case NODE_P_CRAWLER:
	case NODE_P_UDP:
	case NODE_P_UNKNOWN:
		break;
	}

	g_assert_not_reached();
	return 0;
}

/**
 * Parse the first handshake line to determine the protocol version.
 * The major and minor are returned in `major' and `minor' respectively.
 */
static void
get_protocol_version(const gchar *handshake, guint *major, guint *minor)
{
	const gchar *s;

	s = &handshake[GNUTELLA_HELLO_LENGTH];	
	if (0 == parse_major_minor(s, NULL, major, minor))
		return;

	if (GNET_PROPERTY(node_debug))
		g_warning("Unable to parse version number in HELLO, assuming 0.4");
	if (GNET_PROPERTY(node_debug) > 2) {
		guint len = strlen(handshake);
		dump_hex(stderr, "First HELLO Line", handshake, MIN(len, 80));
	}

	*major = 0;
	*minor = 4;
}

/**
 * Decrement the proper node count property, depending on the peermode.
 */
static void
node_type_count_dec(struct gnutella_node *n)
{
	switch (n->peermode) {
	case NODE_P_LEAF:
		g_assert(GNET_PROPERTY(node_leaf_count) > 0);
		gnet_prop_decr_guint32(PROP_NODE_LEAF_COUNT);
		return;
	case NODE_P_NORMAL:
		g_assert(GNET_PROPERTY(node_normal_count) > 0);
		gnet_prop_decr_guint32(PROP_NODE_NORMAL_COUNT);
		return;
	case NODE_P_ULTRA:
		g_assert(GNET_PROPERTY(node_ultra_count) > 0);
		gnet_prop_decr_guint32(PROP_NODE_ULTRA_COUNT);
		return;
	case NODE_P_AUTO:
	case NODE_P_CRAWLER:
	case NODE_P_UDP:
	case NODE_P_UNKNOWN:
		return;
	}
	g_assert_not_reached();
}

static struct gnutella_node *
node_alloc(void)
{
	static const struct gnutella_node zero_node;
	struct gnutella_node *n;

	n = walloc(sizeof *n);
	*n = zero_node;
	n->magic = NODE_MAGIC;
	return n;
}

/**
 * Physically dispose of node.
 */
void
node_real_remove(gnutella_node_t *n)
{
	g_return_if_fail(n);
	node_check(n);

    /*
     * Tell the frontend that the node was removed.
     */
    node_fire_node_removed(n);

	sl_nodes = g_slist_remove(sl_nodes, n);
	sl_nodes_without_broken_gtkg =
		g_slist_remove(sl_nodes_without_broken_gtkg, n);
	g_hash_table_remove(nodes_by_id, NODE_ID(n));

	/*
	 * Now that the node was removed from the list of known nodes, we
	 * can add the host to HL_VALID iff the node was marked NODE_F_VALID,
	 * meaning we identified it as a Gnutella server, even though we
	 * might not have been granted a full connection.
	 *		--RAM, 13/01/2002
	 */

	if (
		!NODE_IS_LEAF(n) &&
		is_host_addr(n->gnet_addr) &&
		(n->flags & NODE_F_VALID)
	)
		hcache_add_valid((n->attrs & NODE_A_ULTRA) ? HOST_ULTRA : HOST_ANY,
            n->gnet_addr, n->gnet_port, "save valid");

	/*
	 * The io_opaque structure is not freed by node_remove(), so that code
	 * can still peruse the headers after node_remove() has been called.
	 */

	if (n->io_opaque)				/* I/O data */
		io_free(n->io_opaque);

	/*
	 * The freeing of the vendor string is delayed, because the GUI update
	 * code reads it.  When this routine is called, the GUI line has been
	 * removed, so it's safe to do it now.
	 */

	atom_str_free_null(&n->vendor);

	/*
	 * The RX stack needs to be dismantled asynchronously, to not be freed
	 * whilst on the "data reception" interrupt path.
	 */

	if (n->rx)
		rx_free(n->rx);

	/*
	 * The TX stack is dismantled asynchronously as well to be on the
	 * safe side.
	 */

	if (n->outq)
		mq_free(n->outq);

	if (n->alive_pings)			/* Must be freed after the TX stack */
		alive_free(n->alive_pings);

	node_id_unref(NODE_ID(n));
	n->id = NULL;

	n->magic = 0;
	wfree(n, sizeof(*n));
}

/**
 * The vectorized (message-wise) version of node_remove().
 */
static G_GNUC_PRINTF(2, 0) void
node_remove_v(struct gnutella_node *n, const gchar *reason, va_list ap)
{
	node_check(n);
	g_assert(n->status != GTA_NODE_REMOVING);
	g_assert(!NODE_IS_UDP(n));

	if (reason && no_reason != reason) {
		gm_vsnprintf(n->error_str, sizeof n->error_str, reason, ap);
		n->remove_msg = n->error_str;
	} else if (n->status != GTA_NODE_SHUTDOWN)	/* Preserve shutdown error */
		n->remove_msg = NULL;

	if (GNET_PROPERTY(node_debug) > 3)
		g_message("Node %s <%s> removed: %s", node_addr(n), node_vendor(n),
			n->remove_msg ? n->remove_msg : "<no reason>");

	if (GNET_PROPERTY(node_debug) > 4) {
		g_message("NODE [%d.%d] %s <%s> TX=%d (drop=%d) RX=%d (drop=%d) "
			"Dup=%d Bad=%d W=%d",
			n->proto_major, n->proto_minor, node_addr(n), node_vendor(n),
			n->sent, n->tx_dropped, n->received, n->rx_dropped,
			n->n_dups, n->n_bad, n->n_weird);
		g_message("NODE \"%s%s\" %s PING (drop=%d acpt=%d spec=%d sent=%d) "
			"PONG (rcvd=%d sent=%d)",
			(n->attrs & NODE_A_PONG_CACHING) ? "new" : "old",
			(n->attrs & NODE_A_PONG_ALIEN) ? "-alien" : "",
			node_addr(n),
			n->n_ping_throttle, n->n_ping_accepted, n->n_ping_special,
			n->n_ping_sent, n->n_pong_received, n->n_pong_sent);
	}

	if (n->routing_data) {
		routing_node_remove(n);
		n->routing_data = NULL;
	}
	if (n->qrt_update) {
		qrt_update_free(n->qrt_update);
		n->qrt_update = NULL;
	}
	if (n->qrt_receive) {
		qrt_receive_free(n->qrt_receive);
		n->qrt_receive = NULL;
	}
	if (n->recv_query_table) {
		qrt_unref(n->recv_query_table);
		n->recv_query_table = NULL;

		/*
		 * I decided to NOT call qrp_leaf_changed() here even if
		 * the node was a leaf node.  Why?  Because that could cause
		 * the regeneration of the last-hop QRP table and all we could
		 * do is clear some slots in the table to get less entries.
		 * Entries that could be filled by the next leaf that will come
		 * to fill the free leaf slot.
		 *
		 * Since having less slots means we'll get less queries, but
		 * having a new table means generating a patch and therefore
		 * consuming network resources, it's not clear what the gain
		 * would be.  Better wait for the new leaf to have sent its
		 * patch to update.
		 *
		 *		--RAM, 2004-08-04
		 */
	}

	if (n->sent_query_table) {
		qrt_unref(n->sent_query_table);
		n->sent_query_table = NULL;
	}
	if (n->qrt_info) {
		WFREE_NULL(n->qrt_info, sizeof(*n->qrt_info));
	}
	if (n->rxfc) {
		WFREE_NULL(n->rxfc, sizeof(*n->rxfc));
	}
	if (n->status == GTA_NODE_CONNECTED) {		/* Already did if shutdown */
		g_assert(connected_node_cnt > 0);
		connected_node_cnt--;
        if (n->attrs & NODE_A_RX_INFLATE) {
			if (n->flags & NODE_F_LEAF) {
				g_assert(compressed_leaf_cnt > 0);
				compressed_leaf_cnt--;
			}
            g_assert(compressed_node_cnt > 0);
            compressed_node_cnt--;
        }
		node_type_count_dec(n);
	}

	if (n->status == GTA_NODE_SHUTDOWN) {
		shutdown_nodes--;
	}
	if (n->hello.ptr) {
		WFREE_NULL(n->hello.ptr, n->hello.size);
	}

	/* n->io_opaque will be freed by node_real_remove() */
	/* n->vendor will be freed by node_real_remove() */

	if (n->allocated) {
		G_FREE_NULL(n->data);
		n->allocated = 0;
	}
	if (n->searchq) {
		sq_free(n->searchq);
		n->searchq = NULL;
	}
	if (n->rx)					/* RX stack freed by node_real_remove() */
		node_disable_read(n);
	if (n->outq)				/* TX stack freed by node_real_remove() */
		mq_shutdown(n->outq);	/* Prevents any further output */

	if (n->socket) {
		socket_check(n->socket);
		g_assert(n->socket->resource.node == n);
		socket_free_null(&n->socket);
	}

	cq_cancel(callout_queue, &n->tsync_ev);

	n->status = GTA_NODE_REMOVING;
	n->flags &= ~(NODE_F_WRITABLE|NODE_F_READABLE|NODE_F_BYE_SENT);
	n->last_update = tm_time();

    node_ht_connected_nodes_remove(n->gnet_addr, n->gnet_port);
	node_proxying_remove(n);

	if (n->flags & NODE_F_EOF_WAIT) {
		g_assert(pending_byes > 0);
		pending_byes--;
	}

	if (is_host_addr(n->proxy_addr)) {
		sl_proxies = g_slist_remove(sl_proxies, n);
	}
	string_table_free(&n->qseen);
	string_table_free(&n->qrelayed);
	string_table_free(&n->qrelayed_old);
	if (n->guid) {
		g_hash_table_remove(nodes_by_guid, n->guid);
		atom_guid_free_null(&n->guid);
	}

	if (!in_shutdown) {
		if (n->attrs & NODE_A_CAN_HSEP) {
			hsep_connection_close(n);
		}
		if (NODE_IS_LEAF(n)) {
			/* Purge dynamic queries for that node */
			dq_node_removed(NODE_ID(n));
		}
		node_fire_node_info_changed(n);
		node_fire_node_flags_changed(n);
	}
}

/**
 * Called when node_bye() or node_shutdown() is called during the time we're
 * in shutdown mode, processing the messages we might still read from the
 * socket.
 */
static void
node_recursive_shutdown_v(
	struct gnutella_node *n,
	const gchar *where, const gchar *reason, va_list ap)
{
	gchar *fmt, *p;

	g_assert(n->status == GTA_NODE_SHUTDOWN);
	g_assert(n->error_str);
	g_assert(reason);

	/* XXX: Could n->error_str contain a format string? Rather make sure
	 *		there isn't any. */
	for (p = n->error_str; *p != '\0'; p++)
		if (*p == '%')
			*p = 'X';

	fmt = g_strdup_printf("%s (%s) [within %s]", where, reason, n->error_str);
	node_remove_v(n, fmt, ap);
	G_FREE_NULL(fmt);
}

/**
 * Removes or shuts down the given node.
 */
void
node_remove_by_id(const node_id_t node_id)
{
    gnutella_node_t *node;

	node = node_by_id(node_id);
	if (node) {
		if (node == udp_node || node == udp6_node) {
			/* Ignore */
		} else if (NODE_IS_WRITABLE(node)) {
			node_bye(node, 201, "User manual removal");
		} else {
			node_remove(node, no_reason);
			node_real_remove(node);
		}
	}
}

/**
 * Check whether node has been identified as having a bad IP or vendor string.
 *
 * @return NODE_BAD_OK if node is OK, the reason why the node is bad otherwise.
 *
 * @note when we're low on pongs, we never refuse a connection, so this
 * routine always returns NODE_BAD_OK.
 */
static enum node_bad
node_is_bad(struct gnutella_node *n)
{
	node_bad_client_t *bad_client = NULL;

	node_check(n);

	if (!GNET_PROPERTY(node_monitor_unstable_ip))
		return NODE_BAD_OK;		/* User disabled monitoring of unstable IPs */

	if (host_low_on_pongs)
		return NODE_BAD_OK;		/* Can't refuse connection */

	if (n->vendor == NULL) {
		if (GNET_PROPERTY(node_debug))
			g_warning("no vendor name in %s node headers from %s",
				NODE_IS_LEAF(n) ? "leaf" :
				NODE_IS_ULTRA(n) ? "ultra" : "legacy",
				node_addr(n));
		return NODE_BAD_NO_VENDOR;
	}

	g_assert(n->vendor != NULL);
	g_assert(is_host_addr(n->addr));

    if (hcache_node_is_bad(n->addr)) {
		if (GNET_PROPERTY(node_debug))
			g_warning("[nodes up] Unstable peer %s (%s)",
				host_addr_to_string(n->addr),
				n->vendor);
		return NODE_BAD_IP;
    }

	if (!GNET_PROPERTY(node_monitor_unstable_servents))
		return NODE_BAD_OK;	/* No monitoring of unstable servents */

	bad_client = g_hash_table_lookup(unstable_servent, n->vendor);

	if (bad_client == NULL)
		return NODE_BAD_OK;

	if (bad_client->errors > node_error_threshold) {
		if (GNET_PROPERTY(node_debug))
			g_warning("[nodes up] Banned client: %s", n->vendor);
		return NODE_BAD_VENDOR;
	}

	return NODE_BAD_OK;
}

/**
 * Gives a specific vendor a bad mark. If a vendor + version gets to many
 * marks, we won't try to connect to it anymore.
 */
void
node_mark_bad_vendor(struct gnutella_node *n)
{
	struct node_bad_client *bad_client = NULL;
	time_t now;

	if (in_shutdown)
		return;

	/*
	 * If the user doesn't want us to protect against unstable IPs, then we
	 * can stop right now. Protecting against unstable servent name will
	 * also be ignored, to prevent marking a servent as unstable while we
	 * are actually connecting to the same IP over and over again
	 */

	if (!GNET_PROPERTY(node_monitor_unstable_ip))
		return;

	node_check(n);
	g_assert(NET_TYPE_LOCAL == host_addr_net(n->addr) || is_host_addr(n->addr));

	/*
	 * Only mark Ultrapeers as bad nodes. Leaves aren't expected to have
	 * high uptimes
	 */

	if (!(n->attrs & NODE_A_ULTRA))
		return;

	/*
	 * Do not mark nodes as bad with which we did not connect at all, we
	 * don't know it's behaviour in this case.
	 */

	if (n->connect_date == 0)
		return;

	now = tm_time();

	/* Don't mark a node with whom we could stay a long time as being bad */
	if (
		delta_time(now, n->connect_date) >
			node_error_cleanup_timer / node_error_threshold
	) {
		if (GNET_PROPERTY(node_debug) > 1)
			g_message("[nodes up] "
				  "%s not marking as bad. Connected for: %d (min: %d)",
				host_addr_to_string(n->addr),
				(gint) delta_time(now, n->connect_date),
				(gint) (node_error_cleanup_timer / node_error_threshold));
		return;
	}

    hcache_add(HCACHE_UNSTABLE, n->addr, 0, "vendor banned");

	if (!GNET_PROPERTY(node_monitor_unstable_servents))
		return;	/* The user doesn't want us to monitor unstable servents. */

	if (n->vendor == NULL)
		return;

	g_assert(n->vendor != NULL);

	bad_client = g_hash_table_lookup(unstable_servent, n->vendor);
	if (bad_client == NULL) {
		bad_client = walloc0(sizeof(*bad_client));
		bad_client->errors = 0;
		bad_client->vendor = atom_str_get(n->vendor);
		gm_hash_table_insert_const(unstable_servent,
			bad_client->vendor, bad_client);
		unstable_servents = g_slist_prepend(unstable_servents, bad_client);
	}

	g_assert(bad_client != NULL);

	bad_client->errors++;

	if (GNET_PROPERTY(node_debug))
		g_warning("[nodes up] Increased error counter (%d) for client: %s",
			bad_client->errors,
			n->vendor);
}

/**
 * Make sure that the vendor of the connecting node does not already use
 * more than "unique_nodes" percent of the slots of its kind.
 *
 * @return TRUE if accepting the node would make us use more slots than
 * what the user has configured as acceptable.
 *
 * @note when low on pongs, monopoly protection is disabled to avoid the
 * host contacting the web caches just because it cannot fulfill its
 * anti-monopoly requirements.
 */
static gboolean
node_avoid_monopoly(struct gnutella_node *n)
{
	guint up_cnt = 0;
	guint leaf_cnt = 0;
	guint normal_cnt = 0;
	GSList *sl;

	g_assert(UNSIGNED(GNET_PROPERTY(unique_nodes) <= 100));

	if (host_low_on_pongs)
		return FALSE;

	if (
		!n->vendor ||
		(n->flags & NODE_F_CRAWLER) ||
		GNET_PROPERTY(unique_nodes) == 100
	)
		return FALSE;

	for (sl = sl_nodes; sl; sl = g_slist_next(sl)) {
		struct gnutella_node *node = sl->data;

		if (node->status != GTA_NODE_CONNECTED || node->vendor == NULL)
			continue;

		/*
		 * Node vendor strings are compared up to the specified delimitor,
		 * i.e. we don't want to take the version number into account.
		 *
		 * The vendor name and the version are normally separated with a "/"
		 * but some people wrongly use " " as the separator.
		 */

		if (ascii_strcasecmp_delimit(n->vendor, node->vendor, "/ 012345678"))
			continue;

		if ((node->attrs & NODE_A_ULTRA) || (node->flags & NODE_F_ULTRA))
			up_cnt++;
		else if (node->flags & NODE_F_LEAF)
			leaf_cnt++;
		else
			normal_cnt++;
	}

	/* Include current node into counter as well */
	if ((n->attrs & NODE_A_ULTRA) || (n->flags & NODE_F_ULTRA))
		up_cnt++;
	else if (n->flags & NODE_F_LEAF)
		leaf_cnt++;
	else
		normal_cnt++;

	switch ((node_peer_t) GNET_PROPERTY(current_peermode)) {
	case NODE_P_ULTRA:
		if ((n->attrs & NODE_A_ULTRA) || (n->flags & NODE_F_ULTRA)) {
			gint max;

			max = GNET_PROPERTY(max_connections)
					- GNET_PROPERTY(normal_connections);
			if (max > 1 && up_cnt * 100 > max * GNET_PROPERTY(unique_nodes))
				return TRUE;	/* Disallow */
		} else if (n->flags & NODE_F_LEAF) {
			if (
				GNET_PROPERTY(max_leaves) > 1 &&
				leaf_cnt * 100 > GNET_PROPERTY(max_leaves)
									* GNET_PROPERTY(unique_nodes)
			)
				return TRUE;
		} else {
			if (
				GNET_PROPERTY(normal_connections) > 1 &&
				normal_cnt * 100 > GNET_PROPERTY(normal_connections)
									* GNET_PROPERTY(unique_nodes)
			)
				return TRUE;
		}
		return FALSE;
	case NODE_P_LEAF:
		if (
			GNET_PROPERTY(max_ultrapeers) > 1 &&
			up_cnt * 100 > GNET_PROPERTY(max_ultrapeers)
							* GNET_PROPERTY(unique_nodes)
		)
			return TRUE;	/* Dissallow */
		return FALSE;
	case NODE_P_NORMAL:
		if (
			GNET_PROPERTY(max_connections) > 1 &&
			normal_cnt * 100 > GNET_PROPERTY(max_connections)
								* GNET_PROPERTY(unique_nodes)
		)
			return TRUE;
		return FALSE;
	case NODE_P_AUTO:
		return FALSE;
	case NODE_P_CRAWLER:
	case NODE_P_UDP:
	case NODE_P_UNKNOWN:
		g_assert_not_reached();
		break;
	}

	g_assert_not_reached();
	return FALSE;
}

/**
 * When we only have "reserve_gtkg_nodes" percent slots left, make sure the
 * connecting node is a GTKG node or refuse the connection.
 *
 * @return TRUE if we should reserve the slot for GTKG, i.e. refuse `n'.
 */
static gboolean
node_reserve_slot(struct gnutella_node *n)
{
	guint up_cnt = 0;		/* GTKG UPs */
	guint leaf_cnt = 0;		/* GTKG leafs */
	guint normal_cnt = 0;	/* GTKG normal nodes */
	GSList *sl;

	g_assert(UNSIGNED(GNET_PROPERTY(reserve_gtkg_nodes)) <= 100);

	if (node_is_gtkg(n))
		return FALSE;

	if (
		!n->vendor ||
		(n->flags & NODE_F_CRAWLER) ||
		!GNET_PROPERTY(reserve_gtkg_nodes)
	)
		return FALSE;

	for (sl = sl_nodes; sl; sl = sl->next) {
		struct gnutella_node *node = sl->data;

		if (node->status != GTA_NODE_CONNECTED || node->vendor == NULL)
			continue;

		if (!node_is_gtkg(node))
			continue;

		/*
		 * Count GTKG nodes we are already connected to, by type
		 */

		if ((node->attrs & NODE_A_ULTRA) || (node->attrs & NODE_F_ULTRA))
			up_cnt++;
		else if (node->flags & NODE_F_LEAF)
			leaf_cnt++;
		else
			normal_cnt++;
	}

	/*
	 * For a given max population `max', already filled by `x' nodes out
	 * of which `y' are GTKG ones, we want to make sure that we can have
	 * "reserve_gtkg_nodes" percent of the slots (i.e. `g' percent) used
	 * by GTKG.
	 *
	 * In other words, we want to ensure that we can have "g*max/100" slots
	 * used by GTKG.  We have already `x' slots used, that leaves "max - x"
	 * ones free.  To be able to have our quota of GTKG slots, we need to
	 * reserve slots to GTKG when "max - x" <= "g*max/100 - y".  I.e.
	 * when `x' >= max - g*max/100 + y.
	 */

	switch ((node_peer_t) GNET_PROPERTY(current_peermode)) {
	case NODE_P_ULTRA:
		if ((n->attrs & NODE_A_ULTRA) || (n->flags & NODE_F_ULTRA)) {
			gint max, gtkg_min;

			/*
			 * If we would reserve a slot to GTKG but we can get rid of
			 * a useless ultra, then do so before checking.  If we don't
			 * remove a useless GTKG node, then this will make room for
			 * the current connection.
			 */

			max = GNET_PROPERTY(max_connections)
					- GNET_PROPERTY(normal_connections);
			gtkg_min = GNET_PROPERTY(reserve_gtkg_nodes) * max / 100;

			if (GNET_PROPERTY(node_ultra_count) >= max + up_cnt - gtkg_min) {
				gboolean is_gtkg;

				if (node_remove_useless_ultra(&is_gtkg) && is_gtkg)
					up_cnt--;
			}

			if (GNET_PROPERTY(node_ultra_count) >= max + up_cnt - gtkg_min)
				return TRUE;
		} else if (n->flags & NODE_F_LEAF) {
			gint gtkg_min;

			/*
			 * If we would reserve a slot to GTKG but we can get rid of
			 * a useless leaf, then do so before checking.  If we don't
			 * remove a useless GTKG node, then this will make room for
			 * the current connection.
			 */

			gtkg_min = GNET_PROPERTY(reserve_gtkg_nodes)
							* GNET_PROPERTY(max_leaves) / 100;
			if (
				GNET_PROPERTY(node_leaf_count)
					>= GNET_PROPERTY(max_leaves) + leaf_cnt - gtkg_min
			) {
				gboolean is_gtkg;
				if (node_remove_useless_leaf(&is_gtkg) && is_gtkg)
					leaf_cnt--;
			}

			if (
				GNET_PROPERTY(node_leaf_count)
					>= GNET_PROPERTY(max_leaves) + leaf_cnt - gtkg_min
			)
				return TRUE;

		} else {
			gint gtkg_min;

			gtkg_min = GNET_PROPERTY(reserve_gtkg_nodes)
							* GNET_PROPERTY(normal_connections) / 100;
			if (
				GNET_PROPERTY(node_normal_count) >=
					GNET_PROPERTY(normal_connections) + normal_cnt - gtkg_min
			)
				return TRUE;
		}
		return FALSE;
	case NODE_P_LEAF:
		if (GNET_PROPERTY(max_ultrapeers) > 0 ) {
			gint gtkg_min;
			gtkg_min = GNET_PROPERTY(reserve_gtkg_nodes)
						* GNET_PROPERTY(max_ultrapeers) / 100;
			if (GNET_PROPERTY(node_ultra_count)
					>= GNET_PROPERTY(max_ultrapeers) + up_cnt - gtkg_min)
				return TRUE;
		}
		return FALSE;
	case NODE_P_NORMAL:
		if (GNET_PROPERTY(max_connections) > 0) {
			gint gtkg_min;

			gtkg_min = GNET_PROPERTY(reserve_gtkg_nodes)
						* GNET_PROPERTY(max_connections) / 100;
			if (
				GNET_PROPERTY(node_normal_count) >=
					GNET_PROPERTY(max_connections) + normal_cnt - gtkg_min
			)
				return TRUE;
		}
		return FALSE;
	case NODE_P_AUTO:
		return FALSE;
	case NODE_P_CRAWLER:
	case NODE_P_UDP:
	case NODE_P_UNKNOWN:
		g_assert_not_reached();
		break;
	}

	g_assert_not_reached();
	return FALSE;
}

/**
 * Terminate connection with remote node, but keep structure around for a
 * while, for displaying purposes, and also to prevent the node from being
 * physically reclaimed within this stack frame.
 *
 * It will be reclaimed on the "idle" stack frame, via node_real_remove().
 */
void
node_remove(struct gnutella_node *n, const gchar *reason, ...)
{
	va_list args;

	node_check(n);

	if (n->status == GTA_NODE_REMOVING)
		return;

	va_start(args, reason);
	node_remove_v(n, reason, args);
	va_end(args);
}

/**
 * Determine if the node with specified IP and port is connected.  If
 * so, schedule it to be removed.
 *
 * @param addr The address of the node.
 * @param port A port number of zero means to match all connections to the
 * 			   host. Often the port is redundant [from a user perspective] as
 *			   it is not often that two nodes will be at the same IP and
 *			   connected to us.
 * @return The number of nodes that have been removed.
 */
guint
node_remove_by_addr(const host_addr_t addr, guint16 port)
{
	const GSList *sl;
	guint n_removed = 0;

	for (sl = sl_nodes; sl; sl = g_slist_next(sl)) {
		const struct gnutella_node *n = sl->data;

		if ((!port || n->port == port) && host_addr_equal(n->addr, addr)) {
			node_remove_by_id(NODE_ID(n));
			n_removed++;
			if (port)
				break;
        }
    }
	return n_removed;
}

/**
 * The vectorized version of node_eof().
 */
static void
node_eof_v(struct gnutella_node *n, const gchar *reason, va_list args)
{
	const gchar *format;

	node_check(n);

	/*
	 * If the Gnutella connection was established, we should have got a BYE
	 * to cleanly shutdown.
	 */

	if (n->flags & NODE_F_ESTABLISHED)
		node_mark_bad_vendor(n);

	if (n->flags & NODE_F_BYE_SENT) {
		g_assert(n->status == GTA_NODE_SHUTDOWN);
		if (GNET_PROPERTY(node_debug) > 4) {
			va_list dbargs;

			printf("EOF-style error during BYE to %s:\n (BYE) ", node_addr(n));

			VA_COPY(dbargs, args);
			vprintf(reason, dbargs);
			va_end(dbargs);

			printf("\n");
		}
	}

	/*
	 * Call node_remove_v() with supplied message unless we already sent a BYE
 	 * message, in which case we're done since the remote end most probably
	 * read it and closed the connection.
     */

	socket_eof(n->socket);

	if (n->flags & NODE_F_CLOSING)		/* Bye sent or explicit shutdown */
		format = NULL;					/* Reuse existing reason */
	else
		format = reason;

	node_remove_v(n, format, args);
}

/**
 * Got an EOF condition, or a read error, whilst reading Gnet data from node.
 *
 * Terminate connection with remote node, but keep structure around for a
 * while, for displaying purposes.
 */
void
node_eof(struct gnutella_node *n, const gchar *reason, ...)
{
	va_list args;

	node_check(n);

	va_start(args, reason);
	node_eof_v(n, reason, args);
	va_end(args);
}

/**
 * Enter shutdown mode: prevent further writes, drop read broadcasted messages,
 * and make sure we flush the buffers at the fastest possible speed.
 */
static void
node_shutdown_mode(struct gnutella_node *n, guint32 delay)
{

	/*
	 * If node is already in shutdown node, simply update the delay.
	 */

	n->shutdown_delay = delay;

	if (n->status == GTA_NODE_SHUTDOWN)
		return;

	if (n->status == GTA_NODE_CONNECTED) {	/* Free Gnet slot */
		connected_node_cnt--;
		g_assert(connected_node_cnt <= INT_MAX);
        if (n->attrs & NODE_A_RX_INFLATE) {
			if (n->flags & NODE_F_LEAF)
				compressed_leaf_cnt--;
            compressed_node_cnt--;
            g_assert(compressed_node_cnt <= INT_MAX);
			g_assert(compressed_leaf_cnt <= INT_MAX);
        }
		node_type_count_dec(n);
 	}

	n->status = GTA_NODE_SHUTDOWN;
	n->flags &= ~(NODE_F_WRITABLE|NODE_F_READABLE);
	n->shutdown_date = tm_time();
	mq_discard(n->outq);					/* Discard any further data */
	node_flushq(n);							/* Fast queue flushing */

	shutdown_nodes++;

    node_fire_node_info_changed(n);
    node_fire_node_flags_changed(n);
}

/**
 * The vectorized version of node_shutdown().
 */
static void
node_shutdown_v(struct gnutella_node *n, const gchar *reason, va_list args)
{
	node_check(n);

	if (n->status == GTA_NODE_SHUTDOWN) {
		node_recursive_shutdown_v(n, "Shutdown", reason, args);
		return;
	}

	n->flags |= NODE_F_CLOSING;

	if (reason) {
		gm_vsnprintf(n->error_str, sizeof n->error_str, reason, args);
		n->remove_msg = n->error_str;
	} else {
		n->remove_msg = "Unknown reason";
		n->error_str[0] = '\0';
	}

	node_shutdown_mode(n, SHUTDOWN_GRACE_DELAY);
}

/**
 * Stop sending data to node, but keep reading buffered data from it, until
 * we hit a Bye packet or EOF.  In that mode, we don't relay Queries we may
 * read, but replies and pushes are still routed back to other nodes.
 *
 * This is mostly called when a fatal write error happens, but we want to
 * see whether the node did not send us a Bye we haven't read yet.
 */
void
node_shutdown(struct gnutella_node *n, const gchar *reason, ...)
{
	va_list args;

	va_start(args, reason);
	node_shutdown_v(n, reason, args);
	va_end(args);
}

/**
 * The vectorized version of node_bye().
 */
static void
node_bye_v(struct gnutella_node *n, gint code, const gchar *reason, va_list ap)
{
	gnutella_header_t head;
	gchar reason_fmt[1024];
	size_t len;
	gint sendbuf_len;
	gchar *reason_base = &reason_fmt[2];	/* Leading 2 bytes for code */

	node_check(n);
	g_assert(!NODE_IS_UDP(n));

	if (n->status == GTA_NODE_SHUTDOWN) {
		node_recursive_shutdown_v(n, "Bye", reason, ap);
		return;
	}

	n->flags |= NODE_F_CLOSING;

	if (reason) {
		gm_vsnprintf(n->error_str, sizeof n->error_str, reason, ap);
		n->remove_msg = n->error_str;
	} else {
		n->remove_msg = NULL;
		n->error_str[0] = '\0';
	}

	/*
	 * Discard all the queued entries, we're not going to send them.
	 * The only message that may remain is the oldest partially sent.
	 */

	if (n->searchq)
		sq_clear(n->searchq);

	mq_clear(n->outq);

	/*
	 * Build the bye message.
	 */

	len = gm_snprintf(reason_base, sizeof reason_fmt - 3,
		"%s", n->error_str);

	/* XXX Add X-Try and X-Try-Ultrapeers */

	if (code != 200) {
		len += gm_snprintf(reason_base + len, sizeof reason_fmt - len - 3,
			"\r\n"
			"Server: %s\r\n"
			"\r\n",
			version_string);
	}

	g_assert(len <= sizeof reason_fmt - 3);

	reason_base[len] = '\0';
	len += 2 + 1;		/* 2 for the leading code, 1 for the trailing NUL */

	gnutella_bye_set_code(reason_fmt, code);

	message_set_muid(&head, GTA_MSG_BYE);
	gnutella_header_set_function(&head, GTA_MSG_BYE);
	gnutella_header_set_ttl(&head, 1);
	gnutella_header_set_hops(&head, 0);
	gnutella_header_set_size(&head, len);

	/*
	 * Send the bye message, enlarging the TCP input buffer to make sure
	 * we can atomically send the message plus the remaining queued data.
	 */

	sendbuf_len = NODE_SEND_BUFSIZE + mq_size(n->outq) +
		len + sizeof(head) + 1024;		/* Slightly larger, for flow-control */

	socket_send_buf(n->socket, sendbuf_len, FALSE);
	gmsg_split_sendto_one(n, &head, reason_fmt, len + sizeof(head));

	/*
	 * Whether we sent the message or not, enter shutdown mode.
	 *
	 * We'll stay in the shutdown mode for some time, then we'll kick the node
	 * out.  But not doing it immediately gives a chance for the message to
	 * proagate AND be read by the remote node.
	 *
	 * When sending is delayed, we will periodically check for the
	 * NODE_F_BYE_SENT condition and change the shutdown delay to a much
	 * shorter period when the TX queue is emptied.
	 *
	 * In shutdown mode, we'll also preserve the existing error message for
	 * node_remove().
	 *
	 * NB: To know whether we sent it or not, we need to probe the size
	 * of the TX stack, since there is a possible compression stage that
	 * can delay sending data for a little while.  That's why we
	 * use mq_pending() and not mq_size().
	 */

	if (mq_pending(n->outq) == 0) {
		if (GNET_PROPERTY(node_debug))
			g_message("successfully sent BYE %d \"%s\" to %s (%s)",
				code, n->error_str, node_addr(n), node_vendor(n));

			socket_tx_shutdown(n->socket);
			node_shutdown_mode(n, BYE_GRACE_DELAY);
	} else {
		if (GNET_PROPERTY(node_debug))
			g_message("delayed sending of BYE %d \"%s\" to %s (%s)",
				code, n->error_str, node_addr(n), node_vendor(n));

		n->flags |= NODE_F_BYE_SENT;

		node_shutdown_mode(n, SHUTDOWN_GRACE_DELAY);
	}
}

/**
 * Terminate connection by sending a bye message to the remote node.  Upon
 * reception of that message, the connection will be closed by the remote
 * party.
 *
 * This is otherwise equivalent to the node_shutdown() call.
 */
void
node_bye(gnutella_node_t *n, gint code, const gchar * reason, ...)
{
	va_list args;

	va_start(args, reason);
	node_bye_v(n, code, reason, args);
	va_end(args);

}

/**
 * If node is writable, act as if node_bye() had been called.
 * Otherwise, act as if node_remove() had been called.
 */
void
node_bye_if_writable(
	struct gnutella_node *n, gint code, const gchar *reason, ...)
{
	va_list args;

	va_start(args, reason);

	if (NODE_IS_WRITABLE(n))
		node_bye_v(n, code, reason, args);
	else
		node_remove_v(n, reason, args);
}

/**
 * Is there a node connected with this IP/port?
 *
 * The port is tested only when `incoming' is FALSE, i.e. we allow
 * only one incoming connection per IP, even when there are several
 * instances, all on different ports.
 */
gboolean
node_is_connected(const host_addr_t addr, guint16 port, gboolean incoming)
{
	if (is_my_address_and_port(addr, port)) {
		return TRUE;
	}

    /*
     * If incoming is TRUE we have to do an exhaustive search because
     * we have to ignore the port. Otherwise we can use the fast
     * hashtable lookup.
     *     -- Richard, 29/04/2004
     */
    if (incoming) {
		const GSList *sl;

        for (sl = sl_nodes; sl; sl = g_slist_next(sl)) {
            const struct gnutella_node *n = sl->data;

            if (
				n->status != GTA_NODE_REMOVING &&
				n->status != GTA_NODE_SHUTDOWN &&
				n->port == port &&
				host_addr_equal(n->addr, addr)
			) {
				return TRUE;
            }
        }
        return FALSE;
    } else {
        return node_ht_connected_nodes_has(addr, port);
    }
}

/**
 * Are we directly connected to that host?
 */
gboolean
node_host_is_connected(const host_addr_t addr, guint16 port)
{
	/* Check our local address */

	return is_my_address(addr) ||
			node_ht_connected_nodes_has(addr, port);
}

/**
 * Build CONNECT_PONGS_COUNT pongs to emit as an X-Try header.
 * We stick to strict formatting rules: no line of more than 76 chars.
 *
 * @return a pointer to static data.
 *
 * @bug
 * XXX Refactoring note: there is a need for generic header formatting
 * routines, and especially the dumping routing, which could be taught
 * basic formatting and splitting so that very long lines are dumped using
 * continuations. --RAM, 10/01/2002
 */
static const gchar *
formatted_connection_pongs(const gchar *field, host_type_t htype, gint num)
{
	struct gnutella_host hosts[CONNECT_PONGS_COUNT];
	const gchar *line = "";
	gint hcount;

	g_assert(num > 0 && num <= CONNECT_PONGS_COUNT);

	hcount = hcache_fill_caught_array(htype, hosts, num);
	g_assert(hcount >= 0 && hcount <= num);

	/* The most a pong can take is "xxx.xxx.xxx.xxx:yyyyy, ", i.e. 23 */
	if (hcount) {
		gint i;
		gpointer fmt = header_fmt_make(field, ", ",
			23 /* 23 == PONG_LEN */ * CONNECT_PONGS_COUNT + 30);

		for (i = 0; i < hcount; i++) {
			header_fmt_append_value(fmt, gnet_host_to_string(&hosts[i]));
		}

		header_fmt_end(fmt);
		line = header_fmt_to_string(fmt);
		header_fmt_free(fmt);
	}

	return line;		/* Pointer to static data */
}

/**
 * qsort() callback for sorting GTKG nodes at the front.
 */
static gint
node_gtkg_cmp(const void *np1, const void *np2)
{
	const gnutella_node_t *n1 = *(const gnutella_node_t **) np1;
	const gnutella_node_t *n2 = *(const gnutella_node_t **) np2;

	if (node_is_gtkg(n1)) {
		return node_is_gtkg(n2) ? 0 : -1;
	} else if (node_is_gtkg(n2)) {
		return 1;
	} else {
		return 0;
	}
}

/**
 * Inflate UDP payload, updating node internal data structures to reflect
 * the new payload size..
 *
 * @return success status, FALSE meaning the message was accounted as dropped
 * already.
 */
static gboolean
node_inflate_payload(gnutella_node_t *n)
{
	gint outlen = payload_inflate_buffer_len;
	gint ret;

	g_assert(NODE_IS_UDP(n));

	gnet_stats_count_general(GNR_UDP_RX_COMPRESSED, 1);

	if (!zlib_is_valid_header(n->data, n->size)) {
		if (GNET_PROPERTY(udp_debug))
			g_warning("UDP got %s with non-deflated payload from %s",
				gmsg_infostr_full_split(&n->header, n->data), node_addr(n));
		gnet_stats_count_dropped(n, MSG_DROP_INFLATE_ERROR);
		return FALSE;
	}

	/*
	 * Start of payload looks OK, attempt inflation.
	 */

	ret = zlib_inflate_into(n->data, n->size, payload_inflate_buffer, &outlen);
	if (ret != Z_OK) {
		if (GNET_PROPERTY(udp_debug))
			g_warning("UDP cannot inflate %s from %s: %s",
				gmsg_infostr_full_split(&n->header, n->data), node_addr(n),
				zlib_strerror(ret));
		gnet_stats_count_dropped(n, MSG_DROP_INFLATE_ERROR);
		return FALSE;
	}

	/*
	 * Inflation worked, update the header and the data pointers.
	 */

	n->data = payload_inflate_buffer;
	gnutella_header_set_ttl(&n->header,
		gnutella_header_get_ttl(&n->header) & ~GTA_UDP_DEFLATED);
	gnutella_header_set_size(&n->header, outlen);

	if (GNET_PROPERTY(udp_debug))
		g_message("UDP inflated %d-byte payload from %s into %s",
			n->size, node_addr(n),
			gmsg_infostr_full_split(&n->header, n->data));

	n->size = outlen;

	return TRUE;
}

/**
 * Generate the "Peers:" and "Leaves:" headers in a static buffer.
 *
 * @return ready-to-insert header chunk, with all lines ending with "\r\n".
 */
static gchar *
node_crawler_headers(struct gnutella_node *n)
{
	static gchar buf[8192];				/* 8 KB */
	gnutella_node_t **ultras = NULL;	/* Array of ultra nodes */
	gnutella_node_t **leaves = NULL;	/* Array of `leaves' */
	size_t ultras_len = 0;				/* Size of `ultras' */
	size_t leaves_len = 0;				/* Size of `leaves' */
	gint ux = 0;						/* Index in `ultras' */
	gint lx = 0;						/* Index in `leaves' */
	gint uw = 0;						/* Amount of ultras written */
	gint lw = 0;						/* Amount of leaves written */
	GSList *sl;
	gint maxsize;
	gint rw;
	gint count;

	if (GNET_PROPERTY(node_ultra_count)) {
		ultras_len = GNET_PROPERTY(node_ultra_count) * sizeof ultras[0];
		ultras = walloc(ultras_len);
	}

	if (GNET_PROPERTY(node_leaf_count)) {
		leaves_len = GNET_PROPERTY(node_leaf_count) * sizeof leaves[0];
		leaves = walloc(leaves_len);
	}

	for (sl = sl_nodes; sl; sl = g_slist_next(sl)) {
		gnutella_node_t *cn = sl->data;

		if (!NODE_IS_ESTABLISHED(cn))
			continue;

		if (!is_host_addr(cn->gnet_addr))		/* No information yet */
			continue;

		if (NODE_IS_ULTRA(cn)) {
			g_assert((guint) ux < GNET_PROPERTY(node_ultra_count));
			ultras[ux++] = cn;
			continue;
		}

		if (NODE_IS_LEAF(cn)) {
			g_assert((guint) lx < GNET_PROPERTY(node_leaf_count));
			leaves[lx++] = cn;
			continue;
		}
	}

	/*
	 * Put gtk-gnutella nodes at the front of the array, so that their
	 * addresses are listed first, in case we cannot list everyone.
	 */

	if (ux)
		qsort(ultras, ux, sizeof(gnutella_node_t *), node_gtkg_cmp);
	if (lx)
		qsort(leaves, lx, sizeof(gnutella_node_t *), node_gtkg_cmp);

	/*
	 * Avoid sending an incomplete trailing IP address by roughly avoiding
	 * any write if less than 32 chars are available in the buffer.
	 */

	maxsize = sizeof(buf) - 32;

	/*
	 * First, the peers.
	 */

	rw = gm_snprintf(buf, sizeof(buf), "Peers: ");

	for (count = 0; count < ux && rw < maxsize; count++) {
		struct gnutella_node *cn = ultras[count];

		if (cn == n)				/* Don't show the crawler itself */
			continue;

		if (uw > 0)
			rw += gm_snprintf(&buf[rw], sizeof(buf)-rw, ", ");

		rw += gm_snprintf(&buf[rw], sizeof(buf)-rw, "%s",
				host_addr_port_to_string(cn->gnet_addr, cn->gnet_port));

		uw++;		/* One more ultra written */
	}

	rw += gm_snprintf(&buf[rw], sizeof(buf)-rw, "\r\n");

	if (GNET_PROPERTY(current_peermode) != NODE_P_ULTRA || rw >= maxsize)
		goto cleanup;

	/*
	 * We're an ultranode, list our leaves.
	 */

	rw += gm_snprintf(&buf[rw], sizeof(buf)-rw, "Leaves: ");

	for (count = 0; count < lx && rw < maxsize; count++) {
		struct gnutella_node *cn = leaves[count];

		if (cn == n)				/* Don't show the crawler itself */
			continue;

		if (lw > 0)
			rw += gm_snprintf(&buf[rw], sizeof(buf)-rw, ", ");

		rw += gm_snprintf(&buf[rw], sizeof(buf)-rw, "%s",
				host_addr_port_to_string(cn->gnet_addr, cn->gnet_port));

		lw++;		/* One more leaf written */
	}

	rw += gm_snprintf(&buf[rw], sizeof(buf)-rw, "\r\n");

	if (GNET_PROPERTY(node_debug)) g_message(
		"TCP crawler sending %d/%d ultra%s and %d/%d lea%s to %s",
			uw, ux, uw == 1 ? "" : "s",
			lw, lx, lw == 1 ? "f" : "ves",
			node_addr(n));

	/* FALL THROUGH */

cleanup:
	if (ultras)
		wfree(ultras, ultras_len);
	if (leaves)
		wfree(leaves, leaves_len);

	return buf;
}

/**
 * Send error message to remote end, a node presumably.
 *
 * @param s		the connected socket (mandatory)
 * @param n		the node (optional, NULL if not available)
 * @param code	the error code to report
 * @param msg	the error message (printf format)
 * @param ap	variable argument pointer, arguments for the error message
 */
static void
send_error(
	struct gnutella_socket *s, struct gnutella_node *n,
	int code, const gchar *msg, va_list ap)
{
	gchar gnet_response[2048];
	gchar msg_tmp[256];
	size_t rw;
	ssize_t sent;
	gboolean saturated = bsched_saturated(BSCHED_BWS_GOUT);
	const gchar *version;
	gchar *token;
	gchar xlive[128];
	gchar xtoken[128];
	gint pongs = saturated ? CONNECT_PONGS_LOW : CONNECT_PONGS_COUNT;

	socket_check(s);
	g_assert(n == NULL || n->socket == s);

	gm_vsnprintf(msg_tmp, sizeof(msg_tmp)-1,  msg, ap);

	/*
	 * Try to limit the size of our reply if we're saturating bandwidth.
	 */

	if (saturated) {
		xlive[0] = '\0';
		version = version_short_string;
		token = socket_omit_token(s) ? NULL : tok_short_version();
	} else {
		gm_snprintf(xlive, sizeof(xlive),
			"X-Live-Since: %s\r\n", start_rfc822_date);
		version = version_string;
		token = socket_omit_token(s) ? NULL : tok_version();
	}

	if (token)
		gm_snprintf(xtoken, sizeof(xtoken), "X-Token: %s\r\n", token);
	else
		xtoken[0] = '\0';

	/*
	 * If we have a node and we know that it is NOT a gtk-gnutella node,
	 * chances are it will not care about the token and the X-Live-Since.
	 *
	 * If it is a genuine gtk-gnutella node, give it the maximum amount
	 * of pongs though, to make it easier for the node to get a connection.
	 */

	if (n != NULL && n->vendor != NULL) {
		if (node_is_gtkg(n)) {
			if (!(n->flags & NODE_F_FAKE_NAME))	/* A genuine GTKG peer */
				pongs = CONNECT_PONGS_COUNT;	/* Give it the maximum */
		} else {
			xlive[0] = '\0';
			xtoken[0] = '\0';
		}
	}

	/*
	 * Do not send them any pong on 403 and 406 errors, even if GTKG.
	 * When banning, the error code is 550 and does not warrant pongs either.
	 */

	if (code == 403 || code == 406 || code == 550)
		pongs = 0;

	/*
	 * Build the response.
	 */

	rw = gm_snprintf(gnet_response, sizeof(gnet_response),
		"GNUTELLA/0.6 %d %s\r\n"
		"User-Agent: %s\r\n"
		"Remote-IP: %s\r\n"
		"%s"		/* X-Token */
		"%s"		/* X-Live-Since */
		"%s"		/* X-Ultrapeer */
		"%s"		/* X-Try */
		"%s"		/* X-Try-Ultrapeers */
		"\r\n",
		code, msg_tmp, version, host_addr_to_string(s->addr), xtoken, xlive,
		GNET_PROPERTY(current_peermode) == NODE_P_NORMAL ? "" :
		GNET_PROPERTY(current_peermode) == NODE_P_LEAF ?
			"X-Ultrapeer: False\r\n": "X-Ultrapeer: True\r\n",
		(GNET_PROPERTY(current_peermode) == NODE_P_NORMAL && pongs) ?
			formatted_connection_pongs("X-Try", HOST_ANY, pongs) : "",
		(GNET_PROPERTY(current_peermode) != NODE_P_NORMAL && pongs) ?
			formatted_connection_pongs("X-Try-Ultrapeers", HOST_ULTRA, pongs)
			: ""
	);

	g_assert(rw < sizeof(gnet_response));

	sent = bws_write(BSCHED_BWS_GOUT, &s->wio, gnet_response, rw);
	if ((ssize_t) -1 == sent) {
		if (GNET_PROPERTY(node_debug))
			g_warning("Unable to send back error %d (%s) to node %s: %s",
			code, msg_tmp, host_addr_to_string(s->addr), g_strerror(errno));
	} else if ((size_t) sent < rw) {
		if (GNET_PROPERTY(node_debug)) {
			g_warning("Only sent %d out of %d bytes of error %d (%s) "
				"to node %s: %s", (int) sent, (int) rw, code, msg_tmp,
				host_addr_to_string(s->addr), g_strerror(errno));
		}
	} else if (GNET_PROPERTY(node_debug) > 2) {
		g_message("----Sent error %d to node %s (%d bytes):\n%.*s----",
			code, host_addr_to_string(s->addr),
			(int) rw, (int) rw, gnet_response);
	}
}

/**
 * Send error message to remote end, a node presumably.
 *
 * @attention
 * NB: We don't need a node to call this routine, only a socket.
 */
void
send_node_error(struct gnutella_socket *s, int code, const gchar *msg, ...)
{
	va_list args;

	va_start(args, msg);
	send_error(s, NULL, code, msg, args);
	va_end(args);
}

/**
 * Send error message to remote node.
 */
static void
node_send_error(struct gnutella_node *n, int code, const gchar *msg, ...)
{
	va_list args;

	va_start(args, msg);
	send_error(n->socket, n, code, msg, args);
	va_end(args);
}

/**
 * Request that node becomes our push-proxy.
 */
static void
send_proxy_request(gnutella_node_t *n)
{
	g_assert(n->attrs & NODE_A_CAN_VENDOR);
	g_assert(GNET_PROPERTY(is_firewalled));
	g_assert(!is_host_addr(n->proxy_addr));		/* Not proxying us yet */

	n->flags |= NODE_F_PROXY;
	vmsg_send_proxy_req(n, GNET_PROPERTY(servent_guid));
}

/**
 * Called when we were not firewalled and suddenly become firewalled.
 * Send proxy requests to our current connections.
 */
void
node_became_firewalled(void)
{
	GSList *sl;
	guint sent = 0;

	g_assert(GNET_PROPERTY(is_firewalled));

	for (sl = sl_nodes; sl; sl = g_slist_next(sl)) {
		struct gnutella_node *n = sl->data;

		if (socket_listen_port() && sent < 10 && n->attrs & NODE_A_CAN_VENDOR) {
			vmsg_send_tcp_connect_back(n, socket_listen_port());
			sent++;

			if (GNET_PROPERTY(node_debug))
				g_message("sent TCP connect back request to %s",
					host_addr_port_to_string(n->addr, n->port));
		}

		if (NODE_IS_LEAF(n))
			continue;

		if (!is_host_addr(n->proxy_addr) && (n->attrs & NODE_A_CAN_VENDOR))
			send_proxy_request(n);
	}
}

/**
 * Called when we were not firewalled and suddenly become UDP firewalled.
 * Send UDP connect back requests to our current connections.
 */
void
node_became_udp_firewalled(void)
{
	GSList *sl;
	guint sent = 0;

	g_assert(GNET_PROPERTY(is_udp_firewalled));

	if (0 == socket_listen_port())
		return;

	for (sl = sl_nodes; sl; sl = g_slist_next(sl)) {
		struct gnutella_node *n = sl->data;

		if (0 == (n->attrs & NODE_A_CAN_VENDOR))
			continue;

		vmsg_send_udp_connect_back(n, socket_listen_port());
		if (GNET_PROPERTY(node_debug))
			g_message("sent UDP connect back request to %s",
				host_addr_port_to_string(n->addr, n->port));

		if (10 == ++sent)
			break;
	}
}

/***
 *** TX deflate callbacks
 ***/

static void
node_add_tx_deflated(gpointer o, gint amount)
{
	gnutella_node_t *n = o;

	n->tx_deflated += amount;
}

static void
node_tx_shutdown(gpointer o, const gchar *reason, ...)
{
	gnutella_node_t *n = o;
	va_list args;

	va_start(args, reason);
	node_shutdown_v(n, reason, args);
	va_end(args);
}

static struct tx_deflate_cb node_tx_deflate_cb = {
	node_add_tx_deflated,		/* add_tx_deflated */
	node_tx_shutdown,			/* shutdown */
};

/***
 *** TX link callbacks
 ***/

static void
node_add_tx_written(gpointer o, gint amount)
{
	gnutella_node_t *n = o;

	n->tx_written += amount;
}

static void
node_tx_eof_remove(gpointer o, const gchar *reason, ...)
{
	gnutella_node_t *n = o;
	va_list args;

	va_start(args, reason);
	socket_eof(n->socket);
	node_remove_v(n, reason, args);
	va_end(args);
}

static void
node_tx_eof_shutdown(gpointer o, const gchar *reason, ...)
{
	gnutella_node_t *n = o;
	va_list args;

	va_start(args, reason);
	socket_eof(n->socket);
	node_shutdown_v(n, reason, args);
	va_end(args);
}

static void
node_tx_unflushq(gpointer o)
{
	gnutella_node_t *n = o;

	node_unflushq(n);
}

static struct tx_link_cb node_tx_link_cb = {
	node_add_tx_written,		/* add_tx_written */
	node_tx_eof_remove,			/* eof_remove */
	node_tx_eof_shutdown,		/* eof_shutdown */
	node_tx_unflushq,			/* unflushq */
};

/***
 *** TX datagram callbacks
 ***/

static struct tx_dgram_cb node_tx_dgram_cb = {
	node_add_tx_written,		/* add_tx_written */
};

/***
 *** RX inflate callbacks
 ***/

static void 
node_add_rx_inflated(gpointer o, gint amount)
{
	gnutella_node_t *n = o;

	n->rx_inflated += amount;
}

static void 
node_rx_inflate_error(gpointer o, const gchar *reason, ...)
{
	gnutella_node_t *n = o;
	va_list args;

	va_start(args, reason);
	node_mark_bad_vendor(n);
	node_bye_v(n, 501, reason, args);
	va_end(args);
}

static struct rx_inflate_cb node_rx_inflate_cb = {
	node_add_rx_inflated,		/* add_rx_inflated */
	node_rx_inflate_error,		/* inflate_error */
};

/***
 *** RX link callbacks
 ***/

static void
node_add_rx_given(gpointer o, ssize_t amount)
{
	gnutella_node_t *n = o;

	n->rx_given += amount;
}

static void
node_rx_read_error(gpointer o, const gchar *reason, ...)
{
	gnutella_node_t *n = o;
	va_list args;

	va_start(args, reason);
	node_eof_v(n, reason, args);
	va_end(args);
}

static void
node_rx_got_eof(gpointer o)
{
	gnutella_node_t *n = o;

	if (n->n_ping_sent <= 2 && n->n_pong_received)
		node_eof(n, NG_("Got %d connection pong", "Got %d connection pongs",
			n->n_pong_received), n->n_pong_received);
	else
		node_eof(n, "Failed (EOF)");
}

static struct rx_link_cb node_rx_link_cb = {
	node_add_rx_given,			/* add_rx_given */
	node_rx_read_error,			/* read_error */
	node_rx_got_eof,			/* got_eof */
};

/**
 * Called when we know that we're connected to the node, at the end of
 * the handshaking (both for incoming and outgoing connections).
 */
static void
node_is_now_connected(struct gnutella_node *n)
{
	gboolean peermode_changed = FALSE;
	gnet_host_t host;
	txdrv_t *tx;

	socket_check(n->socket);

	/*
	 * Temporary: if node is not a broken GTKG node, record it.
	 */

	if (!(n->attrs & NODE_A_NO_DUPS))
		sl_nodes_without_broken_gtkg =
			g_slist_prepend(sl_nodes_without_broken_gtkg, n);

	/*
	 * Cleanup hanshaking objects.
	 */

	if (n->io_opaque)				/* None for outgoing 0.4 connections */
		io_free(n->io_opaque);
	if (n->socket->getline) {
		getline_free(n->socket->getline);
		n->socket->getline = NULL;
	}

	/*
	 * Terminate crawler connection that goes through the whole 3-way
	 * handshaking protocol.
	 */

	if (n->flags & NODE_F_CRAWLER) {
		node_remove(n, _("Sent crawling info"));
		return;
	}

	/*
	 * Make sure we did not change peermode whilst performing the 3-way
	 * handshaking with this node.
	 */

	peermode_changed =
		n->start_peermode != GNET_PROPERTY(current_peermode) ||
		n->start_peermode != peermode.new;

	/*
	 * Determine correct peer mode.
	 *
	 * If we're a leaf node and we connected to an ultranode, send it
	 * our query routing table.
	 */

	n->peermode = NODE_P_NORMAL;

	if (n->flags & NODE_F_ULTRA) {
		if (GNET_PROPERTY(current_peermode) != NODE_P_NORMAL)
			n->peermode = NODE_P_ULTRA;
	} else if (n->flags & NODE_F_LEAF) {
		if (GNET_PROPERTY(current_peermode) == NODE_P_ULTRA)
			n->peermode = NODE_P_LEAF;
	} else if (n->attrs & NODE_A_ULTRA)
		n->peermode = NODE_P_ULTRA;

	/* If peermode did not change, current_peermode = leaf => node is Ultra */
	g_assert(peermode_changed ||
		GNET_PROPERTY(current_peermode) != NODE_P_LEAF || NODE_IS_ULTRA(n));

	/*
	 * Update state, and mark node as valid.
	 */

	n->status = GTA_NODE_CONNECTED;
	n->flags |= NODE_F_VALID;
	n->last_update = n->connect_date = tm_time();

	connected_node_cnt++;

	/*
	 * Count nodes by type.
	 */

	switch (n->peermode) {
	case NODE_P_LEAF:
		gnet_prop_incr_guint32(PROP_NODE_LEAF_COUNT);
		break;
	case NODE_P_NORMAL:
		gnet_prop_incr_guint32(PROP_NODE_NORMAL_COUNT);
		break;
	case NODE_P_ULTRA:
		gnet_prop_set_guint32_val(PROP_NODE_ULTRA_COUNT,
			GNET_PROPERTY(node_ultra_count) + 1);
		break;
	case NODE_P_AUTO:
	case NODE_P_CRAWLER:
	case NODE_P_UDP:
	case NODE_P_UNKNOWN:
		break;
	}

	/*
	 * Determine the frequency at which we will send "alive pings", and at
	 * which we shall accept regular pings on that connection.
	 */

	n->ping_throttle = PING_REG_THROTTLE;

	switch ((node_peer_t) GNET_PROPERTY(current_peermode)) {
	case NODE_P_NORMAL:
		n->alive_period = ALIVE_PERIOD;
		break;
	case NODE_P_ULTRA:
		if (n->peermode == NODE_P_LEAF) {
			n->alive_period = ALIVE_PERIOD_LEAF;
			n->ping_throttle = PING_LEAF_THROTTLE;
		} else
			n->alive_period = ALIVE_PERIOD;
		break;
	case NODE_P_LEAF:
		n->alive_period = ALIVE_PERIOD_LEAF;
		break;
	case NODE_P_AUTO:
	case NODE_P_CRAWLER:
	case NODE_P_UDP:
	case NODE_P_UNKNOWN:
		g_error("Invalid peer mode %d", GNET_PROPERTY(current_peermode));
		break;
	}

	/*
	 * Create the RX stack, and enable reception of data.
	 */

	gnet_host_set(&host, n->addr, n->port);

	{
		struct rx_link_args args;

		args.cb = &node_rx_link_cb;
		args.bws = n->peermode == NODE_P_LEAF
				? BSCHED_BWS_GLIN : BSCHED_BWS_GIN;
		args.wio = &n->socket->wio;

		n->rx = rx_make(n, &host, rx_link_get_ops(), &args);
	}

	if (n->attrs & NODE_A_RX_INFLATE) {
		struct rx_inflate_args args;

		if (GNET_PROPERTY(node_debug) > 4)
			g_message("receiving compressed data from node %s", node_addr(n));

		args.cb = &node_rx_inflate_cb;

		n->rx = rx_make_above(n->rx, rx_inflate_get_ops(), &args);

		if (n->flags & NODE_F_LEAF)
			compressed_leaf_cnt++;
        compressed_node_cnt++;
	}

	rx_set_data_ind(n->rx, node_data_ind);
	rx_enable(n->rx);
	n->flags |= NODE_F_READABLE;

	/*
	 * Create the TX stack, as we're going to transmit Gnet messages.
	 */

	{
		struct tx_link_args args;

		args.cb = &node_tx_link_cb;
		args.bws = n->peermode == NODE_P_LEAF
					? BSCHED_BWS_GLOUT : BSCHED_BWS_GOUT;
		args.wio = &n->socket->wio;

		tx = tx_make(n, &host, tx_link_get_ops(), &args);	/* Cannot fail */
	}

	/*
	 * If we committed on compressing traffic, install layer.
	 */

	if (n->attrs & NODE_A_TX_DEFLATE) {
		struct tx_deflate_args args;
		txdrv_t *ctx;

		if (GNET_PROPERTY(node_debug) > 4)
			g_message("sending compressed data to node %s", node_addr(n));

		args.cq = callout_queue;
		args.cb = &node_tx_deflate_cb;
		args.nagle = TRUE;
		args.gzip = FALSE;
		args.buffer_size = NODE_TX_BUFSIZ;
		args.buffer_flush = NODE_TX_FLUSH;

		ctx = tx_make_above(tx, tx_deflate_get_ops(), &args);
		if (ctx == NULL) {
			tx_free(tx);
			node_remove(n, _("Cannot setup compressing TX stack"));
			return;
		}

		tx = ctx;		/* Use compressing stack */
	}

	g_assert(tx);

	n->outq = mq_tcp_make(GNET_PROPERTY(node_sendqueue_size), n, tx);
	n->flags |= NODE_F_WRITABLE;
	n->alive_pings = alive_make(n, n->alive_period == ALIVE_PERIOD ?
		ALIVE_MAX_PENDING : ALIVE_MAX_PENDING_LEAF);

	/*
	 * In ultra mode, we're not broadcasting queries blindly, we're using
	 * dynamic querying, so there is no need for a per-node search queue.
	 */

	if (GNET_PROPERTY(current_peermode) != NODE_P_ULTRA)
		n->searchq = sq_make(n);

	/*
	 * Terminate connection if the peermode changed during handshaking.
	 */

	if (peermode_changed) {
		node_bye(n, 504, "Switched between Leaf/Ultra during handshake");
		return;
	}

	/*
	 * Initiate QRP sending if we're a leaf node or if we're an ultra node
	 * and the remote note is an UP supporting last-hop QRP.
	 */

	if (
		NODE_IS_ULTRA(n) &&
			(GNET_PROPERTY(current_peermode) == NODE_P_LEAF ||
			(GNET_PROPERTY(current_peermode) == NODE_P_ULTRA &&
			 (n->attrs & NODE_A_UP_QRP)))
	) {
		struct routing_table *qrt = qrt_get_table();

		/*
		 * If we don't even have our first QRT computed yet, we
		 * will send it to the ultranode when node_qrt_changed()
		 * is called by the computation code.
		 */

		if (qrt) {
			node_send_qrt(n, qrt);
			if (!NODE_IS_CONNECTED(n))
				return;
		}
	}

	/*
	 * Set the socket's send buffer size to a small value, to make sure we
	 * flow control early.  Use their setup for the receive buffer.
	 */

	socket_send_buf(n->socket, NODE_IS_LEAF(n) ?
		NODE_SEND_LEAF_BUFSIZE : NODE_SEND_BUFSIZE, TRUE);

	socket_recv_buf(n->socket, GNET_PROPERTY(node_rx_size) * 1024, TRUE);

	/*
	 * If we have an incoming connection, send an "alive" ping.
	 * Otherwise, send a "handshaking" ping.
	 */

	if (n->flags & NODE_F_INCOMING)
		alive_send_ping(n->alive_pings);
	else
		pcache_outgoing_connection(n);	/* Will send proper handshaking ping */

	/*
	 * If node supports vendor-specific messages, advertise the set we support.
	 *
	 * If we are firewalled, and remote node supports vendor-specific
	 * messages, send a connect back, to see whether we are firewalled.
	 */

	if (n->attrs & NODE_A_CAN_VENDOR) {
		vmsg_send_messages_supported(n);
		vmsg_send_features_supported(n);
		if (GNET_PROPERTY(is_firewalled)) {
			if (0 != socket_listen_port())
				vmsg_send_tcp_connect_back(n, socket_listen_port());
			if (!NODE_IS_LEAF(n))
				send_proxy_request(n);
		}
		if (udp_active()) {
			if (!GNET_PROPERTY(recv_solicited_udp))
				udp_send_ping(NULL, n->addr, n->port, FALSE);
			else if (
				GNET_PROPERTY(is_udp_firewalled) &&
				0 != socket_listen_port()
			)
				vmsg_send_udp_connect_back(n, socket_listen_port());
		}
	}

	/*
	 * If we're an Ultranode, we're going to monitor the queries sent by
	 * our leaves and by our neighbours.
	 */

	if (GNET_PROPERTY(current_peermode) != NODE_P_LEAF) {
		if (NODE_IS_LEAF(n))
			n->qseen = g_hash_table_new(g_str_hash, g_str_equal);
		else {
			if (GNET_PROPERTY(node_watch_similar_queries)) {
				n->qrelayed = g_hash_table_new(g_str_hash, g_str_equal);
				n->qrelayed_created = tm_time();
			}
		}
	}

	/*
	 * Update the GUI.
	 */

    node_fire_node_info_changed(n);
    node_fire_node_flags_changed(n);

	node_added = n;
	g_hook_list_invoke(&node_added_hook_list, TRUE);
	node_added = NULL;
}

/**
 * Received a Bye message from remote node.
 */
static void
node_got_bye(struct gnutella_node *n)
{
	guint16 code;
	const gchar *message = n->data + 2;
	const gchar *p;
	guchar c;
	guint cnt;
	gboolean warned = FALSE;
	gboolean is_plain_message = TRUE;
	guint message_len = n->size - 2;

	code = peek_le16(n->data);

	/*
	 * Codes are supposed to be 2xx, 4xx or 5xx.
	 *
	 * But older GnucDNA wer bugged enough to forget about the code and
	 * started to emit the message right away.  Fortunately, we can
	 * detect this because the two ASCII bytes will make the code
	 * appear out of range...  We force code 901 when we detect and
	 * correct this bug.
	 *
	 *		--RAM, 2004-10-19, revised 2005-09-30
	 */

	if (code > 999) {
		guchar c1 = n->data[0];
		guchar c2 = n->data[1];

		if (is_ascii_alnum(c1) && is_ascii_alnum(c2)) {
			message = n->data;
			message_len = n->size;
			code = 901;
		}
	}

	/*
	 * The first line can end with <cr><lf>, in which case we have an RFC-822
	 * style header in the packet.  Since the packet may not be NUL terminated,
	 * perform the scan manually.
	 */

	for (cnt = 0, p = message; cnt < message_len; cnt++, p++) {
		c = *p;
		if (c == '\0') {			/* NUL marks the end of the message */
			if (GNET_PROPERTY(node_debug) && cnt != message_len - 1)
				g_warning("BYE message %u from %s <%s> has early NUL",
					code, node_addr(n), node_vendor(n));
			break;
		} else if (c == '\r') {
			if (++cnt < n->size) {
				if ((c = *(++p)) == '\n') {
					is_plain_message = FALSE;
					message_len = (p - message + 1) - 2;  /* 2 = len("\r\n") */
					break;
				} else {
					p--;			/* Undo our look-ahead */
					cnt--;
				}
			}
			continue;
		}
		if (c && c < ' ' && !warned) {
			warned = TRUE;
			if (GNET_PROPERTY(node_debug))
				g_warning("BYE message %u from %s <%s> contains control chars",
					code, node_addr(n), node_vendor(n));
		}
	}

	if (!is_plain_message) {
		/* XXX parse header */
		if (GNET_PROPERTY(node_debug))
			g_message("----Bye Message from %s:\n%.*s----",
				node_addr(n), (gint) n->size - 2, message);
	}

	if (GNET_PROPERTY(node_debug))
		g_warning("%s node %s (%s) sent us BYE %d %.*s",
			node_type(n), node_addr(n), node_vendor(n),
			code, (int) MIN(120, message_len), message);

	node_remove(n, _("Got BYE %d %.*s"), code,
		(int) MIN(120, message_len), message);
}


/**
 * Whether they want to be "online" within Gnutella or not.
 */
void
node_set_online_mode(gboolean on)
{
	GSList *sl;

	if (allow_gnet_connections == on)		/* No change? */
		return;

	allow_gnet_connections = on;

	if (on)
		return;

	/*
	 * They're disallowing Gnutella connections.
	 */

	for (sl = sl_nodes; sl; sl = g_slist_next(sl)) {
		struct gnutella_node *n = sl->data;

		if (n->status == GTA_NODE_REMOVING)
			continue;

		node_bye_if_writable(n, 202, "User going offline");
	}
}

/**
 * Called from the property system when current peermode is changed.
 */
void
node_current_peermode_changed(node_peer_t mode)
{
	/*
	 * Only record the fact that it changed.
	 *
	 * We'll react by calling node_set_current_peermode() later, in the
	 * node_timer() routine, so that we do not close connections in the
	 * middle of the handshaking handling routing.
	 */

	peermode.changed = TRUE;
	peermode.new = mode;
}

/**
 * Called from the node timer when the current peermode has changed.
 *
 * We call this "asynchronously" because the current peermode can change
 * during handshaking, when we accept the guidance of the remote ultrapeer
 * to become a leaf node.
 */
static void
node_set_current_peermode(node_peer_t mode)
{
	static node_peer_t old_mode = NODE_P_UNKNOWN;
	const gchar *msg = NULL;

	if (NODE_P_UNKNOWN == old_mode)
		old_mode = GNET_PROPERTY(configured_peermode);

	switch (mode) {
	case NODE_P_NORMAL:
		msg = "normal";
		node_bye_flags(NODE_F_LEAF, 203, "Becoming a regular node");
		if (old_mode == NODE_P_LEAF)
			node_bye_flags(NODE_F_ULTRA, 203, "Becoming a regular node");
		break;
	case NODE_P_ULTRA:
		msg = "ultra";
		if (old_mode == NODE_P_LEAF)
			node_bye_flags(NODE_F_ULTRA, 203, "Becoming an ultra node");
		break;
	case NODE_P_LEAF:
		msg = "leaf";
		if (old_mode != NODE_P_LEAF)
			node_bye_flags(0xffffffff, 203, "Becoming a leaf node");
		break;
	case NODE_P_AUTO:
	case NODE_P_CRAWLER:
	case NODE_P_UDP:
	case NODE_P_UNKNOWN:
		g_error("unhandled mode %d", mode);
		break;
	}

	g_assert(msg != NULL);
	if (GNET_PROPERTY(node_debug) > 2)
		g_message("Switching to \"%s\" peer mode", msg);

	if (old_mode != NODE_P_UNKNOWN) {	/* Not at init time */
		bsched_set_peermode(mode);		/* Adapt Gnet bandwidth */
		pcache_set_peermode(mode);		/* Adapt pong cache lifetime */
		qrp_peermode_changed();			/* Compute proper routing table */
		sq_set_peermode(mode);			/* Possibly discard the global SQ */
	}

	dbus_util_send_message(DBS_EVT_PEERMODE_CHANGE, msg);

	old_mode = mode;
}

static guint
feed_host_cache_from_string(const gchar *s, host_type_t type, const gchar *name)
{
	guint n;

    g_assert((guint) type < HOST_MAX);
	g_assert(s);

	for (n = 0; NULL != s; s = strchr(s, ',')) {
		host_addr_t addr;
		guint16 port;

		if (',' == s[0])
			s++;

		s = skip_ascii_spaces(s);
		string_to_host_addr(s, &s, &addr);
		if (!is_host_addr(addr))
			continue;

		if (':' == s[0]) {
			guint32 u;
			gint error;

			s++;
			u = parse_uint32(s, &s, 10, &error);
			port = (error || u < 1024 || u > 65535) ? 0 : u;
		} else {
			port = GTA_PORT;
		}

		if (!port)
			continue;

		hcache_add_caught(type, addr, port, name);
		n++;
	}

	return n;
}

/**
 * Extract host:port information out of a header field and add those to our
 * pong cache. If ``gnet'' is TRUE, the header names without a leading
 * "X-" are checked as variants as well.
 *
 * @param header a valid header_t.
 * @param sender the host_type_t of the sender, if unknown use HOST_ANY.
 * @param gnet should be set to TRUE if the headers come from a Gnutella
 *			handshake.
 * @param peer the peer address who sent the headers.
 *
 * @return the amount of valid peer addresses we parsed.
 *
 * The syntax we expect is:
 *
 *   <header>: <peer> ("," <peer>)*
 *
 *   peer =		<host> [":" <port>] [any except ","]*
 *   header =	"Alt" | Listen-Ip" | "Listen-Ip" |
 *				"My-Address" | "Node" | "Try" | "Try-Ultrapeers"
 *
 */
guint
feed_host_cache_from_headers(header_t *header,
	host_type_t sender, gboolean gnet, const host_addr_t peer)
{
	static const struct {
		const gchar *name;	/* Name of the header */
		gboolean sender;	/* Host type is derived from sender */
		gboolean gnet;		/* Definitely a Gnutella network header */
		host_type_t type;	/* Default type, sender will override */
	} headers[] = {
		{ "X-Alt",				FALSE,	FALSE, HOST_ANY },
		{ "X-Listen-Ip",		TRUE,	TRUE,  HOST_ANY },
		{ "X-My-Address",		TRUE,	TRUE,  HOST_ANY },
		{ "X-Node",				TRUE,	TRUE,  HOST_ANY },
		{ "X-Node-IPv6",		TRUE,	TRUE,  HOST_ANY },
		{ "X-Try",				FALSE,	TRUE,  HOST_ANY },
		{ "X-Try-Ultrapeers",	FALSE,	TRUE,  HOST_ULTRA },
	};
	guint i, n = 0;

	g_assert(header);
    g_assert(UNSIGNED(sender) < HOST_MAX);

	for (;;) {
		for (i = 0; i < G_N_ELEMENTS(headers); i++) {
			const gchar *val, *name, *p;
			host_type_t type;
			guint r;

			/*
			 * One cannot assume that the same port will always be used for
			 * Gnutella connections and HTTP connections.  Do not collect
			 * addresses from ambiguous headers unless we're low on pongs.
			 */

			if (!gnet && !headers[i].gnet && !host_low_on_pongs)
				continue;

			name = headers[i].name;
			if (gnet && NULL != (p = is_strprefix(name, "X-")))
				name = p;

			type = headers[i].sender ? sender : headers[i].type;
			val = header_get(header, name);
			if (!val)
				continue;

			r = feed_host_cache_from_string(val, type, name);
			n += r;

			if (GNET_PROPERTY(node_debug) > 0) {
				if (r > 0)
					g_message("peer %s sent %u pong%s in %s header",
						host_addr_to_string(peer), r, 1 == r ? "" : "s", name);
				else
					g_message("peer %s sent an unparseable %s header",
						host_addr_to_string(peer), name);
			}
		}
		if (!gnet)
			break;
		gnet = FALSE;
	}

	return n;
}

/**
 * Extract the header pongs from the header (X-Try lines).
 * The node is only given for tracing purposes.
 */
static void
extract_header_pongs(header_t *header, struct gnutella_node *n)
{
	feed_host_cache_from_headers(header,
		NODE_P_ULTRA == n->peermode ? HOST_ULTRA : HOST_ANY,
		TRUE, n->addr);
}

/**
 * Try to determine whether headers contain an indication of our own IP.
 *
 * @return 0 if none found, or the indicated IP address.
 */
static host_addr_t
extract_my_addr(header_t *header)
{
	const gchar *field;
	host_addr_t addr;

	field = header_get(header, "Remote-Ip");
	if (!field)
		field = header_get(header, "X-Remote-Ip");

	if (field)
		string_to_host_addr(field, NULL, &addr);
	else
		addr = zero_host_addr;

	return addr;
}

/**
 * Checks for a Remote-IP or X-Remote-IP header and updates our IP address if
 * the current IP address is not enforced. Note that settings_addr_changed()
 * doesn't trust a single source.
 *
 * @param peer the IPv4 address of the peer who sent the header
 * @param head a header_t holding headers sent by the peer
 */
void
node_check_remote_ip_header(const host_addr_t peer, header_t *head)
{
	host_addr_t addr;

	g_assert(head != NULL);

	/*
	 * Remote-IP -- IP address of this node as seen from remote node
	 *
	 * Modern nodes include our own IP, as they see it, in the
	 * handshake headers and reply, whether it indicates a success or not.
	 * Use it as an opportunity to automatically detect changes.
	 *		--RAM, 13/01/2002
	 */

	if (GNET_PROPERTY(force_local_ip))
		return;

	addr = extract_my_addr(head);
	if (!is_host_addr(addr) || is_my_address(addr))
		return;

	if (GNET_PROPERTY(node_debug) > 0) {
		const gchar *ua;

		ua = header_get(head, "User-Agent");
		if (!ua)
			ua = header_get(head, "Server");
		if (!ua)
			ua = "Unknown";

		{
			gchar buf[HOST_ADDR_BUFLEN];

			host_addr_to_string_buf(addr, buf, sizeof buf);
			g_message("Peer %s reported different IP address: %s (%s)\n",
				host_addr_to_string(peer), buf, ua);
		}
	}

	settings_addr_changed(addr, peer);
}


/**
 * Analyses status lines we get from incoming handshakes (final ACK) or
 * outgoing handshakes (inital REPLY, after our HELLO)
 *
 * @return TRUE if acknowledgment was OK, FALSE if an error occurred, in
 * which case the node was removed with proper status.
 *
 * If `code' is not NULL, it is filled with the returned code, or -1 if
 * we were unable to parse the status.
 */
static gboolean
analyse_status(struct gnutella_node *n, gint *code)
{
	struct gnutella_socket *s = n->socket;
	const gchar *status;
	gint ack_code;
	guint major = 0, minor = 0;
	const gchar *ack_message = "";
	gboolean ack_ok = FALSE;
	gboolean incoming = (n->flags & NODE_F_INCOMING) ? TRUE : FALSE;
	const gchar *what = incoming ? "acknowledgment" : "reply";

	socket_check(s);
	status = getline_str(s->getline);

	ack_code = http_status_parse(status, "GNUTELLA",
		&ack_message, &major, &minor);

	if (code)
		*code = ack_code;

	if (GNET_PROPERTY(node_debug))
		g_message("%s: code=%d, message=\"%s\", proto=%u.%u",
			incoming ? "ACK" : "REPLY",
			ack_code, ack_message, major, minor);

	if (ack_code == -1) {
		if (GNET_PROPERTY(node_debug)) {
			if (incoming || 0 != strcmp(status, "GNUTELLA OK")) {
				g_warning("weird GNUTELLA %s status line from %s",
					what, host_addr_to_string(n->addr));
				dump_hex(stderr, "Status Line", status,
					MIN(getline_length(s->getline), 80));
			} else
				g_warning("node %s gave a 0.4 reply to our 0.6 HELLO, dropping",
					node_addr(n));
		}
        hcache_add(HCACHE_UNSTABLE, n->addr, 0, "bad ack_code");
	} else {
		ack_ok = TRUE;
		n->flags |= NODE_F_VALID;		/* This is a Gnutella node */
	}

	if (ack_ok && (major != n->proto_major || minor != n->proto_minor)) {
		if (GNET_PROPERTY(node_debug)) {
			if (incoming)
				g_warning("node %s handshaked at %d.%d and now acks at %d.%d, "
					"adjusting", host_addr_to_string(n->addr),
					n->proto_major, n->proto_minor, major, minor);
			else
				g_warning("node %s was sent %d.%d HELLO but supports %d.%d "
					"only, adjusting", host_addr_to_string(n->addr),
					n->proto_major, n->proto_minor, major, minor);
		}
		n->proto_major = major;
		n->proto_minor = minor;
	}

	/*
	 * Is the connection OK?
	 */

	if (!ack_ok) {
		node_remove(n, _("Weird HELLO %s"), what);
	} else if (ack_code < 200 || ack_code >= 300) {
		if (ack_code == 401) {
            /* Unauthorized */
            hcache_add(HCACHE_UNSTABLE, n->addr, 0, "unauthorized");
        }

        if (ack_code == 503) {
            /* Busy */
            hcache_add(HCACHE_BUSY, n->addr, 0, "ack_code 503");
        }

		node_remove(n, _("HELLO %s error %d (%s)"),
			what, ack_code, ack_message);
		ack_ok = FALSE;
	} else if (!incoming && ack_code == 204) {
		node_remove(n, _("Shielded node"));
		ack_ok = FALSE;
	}
	if (GTA_NODE_REMOVING == n->status) {
		ack_ok = FALSE;
	}
	return ack_ok;
}

/**
 * Can node accept connection?
 *
 * If `handshaking' is true, we're still in the handshaking phase, otherwise
 * we're already connected and can send a BYE.
 *
 * @return TRUE if we can accept the connection, FALSE otherwise, with
 * the node being removed.
 */
static gboolean
node_can_accept_connection(struct gnutella_node *n, gboolean handshaking)
{
	g_assert(handshaking || n->status == GTA_NODE_CONNECTED);
	g_assert(n->attrs & (NODE_A_NO_ULTRA|NODE_A_CAN_ULTRA));

	/*
	 * Deny cleanly if they deactivated "online mode".
	 */

	if (handshaking && !allow_gnet_connections) {
		node_send_error(n, 403,
			"Gnet connections currently disabled");
		node_remove(n, _("Gnet connections disabled"));
		return FALSE;
	}

	/*
	 * Always accept crawler connections.
	 */

	if (n->flags & NODE_F_CRAWLER)
		return TRUE;

	/*
	 * If we are handshaking, we have not incremented the node counts yet.
	 * Hence we can do >= tests against the limits.
	 */

	switch ((node_peer_t) GNET_PROPERTY(current_peermode)) {
	case NODE_P_ULTRA:

		if (n->flags & NODE_F_FORCE)
			return TRUE;

		/*
		 * If we're an ultra node, we need to enforce leaf counts.
		 *
		 * We also enforce ultra node counts if we're issuing an outgoing
		 * connection, but for incoming ones, we'll try to let the other
		 * node become a leaf node, so don't enforce if we're still in the
		 * handshaking phase.
		 */

		if (n->flags & NODE_F_LEAF) {
			/*
			 * Try to preference compressed leaf nodes too
			 * 		-- JA, 08/06/2003
			 */
			if (
				GNET_PROPERTY(prefer_compressed_gnet) &&
				GNET_PROPERTY(up_connections) <=
					GNET_PROPERTY(node_leaf_count) - compressed_leaf_cnt &&
				!(n->attrs & NODE_A_CAN_INFLATE)
			) {
				node_send_error(n, 403,
					"Compressed connection prefered");
				node_remove(n, _("Connection not compressed"));
				return FALSE;
			}

			/*
			 * Remove leaves that do not allow queries when we are
			 * running out of slots.
			 */

			if (GNET_PROPERTY(node_leaf_count) >= GNET_PROPERTY(max_leaves))
				(void) node_remove_useless_leaf(NULL);

			if (
				handshaking &&
				GNET_PROPERTY(node_leaf_count) >= GNET_PROPERTY(max_leaves)
			) {
				node_send_error(n, 503, "Too many leaf connections (%d max)",
					GNET_PROPERTY(max_leaves));
				node_remove(n, _("Too many leaves (%d max)"),
					GNET_PROPERTY(max_leaves));
				return FALSE;
			}
			if (
				!handshaking &&
				GNET_PROPERTY(node_leaf_count) > GNET_PROPERTY(max_leaves)
			) {
				node_bye(n, 503, "Too many leaf connections (%d max)",
					GNET_PROPERTY(max_leaves));
				return FALSE;
			}
		} else if (n->attrs & NODE_A_ULTRA) {
			guint ultra_max;

			/*
			 * Try to preference compressed ultrapeer connections too
			 * 		-- JA, 08/06/2003
			 */
			if (
				GNET_PROPERTY(prefer_compressed_gnet) &&
				GNET_PROPERTY(up_connections) <=
					GNET_PROPERTY(node_ultra_count) -
						(compressed_node_cnt - compressed_leaf_cnt) &&
				!(n->attrs & NODE_A_CAN_INFLATE)
			) {
				node_send_error(n, 403,
					"Compressed connection prefered");
				node_remove(n, _("Connection not compressed"));
				return FALSE;
			}

			ultra_max = GNET_PROPERTY(max_connections) > GNET_PROPERTY(normal_connections)
				? GNET_PROPERTY(max_connections) - GNET_PROPERTY(normal_connections) : 0;

			if (GNET_PROPERTY(node_ultra_count) >= ultra_max)
				(void) node_remove_useless_ultra(NULL);

			if (
				handshaking &&
				GNET_PROPERTY(node_ultra_count) >= ultra_max
			) {
				node_send_error(n, 503,
					"Too many ultra connections (%d max)", ultra_max);
				node_remove(n, _("Too many ultra nodes (%d max)"), ultra_max);
				return FALSE;
			}
			if (!handshaking && GNET_PROPERTY(node_ultra_count) > ultra_max) {
				node_bye(n, 503,
					"Too many ultra connections (%d max)", ultra_max);
				return FALSE;
			}
		}

		/*
		 * Enforce preference for compression only with non-leaf nodes.
		 */

		if (handshaking) {
			guint connected;

			connected = GNET_PROPERTY(node_normal_count)
							+ GNET_PROPERTY(node_ultra_count);

            if (
				GNET_PROPERTY(prefer_compressed_gnet) &&
				!(n->attrs & NODE_A_CAN_INFLATE) &&
				(
					((n->flags & NODE_F_INCOMING) &&
					connected >= GNET_PROPERTY(up_connections) &&
					connected > compressed_node_cnt)
					||
					(n->flags & NODE_F_LEAF)
				)
			) {
				node_send_error(n, 403,
					"Gnet connection not compressed");
				node_remove(n, _("Connection not compressed"));
				return FALSE;
			}
		}

		/*
		 * If we have already enough normal nodes, reject a normal node.
		 */

		if (
			handshaking &&
			(n->attrs & NODE_A_NO_ULTRA) &&
			GNET_PROPERTY(node_normal_count)
				>= GNET_PROPERTY(normal_connections)
		) {
			if (GNET_PROPERTY(normal_connections))
				node_send_error(n, 503, "Too many normal nodes (%d max)",
					GNET_PROPERTY(normal_connections));
			else
				node_send_error(n, 403, "Normal nodes refused");
			node_remove(n, _("Rejected normal node (%d max)"),
				GNET_PROPERTY(normal_connections));
			return FALSE;
		}

		break;
	case NODE_P_NORMAL:
		if (n->flags & NODE_F_FORCE)
			return TRUE;

		if (handshaking) {
			guint connected;

			connected = GNET_PROPERTY(node_normal_count)
							+ GNET_PROPERTY(node_ultra_count);
			if (
				(n->attrs & (NODE_A_CAN_ULTRA|NODE_A_ULTRA)) == NODE_A_CAN_ULTRA
			) {
				node_send_error(n, 503, "Cannot accept leaf node");
				node_remove(n, _("Rejected leaf node"));
				return FALSE;
			}
			if (connected >= GNET_PROPERTY(max_connections)) {
				node_send_error(n, 503, "Too many Gnet connections (%d max)",
					GNET_PROPERTY(max_connections));
				node_remove(n, _("Too many nodes (%d max)"),
					GNET_PROPERTY(max_connections));
				return FALSE;
			}
			if (
				GNET_PROPERTY(prefer_compressed_gnet) &&
				(n->flags & NODE_F_INCOMING) &&
				!(n->attrs & NODE_A_CAN_INFLATE) &&
				connected >= GNET_PROPERTY(up_connections) &&
				connected > compressed_node_cnt
			) {
				node_send_error(n, 403,
					"Gnet connection not compressed");
				node_remove(n, _("Connection not compressed"));
				return FALSE;
			}
		} else if (
			GNET_PROPERTY(node_normal_count) + GNET_PROPERTY(node_ultra_count)
				> GNET_PROPERTY(max_connections)
		) {
			node_bye(n, 503, "Too many Gnet connections (%d max)",
				GNET_PROPERTY(max_connections));
			return FALSE;
		}
		break;
	case NODE_P_LEAF:

		/* Even forced connections are not acceptable unless
		 * the remote node is an ultrapeer. Note: There is also
		 * an assertion in node_process_handshake_header().
		 */
		if ((n->flags & NODE_F_FORCE) && (n->attrs & NODE_A_ULTRA))
			return TRUE;

		if (handshaking) {
			/*
			 * If we're a leaf node, we can only accept incoming connections
			 * from an ultra node.
			 *
			 * The Ultrapeer specs say that two leaf nodes not finding
			 * Ultrapeers could connect to each other like two normal nodes,
			 * but I don't want to support that.  It's insane.
			 *		--RAM, 11/01/2003
			 */

			if (!(n->attrs & NODE_A_ULTRA)) {
				node_send_error(n, 204, "Shielded leaf node (%d peers max)",
					GNET_PROPERTY(max_ultrapeers));
				node_remove(n, _("Sent shielded indication"));
				return FALSE;
			}

			if (!(n->attrs & NODE_A_ULTRA)) {
				node_send_error(n, 503, "Looking for an ultra node");
				node_remove(n, _("Not an ultra node"));
				return FALSE;
			}

			if (
				GNET_PROPERTY(node_ultra_count) >= GNET_PROPERTY(max_ultrapeers)
			) {
				node_send_error(n, 503, "Too many ultra connections (%d max)",
					GNET_PROPERTY(max_ultrapeers));
				node_remove(n, _("Too many ultra nodes (%d max)"),
					GNET_PROPERTY(max_ultrapeers));
				return FALSE;
			}

			/*
			 * Honour the prefer compressed connection setting. Even when making
			 * outgoing connections in leaf mode
			 * 		-- JA 24/5/2003
			 */
			if (
				GNET_PROPERTY(prefer_compressed_gnet) &&
				GNET_PROPERTY(up_connections)
					<= GNET_PROPERTY(node_ultra_count) - compressed_node_cnt &&
				!(n->attrs & NODE_A_CAN_INFLATE)
			) {
				node_send_error(n, 403,
					"Compressed connection prefered");
				node_remove(n, _("Connection not compressed"));
				return FALSE;
			}
		} else if (
			GNET_PROPERTY(node_ultra_count) > GNET_PROPERTY(max_ultrapeers)
		) {
			node_bye(n, 503, "Too many ultra connections (%d max)",
				GNET_PROPERTY(max_ultrapeers));
			return FALSE;
		}
		break;
	case NODE_P_AUTO:
	case NODE_P_CRAWLER:
	case NODE_P_UDP:
	case NODE_P_UNKNOWN:
		g_assert_not_reached();
		break;
	}

	/*
	 * If a specific client version has proven to be very unstable during this
	 * version, don't connect to it.
	 *		-- JA 17/7/200
	 */

	if (n->attrs & NODE_A_ULTRA) {
		const gchar *msg = "Unknown error";
		enum node_bad bad = node_is_bad(n);

		switch (bad) {
		case NODE_BAD_OK:
			break;
		case NODE_BAD_IP:
			msg = _("Unstable IP address");
			break;
		case NODE_BAD_VENDOR:
			msg = _("Servent version appears unstable");
			break;
		case NODE_BAD_NO_VENDOR:
			msg = _("No vendor string supplied");
			break;
		}

		if (NODE_BAD_OK != bad) {
			node_send_error(n, 403, "%s", msg);
			node_remove(n, _("Not connecting: %s"), msg);
			return FALSE;
		}
	}

	return TRUE;
}

/**
 * Check whether we can accept a servent supporting a foreign protocol.
 * Must be called during handshaking.
 *
 * @return TRUE if OK, FALSE if connection was denied.
 */
static gboolean
node_can_accept_protocol(struct gnutella_node *n, header_t *head)
{
	const gchar *field;

	/*
	 * Accept -- protocols supported
	 *
	 * We ban ultrapeers claiming support for "application/x-gnutella2" if
	 * we are an ultranode ourselves.
	 *
	 * Study has shown that this closed protocol is not inter-operating
	 * well with Gnutella: it is more comparable to massive leaching.
	 * See the various GDF articles written on the subject that prove this.
	 *		--RAM, 25/01/2003
	 */

	field = header_get(head, "Accept");
	if (field) {
		if (
			GNET_PROPERTY(current_peermode) != NODE_P_LEAF &&
			!(n->flags & NODE_F_LEAF) &&
			strstr(field, "application/x-gnutella2") /* XXX parse the "," */
		) {
			static const gchar msg[] = N_("Protocol not acceptable");

			node_send_error(n, 406, msg);
			node_remove(n, _(msg));
			return FALSE;
		}
	}

	return TRUE;
}

/**
 * This routine is called to process the whole 0.6+ final handshake header
 * acknowledgement we get back after welcoming an incoming node.
 */
static void
node_process_handshake_ack(struct gnutella_node *n, header_t *head)
{
	struct gnutella_socket *s = n->socket;
	gboolean ack_ok;
	const gchar *field;
	gboolean qrp_final_set = FALSE;

	socket_check(s);

	if (GNET_PROPERTY(node_debug)) {
		g_message("got final acknowledgment headers from node %s:",
			host_addr_to_string(n->addr));
		dump_hex(stdout, "Status Line", getline_str(s->getline),
			MIN(getline_length(s->getline), 80));
		g_message("------ Header Dump:");
		header_dump(head, stderr);
		g_message("------");
		fflush(stderr);
	}

	ack_ok = analyse_status(n, NULL);
	extract_header_pongs(head, n);		/* Some servents always send X-Try-* */

	if (!ack_ok)
		return;			/* s->getline will have been freed by node removal */

	/*
	 * Get rid of the acknowledgment status line.
	 */

	getline_free(s->getline);
	s->getline = NULL;

	/*
	 * Content-Encoding -- compression accepted by the remote side
	 */

	field = header_get(head, "Content-Encoding");
	if (field) {
		/* XXX needs more rigourous parsing */
		if (strstr(field, "deflate"))
			n->attrs |= NODE_A_RX_INFLATE;	/* We shall decompress input */
	}

	if (
		!GNET_PROPERTY(gnet_deflate_enabled) &&
		(n->attrs & NODE_A_RX_INFLATE)
	) {
		g_warning("Content-Encoding \"deflate\" although disabled - from"
			   " node %s <%s>", node_addr(n), node_vendor(n));
        node_bye(n, 400, "Compression was not accepted");
		return;
	}


	/* X-Ultrapeer -- support for ultra peer mode */

	field = header_get(head, "X-Ultrapeer");
	if (field && 0 == ascii_strcasecmp(field, "false")) {
		n->attrs &= ~NODE_A_ULTRA;
		if (GNET_PROPERTY(current_peermode) == NODE_P_ULTRA) {
			n->flags |= NODE_F_LEAF;		/* Remote accepted to become leaf */
			if (GNET_PROPERTY(node_debug)) g_warning(
				"node %s <%s> accepted to become our leaf",
				node_addr(n), node_vendor(n));
		}
	}

	/*
	 * X-Query-Routing -- QRP protocol in use by remote servent (negotiated)
	 *
	 * This header is present in the 3rd handshake only when the two servents
	 * advertised different support.  This last indication is the highest
	 * version supported by the remote end, that is less or equals to ours.
	 * (If not present, it means the remote end implicitly expects us to
	 * comply with his older version.)
	 *
	 * If we don't support that version, we'll BYE the servent later.
	 */

	field = header_get(head, "X-Query-Routing");
	if (field) {
		guint major, minor;

		parse_major_minor(field, NULL, &major, &minor);
		if (major >= n->qrp_major || minor >= n->qrp_minor)
			if (GNET_PROPERTY(node_debug)) g_warning(
				"node %s <%s> now claims QRP version %u.%u, "
				"but advertised %u.%u earlier",
				node_addr(n), node_vendor(n), major, minor,
				(guint) n->qrp_major, (guint) n->qrp_minor);
		n->qrp_major = (guint8) major;
		n->qrp_minor = (guint8) minor;
		qrp_final_set = TRUE;
	}

	/*
	 * Inst