+ch_message_sent (void *cls,
+ struct MeshTunnel3 *t,
+ struct MeshTunnel3Queue *q,
+ uint16_t type, size_t size)
+{
+ struct MeshChannelQueue *chq = cls;
+ struct MeshReliableMessage *copy = chq->copy;
+ struct MeshChannelReliability *rel;
+
+ switch (chq->type)
+ {
+ case GNUNET_MESSAGE_TYPE_MESH_DATA:
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! SENT DATA MID %u\n", copy->mid);
+ GNUNET_assert (chq == copy->chq);
+ copy->timestamp = GNUNET_TIME_absolute_get ();
+ rel = copy->rel;
+ if (GNUNET_SCHEDULER_NO_TASK == rel->retry_task)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "!! scheduling retry in 4 * %s\n",
+ GNUNET_STRINGS_relative_time_to_string (rel->expected_delay,
+ GNUNET_YES));
+ if (0 != rel->expected_delay.rel_value_us)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "!! delay != 0\n");
+ rel->retry_timer =
+ GNUNET_TIME_relative_multiply (rel->expected_delay,
+ MESH_RETRANSMIT_MARGIN);
+ }
+ else
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "!! delay reset\n");
+ rel->retry_timer = MESH_RETRANSMIT_TIME;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "!! using delay %s\n",
+ GNUNET_STRINGS_relative_time_to_string (rel->retry_timer,
+ GNUNET_NO));
+ rel->retry_task =
+ GNUNET_SCHEDULER_add_delayed (rel->retry_timer,
+ &channel_retransmit_message, rel);
+ }
+ else
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "!! retry task %u\n", rel->retry_task);
+ }
+ copy->chq = NULL;
+ break;
+
+
+ case GNUNET_MESSAGE_TYPE_MESH_DATA_ACK:
+ case GNUNET_MESSAGE_TYPE_MESH_CHANNEL_CREATE:
+ case GNUNET_MESSAGE_TYPE_MESH_CHANNEL_ACK:
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! SENT %s\n", GM_m2s (chq->type));
+ rel = chq->rel;
+ GNUNET_assert (rel->uniq == chq);
+ rel->uniq = NULL;
+
+ if (MESH_CHANNEL_READY != rel->ch->state
+ && GNUNET_MESSAGE_TYPE_MESH_DATA_ACK != type
+ && GNUNET_NO == rel->ch->destroy)
+ {
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == rel->retry_task);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! STD BACKOFF %s\n",
+ GNUNET_STRINGS_relative_time_to_string (rel->retry_timer,
+ GNUNET_NO));
+ rel->retry_timer = GNUNET_TIME_STD_BACKOFF (rel->retry_timer);
+ rel->retry_task = GNUNET_SCHEDULER_add_delayed (rel->retry_timer,
+ &channel_recreate, rel);
+ }
+ break;
+
+
+ default:
+ GNUNET_break (0);
+ }
+
+ GNUNET_free (chq);
+}
+
+
+/**
+ * send a channel create message.
+ *
+ * @param ch Channel for which to send.
+ */
+static void
+send_create (struct MeshChannel *ch)
+{
+ struct GNUNET_MESH_ChannelCreate msgcc;
+
+ msgcc.header.size = htons (sizeof (msgcc));
+ msgcc.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_CHANNEL_CREATE);
+ msgcc.chid = htonl (ch->gid);
+ msgcc.port = htonl (ch->port);
+ msgcc.opt = htonl (channel_get_options (ch));
+
+ GMCH_send_prebuilt_message (&msgcc.header, ch, GNUNET_YES, NULL);
+}
+
+
+/**
+ * Confirm we got a channel create or FWD ack.
+ *
+ * @param ch The channel to confirm.
+ * @param fwd Should we send a FWD ACK? (going dest->root)
+ */
+static void
+send_ack (struct MeshChannel *ch, int fwd)