Require a main loop to be set when creating a DHCP client. Set up a timer to resend DHCP Discover messages and add a 0-2 second delay to the timeout value. Move to state Selecting after successful sending of a Discover message. --- v2: - previous 20/28 - use usec_t - adding monotonic event with timeout 0 seems to keep calling the timeout function continuosly, use now() for the time being
src/dhcp/client.c | 74 ++++++++++++++++++++++++++++++++++++++++-- src/dhcp/test-dhcp-client.c | 19 +++++++---- src/systemd/sd-dhcp-client.h | 4 ++- 3 files changed, 87 insertions(+), 10 deletions(-) diff --git a/src/dhcp/client.c b/src/dhcp/client.c index 8735efe..7af0075 100644 --- a/src/dhcp/client.c +++ b/src/dhcp/client.c @@ -34,12 +34,15 @@ struct DHCPClient { DHCPState state; + sd_event *event; + sd_event_source *timeout_resend; int index; uint8_t *req_opts; size_t req_opts_size; uint32_t last_addr; struct ether_addr mac_addr; uint32_t xid; + usec_t start_time; }; static const uint8_t default_req_opts[] = { @@ -124,6 +127,8 @@ static int client_stop(DHCPClient *client, int error) assert_return(client->state != DHCP_STATE_INIT && client->state != DHCP_STATE_INIT_REBOOT, -EALREADY); + client->timeout_resend = sd_event_source_unref(client->timeout_resend); + switch (client->state) { case DHCP_STATE_INIT: @@ -277,8 +282,59 @@ static int client_send_discover(DHCPClient *client, uint16_t secs) return 0; } +static int client_timeout_resend(sd_event_source *s, uint64_t usec, + void *userdata) +{ + DHCPClient *client = userdata; + usec_t next_timeout; + uint16_t secs; + int err = 0; + + switch (client->state) { + case DHCP_STATE_INIT: + case DHCP_STATE_SELECTING: + + if (!client->start_time) + client->start_time = usec; + + secs = (usec - client->start_time) / USEC_PER_SEC; + + next_timeout = usec + 2 * USEC_PER_SEC + (random() & 0x1fffff); + + err = sd_event_add_monotonic(client->event, next_timeout, + 10 * USEC_PER_MSEC, + client_timeout_resend, client, + &client->timeout_resend); + if (err < 0) + goto error; + + if (client_send_discover(client, secs) >= 0) + client->state = DHCP_STATE_SELECTING; + + break; + + case DHCP_STATE_INIT_REBOOT: + case DHCP_STATE_REBOOTING: + case DHCP_STATE_REQUESTING: + case DHCP_STATE_BOUND: + case DHCP_STATE_RENEWING: + case DHCP_STATE_REBINDING: + + break; + } + + return 0; + +error: + client_stop(client, err); + + return 0; +} + int sd_dhcp_client_start(DHCPClient *client) { + int err; + assert_return(client, -EINVAL); assert_return(client->index >= 0, -EINVAL); assert_return(client->state == DHCP_STATE_INIT || @@ -286,7 +342,18 @@ int sd_dhcp_client_start(DHCPClient *client) client->xid = random_u(); - return client_send_discover(client, 0); + err = sd_event_add_monotonic(client->event, now(CLOCK_MONOTONIC), 0, + client_timeout_resend, client, + &client->timeout_resend); + if (err < 0) + goto error; + + return 0; + +error: + client_stop(client, err); + + return err; } int sd_dhcp_client_stop(DHCPClient *client) @@ -294,14 +361,17 @@ int sd_dhcp_client_stop(DHCPClient *client) return client_stop(client, 0); } -DHCPClient *sd_dhcp_client_new(void) +DHCPClient *sd_dhcp_client_new(sd_event *event) { DHCPClient *client; + assert_return(event, NULL); + client = new0(DHCPClient, 1); if (!client) return NULL; + client->event = event; client->state = DHCP_STATE_INIT; client->index = -1; diff --git a/src/dhcp/test-dhcp-client.c b/src/dhcp/test-dhcp-client.c index 03bf348..5a4715e 100644 --- a/src/dhcp/test-dhcp-client.c +++ b/src/dhcp/test-dhcp-client.c @@ -34,11 +34,11 @@ static struct ether_addr mac_addr = { .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'} }; -static void test_request_basic(void) +static void test_request_basic(sd_event *e) { DHCPClient *client; - client = sd_dhcp_client_new(); + client = sd_dhcp_client_new(e); assert(client); @@ -172,12 +172,12 @@ int dhcp_network_send_raw_packet(int index, void *packet, int len) return 575; } -static void test_discover_message(void) +static void test_discover_message(sd_event *e) { DHCPClient *client; int res; - client = sd_dhcp_client_new(); + client = sd_dhcp_client_new(e); assert(client); assert(sd_dhcp_client_set_index(client, 42) >= 0); @@ -187,15 +187,20 @@ static void test_discover_message(void) res = sd_dhcp_client_start(client); - assert(res == 575 || res == -EINPROGRESS); + assert(res == 575 || res == 0); } int main(int argc, char *argv[]) { - test_request_basic(); + sd_event *e; + + assert(sd_event_new(&e) >= 0); + + test_request_basic(e); test_checksum(); - test_discover_message(); + test_discover_message(e); + sd_event_run(e, (uint64_t) -1); return 0; } diff --git a/src/systemd/sd-dhcp-client.h b/src/systemd/sd-dhcp-client.h index 5ca5fd3..177ccfd 100644 --- a/src/systemd/sd-dhcp-client.h +++ b/src/systemd/sd-dhcp-client.h @@ -24,6 +24,8 @@ #include <netinet/in.h> #include <net/ethernet.h> +#include "sd-event.h" + typedef struct DHCPClient DHCPClient; int sd_dhcp_client_set_request_option(DHCPClient *client, const uint8_t option); @@ -34,4 +36,4 @@ int sd_dhcp_client_set_mac(DHCPClient *client, const struct ether_addr *addr); int sd_dhcp_client_stop(DHCPClient *client); int sd_dhcp_client_start(DHCPClient *client); -DHCPClient *sd_dhcp_client_new(void); +DHCPClient *sd_dhcp_client_new(sd_event *event); -- 1.7.10.4 _______________________________________________ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel