+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
+ (GNUNET_TIME_UNIT_MILLISECONDS, 100),
+ &internal_continue_startup,
+ internal_context);
+ }
+}
+
+
+/**
+ * Callback for informing us about a successful
+ * or unsuccessful churn start call.
+ *
+ * @param cls a ChurnContext
+ * @param id the peer identity of the started peer
+ * @param cfg the handle to the configuration of the peer
+ * @param d handle to the daemon for the peer
+ * @param emsg NULL on success, non-NULL on failure
+ *
+ */
+void
+churn_start_callback (void *cls,
+ const struct GNUNET_PeerIdentity *id,
+ const struct GNUNET_CONFIGURATION_Handle *cfg,
+ struct GNUNET_TESTING_Daemon *d, const char *emsg)
+{
+ struct ChurnRestartContext *startup_ctx = cls;
+ struct ChurnContext *churn_ctx = startup_ctx->churn_ctx;
+
+ unsigned int total_left;
+ char *error_message;
+
+ error_message = NULL;
+ if (emsg != NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Churn stop callback failed with error `%s'\n", emsg);
+ churn_ctx->num_failed_start++;
+ }
+ else
+ {
+ churn_ctx->num_to_start--;
+ }
+
+#if DEBUG_CHURN
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Started peer, %d left.\n", churn_ctx->num_to_start);
+#endif
+
+ total_left =
+ (churn_ctx->num_to_stop - churn_ctx->num_failed_stop) +
+ (churn_ctx->num_to_start - churn_ctx->num_failed_start);
+
+ if (total_left == 0)
+ {
+ if ((churn_ctx->num_failed_stop > 0)
+ || (churn_ctx->num_failed_start > 0))
+ GNUNET_asprintf (&error_message,
+ "Churn didn't complete successfully, %u peers failed to start %u peers failed to be stopped!",
+ churn_ctx->num_failed_start,
+ churn_ctx->num_failed_stop);
+ churn_ctx->cb (churn_ctx->cb_cls, error_message);
+ GNUNET_free_non_null (error_message);
+ GNUNET_free (churn_ctx);
+ GNUNET_free (startup_ctx);
+ }
+}
+
+
+static void
+schedule_churn_restart (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct PeerRestartContext *peer_restart_ctx = cls;
+ struct ChurnRestartContext *startup_ctx =
+ peer_restart_ctx->churn_restart_ctx;
+
+ if (startup_ctx->outstanding > MAX_CONCURRENT_STARTING)
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
+ (GNUNET_TIME_UNIT_MILLISECONDS, 100),
+ &schedule_churn_restart, peer_restart_ctx);
+ else
+ {
+ GNUNET_TESTING_daemon_start_stopped (peer_restart_ctx->daemon,
+ startup_ctx->timeout,
+ &churn_start_callback,
+ startup_ctx);
+ GNUNET_free (peer_restart_ctx);