diff options
Diffstat (limited to 'src/libsystemd-network/sd-dhcp-server.c')
-rw-r--r-- | src/libsystemd-network/sd-dhcp-server.c | 89 |
1 files changed, 89 insertions, 0 deletions
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; +} |