X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Flibsystemd-network%2Fsd-dhcp-server.c;h=a9768f8fa2ebc71fb8d73cabed7ada62b74b17ff;hb=ff734080aa02cd70b13bc0fdeec4a5886166163a;hp=885d68d33594ad960b01bb72f4d74d705cca6ed6;hpb=b44cd8821087f2afebf85fec5b588f5720a9415c;p=elogind.git diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c index 885d68d33..a9768f8fa 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 . ***/ +#include + #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; +}