+/**
+ * Percentage of messages that will be dropped (for test purposes only).
+ */
+static unsigned long long drop_percent;
+
+/**
+ * Handle to communicate with core.
+ */
+static struct GNUNET_CORE_Handle *core_handle;
+
+
+/******************************************************************************/
+/***************************** CORE CALLBACKS *********************************/
+/******************************************************************************/
+
+
+/**
+ * Iterator to notify all connections of a broken link. Mark connections
+ * to destroy after all traffic has been sent.
+ *
+ * @param cls Closure (peer disconnected).
+ * @param key Current key code (peer id).
+ * @param value Value in the hash map (connection).
+ *
+ * @return GNUNET_YES if we should continue to iterate,
+ * GNUNET_NO if not.
+ */
+static int
+notify_broken (void *cls,
+ const struct GNUNET_HashCode *key,
+ void *value)
+{
+ struct MeshPeer *peer = cls;
+ struct MeshConnection *c = value;
+
+ GMC_notify_broken (c, peer);
+
+ return GNUNET_YES;
+}
+
+
+/**
+ * Method called whenever a given peer connects.
+ *
+ * @param cls closure
+ * @param peer peer identity this notification is about
+ */
+static void
+core_connect (void *cls, const struct GNUNET_PeerIdentity *peer)
+{
+ struct MeshPeer *mp;
+ struct MeshPeerPath *path;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Peer connected\n");
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " %s\n", GNUNET_i2s (&my_full_id));
+ mp = GMP_get (peer);
+ if (myid == mp->id)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " (self)\n");
+ path = path_new (1);
+ }
+ else
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " %s\n", GNUNET_i2s (peer));
+ path = path_new (2);
+ path->peers[1] = mp->id;
+ GNUNET_PEER_change_rc (mp->id, 1);
+ GNUNET_STATISTICS_update (stats, "# peers", 1, GNUNET_NO);
+ }
+ path->peers[0] = myid;
+ GNUNET_PEER_change_rc (myid, 1);
+ GMP_add_path (mp, path, GNUNET_YES);
+
+ mp->connections = GNUNET_CONTAINER_multihashmap_create (32, GNUNET_YES);
+ return;
+}
+
+
+/**
+ * Method called whenever a peer disconnects.
+ *
+ * @param cls closure
+ * @param peer peer identity this notification is about
+ */
+static void
+core_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
+{
+ struct MeshPeer *pi;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Peer disconnected\n");
+ pi = GNUNET_CONTAINER_multipeermap_get (peers, peer);
+ if (NULL == pi)
+ {
+ GNUNET_break (0);
+ return;
+ }
+
+ GNUNET_CONTAINER_multihashmap_iterate (pi->connections, ¬ify_broken, pi);
+ GNUNET_CONTAINER_multihashmap_destroy (pi->connections);
+ pi->connections = NULL;
+ if (NULL != pi->core_transmit)
+ {
+ GNUNET_CORE_notify_transmit_ready_cancel (pi->core_transmit);
+ pi->core_transmit = NULL;
+ }
+ if (myid == pi->id)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " (self)\n");
+ }
+ GNUNET_STATISTICS_update (stats, "# peers", -1, GNUNET_NO);
+
+ return;
+}
+
+
+/**
+ * Functions to handle messages from core
+ */
+static struct GNUNET_CORE_MessageHandler core_handlers[] = {
+ {&GMC_handle_create, GNUNET_MESSAGE_TYPE_MESH_CONNECTION_CREATE,
+ 0},
+ {&GMC_handle_confirm, GNUNET_MESSAGE_TYPE_MESH_CONNECTION_ACK,
+ sizeof (struct GNUNET_MESH_ConnectionACK)},
+ {&GMC_handle_broken, GNUNET_MESSAGE_TYPE_MESH_CONNECTION_BROKEN,
+ sizeof (struct GNUNET_MESH_ConnectionBroken)},
+ {&GMC_handle_destroy, GNUNET_MESSAGE_TYPE_MESH_CONNECTION_DESTROY,
+ sizeof (struct GNUNET_MESH_ConnectionDestroy)},
+ {&GMC_handle_keepalive, GNUNET_MESSAGE_TYPE_MESH_FWD_KEEPALIVE,
+ sizeof (struct GNUNET_MESH_ConnectionKeepAlive)},
+ {&GMC_handle_keepalive, GNUNET_MESSAGE_TYPE_MESH_BCK_KEEPALIVE,
+ sizeof (struct GNUNET_MESH_ConnectionKeepAlive)},
+ {&GMC_handle_ack, GNUNET_MESSAGE_TYPE_MESH_ACK,
+ sizeof (struct GNUNET_MESH_ACK)},
+ {&GMC_handle_poll, GNUNET_MESSAGE_TYPE_MESH_POLL,
+ sizeof (struct GNUNET_MESH_Poll)},
+ {&GMC_handle_encrypted, GNUNET_MESSAGE_TYPE_MESH_ENCRYPTED, 0},
+ {NULL, 0, 0}
+};
+
+
+/**
+ * To be called on core init/fail.
+ *
+ * @param cls Closure (config)
+ * @param identity the public identity of this peer
+ */
+static void
+core_init (void *cls,
+ const struct GNUNET_PeerIdentity *identity)
+{
+ const struct GNUNET_CONFIGURATION_Handle *c = cls;
+ static int i = 0;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Core init\n");
+ if (0 != memcmp (identity, &my_full_id, sizeof (my_full_id)))
+ {
+ LOG (GNUNET_ERROR_TYPE_ERROR, _("Wrong CORE service\n"));
+ LOG (GNUNET_ERROR_TYPE_ERROR, " core id %s\n", GNUNET_i2s (identity));
+ LOG (GNUNET_ERROR_TYPE_ERROR, " my id %s\n", GNUNET_i2s (&my_full_id));
+ GNUNET_CORE_disconnect (core_handle);
+ core_handle = GNUNET_CORE_connect (c, /* Main configuration */
+ NULL, /* Closure passed to MESH functions */
+ &core_init, /* Call core_init once connected */
+ &core_connect, /* Handle connects */
+ &core_disconnect, /* remove peers on disconnects */
+ NULL, /* Don't notify about all incoming messages */
+ GNUNET_NO, /* For header only in notification */
+ NULL, /* Don't notify about all outbound messages */
+ GNUNET_NO, /* For header-only out notification */
+ core_handlers); /* Register these handlers */
+ if (10 < i++)
+ GNUNET_abort();
+ }
+ GML_start ();
+ return;
+}
+
+/**
+ * Core callback to write a pre-constructed data packet to core buffer
+ *
+ * @param cls Closure (MeshTransmissionDescriptor with data in "data" member).
+ * @param size Number of bytes available in buf.
+ * @param buf Where the to write the message.
+ *
+ * @return number of bytes written to buf
+ */
+static size_t
+send_core_data_raw (void *cls, size_t size, void *buf)
+{
+ struct GNUNET_MessageHeader *msg = cls;
+ size_t total_size;
+
+ GNUNET_assert (NULL != msg);
+ total_size = ntohs (msg->size);
+
+ if (total_size > size)
+ {
+ GNUNET_break (0);
+ return 0;
+ }
+ memcpy (buf, msg, total_size);
+ GNUNET_free (cls);
+ return total_size;
+}
+
+
+/**
+ * Function to send a create connection message to a peer.
+ *
+ * @param c Connection to create.
+ * @param size number of bytes available in buf
+ * @param buf where the callee should write the message
+ * @return number of bytes written to buf
+ */
+static size_t
+send_core_connection_create (struct MeshConnection *c, size_t size, void *buf)
+{
+ struct GNUNET_MESH_ConnectionCreate *msg;
+ struct GNUNET_PeerIdentity *peer_ptr;
+ const struct MeshPeerPath *p = GMC_get_path (c);
+ size_t size_needed;
+ int i;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending CONNECTION CREATE...\n");
+ size_needed =
+ sizeof (struct GNUNET_MESH_ConnectionCreate) +
+ p->length * sizeof (struct GNUNET_PeerIdentity);
+
+ if (size < size_needed || NULL == buf)
+ {
+ GNUNET_break (0);
+ return 0;
+ }
+ msg = (struct GNUNET_MESH_ConnectionCreate *) buf;
+ msg->header.size = htons (size_needed);
+ msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_CONNECTION_CREATE);
+ msg->cid = *GMC_get_id (c);
+
+ peer_ptr = (struct GNUNET_PeerIdentity *) &msg[1];
+ for (i = 0; i < p->length; i++)
+ {
+ GNUNET_PEER_resolve (p->peers[i], peer_ptr++);
+ }
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "CONNECTION CREATE (%u bytes long) sent!\n",
+ size_needed);
+ return size_needed;
+}
+
+
+/**
+ * Creates a path ack message in buf and frees all unused resources.
+ *
+ * @param c Connection to send an ACK on.
+ * @param size number of bytes available in buf
+ * @param buf where the callee should write the message
+ *
+ * @return number of bytes written to buf
+ */
+static size_t
+send_core_connection_ack (struct MeshConnection *c, size_t size, void *buf)
+{
+ struct GNUNET_MESH_ConnectionACK *msg = buf;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending CONNECTION ACK...\n");
+ if (sizeof (struct GNUNET_MESH_ConnectionACK) > size)
+ {
+ GNUNET_break (0);
+ return 0;
+ }
+ msg->header.size = htons (sizeof (struct GNUNET_MESH_ConnectionACK));
+ msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_CONNECTION_ACK);
+ msg->cid = *GMC_get_id (c);
+ msg->reserved = 0;
+
+ /* TODO add signature */
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "CONNECTION ACK sent!\n");
+ return sizeof (struct GNUNET_MESH_ConnectionACK);
+}
+