+/**
+ * We're ready to transmit the request that the transport service
+ * should connect to a new peer. In addition to sending the
+ * request, schedule the next phase for the transmission processing
+ * that caused the connect request in the first place.
+ */
+static size_t
+request_connect (void *cls, size_t size, void *buf)
+{
+ struct GNUNET_TRANSPORT_TransmitHandle *th = cls;
+ struct TryConnectMessage *tcm;
+ struct GNUNET_TRANSPORT_Handle *h;
+
+ GNUNET_assert (th->notify_delay_task == GNUNET_SCHEDULER_NO_TASK);
+ h = th->handle;
+ if (buf == NULL)
+ {
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Failed to transmit `%s' request for `%4s' to service.\n",
+ "TRY_CONNECT",
+ GNUNET_i2s(&th->target));
+#endif
+ if (th->notify_delay_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (h->sched, th->notify_delay_task);
+ th->notify_delay_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ th->notify (th->notify_cls, 0, NULL);
+ GNUNET_free (th);
+ return 0;
+ }
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Transmitting `%s' message for `%4s'.\n",
+ "TRY_CONNECT", GNUNET_i2s (&th->target));
+#endif
+ GNUNET_assert (size >= sizeof (struct TryConnectMessage));
+ tcm = buf;
+ tcm->header.size = htons (sizeof (struct TryConnectMessage));
+ tcm->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TRY_CONNECT);
+ tcm->reserved = htonl (0);
+ memcpy (&tcm->peer, &th->target, sizeof (struct GNUNET_PeerIdentity));
+ th->notify_delay_task
+ = GNUNET_SCHEDULER_add_delayed (h->sched,
+ GNUNET_NO,
+ GNUNET_SCHEDULER_PRIORITY_KEEP,
+ GNUNET_SCHEDULER_NO_TASK,
+ GNUNET_TIME_absolute_get_remaining
+ (th->timeout),
+ &peer_transmit_timeout, th);
+ insert_transmit_handle (&h->connect_wait_head, th);
+ return sizeof (struct TryConnectMessage);
+}
+
+
+/**
+ * Schedule a request to connect to the given
+ * neighbour (and if successful, add the specified
+ * handle to the wait list).
+ *
+ * @param th handle for a request to transmit once we
+ * have connected
+ */
+static void
+try_connect (struct GNUNET_TRANSPORT_TransmitHandle *th)
+{
+ GNUNET_assert (th->notify_delay_task == GNUNET_SCHEDULER_NO_TASK);
+ schedule_control_transmit (th->handle,
+ sizeof (struct TryConnectMessage),
+ GNUNET_NO,
+ GNUNET_TIME_absolute_get_remaining (th->timeout),
+ &request_connect, th);
+}
+
+
+/**
+ * Task for delayed attempts to reconnect to a peer.
+ *
+ * @param cls must be a transmit handle that determines the peer
+ * to which we will try to connect
+ * @param tc scheduler information about why we were triggered (not used)
+ */
+static void
+try_connect_task (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct GNUNET_TRANSPORT_TransmitHandle *th = cls;
+
+ th->notify_delay_task = GNUNET_SCHEDULER_NO_TASK;
+ try_connect (th);
+}
+
+
+/**
+ * Remove neighbour from our list. Will automatically
+ * trigger a re-connect attempt if we have messages pending
+ * for this peer.
+ *
+ * @param h our state
+ * @param peer the peer to remove
+ */
+static void
+remove_neighbour (struct GNUNET_TRANSPORT_Handle *h,
+ const struct GNUNET_PeerIdentity *peer)
+{
+ struct NeighbourList *prev;
+ struct NeighbourList *pos;
+ struct GNUNET_TRANSPORT_TransmitHandle *th;
+
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Removing neighbour `%s' from list of connected peers.\n",
+ GNUNET_i2s (peer));
+#endif
+ prev = NULL;
+ pos = h->neighbours;
+ while ((pos != NULL) &&
+ (0 != memcmp (peer,
+ &pos->id,
+ sizeof (struct GNUNET_PeerIdentity))))
+ {
+ prev = pos;
+ pos = pos->next;
+ }
+ if (pos == NULL)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ if (prev == NULL)
+ h->neighbours = pos->next;
+ else
+ prev->next = pos->next;
+ if (NULL != (th = pos->transmit_handle))
+ {
+ pos->transmit_handle = NULL;
+ th->neighbour = NULL;
+ remove_from_any_list (th);
+ if (GNUNET_TIME_absolute_get_remaining (th->timeout).value <= CONNECT_RETRY_TIMEOUT.value)
+ {
+ /* signal error */
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == th->notify_delay_task);
+ peer_transmit_timeout (th, NULL);
+ }
+ else
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("Connection with `%4s' failed, will keep trying for %llu ms to deliver message\n"),
+ GNUNET_i2s (peer),
+ GNUNET_TIME_absolute_get_remaining (th->timeout).value);
+ /* try again in a bit */
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == th->notify_delay_task);
+ th->notify_delay_task
+ = GNUNET_SCHEDULER_add_delayed (h->sched,
+ GNUNET_NO,
+ GNUNET_SCHEDULER_PRIORITY_KEEP,
+ GNUNET_SCHEDULER_NO_TASK,
+ CONNECT_RETRY_TIMEOUT,
+ &try_connect_task,
+ th);
+ }
+ }
+ if (h->nc_cb != NULL)
+ h->nd_cb (h->cls, peer);
+ GNUNET_free (pos);
+}
+
+