+/**
+ * Notify clients about disconnect and free
+ * the entry for connected peer.
+ *
+ * @param cls the 'struct GNUNET_CORE_Handle*'
+ * @param key the peer identity (not used)
+ * @param value the 'struct PeerRecord' to free.
+ * @return GNUNET_YES (continue)
+ */
+static int
+disconnect_and_free_peer_entry (void *cls,
+ const GNUNET_HashCode *key,
+ void *value)
+{
+ static struct GNUNET_BANDWIDTH_Value32NBO zero;
+ struct GNUNET_CORE_Handle *h = cls;
+ struct GNUNET_CORE_TransmitHandle *th;
+ struct PeerRecord *pr = value;
+ GNUNET_CORE_PeerConfigurationInfoCallback pcic;
+
+ while (NULL != (th = pr->pending_head))
+ {
+ GNUNET_CONTAINER_DLL_remove (pr->pending_head,
+ pr->pending_tail,
+ th);
+ pr->queue_size--;
+ GNUNET_assert (0 ==
+ th->get_message (th->get_message_cls,
+ 0, NULL));
+ GNUNET_free (th);
+ }
+ if (NULL != (pcic = pr->pcic))
+ {
+ pr->pcic = NULL;
+ pcic (pr->pcic_cls,
+ &pr->peer,
+ zero,
+ 0, 0);
+ }
+ if (pr->timeout_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (pr->timeout_task);
+ pr->timeout_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ GNUNET_assert (pr->queue_size == 0);
+ if ( (pr->prev != NULL) ||
+ (pr->next != NULL) ||
+ (h->ready_peer_head == pr) )
+ GNUNET_CONTAINER_DLL_remove (h->ready_peer_head,
+ h->ready_peer_tail,
+ pr);
+ if (h->disconnects != NULL)
+ h->disconnects (h->cls,
+ &pr->peer);
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap_remove (h->peers,
+ key,
+ pr));
+ GNUNET_assert (pr->pending_head == NULL);
+ GNUNET_assert (pr->pending_tail == NULL);
+ GNUNET_assert (pr->ch = h);
+ GNUNET_assert (pr->queue_size == 0);
+ GNUNET_assert (pr->timeout_task == GNUNET_SCHEDULER_NO_TASK);
+ GNUNET_free (pr);
+ return GNUNET_YES;
+}
+
+
+/**
+ * Close down any existing connection to the CORE service and
+ * try re-establishing it later.
+ *
+ * @param h our handle
+ */
+static void
+reconnect_later (struct GNUNET_CORE_Handle *h)
+{
+ struct ControlMessage *cm;
+ struct PeerRecord *pr;
+
+ GNUNET_assert (h->reconnect_task == GNUNET_SCHEDULER_NO_TASK);
+ if (h->client != NULL)
+ {
+ GNUNET_CLIENT_disconnect (h->client, GNUNET_NO);
+ h->client = NULL;
+ h->cth = NULL;
+ GNUNET_CONTAINER_multihashmap_iterate (h->peers,
+ &disconnect_and_free_peer_entry,
+ h);
+ }
+ while (NULL != (pr = h->ready_peer_head))
+ GNUNET_CONTAINER_DLL_remove (h->ready_peer_head,
+ h->ready_peer_tail,
+ pr);
+ h->currently_down = GNUNET_YES;
+ h->reconnect_task = GNUNET_SCHEDULER_add_delayed (h->retry_backoff,
+ &reconnect_task,
+ h);
+ while (NULL != (cm = h->control_pending_head))
+ {
+ GNUNET_CONTAINER_DLL_remove (h->control_pending_head,
+ h->control_pending_tail,
+ cm);
+ if (cm->th != NULL)
+ cm->th->cm = NULL;
+ if (cm->cont != NULL)
+ cm->cont (cm->cont_cls, GNUNET_NO);
+ GNUNET_free (cm);
+ }
+ GNUNET_assert (h->control_pending_head == NULL);
+ h->retry_backoff = GNUNET_TIME_relative_min (GNUNET_TIME_UNIT_SECONDS,
+ h->retry_backoff);
+ h->retry_backoff = GNUNET_TIME_relative_multiply (h->retry_backoff, 2);
+}
+
+