static void fst_plugin_discover_callback (FSTUdpDiscover *discover,
                                          FSTUdpNodeState node_state,
                                          FSTNode *node)
{
	switch (node_state)
	{
	case UdpNodeStateDown:
		/* remove this node from node cache _if_ we know that udp works.
		 * otherwise just move the node to the back of the cache.
		 */
		if (FST_PLUGIN->discover->udp_working)
		{
			FST_HEAVY_DBG_2 ("UdpNodeStateDown: %s:%d, UDP works",
			                 node->host, node->port);
			/* remove node if it is not connected. */
			if (!node->session)
				fst_nodecache_remove (FST_PLUGIN->nodecache, node);
		}
		else
		{
			FST_HEAVY_DBG_2 ("UdpNodeStateDown: %s:%d, UDP not verified",
			                 node->host, node->port);
			/* move the node to back of cache */
			fst_nodecache_move (FST_PLUGIN->nodecache, node, NodeInsertBack);
		}
		break;

	case UdpNodeStateUp:
		FST_HEAVY_DBG_2 ("UdpNodeStateUp: %s:%d", node->host, node->port);
		/* move the node to back of cache */
		fst_nodecache_move (FST_PLUGIN->nodecache, node, NodeInsertBack);
		break;

	case UdpNodeStateFree:
		FST_HEAVY_DBG_2 ("UdpNodeStateFree: %s:%d", node->host, node->port);

		/* Insert node with new load and last_seen values. This will inevitably
		 * Move the node to the front part of the list so it gets picked the 
		 * next time we connect.
		 */
		fst_nodecache_move (FST_PLUGIN->nodecache, node, NodeInsertSorted);
		break;
	}

	/* print out some stats if all pings have come back / timed out */
	if (FST_PLUGIN->discover->pinged_nodes == 0)
	{
		FST_DBG_3 ("discovery cycle complete: %d pings, %d pongs, %d others",
		           discover->sent_pings,
		           discover->received_pongs,
		           discover->received_others);

		discover->sent_pings = 0;
		discover->received_pongs = 0;
		discover->received_others = 0;
	}
}
int fst_cipher_init (FSTCipher *cipher, unsigned int seed, unsigned int enc_type)
{
	int i,j;
	unsigned int temp;
	unsigned int sortpos;
	unsigned char c;

	cipher->enc_type = enc_type;
	cipher->wrapcount = 0;
	cipher->add_to_lookup = 0;
	cipher->seed = seed;

	FST_HEAVY_DBG_2 ("init_cipher: seed = 0x%08x, enc_type = 0x%02x", seed, enc_type);

	if (!pad_init (&seed, enc_type, cipher->pad, sizeof (cipher->pad)))
		return FALSE;

	/* adjust pad */
	c = 0;
	for (i = 0; i < sizeof (cipher->pad); i++)
		c = c | cipher->pad[i];
	if (!(c & 1))
		cipher->pad[0] = cipher->pad[0] | 0x71;

	/* init cipher->pos */
	temp = seed_step (seed);
	temp = temp >> 16;
	cipher->pos = ( (temp << 6) - temp) >> 16;

	/* init cipher->lookup */
	for(i = 0; i <sizeof (cipher->lookup); i++)
		cipher->lookup[i] = (unsigned char)i;

	if (enc_type & 0x08)
	{
		MD5Context ctx;
		unsigned char md5[MD5_HASH_LEN];

		FST_HEAVY_DBG ("init_cipher: enc_type & 0x08");

		MD5Init (&ctx);
		MD5Update (&ctx, cipher->pad, sizeof(cipher->pad));
		MD5Final (md5, &ctx);

		/* correct md5 byte order on big-endian since it's converted to (unsigned int*) below */
		reverse_bytes ( (unsigned int*)&md5, 4);

		/* modify cipher->lookup */
		for (i = 0; i < sizeof (cipher->lookup); i++)
		{
			if ( (j = calculate_num( (unsigned int*) &md5, 0x100 - i) + i) != i)
			{
				unsigned char a = cipher->lookup[j];
				unsigned char b = cipher->lookup[i];
				cipher->lookup[i] = a;
				cipher->lookup[j] = b;
			}
		}
	}


	if(enc_type & 0x10)
	{
		FST_HEAVY_DBG ("init_cipher: enc_type & 0x10");

		for (seed = cipher->pos, i=0; i < 20; i++)
		{
			seed = seed_step (seed);
			cipher->pad16[i] = seed;
		}		
		
		seed = seed_step (seed);

		/* CHECKME: endianess? */
		EncryptionType2::enc_type_2(cipher->pad16, seed);
	}


	/* sort cipher->pad */
	sortpos = ( (cipher->pos * cipher->pos) + 2) % (sizeof(cipher->pad)-4);
	qsort (cipher->pad + sortpos, 5, 1, qsort_cmp_func);

	/* modify every third byte of cipher->pad */
	for (i = 5; i < sizeof (cipher->pad); i += 3) 
	{
		c = cipher->pad[i];
		c = ~c + i;
		cipher->pad[i] = c | 1;
	}

//	print_bin_data(cipher->pad, sizeof(cipher->pad));
//	print_bin_data(cipher->lookup, sizeof(cipher->lookup));

	return TRUE;
}