예제 #1
0
static int PmonInit(sd_bus_message *m, void *userdata, sd_bus_error *retError)
{
	usec_t time = 0;
	sd_bus_message_read(m, "t", &time);
	int id = 0;
	if (openSlots == 0) {
		return sd_bus_reply_method_return(m, "u", -1);
	}

	uint64_t usec = 0;
	sd_event_now(event, CLOCK_MONOTONIC, &usec);
	usec += time;
	if (clients[lastAllocatedId] == NULL) {
		id = lastAllocatedId;

		sd_event_add_time(event, &clients[lastAllocatedId], CLOCK_MONOTONIC, usec, 1000,
					Timeout, (void *)sd_bus_message_get_sender(m));
		lastAllocatedId += 1;
		openSlots -= 1;
		clientTimeout[id] = time;
		return sd_bus_reply_method_return(m, "u", id);
	}

	id = freeIds[lastFreedSlot];

	sd_event_add_time(event, &clients[freeIds[lastFreedSlot]], CLOCK_MONOTONIC, usec, 1000,
				Timeout, (void *)sd_bus_message_get_sender(m));

	lastFreedSlot -= 1;
	openSlots -= 1;
	clientTimeout[id] = time;
	return sd_bus_reply_method_return(m, "u", id);
}
예제 #2
0
static int pppoe_arm_timeout(sd_pppoe *ppp) {
        _cleanup_event_source_unref_ sd_event_source *timeout = NULL;
        usec_t next_timeout;
        int r;

        assert(ppp);

        r = sd_event_now(ppp->event, clock_boottime_or_monotonic(), &next_timeout);
        if (r == -ENODATA)
                next_timeout = now(clock_boottime_or_monotonic());
        else if (r < 0)
                return r;

        next_timeout += 500 * USEC_PER_MSEC;

        r = sd_event_add_time(ppp->event, &timeout, clock_boottime_or_monotonic(), next_timeout,
                              10 * USEC_PER_MSEC, pppoe_timeout, ppp);
        if (r < 0)
                return r;

        r = sd_event_source_set_priority(timeout, ppp->event_priority);
        if (r < 0)
                return r;

        sd_event_source_unref(ppp->timeout);
        ppp->timeout = timeout;
        timeout = NULL;

        return 0;
}
예제 #3
0
static int curl_glue_timer_callback(CURLM *curl, long timeout_ms, void *userdata) {
        CurlGlue *g = userdata;
        usec_t usec;

        assert(curl);
        assert(g);

        if (timeout_ms < 0) {
                if (g->timer) {
                        if (sd_event_source_set_enabled(g->timer, SD_EVENT_OFF) < 0)
                                return -1;
                }

                return 0;
        }

        usec = now(clock_boottime_or_monotonic()) + (usec_t) timeout_ms * USEC_PER_MSEC + USEC_PER_MSEC - 1;

        if (g->timer) {
                if (sd_event_source_set_time(g->timer, usec) < 0)
                        return -1;

                if (sd_event_source_set_enabled(g->timer, SD_EVENT_ONESHOT) < 0)
                        return -1;
        } else {
                if (sd_event_add_time(g->event, &g->timer, clock_boottime_or_monotonic(), usec, 0, curl_glue_on_timer, g) < 0)
                        return -1;

                (void) sd_event_source_set_description(g->timer, "curl-timer");
        }

        return 0;
}
예제 #4
0
static int ipv4acd_set_next_wakeup(sd_ipv4acd *acd, usec_t usec, usec_t random_usec) {
        _cleanup_(sd_event_source_unrefp) sd_event_source *timer = NULL;
        usec_t next_timeout, time_now;
        int r;

        assert(acd);

        next_timeout = usec;

        if (random_usec > 0)
                next_timeout += (usec_t) random_u64() % random_usec;

        assert_se(sd_event_now(acd->event, clock_boottime_or_monotonic(), &time_now) >= 0);

        r = sd_event_add_time(acd->event, &timer, clock_boottime_or_monotonic(), time_now + next_timeout, 0, ipv4acd_on_timeout, acd);
        if (r < 0)
                return r;

        r = sd_event_source_set_priority(timer, acd->event_priority);
        if (r < 0)
                return r;

        (void) sd_event_source_set_description(timer, "ipv4acd-timer");

        sd_event_source_unref(acd->timer_event_source);
        acd->timer_event_source = timer;
        timer = NULL;

        return 0;
}
static int busname_arm_timer(BusName *n) {
        int r;

        assert(n);

        if (n->timeout_usec <= 0) {
                n->timer_event_source = sd_event_source_unref(n->timer_event_source);
                return 0;
        }

        if (n->timer_event_source) {
                r = sd_event_source_set_time(n->timer_event_source, now(CLOCK_MONOTONIC) + n->timeout_usec);
                if (r < 0)
                        return r;

                return sd_event_source_set_enabled(n->timer_event_source, SD_EVENT_ONESHOT);
        }

        return sd_event_add_time(
                        UNIT(n)->manager->event,
                        &n->timer_event_source,
                        CLOCK_MONOTONIC,
                        now(CLOCK_MONOTONIC) + n->timeout_usec, 0,
                        busname_dispatch_timer, n);
}
예제 #6
0
파일: busname.c 프로젝트: achanda/systemd
static int busname_arm_timer(BusName *n, usec_t usec) {
        int r;

        assert(n);

        if (n->timer_event_source) {
                r = sd_event_source_set_time(n->timer_event_source, usec);
                if (r < 0)
                        return r;

                return sd_event_source_set_enabled(n->timer_event_source, SD_EVENT_ONESHOT);
        }

        if (usec == USEC_INFINITY)
                return 0;

        r = sd_event_add_time(
                        UNIT(n)->manager->event,
                        &n->timer_event_source,
                        CLOCK_MONOTONIC,
                        usec, 0,
                        busname_dispatch_timer, n);
        if (r < 0)
                return r;

        (void) sd_event_source_set_description(n->timer_event_source, "busname-timer");

        return 0;
}
예제 #7
0
파일: scope.c 프로젝트: gergpetr/systemd
static int scope_arm_timer(Scope *s) {
        int r;

        assert(s);

        if (s->timeout_stop_usec <= 0) {
                s->timer_event_source = sd_event_source_unref(s->timer_event_source);
                return 0;
        }

        if (s->timer_event_source) {
                r = sd_event_source_set_time(s->timer_event_source, now(CLOCK_MONOTONIC) + s->timeout_stop_usec);
                if (r < 0)
                        return r;

                return sd_event_source_set_enabled(s->timer_event_source, SD_EVENT_ONESHOT);
        }

        r = sd_event_add_time(
                        UNIT(s)->manager->event,
                        &s->timer_event_source,
                        CLOCK_MONOTONIC,
                        now(CLOCK_MONOTONIC) + s->timeout_stop_usec, 0,
                        scope_dispatch_timer, s);
        if (r < 0)
                return r;

        (void) sd_event_source_set_description(s->timer_event_source, "scope-timer");

        return 0;
}
예제 #8
0
static void test_rs(sd_event *e) {
        usec_t time_now = now(CLOCK_MONOTONIC);
        sd_icmp6_nd *nd;

        if (verbose)
                printf("* %s\n", __FUNCTION__);

        assert(sd_icmp6_nd_new(&nd) >= 0);
        assert(nd);

        assert(sd_icmp6_nd_attach_event(nd, e, 0) >= 0);

        assert(sd_icmp6_nd_set_index(nd, 42) >= 0);
        assert(sd_icmp6_nd_set_mac(nd, &mac_addr) >= 0);
        assert(sd_icmp6_nd_set_callback(nd, test_rs_done, e) >= 0);

        assert(sd_event_add_time(e, &test_hangcheck, CLOCK_MONOTONIC,
                                 time_now + 2 *USEC_PER_SEC, 0,
                                 test_rs_hangcheck, NULL) >= 0);

        assert(sd_icmp6_nd_stop(nd) >= 0);
        assert(sd_icmp6_router_solicitation_start(nd) >= 0);
        assert(sd_icmp6_nd_stop(nd) >= 0);

        assert(sd_icmp6_router_solicitation_start(nd) >= 0);

        sd_event_loop(e);

        test_hangcheck = sd_event_source_unref(test_hangcheck);

        nd = sd_icmp6_nd_unref(nd);
        assert(!nd);

        close(test_fd[1]);
}
예제 #9
0
static int manager_arm_timer(Manager *m, usec_t next) {
        int r;

        assert(m);
        assert(m->event_receive);

        if (next == 0) {
                m->event_timer = sd_event_source_unref(m->event_timer);
                return 0;
        }

        if (m->event_timer) {
                r = sd_event_source_set_time(m->event_timer, now(clock_boottime_or_monotonic()) + next);
                if (r < 0)
                        return r;

                return sd_event_source_set_enabled(m->event_timer, SD_EVENT_ONESHOT);
        }

        return sd_event_add_time(
                        m->event,
                        &m->event_timer,
                        clock_boottime_or_monotonic(),
                        now(clock_boottime_or_monotonic()) + next, 0,
                        manager_timer, m);
}
예제 #10
0
파일: scope.c 프로젝트: halfline/systemd
static int scope_arm_timer(Scope *s, usec_t usec) {
        int r;

        assert(s);

        if (s->timer_event_source) {
                r = sd_event_source_set_time(s->timer_event_source, usec);
                if (r < 0)
                        return r;

                return sd_event_source_set_enabled(s->timer_event_source, SD_EVENT_ONESHOT);
        }

        if (usec == USEC_INFINITY)
                return 0;

        r = sd_event_add_time(
                        UNIT(s)->manager->event,
                        &s->timer_event_source,
                        CLOCK_MONOTONIC,
                        usec, 0,
                        scope_dispatch_timer, s);
        if (r < 0)
                return r;

        (void) sd_event_source_set_description(s->timer_event_source, "scope-timer");

        return 0;
}
예제 #11
0
파일: automount.c 프로젝트: aulanov/systemd
static int automount_start_expire(Automount *a) {
        int r;
        usec_t timeout;

        assert(a);

        if (a->timeout_idle_usec == 0)
                return 0;

        timeout = now(CLOCK_MONOTONIC) + MAX(a->timeout_idle_usec/3, USEC_PER_SEC);

        if (a->expire_event_source) {
                r = sd_event_source_set_time(a->expire_event_source, timeout);
                if (r < 0)
                        return r;

                return sd_event_source_set_enabled(a->expire_event_source, SD_EVENT_ONESHOT);
        }

        r = sd_event_add_time(
                        UNIT(a)->manager->event,
                        &a->expire_event_source,
                        CLOCK_MONOTONIC, timeout, 0,
                        automount_dispatch_expire, a);
        if (r < 0)
                return r;

        (void) sd_event_source_set_description(a->expire_event_source, "automount-expire");

        return 0;
}
예제 #12
0
static int sntp_arm_timer(SNTPContext *sntp, usec_t next) {
        sd_event *e;
        int r;

        assert(sntp);
        assert(sntp->event_receive);

        if (next == 0) {
                sntp->event_timer = sd_event_source_unref(sntp->event_timer);
                return 0;
        }

        if (sntp->event_timer) {
                r = sd_event_source_set_time(sntp->event_timer, now(CLOCK_MONOTONIC) + next);
                if (r < 0)
                        return r;

                return sd_event_source_set_enabled(sntp->event_timer, SD_EVENT_ONESHOT);
        }

        e = sd_event_source_get_event(sntp->event_receive);
        r = sd_event_add_time(
                        e,
                        &sntp->event_timer,
                        CLOCK_MONOTONIC,
                        now(CLOCK_MONOTONIC) + next, 0,
                        sntp_timer, sntp);
        if (r < 0)
                return r;

        return 0;
}
예제 #13
0
static int icmp6_router_solicitation_timeout(sd_event_source *s, uint64_t usec,
                                             void *userdata)
{
        sd_icmp6_nd *nd = userdata;
        uint64_t time_now, next_timeout;
        struct ether_addr unset = { };
        struct ether_addr *addr = NULL;
        int r;

        assert(s);
        assert(nd);
        assert(nd->event);

        nd->timeout = sd_event_source_unref(nd->timeout);

        if (nd->nd_sent >= ICMP6_MAX_ROUTER_SOLICITATIONS) {
                icmp6_nd_notify(nd, ICMP6_EVENT_ROUTER_ADVERTISMENT_TIMEOUT);
                nd->state = ICMP6_ROUTER_ADVERTISMENT_LISTEN;
        } else {
                if (memcmp(&nd->mac_addr, &unset, sizeof(struct ether_addr)))
                        addr = &nd->mac_addr;

                r = dhcp_network_icmp6_send_router_solicitation(nd->fd, addr);
                if (r < 0)
                        log_icmp6_nd(nd, "Error sending Router Solicitation");
                else {
                        nd->state = ICMP6_ROUTER_SOLICITATION_SENT;
                        log_icmp6_nd(nd, "Sent Router Solicitation");
                }

                nd->nd_sent++;

                r = sd_event_now(nd->event, CLOCK_MONOTONIC, &time_now);
                if (r < 0) {
                        icmp6_nd_notify(nd, r);
                        return 0;
                }

                next_timeout = time_now + ICMP6_ROUTER_SOLICITATION_INTERVAL;

                r = sd_event_add_time(nd->event, &nd->timeout, CLOCK_MONOTONIC,
                                      next_timeout, 0,
                                      icmp6_router_solicitation_timeout, nd);
                if (r < 0) {
                        icmp6_nd_notify(nd, r);
                        return 0;
                }

                r = sd_event_source_set_priority(nd->timeout,
                                                 nd->event_priority);
                if (r < 0) {
                        icmp6_nd_notify(nd, r);
                        return 0;
                }
        }

        return 0;
}
예제 #14
0
int sd_icmp6_router_solicitation_start(sd_icmp6_nd *nd) {
        int r;

        assert(nd);
        assert(nd->event);

        if (nd->state != ICMP6_NEIGHBOR_DISCOVERY_IDLE)
                return -EINVAL;

        if (nd->index < 1)
                return -EINVAL;

        r = dhcp_network_icmp6_bind_router_solicitation(nd->index);
        if (r < 0)
                return r;

        nd->fd = r;

        r = sd_event_add_io(nd->event, &nd->recv, nd->fd, EPOLLIN,
                            icmp6_router_advertisment_recv, nd);
        if (r < 0)
                goto error;

        r = sd_event_source_set_priority(nd->recv, nd->event_priority);
        if (r < 0)
                goto error;

        r = sd_event_source_set_description(nd->recv, "icmp6-receive-message");
        if (r < 0)
                goto error;

        r = sd_event_add_time(nd->event, &nd->timeout, clock_boottime_or_monotonic(),
                              0, 0, icmp6_router_solicitation_timeout, nd);
        if (r < 0)
                goto error;

        r = sd_event_source_set_priority(nd->timeout, nd->event_priority);
        if (r < 0)
                goto error;

        r = sd_event_source_set_description(nd->timeout, "icmp6-timeout");
error:
        if (r < 0)
                icmp6_nd_init(nd);
        else
                log_icmp6_nd(client, "Start Router Solicitation");

        return r;
}
예제 #15
0
int manager_setup_wall_message_timer(Manager *m) {

        usec_t n, elapse;
        int r;

        assert(m);

        n = now(CLOCK_REALTIME);
        elapse = m->scheduled_shutdown_timeout;

        /* wall message handling */

        if (isempty(m->scheduled_shutdown_type)) {
                warn_wall(m, n);
                return 0;
        }

        if (elapse < n)
                return 0;

        /* Warn immediately if less than 15 minutes are left */
        if (elapse - n < 15 * USEC_PER_MINUTE) {
                r = warn_wall(m, n);
                if (r == 0)
                        return 0;
        }

        elapse = when_wall(n, elapse);
        if (elapse == 0)
                return 0;

        if (m->wall_message_timeout_source) {
                r = sd_event_source_set_time(m->wall_message_timeout_source, n + elapse);
                if (r < 0)
                        return log_error_errno(r, "sd_event_source_set_time() failed. %m");

                r = sd_event_source_set_enabled(m->wall_message_timeout_source, SD_EVENT_ONESHOT);
                if (r < 0)
                        return log_error_errno(r, "sd_event_source_set_enabled() failed. %m");
        } else {
                r = sd_event_add_time(m->event, &m->wall_message_timeout_source,
                                      CLOCK_REALTIME, n + elapse, 0, wall_message_timeout_handler, m);
                if (r < 0)
                        return log_error_errno(r, "sd_event_add_time() failed. %m");
        }

        return 0;
}
예제 #16
0
int link_lldp_emit_start(Link *link) {
        usec_t next;
        int r;

        assert(link);

        if (!link->network || link->network->lldp_emit == LLDP_EMIT_NO) {
                link_lldp_emit_stop(link);
                return 0;
        }

        /* Starts the LLDP transmission in "fast" mode. If it is already started, turns "fast" mode back on again. */

        link->lldp_tx_fast = LLDP_TX_FAST_INIT;

        next = usec_add(usec_add(now(clock_boottime_or_monotonic()), LLDP_FAST_TX_USEC),
                     (usec_t) random_u64() % LLDP_JITTER_USEC);

        if (link->lldp_emit_event_source) {
                usec_t old;

                /* Lower the timeout, maybe */
                r = sd_event_source_get_time(link->lldp_emit_event_source, &old);
                if (r < 0)
                        return r;

                if (old <= next)
                        return 0;

                return sd_event_source_set_time(link->lldp_emit_event_source, next);
        } else {
                r = sd_event_add_time(
                                link->manager->event,
                                &link->lldp_emit_event_source,
                                clock_boottime_or_monotonic(),
                                next,
                                0,
                                on_lldp_timer,
                                link);
                if (r < 0)
                        return r;

                (void) sd_event_source_set_description(link->lldp_emit_event_source, "lldp-tx");
        }

        return 0;
}
예제 #17
0
static int test_client_solicit(sd_event *e) {
        sd_dhcp6_client *client;
        usec_t time_now = now(clock_boottime_or_monotonic());
        struct in6_addr address = { { { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01 } } };
        int val;

        if (verbose)
                printf("* %s\n", __FUNCTION__);

        assert_se(sd_dhcp6_client_new(&client) >= 0);
        assert_se(client);

        assert_se(sd_dhcp6_client_attach_event(client, e, 0) >= 0);

        assert_se(sd_dhcp6_client_set_ifindex(client, test_index) == 0);
        assert_se(sd_dhcp6_client_set_mac(client, (const uint8_t *) &mac_addr,
                                          sizeof (mac_addr),
                                          ARPHRD_ETHER) >= 0);
        assert_se(sd_dhcp6_client_set_fqdn(client, "host.lab.intra") == 1);

        assert_se(sd_dhcp6_client_get_information_request(client, &val) >= 0);
        assert_se(val == 0);
        assert_se(sd_dhcp6_client_set_information_request(client, 42) >= 0);
        assert_se(sd_dhcp6_client_get_information_request(client, &val) >= 0);
        assert_se(val);

        assert_se(sd_dhcp6_client_set_callback(client,
                                               test_client_information_cb, e) >= 0);

        assert_se(sd_event_add_time(e, &hangcheck, clock_boottime_or_monotonic(),
                                    time_now + 2 * USEC_PER_SEC, 0,
                                    test_hangcheck, NULL) >= 0);

        assert_se(sd_dhcp6_client_set_local_address(client, &address) >= 0);

        assert_se(sd_dhcp6_client_start(client) >= 0);

        sd_event_loop(e);

        hangcheck = sd_event_source_unref(hangcheck);

        assert_se(!sd_dhcp6_client_unref(client));

        test_dhcp_fd[1] = safe_close(test_dhcp_fd[1]);

        return 0;
}
예제 #18
0
static void test_addr_acq(sd_event *e) {
        usec_t time_now = now(CLOCK_MONOTONIC);
        sd_dhcp_client *client;
        int res, r;

        if (verbose)
                printf("* %s\n", __FUNCTION__);

        r = sd_dhcp_client_new(&client);
        assert_se(r >= 0);
        assert_se(client);

        r = sd_dhcp_client_attach_event(client, e, 0);
        assert_se(r >= 0);

        assert_se(sd_dhcp_client_set_index(client, 42) >= 0);
        assert_se(sd_dhcp_client_set_mac(client, &mac_addr) >= 0);

        assert_se(sd_dhcp_client_set_callback(client, test_addr_acq_acquired, e)
                >= 0);

        callback_recv = test_addr_acq_recv_discover;

        assert_se(sd_event_add_time(e, &test_hangcheck,
                                    CLOCK_MONOTONIC,
                                    time_now + 2 * USEC_PER_SEC, 0,
                                    test_dhcp_hangcheck, NULL) >= 0);

        res = sd_dhcp_client_start(client);
        assert_se(res == 0 || res == -EINPROGRESS);

        sd_event_loop(e);

        test_hangcheck = sd_event_source_unref(test_hangcheck);

        sd_dhcp_client_set_callback(client, NULL, NULL);
        sd_dhcp_client_stop(client);
        sd_dhcp_client_unref(client);

        test_fd[1] = safe_close(test_fd[1]);

        callback_recv = NULL;
        xid = 0;
}
예제 #19
0
static void test_addr_acq(sd_event *e) {
        usec_t time_now = now(clock_boottime_or_monotonic());
        sd_dhcp_client *client;
        int res, r;

        if (verbose)
                printf("* %s\n", __FUNCTION__);

        r = sd_dhcp_client_new(&client, false);
        assert_se(r >= 0);
        assert_se(client);

        r = sd_dhcp_client_attach_event(client, e, 0);
        assert_se(r >= 0);

        assert_se(sd_dhcp_client_set_ifindex(client, 42) >= 0);
        assert_se(sd_dhcp_client_set_mac(client, mac_addr, ETH_ALEN, ARPHRD_ETHER) >= 0);

        assert_se(sd_dhcp_client_set_callback(client, test_addr_acq_acquired, e) >= 0);

        callback_recv = test_addr_acq_recv_discover;

        assert_se(sd_event_add_time(e, &test_hangcheck,
                                    clock_boottime_or_monotonic(),
                                    time_now + 2 * USEC_PER_SEC, 0,
                                    test_dhcp_hangcheck, NULL) >= 0);

        res = sd_dhcp_client_start(client);
        assert_se(IN_SET(res, 0, -EINPROGRESS));

        assert_se(sd_event_loop(e) >= 0);

        test_hangcheck = sd_event_source_unref(test_hangcheck);

        assert_se(sd_dhcp_client_set_callback(client, NULL, NULL) >= 0);
        assert_se(sd_dhcp_client_stop(client) >= 0);
        sd_dhcp_client_unref(client);

        test_fd[1] = safe_close(test_fd[1]);

        callback_recv = NULL;
        xid = 0;
}
예제 #20
0
int sd_icmp6_router_solicitation_start(sd_icmp6_nd *nd) {
        int r;

        assert(nd);
        assert(nd->event);

        if (nd->state != ICMP6_NEIGHBOR_DISCOVERY_IDLE)
                return -EINVAL;

        if (nd->index < 1)
                return -EINVAL;

        r = dhcp_network_icmp6_bind_router_solicitation(nd->index);
        if (r < 0)
                return r;

        nd->fd = r;

        r = sd_event_add_io(nd->event, &nd->recv, nd->fd, EPOLLIN,
                            icmp6_router_advertisment_recv, nd);
        if (r < 0)
                goto error;

        r = sd_event_source_set_priority(nd->recv, nd->event_priority);
        if (r < 0)
                goto error;

        r = sd_event_add_time(nd->event, &nd->timeout, CLOCK_MONOTONIC,
                              0, 0, icmp6_router_solicitation_timeout, nd);
        if (r < 0)
                goto error;

        r = sd_event_source_set_priority(nd->timeout, nd->event_priority);

error:
        if (r < 0)
                icmp6_nd_init(nd);
        else
                log_icmp6_nd(client, "Start Router Solicitation");

        return r;
}
예제 #21
0
static void test_rs(void) {
        sd_event *e;
        sd_icmp6_nd *nd;
        usec_t time_now = now(clock_boottime_or_monotonic());

        if (verbose)
                printf("* %s\n", __FUNCTION__);

        send_ra_function = send_ra;

        assert_se(sd_event_new(&e) >= 0);

        assert_se(sd_icmp6_nd_new(&nd) >= 0);
        assert_se(nd);

        assert_se(sd_icmp6_nd_attach_event(nd, e, 0) >= 0);

        assert_se(sd_icmp6_nd_set_index(nd, 42) >= 0);
        assert_se(sd_icmp6_nd_set_mac(nd, &mac_addr) >= 0);
        assert_se(sd_icmp6_nd_set_callback(nd, test_rs_done, e) >= 0);

        assert_se(sd_event_add_time(e, &test_hangcheck, clock_boottime_or_monotonic(),
                                 time_now + 2 *USEC_PER_SEC, 0,
                                 test_rs_hangcheck, NULL) >= 0);

        assert_se(sd_icmp6_nd_stop(nd) >= 0);
        assert_se(sd_icmp6_router_solicitation_start(nd) >= 0);
        assert_se(sd_icmp6_nd_stop(nd) >= 0);

        assert_se(sd_icmp6_router_solicitation_start(nd) >= 0);

        sd_event_loop(e);

        test_hangcheck = sd_event_source_unref(test_hangcheck);

        nd = sd_icmp6_nd_unref(nd);
        assert_se(!nd);

        close(test_fd[1]);

        sd_event_unref(e);
}
예제 #22
0
static int lldp_start_timer(sd_lldp *lldp, sd_lldp_neighbor *neighbor) {
        sd_lldp_neighbor *n;
        int r;

        assert(lldp);

        if (neighbor)
                lldp_neighbor_start_ttl(neighbor);

        n = prioq_peek(lldp->neighbor_by_expiry);
        if (!n) {

                if (lldp->timer_event_source)
                        return sd_event_source_set_enabled(lldp->timer_event_source, SD_EVENT_OFF);

                return 0;
        }

        if (lldp->timer_event_source) {
                r = sd_event_source_set_time(lldp->timer_event_source, n->until);
                if (r < 0)
                        return r;

                return sd_event_source_set_enabled(lldp->timer_event_source, SD_EVENT_ONESHOT);
        }

        if (!lldp->event)
                return 0;

        r = sd_event_add_time(lldp->event, &lldp->timer_event_source, clock_boottime_or_monotonic(), n->until, 0, on_timer_event, lldp);
        if (r < 0)
                return r;

        r = sd_event_source_set_priority(lldp->timer_event_source, lldp->event_priority);
        if (r < 0)
                return r;

        (void) sd_event_source_set_description(lldp->timer_event_source, "lldp-timer");
        return 0;
}
예제 #23
0
static int client_initialize_events(sd_dhcp_client *client,
                                    sd_event_io_handler_t io_callback) {
        int r;

        assert(client);
        assert(client->event);

        r = sd_event_add_io(client->event, &client->receive_message,
                            client->fd, EPOLLIN, io_callback,
                            client);
        if (r < 0)
                goto error;

        r = sd_event_source_set_priority(client->receive_message,
                                         client->event_priority);
        if (r < 0)
                goto error;

        client->timeout_resend = sd_event_source_unref(client->timeout_resend);

        r = sd_event_add_time(client->event,
                              &client->timeout_resend,
                              CLOCK_MONOTONIC,
                              0, 0,
                              client_timeout_resend, client);
        if (r < 0)
                goto error;

        r = sd_event_source_set_priority(client->timeout_resend,
                                         client->event_priority);

error:
        if (r < 0)
                client_stop(client, r);

        return 0;

}
예제 #24
0
static int ipv4acd_set_next_wakeup(sd_ipv4acd *ll, int sec, int random_sec) {
        _cleanup_(sd_event_source_unrefp) sd_event_source *timer = NULL;
        usec_t next_timeout;
        usec_t time_now;
        int r;

        assert(sec >= 0);
        assert(random_sec >= 0);
        assert(ll);

        next_timeout = sec * USEC_PER_SEC;

        if (random_sec)
                next_timeout += random_u32() % (random_sec * USEC_PER_SEC);

        assert_se(sd_event_now(ll->event, clock_boottime_or_monotonic(), &time_now) >= 0);

        r = sd_event_add_time(ll->event, &timer, clock_boottime_or_monotonic(),
                              time_now + next_timeout, 0, ipv4acd_on_timeout, ll);
        if (r < 0)
                return r;

        r = sd_event_source_set_priority(timer, ll->event_priority);
        if (r < 0)
                return r;

        r = sd_event_source_set_description(timer, "ipv4acd-timer");
        if (r < 0)
                return r;

        ll->timer = sd_event_source_unref(ll->timer);
        ll->timer = timer;
        timer = NULL;

        return 0;
}
예제 #25
0
static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message,
                                 int len) {
        int r = 0, notify_event = 0;

        assert(client);
        assert(client->event);
        assert(message);

        if (be32toh(message->magic) != DHCP_MAGIC_COOKIE) {
                log_dhcp_client(client, "not a DHCP message: ignoring");
                return 0;
        }

        if (message->op != BOOTREPLY) {
                log_dhcp_client(client, "not a BOOTREPLY message: ignoring");
                return 0;
        }

        if (be32toh(message->xid) != client->xid) {
                log_dhcp_client(client, "received xid (%u) does not match "
                                "expected (%u): ignoring",
                                be32toh(message->xid), client->xid);
                return 0;
        }

        if (message->htype != ARPHRD_ETHER || message->hlen != ETHER_ADDR_LEN) {
                log_dhcp_client(client, "not an ethernet packet");
                return 0;
        }

        if (memcmp(&message->chaddr[0], &client->client_id.mac_addr,
                   ETH_ALEN)) {
                log_dhcp_client(client, "received chaddr does not match "
                                "expected: ignoring");
                return 0;
        }

        switch (client->state) {
        case DHCP_STATE_SELECTING:

                r = client_handle_offer(client, message, len);
                if (r >= 0) {

                        client->timeout_resend =
                                sd_event_source_unref(client->timeout_resend);

                        client->state = DHCP_STATE_REQUESTING;
                        client->attempt = 1;

                        r = sd_event_add_time(client->event,
                                              &client->timeout_resend,
                                              CLOCK_MONOTONIC,
                                              0, 0,
                                              client_timeout_resend, client);
                        if (r < 0)
                                goto error;

                        r = sd_event_source_set_priority(client->timeout_resend,
                                                         client->event_priority);
                        if (r < 0)
                                goto error;
                } else if (r == -ENOMSG)
                        /* invalid message, let's ignore it */
                        return 0;

                break;

        case DHCP_STATE_REBOOTING:
        case DHCP_STATE_REQUESTING:
        case DHCP_STATE_RENEWING:
        case DHCP_STATE_REBINDING:

                r = client_handle_ack(client, message, len);
                if (r == DHCP_EVENT_NO_LEASE) {

                        client->timeout_resend =
                                sd_event_source_unref(client->timeout_resend);

                        if (client->state == DHCP_STATE_REBOOTING) {
                                r = client_initialize(client);
                                if (r < 0)
                                        goto error;

                                r = client_start(client);
                                if (r < 0)
                                        goto error;

                                log_dhcp_client(client, "REBOOTED");
                        }

                        goto error;
                } else if (r >= 0) {
                        client->timeout_resend =
                                sd_event_source_unref(client->timeout_resend);

                        if (IN_SET(client->state, DHCP_STATE_REQUESTING,
                                   DHCP_STATE_REBOOTING))
                                notify_event = DHCP_EVENT_IP_ACQUIRE;
                        else if (r != DHCP_EVENT_IP_ACQUIRE)
                                notify_event = r;

                        client->state = DHCP_STATE_BOUND;
                        client->attempt = 1;

                        client->last_addr = client->lease->address;

                        r = client_set_lease_timeouts(client);
                        if (r < 0)
                                goto error;

                        if (notify_event) {
                                client = client_notify(client, notify_event);
                                if (!client ||
                                    client->state == DHCP_STATE_STOPPED)
                                        return 0;
                        }

                        client->receive_message =
                                sd_event_source_unref(client->receive_message);
                        client->fd = asynchronous_close(client->fd);
                } else if (r == -ENOMSG)
                        /* invalid message, let's ignore it */
                        return 0;

                break;

        case DHCP_STATE_INIT:
        case DHCP_STATE_INIT_REBOOT:
        case DHCP_STATE_BOUND:

                break;

        case DHCP_STATE_STOPPED:
                r = -EINVAL;
                goto error;
        }

error:
        if (r < 0 || r == DHCP_EVENT_NO_LEASE)
                client_stop(client, r);

        return r;
}
예제 #26
0
int sd_ipv4ll_start (sd_ipv4ll *ll) {
    int r;

    assert_return(ll, -EINVAL);
    assert_return(ll->event, -EINVAL);
    assert_return(ll->index > 0, -EINVAL);
    assert_return(IN_SET(ll->state, IPV4LL_STATE_INIT,
                         IPV4LL_STATE_STOPPED), -EBUSY);

    ll->state = IPV4LL_STATE_INIT;

    r = arp_network_bind_raw_socket(ll->index, &ll->link);

    if (r < 0)
        goto out;

    ll->fd = r;
    ll->conflict = 0;
    ll->defend_window = 0;
    ll->claimed_address = 0;

    if (!ll->random_data) {
        uint8_t seed[8];

        /* Fallback to mac */
        siphash24(seed, &ll->mac_addr.ether_addr_octet,
                  ETH_ALEN, HASH_KEY.bytes);

        r = sd_ipv4ll_set_address_seed(ll, seed);
        if (r < 0)
            goto out;
    }

    if (ll->address == 0) {
        r = ipv4ll_pick_address(ll, &ll->address);
        if (r < 0)
            goto out;
    }

    ipv4ll_set_state (ll, IPV4LL_STATE_INIT, 1);

    r = sd_event_add_io(ll->event, &ll->receive_message, ll->fd,
                        EPOLLIN, ipv4ll_receive_message, ll);
    if (r < 0)
        goto out;

    r = sd_event_source_set_priority(ll->receive_message, ll->event_priority);
    if (r < 0)
        goto out;

    r = sd_event_source_set_description(ll->receive_message, "ipv4ll-receive-message");
    if (r < 0)
        goto out;

    r = sd_event_add_time(ll->event,
                          &ll->timer,
                          clock_boottime_or_monotonic(),
                          now(clock_boottime_or_monotonic()), 0,
                          ipv4ll_timer, ll);

    if (r < 0)
        goto out;

    r = sd_event_source_set_priority(ll->timer, ll->event_priority);
    if (r < 0)
        goto out;

    r = sd_event_source_set_description(ll->timer, "ipv4ll-timer");
out:
    if (r < 0)
        ipv4ll_stop(ll, IPV4LL_EVENT_STOP);

    return 0;
}
예제 #27
0
static void ipv4ll_run_state_machine(sd_ipv4ll *ll, IPv4LLTrigger trigger, void *trigger_data) {
    struct ether_arp out_packet;
    int out_packet_ready = 0;
    int r = 0;

    assert(ll);
    assert(trigger < _IPV4LL_TRIGGER_MAX);

    if (ll->state == IPV4LL_STATE_INIT) {

        log_ipv4ll(ll, "PROBE");
        ipv4ll_set_state(ll, IPV4LL_STATE_WAITING_PROBE, 1);
        ipv4ll_set_next_wakeup(ll, 0, PROBE_WAIT);

    } else if ((ll->state == IPV4LL_STATE_WAITING_PROBE && trigger == IPV4LL_TRIGGER_TIMEOUT) ||
               (ll->state == IPV4LL_STATE_PROBING && trigger == IPV4LL_TRIGGER_TIMEOUT && ll->iteration < PROBE_NUM-2)) {

        /* Send a probe */
        arp_packet_probe(&out_packet, ll->address, &ll->mac_addr);
        out_packet_ready = 1;
        ipv4ll_set_state(ll, IPV4LL_STATE_PROBING, 0);

        ipv4ll_set_next_wakeup(ll, PROBE_MIN, (PROBE_MAX-PROBE_MIN));

    } else if (ll->state == IPV4LL_STATE_PROBING && trigger == IPV4LL_TRIGGER_TIMEOUT && ll->iteration >= PROBE_NUM-2) {

        /* Send the last probe */
        arp_packet_probe(&out_packet, ll->address, &ll->mac_addr);
        out_packet_ready = 1;
        ipv4ll_set_state(ll, IPV4LL_STATE_WAITING_ANNOUNCE, 1);

        ipv4ll_set_next_wakeup(ll, ANNOUNCE_WAIT, 0);

    } else if ((ll->state == IPV4LL_STATE_WAITING_ANNOUNCE && trigger == IPV4LL_TRIGGER_TIMEOUT) ||
               (ll->state == IPV4LL_STATE_ANNOUNCING && trigger == IPV4LL_TRIGGER_TIMEOUT && ll->iteration < ANNOUNCE_NUM-1)) {

        /* Send announcement packet */
        arp_packet_announcement(&out_packet, ll->address, &ll->mac_addr);
        out_packet_ready = 1;
        ipv4ll_set_state(ll, IPV4LL_STATE_ANNOUNCING, 0);

        ipv4ll_set_next_wakeup(ll, ANNOUNCE_INTERVAL, 0);

        if (ll->iteration == 0) {
            log_ipv4ll(ll, "ANNOUNCE");
            ll->claimed_address = ll->address;
            ll = ipv4ll_client_notify(ll, IPV4LL_EVENT_BIND);
            if (!ll || ll->state == IPV4LL_STATE_STOPPED)
                goto out;

            ll->conflict = 0;
        }

    } else if ((ll->state == IPV4LL_STATE_ANNOUNCING && trigger == IPV4LL_TRIGGER_TIMEOUT &&
                ll->iteration >= ANNOUNCE_NUM-1)) {

        ipv4ll_set_state(ll, IPV4LL_STATE_RUNNING, 0);
        ll->next_wakeup_valid = 0;

    } else if (trigger == IPV4LL_TRIGGER_PACKET) {

        int conflicted = 0;
        usec_t time_now;
        struct ether_arp* in_packet = (struct ether_arp*)trigger_data;

        assert(in_packet);

        if (IN_SET(ll->state, IPV4LL_STATE_ANNOUNCING, IPV4LL_STATE_RUNNING)) {

            if (ipv4ll_arp_conflict(ll, in_packet)) {

                r = sd_event_now(ll->event, clock_boottime_or_monotonic(), &time_now);
                if (r < 0)
                    goto out;

                /* Defend address */
                if (time_now > ll->defend_window) {
                    ll->defend_window = time_now + DEFEND_INTERVAL * USEC_PER_SEC;
                    arp_packet_announcement(&out_packet, ll->address, &ll->mac_addr);
                    out_packet_ready = 1;
                } else
                    conflicted = 1;
            }

        } else if (IN_SET(ll->state, IPV4LL_STATE_WAITING_PROBE,
                          IPV4LL_STATE_PROBING,
                          IPV4LL_STATE_WAITING_ANNOUNCE)) {

            conflicted = ipv4ll_arp_probe_conflict(ll, in_packet);
        }

        if (conflicted) {
            log_ipv4ll(ll, "CONFLICT");
            ll = ipv4ll_client_notify(ll, IPV4LL_EVENT_CONFLICT);
            if (!ll || ll->state == IPV4LL_STATE_STOPPED)
                goto out;

            ll->claimed_address = 0;

            /* Pick a new address */
            r = ipv4ll_pick_address(ll, &ll->address);
            if (r < 0)
                goto out;
            ll->conflict++;
            ll->defend_window = 0;
            ipv4ll_set_state(ll, IPV4LL_STATE_WAITING_PROBE, 1);

            if (ll->conflict >= MAX_CONFLICTS) {
                log_ipv4ll(ll, "MAX_CONFLICTS");
                ipv4ll_set_next_wakeup(ll, RATE_LIMIT_INTERVAL, PROBE_WAIT);
            } else
                ipv4ll_set_next_wakeup(ll, 0, PROBE_WAIT);

        }
    }

    if (out_packet_ready) {
        r = arp_network_send_raw_socket(ll->fd, &ll->link, &out_packet);
        if (r < 0) {
            log_ipv4ll(ll, "failed to send arp packet out");
            goto out;
        }
    }

    if (ll->next_wakeup_valid) {
        ll->timer = sd_event_source_unref(ll->timer);
        r = sd_event_add_time(ll->event, &ll->timer, clock_boottime_or_monotonic(),
                              ll->next_wakeup, 0, ipv4ll_timer, ll);
        if (r < 0)
            goto out;

        r = sd_event_source_set_priority(ll->timer, ll->event_priority);
        if (r < 0)
            goto out;

        r = sd_event_source_set_description(ll->timer, "ipv4ll-timer");
        if (r < 0)
            goto out;
    }

out:
    if (r < 0 && ll)
        ipv4ll_stop(ll, r);
}
int main(int argc, char *argv[]) {
        sd_event *e = NULL;
        sd_event_source *w = NULL, *x = NULL, *y = NULL, *z = NULL, *q = NULL, *t = NULL;
        static const char ch = 'x';
        int a[2] = { -1, -1 }, b[2] = { -1, -1}, d[2] = { -1, -1}, k[2] = { -1, -1 };

        assert_se(pipe(a) >= 0);
        assert_se(pipe(b) >= 0);
        assert_se(pipe(d) >= 0);
        assert_se(pipe(k) >= 0);

        assert_se(sd_event_default(&e) >= 0);

        assert_se(sd_event_set_watchdog(e, true) >= 0);

        /* Test whether we cleanly can destroy an io event source from its own handler */
        got_unref = false;
        assert_se(sd_event_add_io(e, &t, k[0], EPOLLIN, unref_handler, NULL) >= 0);
        assert_se(write(k[1], &ch, 1) == 1);
        assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
        assert_se(got_unref);

        got_a = false, got_b = false, got_c = false, got_d = 0;

        /* Add a oneshot handler, trigger it, re-enable it, and trigger
         * it again. */
        assert_se(sd_event_add_io(e, &w, d[0], EPOLLIN, io_handler, INT_TO_PTR('d')) >= 0);
        assert_se(sd_event_source_set_enabled(w, SD_EVENT_ONESHOT) >= 0);
        assert_se(write(d[1], &ch, 1) >= 0);
        assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
        assert_se(got_d == 1);
        assert_se(write(d[1], &ch, 1) >= 0);
        assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
        assert_se(got_d == 2);

        assert_se(sd_event_add_io(e, &x, a[0], EPOLLIN, io_handler, INT_TO_PTR('a')) >= 0);
        assert_se(sd_event_add_io(e, &y, b[0], EPOLLIN, io_handler, INT_TO_PTR('b')) >= 0);
        assert_se(sd_event_add_time(e, &z, CLOCK_MONOTONIC, 0, 0, time_handler, INT_TO_PTR('c')) >= 0);
        assert_se(sd_event_add_exit(e, &q, exit_handler, INT_TO_PTR('g')) >= 0);

        assert_se(sd_event_source_set_priority(x, 99) >= 0);
        assert_se(sd_event_source_set_enabled(y, SD_EVENT_ONESHOT) >= 0);
        assert_se(sd_event_source_set_prepare(x, prepare_handler) >= 0);
        assert_se(sd_event_source_set_priority(z, 50) >= 0);
        assert_se(sd_event_source_set_enabled(z, SD_EVENT_ONESHOT) >= 0);
        assert_se(sd_event_source_set_prepare(z, prepare_handler) >= 0);

        /* Test for floating event sources */
        assert_se(sigprocmask_many(SIG_BLOCK, SIGRTMIN+1, -1) == 0);
        assert_se(sd_event_add_signal(e, NULL, SIGRTMIN+1, NULL, NULL) >= 0);

        assert_se(write(a[1], &ch, 1) >= 0);
        assert_se(write(b[1], &ch, 1) >= 0);

        assert_se(!got_a && !got_b && !got_c);

        assert_se(sd_event_run(e, (uint64_t) -1) >= 1);

        assert_se(!got_a && got_b && !got_c);

        assert_se(sd_event_run(e, (uint64_t) -1) >= 1);

        assert_se(!got_a && got_b && got_c);

        assert_se(sd_event_run(e, (uint64_t) -1) >= 1);

        assert_se(got_a && got_b && got_c);

        sd_event_source_unref(x);
        sd_event_source_unref(y);

        do_quit = true;
        assert_se(sd_event_source_set_time(z, now(CLOCK_MONOTONIC) + 200 * USEC_PER_MSEC) >= 0);
        assert_se(sd_event_source_set_enabled(z, SD_EVENT_ONESHOT) >= 0);

        assert_se(sd_event_loop(e) >= 0);

        sd_event_source_unref(z);
        sd_event_source_unref(q);

        sd_event_source_unref(w);

        sd_event_unref(e);

        safe_close_pair(a);
        safe_close_pair(b);
        safe_close_pair(d);
        safe_close_pair(k);

        return 0;
}
예제 #29
0
static int client_timeout_resend(sd_event_source *s, uint64_t usec,
                                 void *userdata) {
        sd_dhcp_client *client = userdata;
        usec_t next_timeout = 0;
        uint64_t time_now;
        uint32_t time_left;
        int r;

        assert(s);
        assert(client);
        assert(client->event);

        r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now);
        if (r < 0)
                goto error;

        switch (client->state) {
        case DHCP_STATE_RENEWING:

                time_left = (client->lease->t2 - client->lease->t1) / 2;
                if (time_left < 60)
                        time_left = 60;

                next_timeout = time_now + time_left * USEC_PER_SEC;

                break;

        case DHCP_STATE_REBINDING:

                time_left = (client->lease->lifetime - client->lease->t2) / 2;
                if (time_left < 60)
                        time_left = 60;

                next_timeout = time_now + time_left * USEC_PER_SEC;
                break;

        case DHCP_STATE_REBOOTING:
                /* start over as we did not receive a timely ack or nak */
                r = client_initialize(client);
                if (r < 0)
                        goto error;

                r = client_start(client);
                if (r < 0)
                        goto error;
                else {
                        log_dhcp_client(client, "REBOOTED");
                        return 0;
                }

        case DHCP_STATE_INIT:
        case DHCP_STATE_INIT_REBOOT:
        case DHCP_STATE_SELECTING:
        case DHCP_STATE_REQUESTING:
        case DHCP_STATE_BOUND:

                if (client->attempt < 64)
                        client->attempt *= 2;

                next_timeout = time_now + (client->attempt - 1) * USEC_PER_SEC;

                break;

        case DHCP_STATE_STOPPED:
                r = -EINVAL;
                goto error;
        }

        next_timeout += (random_u32() & 0x1fffff);

        client->timeout_resend = sd_event_source_unref(client->timeout_resend);

        r = sd_event_add_time(client->event,
                              &client->timeout_resend,
                              CLOCK_MONOTONIC,
                              next_timeout, 10 * USEC_PER_MSEC,
                              client_timeout_resend, client);
        if (r < 0)
                goto error;

        r = sd_event_source_set_priority(client->timeout_resend,
                                         client->event_priority);
        if (r < 0)
                goto error;

        switch (client->state) {
        case DHCP_STATE_INIT:
                r = client_send_discover(client);
                if (r >= 0) {
                        client->state = DHCP_STATE_SELECTING;
                        client->attempt = 1;
                } else {
                        if (client->attempt >= 64)
                                goto error;
                }

                break;

        case DHCP_STATE_SELECTING:
                r = client_send_discover(client);
                if (r < 0 && client->attempt >= 64)
                        goto error;

                break;

        case DHCP_STATE_INIT_REBOOT:
        case DHCP_STATE_REQUESTING:
        case DHCP_STATE_RENEWING:
        case DHCP_STATE_REBINDING:
                r = client_send_request(client);
                if (r < 0 && client->attempt >= 64)
                         goto error;

                if (client->state == DHCP_STATE_INIT_REBOOT)
                        client->state = DHCP_STATE_REBOOTING;

                client->request_sent = time_now;

                break;

        case DHCP_STATE_REBOOTING:
        case DHCP_STATE_BOUND:

                break;

        case DHCP_STATE_STOPPED:
                r = -EINVAL;
                goto error;
        }

        return 0;

