* @brief high-level P2P messaging
* @author Christian Grothoff
*
+ * Type map implementation:
+ * - track type maps for neighbours (can wait)
+ * - only notify clients about peers with matching type maps (can wait)
+ *
* Considerations for later:
* - check that hostkey used by transport (for HELLOs) is the
* same as the hostkey that we are using!
- * - add code to send PINGs if we are about to time-out otherwise
- * - optimize lookup (many O(n) list traversals
- * could ideally be changed to O(1) hash map lookups)
*/
#include "platform.h"
+#include <zlib.h>
#include "gnunet_constants.h"
#include "gnunet_util_lib.h"
#include "gnunet_hello_lib.h"
*/
static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
+/**
+ * Bitmap of message types this peer is able to handle.
+ */
+static uint32_t my_type_map[(UINT16_MAX + 1)/32];
/**
* Handle to peerinfo service.
}
+/**
+ * Compute a type map message for this peer.
+ *
+ * @return this peers current type map message.
+ */
+static struct GNUNET_MessageHeader *
+compute_type_map_message ()
+{
+ char *tmp;
+ uLongf dlen;
+ struct GNUNET_MessageHeader *hdr;
+
+#ifdef compressBound
+ dlen = compressBound (sizeof(my_type_map));
+#else
+ dlen = sizeof(my_type_map) + (sizeof(my_type_map) / 100) + 20;
+ /* documentation says 100.1% oldSize + 12 bytes, but we
+ should be able to overshoot by more to be safe */
+#endif
+ hdr = GNUNET_malloc (dlen + sizeof (struct GNUNET_MessageHeader));
+ hdr->size = htons ((uint16_t) dlen + sizeof (struct GNUNET_MessageHeader));
+ tmp = (char*) &hdr[1];
+ if ( (Z_OK != compress2 ((Bytef *) tmp,
+ &dlen, (const Bytef *) my_type_map, sizeof (my_type_map), 9)) ||
+ (dlen >= sizeof(my_type_map)) )
+ {
+ dlen = sizeof (my_type_map);
+ memcpy (tmp, my_type_map, sizeof (my_type_map));
+ hdr->type = htons (GNUNET_MESSAGE_TYPE_CORE_BINARY_TYPE_MAP);
+ }
+ else
+ {
+ hdr->type = htons (GNUNET_MESSAGE_TYPE_CORE_COMPRESSED_TYPE_MAP);
+ }
+ return hdr;
+}
+
+
+/**
+ * Send a type map message to the neighbour.
+ *
+ * @param cls the type map message
+ * @param key neighbour's identity
+ * @param value 'struct Neighbour' of the target
+ * @return always GNUNET_OK
+ */
+static int
+send_type_map_to_neighbour (void *cls,
+ const GNUNET_HashCode *key,
+ void *value)
+{
+ struct GNUNET_MessageHeader *hdr = cls;
+ struct Neighbour *n = value;
+ struct MessageEntry *m;
+ uint16_t size;
+
+ if (n == &self)
+ return GNUNET_OK;
+ size = ntohs (hdr->size);
+ m = GNUNET_malloc (sizeof (struct MessageEntry) + size);
+ memcpy (&m[1], hdr, size);
+ m->deadline = GNUNET_TIME_UNIT_FOREVER_ABS;
+ m->slack_deadline = GNUNET_TIME_UNIT_FOREVER_ABS;
+ m->priority = UINT_MAX;
+ m->sender_status = n->status;
+ m->size = size;
+ m->next = n->messages;
+ n->messages = m;
+ return GNUNET_OK;
+}
+
+
+
+/**
+ * Send my type map to all connected peers (it got changed).
+ */
+static void
+broadcast_my_type_map ()
+{
+ struct GNUNET_MessageHeader *hdr;
+
+ hdr = compute_type_map_message ();
+ GNUNET_CONTAINER_multihashmap_iterate (neighbours,
+ &send_type_map_to_neighbour,
+ hdr);
+ GNUNET_free (hdr);
+}
+
+
/**
* Handle CORE_SEND_REQUEST message.
*/
c->types = (const uint16_t *) &c[1];
wtypes = (uint16_t *) &c[1];
for (i=0;i<c->tcnt;i++)
- wtypes[i] = ntohs (types[i]);
+ {
+ wtypes[i] = ntohs (types[i]);
+ my_type_map[wtypes[i]/32] |= (1 << (wtypes[i] % 32));
+ }
+ if (c->tcnt > 0)
+ broadcast_my_type_map ();
c->options = ntohl (im->options);
#if DEBUG_CORE_CLIENT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
{
struct Client *pos;
struct Client *prev;
+ unsigned int i;
+ const uint16_t *wtypes;
if (client == NULL)
return;
GNUNET_CONTAINER_multihashmap_destroy (pos->requests);
}
GNUNET_free (pos);
+
+ /* rebuild my_type_map */
+ memset (my_type_map, 0, sizeof (my_type_map));
+ for (pos = clients; NULL != pos; pos = pos->next)
+ {
+ wtypes = (const uint16_t *) &pos[1];
+ for (i=0;i<pos->tcnt;i++)
+ my_type_map[wtypes[i]/32] |= (1 << (wtypes[i] % 32));
+ }
+ broadcast_my_type_map ();
}
GNUNET_TIME_UNIT_FOREVER_REL);
}
+
/**
- * Handle CORE_ITERATE_PEERS request. Notify client about existing neighbours.
+ * Handle CORE_PEER_CONNECTED request. Notify client about existing neighbours.
*
* @param cls unused
* @param client client sending the iteration request
1,
GNUNET_NO);
n->status = PEER_STATE_KEY_CONFIRMED;
+ {
+ struct GNUNET_MessageHeader *hdr;
+
+ hdr = compute_type_map_message ();
+ send_type_map_to_neighbour (hdr, &n->peer.hashPubKey, n);
+ GNUNET_free (hdr);
+ }
if (n->bw_out_external_limit.value__ != t.inbound_bw_limit.value__)
{
n->bw_out_external_limit = t.inbound_bw_limit;
buf,
msize,
GNUNET_NO);
+ if ( (GNUNET_MESSAGE_TYPE_CORE_BINARY_TYPE_MAP == type) ||
+ (GNUNET_MESSAGE_TYPE_CORE_COMPRESSED_TYPE_MAP == type) )
+ {
+ /* FIXME: update message type map for 'Neighbour' */
+ return;
+ }
dropped = GNUNET_YES;
cpos = clients;
while (cpos != NULL)
GNUNET_assert (NULL != transport);
stats = GNUNET_STATISTICS_create ("core", cfg);
- GNUNET_STATISTICS_set (stats, gettext_noop ("# discarded CORE_SEND requests"), 0, GNUNET_NO);
- GNUNET_STATISTICS_set (stats, gettext_noop ("# discarded lower priority CORE_SEND requests"), 0, GNUNET_NO);
+ GNUNET_STATISTICS_set (stats,
+ gettext_noop ("# discarded CORE_SEND requests"),
+ 0, GNUNET_NO);
+ GNUNET_STATISTICS_set (stats,
+ gettext_noop ("# discarded lower priority CORE_SEND requests"),
+ 0, GNUNET_NO);
mst = GNUNET_SERVER_mst_create (&deliver_message,
NULL);