예제 #1
0
int sd_ipv4ll_start (sd_ipv4ll *ll) {
        int r;

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

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

        if (r < 0)
                goto out;

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

        if (ll->address == 0)
                ll->address = ipv4ll_pick_address(ll);

        ipv4ll_set_state (ll, IPV4LL_STATE_INIT, 1);

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

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

        r = sd_event_add_monotonic(ll->event, &ll->timer, now(CLOCK_MONOTONIC), 0,
                                   ipv4ll_timer, ll);

        if (r < 0)
                goto out;

        r = sd_event_source_set_priority(ll->timer, ll->event_priority);

out:
        if (r < 0)
                ipv4ll_stop(ll, IPV4LL_EVENT_STOP);

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

        assert(s);

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

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

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

        return sd_event_add_monotonic(UNIT(s)->manager->event, now(CLOCK_MONOTONIC) + s->timeout_stop_usec, 0, scope_dispatch_timer, s, &s->timer_event_source);
}
예제 #3
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;
                        r = ipv4ll_client_notify(ll, IPV4LL_EVENT_BIND);
                        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_get_now_monotonic(ll->event, &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");
                        r = ipv4ll_client_notify(ll, IPV4LL_EVENT_CONFLICT);
                        ll->claimed_address = 0;

                        /* Pick a new address */
                        ll->address = ipv4ll_pick_address(ll);
                        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_monotonic(ll->event, &ll->timer,
                                   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;
        }

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

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

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

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

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

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

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

        assert_se(sd_event_add_io(e, &x, a[0], EPOLLIN, io_handler, INT_TO_PTR('a')) >= 0);
        assert_se(sd_event_add_io(e, &y, b[0], EPOLLIN, io_handler, INT_TO_PTR('b')) >= 0);
        assert_se(sd_event_add_monotonic(e, &z, 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);

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

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

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

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

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

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

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

        assert_se(got_a && got_b && got_c);

        sd_event_source_unref(x);
        sd_event_source_unref(y);

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

        assert_se(sd_event_loop(e) >= 0);

        sd_event_source_unref(z);
        sd_event_source_unref(q);

        sd_event_source_unref(w);

        sd_event_unref(e);

        close_pipe(a);
        close_pipe(b);
        close_pipe(d);
        close_pipe(k);

        return 0;
}