diff options
-rw-r--r-- | src/libsystemd-network/dhcp-server-internal.h | 2 | ||||
-rw-r--r-- | src/libsystemd-network/sd-dhcp-server.c | 89 | ||||
-rw-r--r-- | src/libsystemd-network/test-dhcp-server.c | 6 | ||||
-rw-r--r-- | src/systemd/sd-dhcp-server.h | 3 |
4 files changed, 100 insertions, 0 deletions
diff --git a/src/libsystemd-network/dhcp-server-internal.h b/src/libsystemd-network/dhcp-server-internal.h index e09b35936f..8191ef7fd7 100644 --- a/src/libsystemd-network/dhcp-server-internal.h +++ b/src/libsystemd-network/dhcp-server-internal.h @@ -32,6 +32,8 @@ struct sd_dhcp_server { sd_event *event; int event_priority; + sd_event_source *receive_message; + int fd; }; DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp_server*, sd_dhcp_server_unref); diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c index 885d68d335..a9768f8fa2 100644 --- a/src/libsystemd-network/sd-dhcp-server.c +++ b/src/libsystemd-network/sd-dhcp-server.c @@ -20,8 +20,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <sys/ioctl.h> + #include "sd-dhcp-server.h" #include "dhcp-server-internal.h" +#include "dhcp-internal.h" sd_dhcp_server *sd_dhcp_server_ref(sd_dhcp_server *server) { if (server) @@ -34,6 +37,8 @@ sd_dhcp_server *sd_dhcp_server_unref(sd_dhcp_server *server) { if (server && REFCNT_DEC(server->n_ref) <= 0) { log_dhcp_server(server, "UNREF"); + sd_dhcp_server_stop(server); + sd_event_unref(server->event); free(server); } @@ -51,6 +56,7 @@ int sd_dhcp_server_new(sd_dhcp_server **ret) { return -ENOMEM; server->n_ref = REFCNT_INIT; + server->fd = -1; *ret = server; server = NULL; @@ -90,3 +96,86 @@ sd_event *sd_dhcp_server_get_event(sd_dhcp_server *server) { return server->event; } + +int sd_dhcp_server_stop(sd_dhcp_server *server) { + assert_return(server, -EINVAL); + + server->receive_message = + sd_event_source_unref(server->receive_message); + + server->fd = safe_close(server->fd); + + log_dhcp_server(server, "STOPPED"); + + return 0; +} + +static int server_receive_message(sd_event_source *s, int fd, + uint32_t revents, void *userdata) { + _cleanup_free_ uint8_t *message = NULL; + sd_dhcp_server *server = userdata; + struct iovec iov = {}; + struct msghdr msg = { + .msg_iov = &iov, + .msg_iovlen = 1, + }; + int buflen = 0, len, r; + + assert(server); + + r = ioctl(fd, FIONREAD, &buflen); + if (r < 0) + return r; + if (buflen < 0) + return -EIO; + + message = malloc0(buflen); + if (!message) + return -ENOMEM; + + iov.iov_base = message; + iov.iov_len = buflen; + + len = recvmsg(fd, &msg, 0); + if (len < buflen) + return 0; + + log_dhcp_server(server, "received message"); + + return 1; +} + +int sd_dhcp_server_start(sd_dhcp_server *server) { + int r; + + assert_return(server, -EINVAL); + assert_return(server->event, -EINVAL); + assert_return(!server->receive_message, -EBUSY); + assert_return(server->fd == -1, -EBUSY); + + r = dhcp_network_bind_udp_socket(INADDR_ANY, DHCP_PORT_SERVER); + if (r < 0) { + sd_dhcp_server_stop(server); + return r; + } + server->fd = r; + + r = sd_event_add_io(server->event, &server->receive_message, + server->fd, EPOLLIN, + server_receive_message, server); + if (r < 0) { + sd_dhcp_server_stop(server); + return r; + } + + r = sd_event_source_set_priority(server->receive_message, + server->event_priority); + if (r < 0) { + sd_dhcp_server_stop(server); + return r; + } + + log_dhcp_server(server, "STARTED"); + + return 0; +} diff --git a/src/libsystemd-network/test-dhcp-server.c b/src/libsystemd-network/test-dhcp-server.c index bd0913d51c..80d2184b70 100644 --- a/src/libsystemd-network/test-dhcp-server.c +++ b/src/libsystemd-network/test-dhcp-server.c @@ -45,6 +45,12 @@ static void test_basic(sd_event *event) { assert_se(sd_dhcp_server_ref(server) == server); assert_se(!sd_dhcp_server_unref(server)); + + assert_se(sd_dhcp_server_start(server) >= 0); + assert_se(sd_dhcp_server_start(server) == -EBUSY); + assert_se(sd_dhcp_server_stop(server) >= 0); + assert_se(sd_dhcp_server_stop(server) >= 0); + assert_se(sd_dhcp_server_start(server) >= 0); } int main(int argc, char *argv[]) { diff --git a/src/systemd/sd-dhcp-server.h b/src/systemd/sd-dhcp-server.h index ab3e707ada..47962e550c 100644 --- a/src/systemd/sd-dhcp-server.h +++ b/src/systemd/sd-dhcp-server.h @@ -38,4 +38,7 @@ int sd_dhcp_server_attach_event(sd_dhcp_server *client, sd_event *event, int pri int sd_dhcp_server_detach_event(sd_dhcp_server *client); sd_event *sd_dhcp_server_get_event(sd_dhcp_server *client); +int sd_dhcp_server_start(sd_dhcp_server *server); +int sd_dhcp_server_stop(sd_dhcp_server *server); + #endif |