示例#1
0
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(), &current) >= 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;
}
示例#2
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;
}
示例#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;
}
示例#5
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;
}
示例#6
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;
}
示例#7
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);
}
示例#8
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;
}
示例#9
0
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;
}
示例#10
0
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;
}
示例#11
0
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);
}
示例#12
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;
}
示例#13
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;
}
示例#14
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);
}
示例#15
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);
}
示例#16
0
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;
}
示例#17
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;
}
示例#18
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;
}
示例#19
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;
}
示例#20
0
文件: sandbox.c 项目: alphaKAI/poe
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");
}
示例#21
0
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);
}
示例#22
0
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);
}