about summary refs log tree commit diff
path: root/shared/n-dhcp4/src/n-dhcp4-client.c
diff options
context:
space:
mode:
Diffstat (limited to 'shared/n-dhcp4/src/n-dhcp4-client.c')
-rw-r--r--shared/n-dhcp4/src/n-dhcp4-client.c42
1 files changed, 38 insertions, 4 deletions
diff --git a/shared/n-dhcp4/src/n-dhcp4-client.c b/shared/n-dhcp4/src/n-dhcp4-client.c
index 5f7794fb..0bfe48ee 100644
--- a/shared/n-dhcp4/src/n-dhcp4-client.c
+++ b/shared/n-dhcp4/src/n-dhcp4-client.c
@@ -94,6 +94,9 @@ int n_dhcp4_client_config_dup(NDhcp4ClientConfig *config, NDhcp4ClientConfig **d
         dup->n_mac = config->n_mac;
         memcpy(dup->broadcast_mac, config->broadcast_mac, sizeof(dup->broadcast_mac));
         dup->n_broadcast_mac = config->n_broadcast_mac;
+        dup->log.level = config->log.level;
+        dup->log.func = config->log.func;
+        dup->log.data = config->log.data;
 
         r = n_dhcp4_client_config_set_client_id(dup,
                                                 config->client_id,
@@ -248,6 +251,15 @@ _c_public_ int n_dhcp4_client_config_set_client_id(NDhcp4ClientConfig *config, c
         return 0;
 }
 
+_c_public_ void n_dhcp4_client_config_set_log_level(NDhcp4ClientConfig *config, int level) {
+        config->log.level = level;
+}
+
+_c_public_ void n_dhcp4_client_config_set_log_func(NDhcp4ClientConfig *config, NDhcp4LogFunc func, void *data) {
+        config->log.func = func;
+        config->log.data = data;
+}
+
 /**
  * n_dhcp4_c_event_node_new() - allocate new event
  * @nodep:                      output argument for new event
@@ -376,8 +388,14 @@ _c_public_ int n_dhcp4_client_new(NDhcp4Client **clientp, NDhcp4ClientConfig *co
                 return -errno;
 
         client->fd_timer = timerfd_create(CLOCK_BOOTTIME, TFD_CLOEXEC | TFD_NONBLOCK);
-        if (client->fd_timer < 0)
-                return -errno;
+        if (client->fd_timer < 0) {
+                if (errno != EINVAL)
+                        return -errno;
+                client->fd_timer = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
+                if (client->fd_timer < 0)
+                        return -errno;
+                client->timerfd_is_monotonic = true;
+        }
 
         ev.data.u32 = N_DHCP4_CLIENT_EPOLL_TIMER;
         r = epoll_ctl(client->fd_epoll, EPOLL_CTL_ADD, client->fd_timer, &ev);
@@ -487,8 +505,24 @@ void n_dhcp4_client_arm_timer(NDhcp4Client *client) {
                 n_dhcp4_client_probe_get_timeout(client->current_probe, &timeout);
 
         if (timeout != client->scheduled_timeout) {
+                uint64_t scheduled_timeout = timeout;
+                int flags = TFD_TIMER_ABSTIME;
+
+                if (   timeout != 0
+                    && client->timerfd_is_monotonic) {
+                        uint64_t now;
+
+                        /* the timerfd ticks with CLOCK_MONOTONIC. Calculate and set the relative
+                         * timeout. */
+                        now = n_dhcp4_gettime(CLOCK_BOOTTIME);
+                        if (timeout <= now)
+                                timeout = 1;
+                        else
+                                timeout = timeout - now;
+                        flags = 0;
+                }
                 r = timerfd_settime(client->fd_timer,
-                                    TFD_TIMER_ABSTIME,
+                                    flags,
                                     &(struct itimerspec){
                                         .it_value = {
                                                 .tv_sec = timeout / UINT64_C(1000000000),
@@ -498,7 +532,7 @@ void n_dhcp4_client_arm_timer(NDhcp4Client *client) {
                                     NULL);
                 c_assert(r >= 0);
 
-                client->scheduled_timeout = timeout;
+                client->scheduled_timeout = scheduled_timeout;
         }
 }