#endif /* ENABLE_CAP_NG */
}
-static void check_loaded(server_t *server)
+static int check_loaded(server_t *server, bool async)
{
- static bool finished = false;
- if (finished) {
- return;
+ /*
+ * Started: all zones loaded or at least tried to load at least once,
+ * the server is already running and accepting queries.
+ * Loaded: all zones successfully loaded, it implies 'started',
+ * KNOT_BUS_EVENT_STARTED already emitted over DBus.
+ */
+ static bool started = false;
+ static bool loaded = false;
+ assert(server->state & ServerRunning);
+ if (loaded) {
+ assert(server->state & ServerAnswering);
+ return KNOT_EOK;
}
/* Avoid traversing the zonedb too frequently. */
static struct timespec last = { 0 };
struct timespec now = time_now();
if (last.tv_sec == now.tv_sec) {
- return;
+ return KNOT_EOK;
}
last = now;
- if (!(conf()->cache.srv_dbus_event & DBUS_EVENT_RUNNING)) {
- finished = true;
- return;
- }
-
+ started = started || async;
+ bool start = true;
+ bool load = true;
rcu_read_lock();
knot_zonedb_iter_t *it = knot_zonedb_iter_begin(server->zone_db);
while (!knot_zonedb_iter_finished(it)) {
zone_t *zone = (zone_t *)knot_zonedb_iter_val(it);
- if (zone->contents == NULL) {
- knot_zonedb_iter_free(it);
- rcu_read_unlock();
- return;
+ if (zone->contents != NULL) {
+ knot_zonedb_iter_next(it);
+ continue;
}
+ load = false;
+ if (started) {
+ break;
+ } else if (!zone->started) {
+ start = false;
+ break;
+ }
+
knot_zonedb_iter_next(it);
}
knot_zonedb_iter_free(it);
rcu_read_unlock();
- finished = true;
- dbus_emit_running(true);
+ if (!start) {
+ return KNOT_EOK;
+ }
+ if (!started) {
+ int ret = server_start_answering(server);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ started = true;
+ }
+
+ assert(server->state & ServerAnswering);
+ if (!(conf()->cache.srv_dbus_event & DBUS_EVENT_RUNNING)) {
+ loaded = true;
+ return KNOT_EOK;
+ }
+
+ if (load) { /* Not 'loaded' yet. */
+ dbus_emit_running(true);
+ loaded = true;
+ }
+
+ return KNOT_EOK;
}
static void deinit_ctls(knot_ctl_t **ctls, unsigned count)
}
/*! \brief Event loop listening for signals and remote commands. */
-static void event_loop(server_t *server, const char *socket, bool daemonize,
- unsigned long pid)
+static int event_loop(server_t *server, const char *socket, bool daemonize,
+ unsigned long pid, bool async)
{
knot_ctl_t **ctls = init_ctls(socket);
if (ctls == NULL) {
- return;
+ return KNOT_ERROR;
}
conf_val_t listen_val = conf_get(conf(), C_CTL, C_LISTEN);
if (ret != KNOT_EOK) {
log_fatal("control, failed to launch socket threads (%s)",
knot_strerror(ret));
- return;
+ return ret;
}
signals_enable();
continue;
}
- check_loaded(server);
+ ret = check_loaded(server, async);
+ if (ret != KNOT_EOK) {
+ goto done;
+ }
sleep(5); // wait for signals to arrive
}
dbus_emit_running(false);
}
+done:
ctl_socket_thr_end(&sctx);
deinit_ctls(ctls, sock_count);
+ return ret;
}
static void print_help(void)
stats_reconfigure(conf(), &server);
/* Start it up. */
- log_info("starting server");
+ /* In async-start mode, start answering early, otherwise in the event loop. */
conf_val_t async_val = conf_get(conf(), C_SRV, C_ASYNC_START);
- ret = server_start(&server, conf_bool(&async_val));
- if (ret != KNOT_EOK) {
+ bool async = conf_bool(&async_val);
+ if ((ret = server_start(&server, async)) != KNOT_EOK ||
+ (ret = event_loop(&server, socket, daemonize, pid, async)) != KNOT_EOK) {
log_fatal("failed to start server (%s)", knot_strerror(ret));
+ server_stop(&server);
server_wait(&server);
stats_deinit();
- server_deinit(&server);
- rcu_unregister_thread();
pid_cleanup();
+ server_deinit(&server);
conf_free(conf());
+ rcu_unregister_thread();
dbus_close();
log_close();
dnssec_crypto_cleanup();
return EXIT_FAILURE;
}
- /* Start the event loop. */
- event_loop(&server, socket, daemonize, pid);
-
/* Teardown server. */
server_stop(&server);
server_wait(&server);