static int on_lldp_timer(sd_event_source *s, usec_t t, void *userdata) { Link *link = userdata; usec_t current, delay, next; int r; assert(s); assert(userdata); log_link_debug(link, "Sending LLDP packet..."); r = link_send_lldp(link); if (r < 0) log_link_debug_errno(link, r, "Failed to send LLDP packet, ignoring: %m"); if (link->lldp_tx_fast > 0) link->lldp_tx_fast--; assert_se(sd_event_now(sd_event_source_get_event(s), clock_boottime_or_monotonic(), ¤t) >= 0); delay = link->lldp_tx_fast > 0 ? LLDP_FAST_TX_USEC : LLDP_TX_INTERVAL_USEC; next = usec_add(usec_add(current, delay), (usec_t) random_u64() % LLDP_JITTER_USEC); r = sd_event_source_set_time(s, next); if (r < 0) return log_link_error_errno(link, r, "Failed to restart LLDP timer: %m"); r = sd_event_source_set_enabled(s, SD_EVENT_ONESHOT); if (r < 0) return log_link_error_errno(link, r, "Failed to enable LLDP timer: %m"); return 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); }
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 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 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; }
static int client_send_discover(sd_dhcp_client *client) { _cleanup_free_ DHCPPacket *discover = NULL; size_t optoffset, optlen; usec_t time_now; int r; assert(client); assert(client->state == DHCP_STATE_INIT || client->state == DHCP_STATE_SELECTING); /* See RFC2131 section 4.4.1 */ r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now); if (r < 0) return r; assert(time_now >= client->start_time); /* seconds between sending first and last DISCOVER * must always be strictly positive to deal with broken servers */ client->secs = ((time_now - client->start_time) / USEC_PER_SEC) ? : 1; r = client_message_init(client, &discover, DHCP_DISCOVER, &optlen, &optoffset); if (r < 0) return r; /* the client may suggest values for the network address and lease time in the DHCPDISCOVER message. The client may include the ’requested IP address’ option to suggest that a particular IP address be assigned, and may include the ’IP address lease time’ option to suggest the lease time it would like. */ if (client->last_addr != INADDR_ANY) { r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0, DHCP_OPTION_REQUESTED_IP_ADDRESS, 4, &client->last_addr); if (r < 0) return r; } r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0, DHCP_OPTION_END, 0, NULL); /* We currently ignore: The client SHOULD wait a random time between one and ten seconds to desynchronize the use of DHCP at startup. */ r = dhcp_client_send_raw(client, discover, sizeof(DHCPPacket) + optoffset); if (r < 0) return r; log_dhcp_client(client, "DISCOVER"); return 0; }
static void dns_server_verified(DnsServer *s, DnsServerFeatureLevel level) { assert(s); if (s->verified_feature_level > level) return; if (s->verified_feature_level != level) { log_debug("Verified we get a response at feature level %s from DNS server %s.", dns_server_feature_level_to_string(level), dns_server_string(s)); s->verified_feature_level = level; } assert_se(sd_event_now(s->manager->event, clock_boottime_or_monotonic(), &s->verified_usec) >= 0); }
static bool dns_server_grace_period_expired(DnsServer *s) { usec_t ts; assert(s); assert(s->manager); if (s->verified_usec == 0) return false; assert_se(sd_event_now(s->manager->event, clock_boottime_or_monotonic(), &ts) >= 0); if (s->verified_usec + s->features_grace_period_usec > ts) return false; s->features_grace_period_usec = MIN(s->features_grace_period_usec * 2, DNS_SERVER_FEATURE_GRACE_PERIOD_MAX_USEC); return true; }
static void ipv4ll_set_next_wakeup(sd_ipv4ll *ll, int sec, int random_sec) { usec_t next_timeout = 0; usec_t time_now = 0; 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); ll->next_wakeup = time_now + next_timeout; ll->next_wakeup_valid = 1; }
static void ipv4ll_set_next_wakeup(sd_ipv4ll *ll, int sec, int random_sec) { usec_t next_timeout = 0; usec_t time_now = 0; 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); if (sd_event_now(ll->event, CLOCK_MONOTONIC, &time_now) < 0) time_now = now(CLOCK_MONOTONIC); ll->next_wakeup = time_now + next_timeout; ll->next_wakeup_valid = 1; }
static int PmonPing(sd_bus_message *m, void *userdata, sd_bus_error *retError) { int id = 0; sd_bus_message_read(m, "u", &id); char *sid = (char*)sd_event_source_get_userdata(clients[id]); if (sid == NULL) { return sd_bus_reply_method_return(m, "b", false); } if (strcmp((char*)sd_event_source_get_userdata(clients[id]), sd_bus_message_get_sender(m)) != 0) { return sd_bus_reply_method_return(m, "b", false); } uint64_t usec = 0; sd_event_now(event, CLOCK_MONOTONIC, &usec); sd_event_source_set_time(clients[id], clientTimeout[id]+usec); return sd_bus_reply_method_return(m, "b", true); }
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 ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata) { sd_ipv4acd *acd = userdata; int r = 0; assert(acd); switch (acd->state) { case IPV4ACD_STATE_STARTED: ipv4acd_set_state(acd, IPV4ACD_STATE_WAITING_PROBE, true); if (acd->n_conflict >= MAX_CONFLICTS) { char ts[FORMAT_TIMESPAN_MAX]; log_ipv4acd(acd, "Max conflicts reached, delaying by %s", format_timespan(ts, sizeof(ts), RATE_LIMIT_INTERVAL_USEC, 0)); r = ipv4acd_set_next_wakeup(acd, RATE_LIMIT_INTERVAL_USEC, PROBE_WAIT_USEC); if (r < 0) goto fail; } else { r = ipv4acd_set_next_wakeup(acd, 0, PROBE_WAIT_USEC); if (r < 0) goto fail; } break; case IPV4ACD_STATE_WAITING_PROBE: case IPV4ACD_STATE_PROBING: /* Send a probe */ r = arp_send_probe(acd->fd, acd->ifindex, acd->address, &acd->mac_addr); if (r < 0) { log_ipv4acd_errno(acd, r, "Failed to send ARP probe: %m"); goto fail; } else { _cleanup_free_ char *address = NULL; union in_addr_union addr = { .in.s_addr = acd->address }; (void) in_addr_to_string(AF_INET, &addr, &address); log_ipv4acd(acd, "Probing %s", strna(address)); } if (acd->n_iteration < PROBE_NUM - 2) { ipv4acd_set_state(acd, IPV4ACD_STATE_PROBING, false); r = ipv4acd_set_next_wakeup(acd, PROBE_MIN_USEC, (PROBE_MAX_USEC-PROBE_MIN_USEC)); if (r < 0) goto fail; } else { ipv4acd_set_state(acd, IPV4ACD_STATE_WAITING_ANNOUNCE, true); r = ipv4acd_set_next_wakeup(acd, ANNOUNCE_WAIT_USEC, 0); if (r < 0) goto fail; } break; case IPV4ACD_STATE_ANNOUNCING: if (acd->n_iteration >= ANNOUNCE_NUM - 1) { ipv4acd_set_state(acd, IPV4ACD_STATE_RUNNING, false); break; } /* fall through */ case IPV4ACD_STATE_WAITING_ANNOUNCE: /* Send announcement packet */ r = arp_send_announcement(acd->fd, acd->ifindex, acd->address, &acd->mac_addr); if (r < 0) { log_ipv4acd_errno(acd, r, "Failed to send ARP announcement: %m"); goto fail; } else log_ipv4acd(acd, "ANNOUNCE"); ipv4acd_set_state(acd, IPV4ACD_STATE_ANNOUNCING, false); r = ipv4acd_set_next_wakeup(acd, ANNOUNCE_INTERVAL_USEC, 0); if (r < 0) goto fail; if (acd->n_iteration == 0) { acd->n_conflict = 0; ipv4acd_client_notify(acd, SD_IPV4ACD_EVENT_BIND); } break; default: assert_not_reached("Invalid state."); } return 0; fail: sd_ipv4acd_stop(acd); return 0; } static void ipv4acd_on_conflict(sd_ipv4acd *acd) { _cleanup_free_ char *address = NULL; union in_addr_union addr = { .in.s_addr = acd->address }; assert(acd); acd->n_conflict++; (void) in_addr_to_string(AF_INET, &addr, &address); log_ipv4acd(acd, "Conflict on %s (%u)", strna(address), acd->n_conflict); ipv4acd_reset(acd); ipv4acd_client_notify(acd, SD_IPV4ACD_EVENT_CONFLICT); } static int ipv4acd_on_packet( sd_event_source *s, int fd, uint32_t revents, void *userdata) { sd_ipv4acd *acd = userdata; struct ether_arp packet; ssize_t n; int r; assert(s); assert(acd); assert(fd >= 0); n = recv(fd, &packet, sizeof(struct ether_arp), 0); if (n < 0) { if (errno == EAGAIN || errno == EINTR) return 0; log_ipv4acd_errno(acd, errno, "Failed to read ARP packet: %m"); goto fail; } if ((size_t) n != sizeof(struct ether_arp)) { log_ipv4acd(acd, "Ignoring too short ARP packet."); return 0; } switch (acd->state) { case IPV4ACD_STATE_ANNOUNCING: case IPV4ACD_STATE_RUNNING: if (ipv4acd_arp_conflict(acd, &packet)) { usec_t ts; assert_se(sd_event_now(acd->event, clock_boottime_or_monotonic(), &ts) >= 0); /* Defend address */ if (ts > acd->defend_window) { acd->defend_window = ts + DEFEND_INTERVAL_USEC; r = arp_send_announcement(acd->fd, acd->ifindex, acd->address, &acd->mac_addr); if (r < 0) { log_ipv4acd_errno(acd, r, "Failed to send ARP announcement: %m"); goto fail; } else log_ipv4acd(acd, "DEFEND"); } else ipv4acd_on_conflict(acd); } break; case IPV4ACD_STATE_WAITING_PROBE: case IPV4ACD_STATE_PROBING: case IPV4ACD_STATE_WAITING_ANNOUNCE: /* BPF ensures this packet indicates a conflict */ ipv4acd_on_conflict(acd); break; default: assert_not_reached("Invalid state."); } return 0; fail: sd_ipv4acd_stop(acd); return 0; }
void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { usec_t ts; int r; assert(t); assert(p); assert(t->state == DNS_TRANSACTION_PENDING); assert(t->scope); assert(t->scope->manager); /* Note that this call might invalidate the query. Callers * should hence not attempt to access the query or transaction * after calling this function. */ switch (t->scope->protocol) { case DNS_PROTOCOL_LLMNR: assert(t->scope->link); /* For LLMNR we will not accept any packets from other * interfaces */ if (p->ifindex != t->scope->link->ifindex) return; if (p->family != t->scope->family) return; /* Tentative packets are not full responses but still * useful for identifying uniqueness conflicts during * probing. */ if (DNS_PACKET_LLMNR_T(p)) { dns_transaction_tentative(t, p); return; } break; case DNS_PROTOCOL_DNS: break; default: assert_not_reached("Invalid DNS protocol."); } if (t->received != p) { dns_packet_unref(t->received); t->received = dns_packet_ref(p); } if (p->ipproto == IPPROTO_TCP) { if (DNS_PACKET_TC(p)) { /* Truncated via TCP? Somebody must be f*****g with us */ dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY); return; } if (DNS_PACKET_ID(p) != t->id) { /* Not the reply to our query? Somebody must be f*****g with us */ dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY); return; } } assert_se(sd_event_now(t->scope->manager->event, clock_boottime_or_monotonic(), &ts) >= 0); switch (t->scope->protocol) { case DNS_PROTOCOL_DNS: assert(t->server); dns_server_packet_received(t->server, ts - t->start_usec); break; case DNS_PROTOCOL_LLMNR: case DNS_PROTOCOL_MDNS: dns_scope_packet_received(t->scope, ts - t->start_usec); break; default: break; } if (DNS_PACKET_TC(p)) { /* Response was truncated, let's try again with good old TCP */ r = dns_transaction_open_tcp(t); if (r == -ESRCH) { /* No servers found? Damn! */ dns_transaction_complete(t, DNS_TRANSACTION_NO_SERVERS); return; } if (r < 0) { /* On LLMNR, if we cannot connect to the host, * we immediately give up */ if (t->scope->protocol == DNS_PROTOCOL_LLMNR) { dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES); return; } /* On DNS, couldn't send? Try immediately again, with a new server */ dns_transaction_next_dns_server(t); r = dns_transaction_go(t); if (r < 0) { dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES); return; } return; } } /* Parse and update the cache */ r = dns_packet_extract(p); if (r < 0) { dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY); return; } /* Only consider responses with equivalent query section to the request */ if (p->question->n_keys != 1 || dns_resource_key_equal(p->question->keys[0], t->key) <= 0) { dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY); return; } /* According to RFC 4795, section 2.9. only the RRs from the answer section shall be cached */ dns_cache_put(&t->scope->cache, p->question, DNS_PACKET_RCODE(p), p->answer, DNS_PACKET_ANCOUNT(p), 0, p->family, &p->sender); if (DNS_PACKET_RCODE(p) == DNS_RCODE_SUCCESS) dns_transaction_complete(t, DNS_TRANSACTION_SUCCESS); else dns_transaction_complete(t, DNS_TRANSACTION_FAILURE); }
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 dns_transaction_go(DnsTransaction *t) { bool had_stream; usec_t ts; int r; assert(t); had_stream = !!t->stream; dns_transaction_stop(t); log_debug("Excercising transaction on scope %s on %s/%s", dns_protocol_to_string(t->scope->protocol), t->scope->link ? t->scope->link->name : "*", t->scope->family == AF_UNSPEC ? "*" : af_to_name(t->scope->family)); if (t->n_attempts >= TRANSACTION_ATTEMPTS_MAX(t->scope->protocol)) { dns_transaction_complete(t, DNS_TRANSACTION_ATTEMPTS_MAX_REACHED); return 0; } if (t->scope->protocol == DNS_PROTOCOL_LLMNR && had_stream) { /* If we already tried via a stream, then we don't * retry on LLMNR. See RFC 4795, Section 2.7. */ dns_transaction_complete(t, DNS_TRANSACTION_ATTEMPTS_MAX_REACHED); return 0; } assert_se(sd_event_now(t->scope->manager->event, clock_boottime_or_monotonic(), &ts) >= 0); t->n_attempts++; t->start_usec = ts; t->received = dns_packet_unref(t->received); t->cached = dns_answer_unref(t->cached); t->cached_rcode = 0; /* Check the cache, but only if this transaction is not used * for probing or verifying a zone item. */ if (set_isempty(t->zone_items)) { /* Before trying the cache, let's make sure we figured out a * server to use. Should this cause a change of server this * might flush the cache. */ dns_scope_get_dns_server(t->scope); /* Let's then prune all outdated entries */ dns_cache_prune(&t->scope->cache); r = dns_cache_lookup(&t->scope->cache, t->key, &t->cached_rcode, &t->cached); if (r < 0) return r; if (r > 0) { if (t->cached_rcode == DNS_RCODE_SUCCESS) dns_transaction_complete(t, DNS_TRANSACTION_SUCCESS); else dns_transaction_complete(t, DNS_TRANSACTION_FAILURE); return 0; } } if (t->scope->protocol == DNS_PROTOCOL_LLMNR && !t->initial_jitter) { usec_t jitter; /* RFC 4795 Section 2.7 suggests all queries should be * delayed by a random time from 0 to JITTER_INTERVAL. */ t->initial_jitter = true; random_bytes(&jitter, sizeof(jitter)); jitter %= LLMNR_JITTER_INTERVAL_USEC; r = sd_event_add_time( t->scope->manager->event, &t->timeout_event_source, clock_boottime_or_monotonic(), ts + jitter, LLMNR_JITTER_INTERVAL_USEC, on_transaction_timeout, t); if (r < 0) return r; t->n_attempts = 0; t->state = DNS_TRANSACTION_PENDING; log_debug("Delaying LLMNR transaction for " USEC_FMT "us.", jitter); return 0; } /* Otherwise, we need to ask the network */ r = dns_transaction_make_packet(t); if (r == -EDOM) { /* Not the right request to make on this network? * (i.e. an A request made on IPv6 or an AAAA request * made on IPv4, on LLMNR or mDNS.) */ dns_transaction_complete(t, DNS_TRANSACTION_NO_SERVERS); return 0; } if (r < 0) return r; if (t->scope->protocol == DNS_PROTOCOL_LLMNR && (dns_name_endswith(DNS_RESOURCE_KEY_NAME(t->key), "in-addr.arpa") > 0 || dns_name_endswith(DNS_RESOURCE_KEY_NAME(t->key), "ip6.arpa") > 0)) { /* RFC 4795, Section 2.4. says reverse lookups shall * always be made via TCP on LLMNR */ r = dns_transaction_open_tcp(t); } else { /* Try via UDP, and if that fails due to large size try via TCP */ r = dns_transaction_emit(t); if (r == -EMSGSIZE) r = dns_transaction_open_tcp(t); } if (r == -ESRCH) { /* No servers to send this to? */ dns_transaction_complete(t, DNS_TRANSACTION_NO_SERVERS); return 0; } else if (r < 0) { if (t->scope->protocol != DNS_PROTOCOL_DNS) { dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES); return 0; } /* Couldn't send? Try immediately again, with a new server */ dns_transaction_next_dns_server(t); return dns_transaction_go(t); } r = sd_event_add_time( t->scope->manager->event, &t->timeout_event_source, clock_boottime_or_monotonic(), ts + transaction_get_resend_timeout(t), 0, on_transaction_timeout, t); if (r < 0) return r; t->state = DNS_TRANSACTION_PENDING; return 1; }
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; }
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 ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata) { sd_ipv4acd *ll = userdata; int r = 0; assert(ll); switch (ll->state) { case IPV4ACD_STATE_INIT: ipv4acd_set_state(ll, IPV4ACD_STATE_WAITING_PROBE, true); if (ll->conflict >= MAX_CONFLICTS) { log_ipv4acd_notice(ll, "Max conflicts reached, delaying by %us", RATE_LIMIT_INTERVAL); r = ipv4acd_set_next_wakeup(ll, RATE_LIMIT_INTERVAL, PROBE_WAIT); if (r < 0) goto out; ll->conflict = 0; } else { r = ipv4acd_set_next_wakeup(ll, 0, PROBE_WAIT); if (r < 0) goto out; } break; case IPV4ACD_STATE_WAITING_PROBE: case IPV4ACD_STATE_PROBING: /* Send a probe */ r = arp_send_probe(ll->fd, ll->index, ll->address, &ll->mac_addr); if (r < 0) { log_ipv4acd_error_errno(ll, r, "Failed to send ARP probe: %m"); goto out; } else { _cleanup_free_ char *address = NULL; union in_addr_union addr = { .in.s_addr = ll->address }; r = in_addr_to_string(AF_INET, &addr, &address); if (r >= 0) log_ipv4acd_debug(ll, "Probing %s", address); } if (ll->iteration < PROBE_NUM - 2) { ipv4acd_set_state(ll, IPV4ACD_STATE_PROBING, false); r = ipv4acd_set_next_wakeup(ll, PROBE_MIN, (PROBE_MAX-PROBE_MIN)); if (r < 0) goto out; } else { ipv4acd_set_state(ll, IPV4ACD_STATE_WAITING_ANNOUNCE, true); r = ipv4acd_set_next_wakeup(ll, ANNOUNCE_WAIT, 0); if (r < 0) goto out; } break; case IPV4ACD_STATE_ANNOUNCING: if (ll->iteration >= ANNOUNCE_NUM - 1) { ipv4acd_set_state(ll, IPV4ACD_STATE_RUNNING, false); break; } case IPV4ACD_STATE_WAITING_ANNOUNCE: /* Send announcement packet */ r = arp_send_announcement(ll->fd, ll->index, ll->address, &ll->mac_addr); if (r < 0) { log_ipv4acd_error_errno(ll, r, "Failed to send ARP announcement: %m"); goto out; } else log_ipv4acd_debug(ll, "ANNOUNCE"); ipv4acd_set_state(ll, IPV4ACD_STATE_ANNOUNCING, false); r = ipv4acd_set_next_wakeup(ll, ANNOUNCE_INTERVAL, 0); if (r < 0) goto out; if (ll->iteration == 0) { ll->conflict = 0; ipv4acd_client_notify(ll, SD_IPV4ACD_EVENT_BIND); } break; default: assert_not_reached("Invalid state."); } out: if (r < 0) sd_ipv4acd_stop(ll); return 1; } static void ipv4acd_on_conflict(sd_ipv4acd *ll) { _cleanup_free_ char *address = NULL; union in_addr_union addr = { .in.s_addr = ll->address }; int r; assert(ll); ll->conflict++; r = in_addr_to_string(AF_INET, &addr, &address); if (r >= 0) log_ipv4acd_debug(ll, "Conflict on %s (%u)", address, ll->conflict); ipv4acd_stop(ll); ipv4acd_client_notify(ll, SD_IPV4ACD_EVENT_CONFLICT); } static int ipv4acd_on_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) { sd_ipv4acd *ll = userdata; struct ether_arp packet; int r; assert(ll); assert(fd >= 0); r = read(fd, &packet, sizeof(struct ether_arp)); if (r < (int) sizeof(struct ether_arp)) goto out; switch (ll->state) { case IPV4ACD_STATE_ANNOUNCING: case IPV4ACD_STATE_RUNNING: if (ipv4acd_arp_conflict(ll, &packet)) { usec_t ts; assert_se(sd_event_now(ll->event, clock_boottime_or_monotonic(), &ts) >= 0); /* Defend address */ if (ts > ll->defend_window) { ll->defend_window = ts + DEFEND_INTERVAL * USEC_PER_SEC; r = arp_send_announcement(ll->fd, ll->index, ll->address, &ll->mac_addr); if (r < 0) { log_ipv4acd_error_errno(ll, r, "Failed to send ARP announcement: %m"); goto out; } else log_ipv4acd_debug(ll, "DEFEND"); } else ipv4acd_on_conflict(ll); } break; case IPV4ACD_STATE_WAITING_PROBE: case IPV4ACD_STATE_PROBING: case IPV4ACD_STATE_WAITING_ANNOUNCE: /* BPF ensures this packet indicates a conflict */ ipv4acd_on_conflict(ll); break; default: assert_not_reached("Invalid state."); } out: if (r < 0) sd_ipv4acd_stop(ll); return 1; }
int main(int argc, char *argv[]) { if (argc < 5) { ERROR("usage: %s baseroot envroot program cmdl..", program_invocation_short_name); } const char *root = poe_init_playground(argv[1], argv[2]); const char *prog = copy_program(root, argv[3]); char **cmdl = construct_cmdl(argc - 4, argv + 4, prog); int stdout_fd[2], stderr_fd[2]; NONNEGATIVE(pipe2(stdout_fd, O_DIRECT)); NONNEGATIVE(pipe2(stderr_fd, O_DIRECT)); // TODO: CLONE_NEWUSER pid_t pid = (pid_t)syscall(SYS_clone, SIGCHLD | CLONE_NEWIPC | CLONE_NEWNS | CLONE_NEWPID | CLONE_NEWUTS | CLONE_NEWNET, 0); NONNEGATIVE(pid); if (pid == 0) { dup2(stdout_fd[1], STDOUT_FILENO); close(stdout_fd[0]); close(stdout_fd[1]); dup2(stderr_fd[1], STDERR_FILENO); close(stderr_fd[0]); close(stderr_fd[1]); child(root, cmdl); } else { sd_event *event = NULL; uint64_t now; int stdout_fileno = STDOUT_FILENO; int stderr_fileno = STDERR_FILENO; int fflags; fflags = fcntl(stdout_fd[0], F_GETFL, 0); NONNEGATIVE(fflags); NONNEGATIVE(fcntl(stdout_fd[0], F_SETFL, fflags | O_NONBLOCK)); fflags = fcntl(stderr_fd[0], F_GETFL, 0); NONNEGATIVE(fflags); NONNEGATIVE(fcntl(stderr_fd[0], F_SETFL, fflags | O_NONBLOCK)); sigset_t mask; sigemptyset(&mask); sigaddset(&mask, SIGCHLD); sigaddset(&mask, SIGINT); sigaddset(&mask, SIGTERM); sigprocmask(SIG_BLOCK, &mask, NULL); NONNEGATIVE(sd_event_default(&event)); NONNEGATIVE(sd_event_add_signal(event, NULL, SIGCHLD, sigchld_handler, &pid)); NONNEGATIVE(sd_event_add_signal(event, NULL, SIGINT, sigint_handler, &pid)); NONNEGATIVE(sd_event_add_signal(event, NULL, SIGTERM, sigint_handler, &pid)); NONNEGATIVE(sd_event_now(event, CLOCK_MONOTONIC, &now)); NONNEGATIVE(sd_event_add_time(event, NULL, CLOCK_MONOTONIC, now + POE_TIME_LIMIT, 0, timer_handler, &pid)); NONNEGATIVE(sd_event_add_io(event, NULL, stdout_fd[0], EPOLLIN, stdout_handler, &stdout_fileno)); NONNEGATIVE(sd_event_add_io(event, NULL, stderr_fd[0], EPOLLIN, stdout_handler, &stderr_fileno)); NONNEGATIVE(ptrace(PTRACE_SEIZE, pid, NULL, PTRACE_O_TRACECLONE | PTRACE_O_TRACEFORK | PTRACE_O_TRACESECCOMP | PTRACE_O_TRACEVFORK)); poe_init_systemd(pid); NONNEGATIVE(sd_event_loop(event)); } ERROR("unreachable"); }
static void test_sd_event_now(void) { _cleanup_(sd_event_unrefp) sd_event *e = NULL; uint64_t event_now; assert_se(sd_event_new(&e) >= 0); assert_se(sd_event_now(e, CLOCK_MONOTONIC, &event_now) > 0); assert_se(sd_event_now(e, CLOCK_REALTIME, &event_now) > 0); assert_se(sd_event_now(e, CLOCK_REALTIME_ALARM, &event_now) > 0); if (clock_boottime_supported()) { assert_se(sd_event_now(e, CLOCK_BOOTTIME, &event_now) > 0); assert_se(sd_event_now(e, CLOCK_BOOTTIME_ALARM, &event_now) > 0); } assert_se(sd_event_now(e, -1, &event_now) == -EOPNOTSUPP); assert_se(sd_event_now(e, 900 /* arbitrary big number */, &event_now) == -EOPNOTSUPP); assert_se(sd_event_run(e, 0) == 0); assert_se(sd_event_now(e, CLOCK_MONOTONIC, &event_now) == 0); assert_se(sd_event_now(e, CLOCK_REALTIME, &event_now) == 0); assert_se(sd_event_now(e, CLOCK_REALTIME_ALARM, &event_now) == 0); if (clock_boottime_supported()) { assert_se(sd_event_now(e, CLOCK_BOOTTIME, &event_now) == 0); assert_se(sd_event_now(e, CLOCK_BOOTTIME_ALARM, &event_now) == 0); } assert_se(sd_event_now(e, -1, &event_now) == -EOPNOTSUPP); assert_se(sd_event_now(e, 900 /* arbitrary big number */, &event_now) == -EOPNOTSUPP); }
static void test_basic(void) { 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 }; uint64_t event_now; 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_now(e, CLOCK_MONOTONIC, &event_now) > 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, NULL, 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_add_post(e, NULL, post_handler, NULL) >= 0); assert_se(sd_event_now(e, CLOCK_MONOTONIC, &event_now) == 0); assert_se(sd_event_source_set_time(z, event_now + 200 * USEC_PER_MSEC) >= 0); assert_se(sd_event_source_set_enabled(z, SD_EVENT_ONESHOT) >= 0); assert_se(sd_event_loop(e) >= 0); assert_se(got_post); assert_se(got_exit); 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); }