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); }
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; }
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; }
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); }
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; }
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; }
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]); }
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); }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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); }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }