rpcd-mod-luci: various improvements
authorJo-Philipp Wich <jo@mein.io>
Fri, 8 Nov 2019 09:01:06 +0000 (10:01 +0100)
committerJo-Philipp Wich <jo@mein.io>
Fri, 8 Nov 2019 09:02:37 +0000 (10:02 +0100)
 - Properly handle infinite dnsmasq leases
 - Use a more efficient approach to free internal AVL trees
 - Remove redundant uci context creation
 - Add new getDUIDHints method

Fixes: #3277
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
libs/rpcd-mod-luci/Makefile
libs/rpcd-mod-luci/src/luci.c

index 51e311e7f3112ac0594dc622f13b1fece7aebb26..5a25f681bf945526a700a8555b5b9c121a164507 100644 (file)
@@ -7,7 +7,7 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=rpcd-mod-luci
-PKG_VERSION:=20191103
+PKG_VERSION:=20191108
 PKG_MAINTAINER:=Jo-Philipp Wich <jo@mein.io>
 
 PKG_LICENSE:=Apache-2.0
index 12a22c889126fa13a17e9cb302c8c2aea22b17b0..77781b2e892cf3767a0382f5f683e71a90e00203 100644 (file)
@@ -420,6 +420,7 @@ lease_next(void)
        static struct lease_entry e;
        struct ether_addr *ea;
        char *p;
+       int n;
 
        memset(&e, 0, sizeof(e));
 
@@ -430,8 +431,14 @@ lease_next(void)
                        if (!p)
                                continue;
 
-                       e.expire = strtol(p, NULL, 10);
-                       e.expire = (e.expire >= 0) ? e.expire - lease_state.now : 0;
+                       n = strtol(p, NULL, 10);
+
+                       if (n > lease_state.now)
+                               e.expire = n - lease_state.now;
+                       else if (n > 0)
+                               e.expire = 0;
+                       else
+                               e.expire = -1;
 
                        p = strtok(NULL, " \t\n");
 
@@ -504,8 +511,14 @@ lease_next(void)
                        if (!p)
                                continue;
 
-                       e.expire = strtol(p, NULL, 10);
-                       e.expire = (e.expire > 0) ? e.expire - lease_state.now : e.expire;
+                       n = strtol(p, NULL, 10);
+
+                       if (n > lease_state.now)
+                               e.expire = n - lease_state.now;
+                       else if (n >= 0)
+                               e.expire = 0;
+                       else
+                               e.expire = -1;
 
                        strtok(NULL, " \t\n"); /* id */
                        strtok(NULL, " \t\n"); /* length */
@@ -1403,7 +1416,7 @@ rpc_luci_get_host_hints_ifaddrs(struct reply_context *rctx)
 
        freeifaddrs(ifaddr);
 
-       avl_for_each_element_safe(&devices, device, avl, nextdevice) {
+       avl_remove_all_elements(&devices, device, avl, nextdevice) {
                if (memcmp(&device->ea, &empty_ea, sizeof(empty_ea)) &&
                    (memcmp(&device->in6, &empty_in6, sizeof(empty_in6)) ||
                     device->in.s_addr != 0)) {
@@ -1419,7 +1432,6 @@ rpc_luci_get_host_hints_ifaddrs(struct reply_context *rctx)
                        }
                }
 
-               avl_delete(&devices, &device->avl);
                free(device);
        }
 }
@@ -1524,7 +1536,7 @@ rpc_luci_get_host_hints_finish(struct reply_context *rctx)
        struct in_addr in = {};
        void *o;
 