error:
        client_stop(client, r);

        /* Errors were dealt with when stopping the client, don't spill
           errors into the event loop handler */
        return 0;
}
예제 #30
0
static int client_set_lease_timeouts(sd_dhcp_client *client) {
        usec_t time_now;
        uint64_t lifetime_timeout;
        uint64_t t2_timeout;
        uint64_t t1_timeout;
        char time_string[FORMAT_TIMESPAN_MAX];
        int r;

        assert(client);
        assert(client->event);
        assert(client->lease);
        assert(client->lease->lifetime);

        client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
        client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
        client->timeout_expire = sd_event_source_unref(client->timeout_expire);

        /* don't set timers for infinite leases */
        if (client->lease->lifetime == 0xffffffff)
                return 0;

        r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now);
        if (r < 0)
                return r;
        assert(client->request_sent <= time_now);

        /* convert the various timeouts from relative (secs) to absolute (usecs) */
        lifetime_timeout = client_compute_timeout(client, client->lease->lifetime, 1);
        if (client->lease->t1 && client->lease->t2) {
                /* both T1 and T2 are given */
                if (client->lease->t1 < client->lease->t2 &&
                    client->lease->t2 < client->lease->lifetime) {
                        /* they are both valid */
                        t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
                        t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
                } else {
                        /* discard both */
                        t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
                        client->lease->t2 = (client->lease->lifetime * 7) / 8;
                        t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
                        client->lease->t1 = client->lease->lifetime / 2;
                }
        } else if (client->lease->t2 && client->lease->t2 < client->lease->lifetime) {
                /* only T2 is given, and it is valid */
                t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
                t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
                client->lease->t1 = client->lease->lifetime / 2;
                if (t2_timeout <= t1_timeout) {
                        /* the computed T1 would be invalid, so discard T2 */
                        t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
                        client->lease->t2 = (client->lease->lifetime * 7) / 8;
                }
        } else if (client->lease->t1 && client->lease->t1 < client->lease->lifetime) {
                /* only T1 is given, and it is valid */
                t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
                t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
                client->lease->t2 = (client->lease->lifetime * 7) / 8;
                if (t2_timeout <= t1_timeout) {
                        /* the computed T2 would be invalid, so discard T1 */
                        t2_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
                        client->lease->t2 = client->lease->lifetime / 2;
                }
        } else {
                /* fall back to the default timeouts */
                t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
                client->lease->t1 = client->lease->lifetime / 2;
                t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
                client->lease->t2 = (client->lease->lifetime * 7) / 8;
        }

        /* arm lifetime timeout */
        r = sd_event_add_time(client->event, &client->timeout_expire,
                              CLOCK_MONOTONIC,
                              lifetime_timeout, 10 * USEC_PER_MSEC,
                              client_timeout_expire, client);
        if (r < 0)
                return r;

        r = sd_event_source_set_priority(client->timeout_expire,
                                         client->event_priority);
        if (r < 0)
                return r;

        log_dhcp_client(client, "lease expires in %s",
                        format_timespan(time_string, FORMAT_TIMESPAN_MAX,
                        lifetime_timeout - time_now, 0));

        /* don't arm earlier timeouts if this has already expired */
        if (lifetime_timeout <= time_now)
                return 0;

        /* arm T2 timeout */
        r = sd_event_add_time(client->event,
                              &client->timeout_t2,
                              CLOCK_MONOTONIC,
                              t2_timeout,
                              10 * USEC_PER_MSEC,
                              client_timeout_t2, client);
        if (r < 0)
                return r;

        r = sd_event_source_set_priority(client->timeout_t2,
                                         client->event_priority);
        if (r < 0)
                return r;

        log_dhcp_client(client, "T2 expires in %s",
                        format_timespan(time_string, FORMAT_TIMESPAN_MAX,
                        t2_timeout - time_now, 0));

        /* don't arm earlier timeout if this has already expired */
        if (t2_timeout <= time_now)
                return 0;

        /* arm T1 timeout */
        r = sd_event_add_time(client->event,
                              &client->timeout_t1,
                              CLOCK_MONOTONIC,
                              t1_timeout, 10 * USEC_PER_MSEC,
                              client_timeout_t1, client);
        if (r < 0)
                return r;

        r = sd_event_source_set_priority(client->timeout_t1,
                                         client->event_priority);
        if (r < 0)
                return r;

        log_dhcp_client(client, "T1 expires in %s",
                        format_timespan(time_string, FORMAT_TIMESPAN_MAX,
                        t1_timeout - time_now, 0));

        return 0;
}