// Event Loop
sd_event* loop;
+
+ // Connection Timer and Holdoff Time
+ sd_event_source* connect_timer;
+ unsigned int reconnect_holdoff;
};
static int pakfire_daemon_terminate(sd_event_source* source,
return sd_event_exit(sd_event_source_get_event(source), 0);
}
+/*
+ Called when a new job has been received
+*/
+static int pakfire_daemon_job(struct pakfire_daemon* daemon, json_object* m) {
+ return 0;
+}
+
+static int pakfire_daemon_recv(struct pakfire_xfer* xfer,
+ const char* message, const size_t size, void* data) {
+ struct pakfire_daemon* daemon = data;
+ struct json_object* type = NULL;
+ struct json_object* m = NULL;
+ int r;
+
+ // Reset the holdoff timer
+ daemon->reconnect_holdoff = 1000000;
+
+ // Parse the JSON message
+ m = pakfire_json_parse(daemon->ctx, message, size);
+ if (!m) {
+ r = -errno;
+ goto ERROR;
+ }
+
+ // Fetch the message type
+ if (!json_object_object_get_ex(m, "type", &type)) {
+ CTX_ERROR(daemon->ctx, "Invalid message with missing type\n");
+
+ return -EINVAL;
+ }
+
+ // Fetch the type
+ const char* t = json_object_get_string(type);
+
+ // Handle new jobs
+ if (strcmp(t, "job") == 0) {
+ r = pakfire_daemon_job(daemon, m);
+
+ } else {
+ CTX_ERROR(daemon->ctx, "Unknown message. Ignoring:\n%s\n",
+ json_object_to_json_string_ext(m, JSON_C_TO_STRING_SPACED | JSON_C_TO_STRING_PRETTY));
+
+ r = 0;
+ }
+
+ERROR:
+ if (m)
+ json_object_put(m);
+
+ return r;
+}
+
+/*
+ This function is called whenever the connection to the build service could not
+ be established or was interrupted. It will try to reconnect.
+*/
+static int pakfire_daemon_close(struct pakfire_xfer* xfer, int code, void* data) {
+ struct pakfire_daemon* daemon = data;
+ int r;
+
+ CTX_INFO(daemon->ctx, "Will attempt to reconnect in %u second(s)\n",
+ daemon->reconnect_holdoff / 1000000);
+
+ // Set the reconnection timer
+ r = sd_event_source_set_time_relative(daemon->connect_timer, daemon->reconnect_holdoff);
+ if (r < 0) {
+ CTX_ERROR(daemon->ctx, "Could not set the reconnection timer: %s\n", strerror(-r));
+ return r;
+ }
+
+ // Activate the timer
+ r = sd_event_source_set_enabled(daemon->connect_timer, SD_EVENT_ONESHOT);
+ if (r < 0) {
+ CTX_ERROR(daemon->ctx, "Could not activate the connect timer: %s\n", strerror(-r));
+ return r;
+ }
+
+ // Double the holdoff time
+ daemon->reconnect_holdoff *= 2;
+
+ // Cap reconnection attempts to every minute
+ if (daemon->reconnect_holdoff > 60000000)
+ daemon->reconnect_holdoff = 60000000;
+
+ return 0;
+}
+
+static int pakfire_daemon_connect(sd_event_source* s, uint64_t usec, void* data) {
+ struct pakfire_daemon* daemon = data;
+ int r;
+
+ CTX_INFO(daemon->ctx, "Connecting...\n");
+
+ // Connect to the build service
+ r = pakfire_buildservice_daemon(daemon->service,
+ pakfire_daemon_recv, NULL, pakfire_daemon_close, daemon);
+ if (r)
+ CTX_ERROR(daemon->ctx, "Connection attempt failed\n");
+
+ return r;
+}
+
static int pakfire_daemon_setup_loop(struct pakfire_daemon* daemon) {
int r;
r = sd_event_default(&daemon->loop);
if (r < 0) {
CTX_ERROR(daemon->ctx, "Could not setup event loop: %s\n", strerror(-r));
- return 1;
+ return r;
}
// Enable the watchdog
r = sd_event_set_watchdog(daemon->loop, 1);
if (r < 0) {
CTX_ERROR(daemon->ctx, "Could not activate watchdog: %s\n", strerror(-r));
- return 1;
+ return r;
}
// Listen for SIGTERM
pakfire_daemon_terminate, daemon);
if (r < 0) {
CTX_ERROR(daemon->ctx, "Could not register handling SIGTERM: %s\n", strerror(-r));
- return 1;
+ return r;
}
// Listen for SIGINT
pakfire_daemon_terminate, daemon);
if (r < 0) {
CTX_ERROR(daemon->ctx, "Could not register handling SIGINT: %s\n", strerror(-r));
- return 1;
+ return r;
+ }
+
+ // Setup the reconnection timer
+ r = sd_event_add_time_relative(daemon->loop, &daemon->connect_timer,
+ CLOCK_MONOTONIC, 0, 0, pakfire_daemon_connect, daemon);
+ if (r < 0) {
+ CTX_ERROR(daemon->ctx, "Could not register the connection timer: %s\n", strerror(-r));
+ return r;
}
return 0;
}
static void pakfire_daemon_free(struct pakfire_daemon* daemon) {
+ if (daemon->connect_timer)
+ sd_event_source_unref(daemon->connect_timer);
if (daemon->service)
pakfire_buildservice_unref(daemon->service);
if (daemon->loop)
if (r)
goto ERROR;
+ // Reconnect after one second
+ d->reconnect_holdoff = 1000000;
+
// Return the pointer
*daemon = d;
return NULL;
}
-/*
- Called when a new job has been received
-*/
-static int pakfire_daemon_job(struct pakfire_daemon* daemon, json_object* m) {
- return 0;
-}
-
-static int pakfire_daemon_recv(struct pakfire_xfer* xfer,
- const char* message, const size_t size, void* data) {
- struct pakfire_daemon* daemon = data;
- struct json_object* type = NULL;
- struct json_object* m = NULL;
- int r;
-
- // Parse the JSON message
- m = pakfire_json_parse(daemon->ctx, message, size);
- if (!m) {
- r = -errno;
- goto ERROR;
- }
-
- // Fetch the message type
- if (!json_object_object_get_ex(m, "type", &type)) {
- CTX_ERROR(daemon->ctx, "Invalid message with missing type\n");
-
- return -EINVAL;
- }
-
- // Fetch the type
- const char* t = json_object_get_string(type);
-
- // Handle new jobs
- if (strcmp(t, "job") == 0) {
- r = pakfire_daemon_job(daemon, m);
-
- } else {
- CTX_ERROR(daemon->ctx, "Unknown message. Ignoring:\n%s\n",
- json_object_to_json_string_ext(m, JSON_C_TO_STRING_SPACED | JSON_C_TO_STRING_PRETTY));
-
- r = 0;
- }
-
-ERROR:
- if (m)
- json_object_put(m);
-
- return r;
-}
-
static int pakfire_daemon_loop(struct pakfire_daemon* daemon) {
int r;
}
int pakfire_daemon_main(struct pakfire_daemon* daemon) {
- int r;
-
- // Connect to the build service
- r = pakfire_buildservice_daemon(daemon->service,
- pakfire_daemon_recv, NULL, NULL, daemon);
- if (r)
- return r;
-
return pakfire_daemon_loop(daemon);
}