1
0
mirror of https://github.com/systemd/systemd.git synced 2024-11-07 18:27:04 +03:00

dhcp: Add timeout and main loop support

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.
This commit is contained in:
Patrik Flykt 2013-12-09 23:43:25 +02:00 committed by Zbigniew Jędrzejewski-Szmek
parent 117539f8b7
commit d3d8ac2f2b
3 changed files with 88 additions and 9 deletions

View File

@ -34,12 +34,15 @@
struct sd_dhcp_client { struct sd_dhcp_client {
DHCPState state; DHCPState state;
sd_event *event;
sd_event_source *timeout_resend;
int index; int index;
uint8_t *req_opts; uint8_t *req_opts;
size_t req_opts_size; size_t req_opts_size;
uint32_t last_addr; uint32_t last_addr;
struct ether_addr mac_addr; struct ether_addr mac_addr;
uint32_t xid; uint32_t xid;
usec_t start_time;
}; };
static const uint8_t default_req_opts[] = { static const uint8_t default_req_opts[] = {
@ -125,6 +128,8 @@ static int client_stop(sd_dhcp_client *client, int error)
assert_return(client->state != DHCP_STATE_INIT && assert_return(client->state != DHCP_STATE_INIT &&
client->state != DHCP_STATE_INIT_REBOOT, -EALREADY); client->state != DHCP_STATE_INIT_REBOOT, -EALREADY);
client->timeout_resend = sd_event_source_unref(client->timeout_resend);
switch (client->state) { switch (client->state) {
case DHCP_STATE_INIT: case DHCP_STATE_INIT:
@ -278,8 +283,61 @@ static int client_send_discover(sd_dhcp_client *client, uint16_t secs)
return 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;
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);
/* Errors were dealt with when stopping the client, don't spill
errors into the event loop handler */
return 0;
}
int sd_dhcp_client_start(sd_dhcp_client *client) int sd_dhcp_client_start(sd_dhcp_client *client)
{ {
int err;
assert_return(client, -EINVAL); assert_return(client, -EINVAL);
assert_return(client->index >= 0, -EINVAL); assert_return(client->index >= 0, -EINVAL);
assert_return(client->state == DHCP_STATE_INIT || assert_return(client->state == DHCP_STATE_INIT ||
@ -287,7 +345,18 @@ int sd_dhcp_client_start(sd_dhcp_client *client)
client->xid = random_u(); 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(sd_dhcp_client *client) int sd_dhcp_client_stop(sd_dhcp_client *client)
@ -295,14 +364,17 @@ int sd_dhcp_client_stop(sd_dhcp_client *client)
return client_stop(client, 0); return client_stop(client, 0);
} }
sd_dhcp_client *sd_dhcp_client_new(void) sd_dhcp_client *sd_dhcp_client_new(sd_event *event)
{ {
sd_dhcp_client *client; sd_dhcp_client *client;
assert_return(event, NULL);
client = new0(sd_dhcp_client, 1); client = new0(sd_dhcp_client, 1);
if (!client) if (!client)
return NULL; return NULL;
client->event = sd_event_ref(event);
client->state = DHCP_STATE_INIT; client->state = DHCP_STATE_INIT;
client->index = -1; client->index = -1;

View File

@ -34,11 +34,11 @@ static struct ether_addr mac_addr = {
.ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'} .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
}; };
static void test_request_basic(void) static void test_request_basic(sd_event *e)
{ {
sd_dhcp_client *client; sd_dhcp_client *client;
client = sd_dhcp_client_new(); client = sd_dhcp_client_new(e);
assert(client); assert(client);
@ -172,12 +172,12 @@ int dhcp_network_send_raw_packet(int index, const void *packet, size_t len)
return 575; return 575;
} }
static void test_discover_message(void) static void test_discover_message(sd_event *e)
{ {
sd_dhcp_client *client; sd_dhcp_client *client;
int res; int res;
client = sd_dhcp_client_new(); client = sd_dhcp_client_new(e);
assert(client); assert(client);
assert(sd_dhcp_client_set_index(client, 42) >= 0); assert(sd_dhcp_client_set_index(client, 42) >= 0);
@ -192,10 +192,15 @@ static void test_discover_message(void)
int main(int argc, char *argv[]) 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_checksum();
test_discover_message(); test_discover_message(e);
sd_event_run(e, (uint64_t) -1);
return 0; return 0;
} }

View File

@ -25,6 +25,8 @@
#include <netinet/in.h> #include <netinet/in.h>
#include <net/ethernet.h> #include <net/ethernet.h>
#include "sd-event.h"
typedef struct sd_dhcp_client sd_dhcp_client; typedef struct sd_dhcp_client sd_dhcp_client;
int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option); int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option);
@ -36,6 +38,6 @@ int sd_dhcp_client_set_mac(sd_dhcp_client *client,
int sd_dhcp_client_stop(sd_dhcp_client *client); int sd_dhcp_client_stop(sd_dhcp_client *client);
int sd_dhcp_client_start(sd_dhcp_client *client); int sd_dhcp_client_start(sd_dhcp_client *client);
sd_dhcp_client *sd_dhcp_client_new(void); sd_dhcp_client *sd_dhcp_client_new(sd_event *event);
#endif #endif