-       avl_for_each_element_safe(&rctx->avl, hint, avl, nexthint) {
+       avl_remove_all_elements(&rctx->avl, hint, avl, nexthint) {
                o = blobmsg_open_table(&rctx->blob, hint->avl.key);
 
                if (memcmp(&hint->ip, &in, sizeof(in))) {
@@ -1542,8 +1554,6 @@ rpc_luci_get_host_hints_finish(struct reply_context *rctx)
 
                blobmsg_close_table(&rctx->blob, o);
 
-               avl_delete(&rctx->avl, &hint->avl);
-
                if (hint->hostname)
                        free(hint->hostname);
 
@@ -1572,6 +1582,65 @@ rpc_luci_get_host_hints(struct ubus_context *ctx, struct ubus_object *obj,
        return UBUS_STATUS_OK;
 }
 
+static int
+rpc_luci_get_duid_hints(struct ubus_context *ctx, struct ubus_object *obj,
+                        struct ubus_request_data *req, const char *method,
+                        struct blob_attr *msg)
+{
+       struct { struct avl_node avl; } *e, *next;
+       char s[INET6_ADDRSTRLEN], *p;
+       struct ether_addr empty = {};
+       struct lease_entry *lease;
+       struct avl_tree avl;
+       void *o;
+
+       avl_init(&avl, avl_strcmp, false, NULL);
+       blob_buf_init(&blob, 0);
+
+       lease_open();
+
+       while ((lease = lease_next()) != NULL) {
+               if (lease->af != AF_INET6 || lease->duid == NULL)
+                       continue;
+
+               e = avl_find_element(&avl, lease->duid, e, avl);
+
+               if (e)
+                       continue;
+
+               e = calloc_a(sizeof(*e), &p, strlen(lease->duid) + 1);
+
+               if (!e)
+                       continue;
+
+               o = blobmsg_open_table(&blob, lease->duid);
+
+               inet_ntop(AF_INET6, &lease->addr.in6, s, sizeof(s));
+               blobmsg_add_string(&blob, "ip6addr", s);
+
+               if (lease->hostname)
+                       blobmsg_add_string(&blob, "hostname", lease->hostname);
+
+               if (memcmp(&lease->mac, &empty, sizeof(empty)))
+                       blobmsg_add_string(&blob, "macaddr", ea2str(&lease->mac));
+
+               blobmsg_close_table(&blob, o);
+
+               e->avl.key = strcpy(p, lease->duid);
+               avl_insert(&avl, &e->avl);
+       }
+
+       lease_close();
+
+       avl_remove_all_elements(&avl, e, avl, next) {
+               free(e);
+       }
+
+       ubus_send_reply(ctx, req, blob.head);
+
+       return UBUS_STATUS_OK;
+}
+
 static int
 rpc_luci_get_board_json(struct ubus_context *ctx, struct ubus_object *obj,
                         struct ubus_request_data *req, const char *method,
@@ -1658,7 +1727,6 @@ rpc_luci_get_dhcp_leases(struct ubus_context *ctx, struct ubus_object *obj,
        struct ether_addr emptymac = {};
        struct lease_entry *lease;
        char s[INET6_ADDRSTRLEN];
-       struct uci_context *uci;
        int af, family = 0;
        void *a, *o;
 
@@ -1682,11 +1750,6 @@ rpc_luci_get_dhcp_leases(struct ubus_context *ctx, struct ubus_object *obj,
                return UBUS_STATUS_INVALID_ARGUMENT;
        }
 
-       uci = uci_alloc_context();
-
-       if (!uci)
-               return UBUS_STATUS_UNKNOWN_ERROR;
-
        blob_buf_init(&blob, 0);
 
        for (af = family ? family : AF_INET;
@@ -1730,7 +1793,6 @@ rpc_luci_get_dhcp_leases(struct ubus_context *ctx, struct ubus_object *obj,
                blobmsg_close_array(&blob, a);
        }
 
-       uci_free_context(uci);
        ubus_send_reply(ctx, req, blob.head);
 
        return UBUS_STATUS_OK;
@@ -1743,6 +1805,7 @@ rpc_luci_api_init(const struct rpc_daemon_ops *o, struct ubus_context *ctx)
                UBUS_METHOD_NOARG("getNetworkDevices", rpc_luci_get_network_devices),
                UBUS_METHOD_NOARG("getWirelessDevices", rpc_luci_get_wireless_devices),
                UBUS_METHOD_NOARG("getHostHints", rpc_luci_get_host_hints),
+               UBUS_METHOD_NOARG("getDUIDHints", rpc_luci_get_duid_hints),
                UBUS_METHOD_NOARG("getBoardJSON", rpc_luci_get_board_json),
                UBUS_METHOD_NOARG("getDSLStatus", rpc_luci_get_dsl_status),
                UBUS_METHOD("getDHCPLeases", rpc_luci_get_dhcp_leases, rpc_get_leases_policy)