+ tunnel_change_state (t, MESH_TUNNEL_WAITING);
+}
+
+
+/**
+ * Build an ACK message and queue it to send to the given peer.
+ *
+ * @param t Tunnel on which to send the ACK.
+ * @param peer Peer to whom send the ACK.
+ * @param ack Value of the ACK.
+ */
+static void
+send_ack (struct MeshTunnel *t, GNUNET_PEER_Id peer, uint32_t ack)
+{
+ struct GNUNET_MESH_ACK msg;
+
+ GNUNET_PEER_resolve (t->id.oid, &msg.oid);
+ msg.header.size = htons (sizeof (msg));
+ msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_ACK);
+ msg.pid = htonl (ack);
+ msg.tid = htonl (t->id.tid);
+
+ send_prebuilt_message (&msg.header, peer, t);
+}
+
+
+/**
+ * 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 path packet to a peer.
+ *
+ * @param cls closure
+ * @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_path_create (void *cls, size_t size, void *buf)
+{
+ struct MeshTunnel *t = cls;
+ struct GNUNET_MESH_CreateTunnel *msg;
+ struct GNUNET_PeerIdentity *peer_ptr;
+ struct MeshPeerPath *p = t->path;
+ size_t size_needed;
+ uint32_t opt;
+ int i;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "CREATE PATH sending...\n");
+ size_needed =
+ sizeof (struct GNUNET_MESH_CreateTunnel) +
+ p->length * sizeof (struct GNUNET_PeerIdentity);
+
+ if (size < size_needed || NULL == buf)
+ {
+ GNUNET_break (0);
+ return 0;
+ }
+ msg = (struct GNUNET_MESH_CreateTunnel *) buf;
+ msg->header.size = htons (size_needed);
+ msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_PATH_CREATE);
+ msg->tid = ntohl (t->id.tid);
+
+ opt = 0;
+ if (GNUNET_YES == t->nobuffer)
+ opt |= GNUNET_MESH_OPTION_NOBUFFER;
+ if (GNUNET_YES == t->reliable)
+ opt |= GNUNET_MESH_OPTION_RELIABLE;
+ msg->opt = htonl (opt);
+ msg->port = htonl (t->port);
+
+ peer_ptr = (struct GNUNET_PeerIdentity *) &msg[1];
+ for (i = 0; i < p->length; i++)
+ {
+ GNUNET_PEER_resolve (p->peers[i], peer_ptr++);
+ }
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "CREATE PATH (%u bytes long) sent!\n", size_needed);
+ return size_needed;
+}
+
+
+/**
+ * Creates a path ack message in buf and frees all unused resources.
+ *
+ * @param cls closure (MeshTransmissionDescriptor)
+ * @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_path_ack (void *cls, size_t size, void *buf)
+{
+ struct MeshTunnel *t = cls;
+ struct GNUNET_MESH_PathACK *msg = buf;
+
+ GNUNET_assert (NULL != t);
+ if (sizeof (struct GNUNET_MESH_PathACK) > size)
+ {
+ GNUNET_break (0);
+ return 0;
+ }
+ t->prev_fc.last_ack_sent = t->nobuffer ? 0 : t->queue_max - 1;
+ msg->header.size = htons (sizeof (struct GNUNET_MESH_PathACK));
+ msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_PATH_ACK);
+ GNUNET_PEER_resolve (t->id.oid, &msg->oid);
+ msg->tid = htonl (t->id.tid);
+ msg->peer_id = my_full_id;
+ msg->ack = htonl (t->prev_fc.last_ack_sent);
+
+ /* TODO add signature */
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "PATH ACK sent!\n");
+ return sizeof (struct GNUNET_MESH_PathACK);
+}
+
+
+/**
+ * Iterator over all the peers to remove the oldest not-used entry.
+ *
+ * @param cls Closure (unsued).
+ * @param key ID of the peer.
+ * @param value Peer_Info of the peer.
+ *
+ * FIXME implement
+ */
+static int
+peer_timeout (void *cls,
+ const struct GNUNET_PeerIdentity *key,
+ void *value)
+{
+ return GNUNET_YES;
+}
+
+
+/**
+ * Retrieve the MeshPeer stucture associated with the peer, create one
+ * and insert it in the appropriate structures if the peer is not known yet.
+ *
+ * @param peer Full identity of the peer.
+ *
+ * @return Existing or newly created peer info.
+ */
+static struct MeshPeer *
+peer_get (const struct GNUNET_PeerIdentity *peer_id)
+{
+ struct MeshPeer *peer;
+
+ peer = GNUNET_CONTAINER_multipeermap_get (peers, peer_id);
+ if (NULL == peer)
+ {
+ peer = GNUNET_new (struct MeshPeer);
+ if (GNUNET_CONTAINER_multipeermap_size (peers) > max_peers)
+ {
+ GNUNET_CONTAINER_multipeermap_iterate (peers,
+ &peer_timeout,
+ NULL);
+ }
+ GNUNET_CONTAINER_multipeermap_put (peers, peer_id, peer,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
+ peer->id = GNUNET_PEER_intern (peer_id);
+ }
+ peer->last_contact = GNUNET_TIME_absolute_get();
+
+ return peer;
+}
+
+
+/**
+ * Retrieve the MeshPeer stucture associated with the peer, create one
+ * and insert it in the appropriate structures if the peer is not known yet.
+ *
+ * @param peer Short identity of the peer.
+ *
+ * @return Existing or newly created peer info.
+ */
+static struct MeshPeer *
+peer_get_short (const GNUNET_PEER_Id peer)
+{
+ return peer_get (GNUNET_PEER_resolve2 (peer));
+}
+
+
+/**
+ * Select which PID to POLL for, to compensate for lost messages.
+ *
+ * @param pi Peer we want to poll.
+ * @param t Tunnel about which we want to poll.
+ *
+ * @return PID to use, either last sent or first_in_queue - 1
+ */
+static uint32_t
+peer_get_first_payload_pid (struct MeshPeer *p, struct MeshTunnel *t)
+{
+ struct MeshPeerQueue *q;
+ uint16_t type;
+
+ type = p->id == t->next_hop ? GNUNET_MESSAGE_TYPE_MESH_UNICAST :
+ GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN;
+
+ for (q = p->queue_head; NULL != q; q = q->next)
+ {
+ if (q->type == type && q->tunnel == t)
+ {
+ struct GNUNET_MESH_Data *msg = q->cls;
+
+ /* Pretend that the last one sent was the previous to this */
+ return ntohl (msg->pid) - 1;
+ }
+ }
+
+ /* No data in queue, use last sent */
+ {
+ struct MeshFlowControl *fc;
+
+ fc = p->id == t->next_hop ? &t->next_fc : &t->prev_fc;
+ return fc->last_pid_sent;
+ }
+}
+
+
+/**
+ * Choose the best path towards a peer considering the tunnel properties.
+ *
+ * @param peer The destination peer.
+ * @param t The tunnel the path is for.
+ *
+ * @return Best current known path towards the peer, if any.
+ */
+static struct MeshPeerPath *
+peer_get_best_path (const struct MeshPeer *peer, const struct MeshTunnel *t)
+{
+ struct MeshPeerPath *best_p;
+ struct MeshPeerPath *p;
+ unsigned int best_cost;
+ unsigned int cost;
+
+ best_p = p = peer->path_head;
+ best_cost = cost = p->length;
+ while (NULL != p)
+ {
+ if ((cost = p->length) < best_cost)
+ {
+ best_cost = cost;
+ best_p = p;
+ }
+ p = p->next;
+ }
+ return best_p;