From d7fb0c7fa02a693776e9f09b64d014972033ff1f Mon Sep 17 00:00:00 2001 From: Matthias Schiffer <mschiffer@universe-factory.net> Date: Thu, 23 Apr 2015 18:18:13 +0200 Subject: [PATCH] gluon-announced: use respondd This also adds an extended query protocol and deflate compression. --- package/gluon-announced/Makefile | 14 +- .../etc/hotplug.d/iface/10-gluon-announced | 16 +- .../files/usr/lib/lua/gluon/announced.lua | 33 +++ package/gluon-announced/src/Makefile | 6 - package/gluon-announced/src/gluon-announced.c | 221 ------------------ 5 files changed, 44 insertions(+), 246 deletions(-) create mode 100644 package/gluon-announced/files/usr/lib/lua/gluon/announced.lua delete mode 100644 package/gluon-announced/src/Makefile delete mode 100644 package/gluon-announced/src/gluon-announced.c diff --git a/package/gluon-announced/Makefile b/package/gluon-announced/Makefile index 1f802dc2e..d5b06dce6 100644 --- a/package/gluon-announced/Makefile +++ b/package/gluon-announced/Makefile @@ -1,7 +1,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=gluon-announced -PKG_VERSION:=1 +PKG_VERSION:=2 PKG_RELEASE:=1 PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) @@ -11,30 +11,22 @@ include $(INCLUDE_DIR)/package.mk define Package/gluon-announced SECTION:=gluon CATEGORY:=Gluon - TITLE:=announced support - DEPENDS:=+gluon-announce -endef - -define Package/gluon-announced/description - Gluon community wifi mesh firmware framework: announced support + TITLE:=Provides node information to the network + DEPENDS:=+gluon-announce +respondd +lua-deflate endef define Build/Prepare mkdir -p $(PKG_BUILD_DIR) - $(CP) ./src/* $(PKG_BUILD_DIR)/ endef define Build/Configure endef define Build/Compile - CFLAGS="$(TARGET_CFLAGS)" CPPFLAGS="$(TARGET_CPPFLAGS)" $(MAKE) -C $(PKG_BUILD_DIR) $(TARGET_CONFIGURE_OPTS) endef define Package/gluon-announced/install $(CP) ./files/* $(1)/ - $(INSTALL_DIR) $(1)/usr/bin - $(INSTALL_BIN) $(PKG_BUILD_DIR)/gluon-announced $(1)/usr/bin/ endef $(eval $(call BuildPackage,gluon-announced)) diff --git a/package/gluon-announced/files/etc/hotplug.d/iface/10-gluon-announced b/package/gluon-announced/files/etc/hotplug.d/iface/10-gluon-announced index 4e8635bd9..a1e2c45fd 100644 --- a/package/gluon-announced/files/etc/hotplug.d/iface/10-gluon-announced +++ b/package/gluon-announced/files/etc/hotplug.d/iface/10-gluon-announced @@ -4,7 +4,7 @@ . /lib/functions/service.sh DEVLIST=/var/run/gluon-announced.devs -DAEMON=/usr/bin/gluon-announced +DAEMON=/usr/bin/respondd ifname_to_dev () { json_load "$(ubus call network.interface.$1 status)" @@ -18,10 +18,10 @@ restart_announced () { SERVICE_WRITE_PID=1 SERVICE_DAEMONIZE=1 - DEVS=$(cat $DEVLIST | while read dev iface;do echo -n " -i $dev";done) + DEVS=$(cat $DEVLIST | while read dev iface; do echo -n " -i $dev"; done) service_stop $DAEMON - service_start $DAEMON -g ff02:0:0:0:0:0:2:1001 -p 1001 -s '/lib/gluon/announce/collect.lua nodeinfo' $DEVS + service_start $DAEMON -g ff02::2:1001 -p 1001 -c 'return require("gluon.announced").handle_request' $DEVS } case "$ACTION" in @@ -29,14 +29,14 @@ case "$ACTION" in sed -i "/$INTERFACE/d" $DEVLIST ;; ifup) - DEVICE=$(ifname_to_dev $INTERFACE) - MESH=$(cat /sys/class/net/$DEVICE/batman_adv/mesh_iface) + DEVICE="$(ifname_to_dev "$INTERFACE")" + MESH="$(cat "/sys/class/net/$DEVICE/batman_adv/mesh_iface" 2>/dev/null)" - [ $MESH = "bat0" ] || exit 0 + [ "$MESH" = "bat0" -o "$INTERFACE" = "client" ] || exit 0 - DEVS="$(cat $DEVLIST; echo $DEVICE $INTERFACE)" + DEVS=$(cat $DEVLIST; echo $DEVICE $INTERFACE) - echo "$DEVS" | sort | uniq > $DEVLIST + echo "$DEVS" | sort -u > $DEVLIST restart_announced diff --git a/package/gluon-announced/files/usr/lib/lua/gluon/announced.lua b/package/gluon-announced/files/usr/lib/lua/gluon/announced.lua new file mode 100644 index 000000000..99116b81a --- /dev/null +++ b/package/gluon-announced/files/usr/lib/lua/gluon/announced.lua @@ -0,0 +1,33 @@ +local announce = require 'gluon.announce' +local deflate = require 'deflate' +local json = require 'luci.json' + + +local function collect(type) + return announce.collect_dir('/lib/gluon/announce/' .. type .. '.d') +end + + +module('gluon.announced', package.seeall) + +function handle_request(query) + if query:match('^nodeinfo$') then + return json.encode(collect('nodeinfo')) + end + + local m = query:match('^GET ([a-z ]+)$') + if m then + local data = {} + + for q in m:gmatch('([a-z]+)') do + local ok, val = pcall(collect, q) + if ok then + data[q] = val + end + end + + if next(data) then + return deflate.compress(json.encode(data)) + end + end +end diff --git a/package/gluon-announced/src/Makefile b/package/gluon-announced/src/Makefile deleted file mode 100644 index 73e7a9e21..000000000 --- a/package/gluon-announced/src/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -all: gluon-announced - -gluon-announced: gluon-announced.c - -clean: - rm gluon-announced diff --git a/package/gluon-announced/src/gluon-announced.c b/package/gluon-announced/src/gluon-announced.c deleted file mode 100644 index 27de6ecec..000000000 --- a/package/gluon-announced/src/gluon-announced.c +++ /dev/null @@ -1,221 +0,0 @@ -/* - Copyright (c) 2014, Nils Schneider <nils@nilsschneider.net> - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <stdio.h> -#include <unistd.h> -#include <stdlib.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <net/if.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <string.h> - -void usage() { - puts("Usage: gluon-announced [-h] -g <group> -p <port> -i <if0> [-i <if1> ..] -s <script>"); - puts(" -g <ip6> multicast group, e.g. ff02:0:0:0:0:0:2:1001"); - puts(" -p <int> port number to listen on"); - puts(" -i <string> interface on which the group is joined"); - puts(" -s <string> script to be executed for each request"); - puts(" -h this help\n"); -} - -/* The maximum size of output returned is limited to 8192 bytes (including - * terminating null byte) for now. If this turns out to be problem, a - * dynamic buffer should be implemented instead of increasing the - * limit. - */ -#define BUFFER 8192 - -char *run_script(size_t *length, const char *script) { - FILE *f; - char *buffer; - - buffer = calloc(BUFFER, sizeof(char)); - - if (buffer == NULL) { - fprintf(stderr, "couldn't allocate buffer\n"); - return NULL; - } - - f = popen(script, "r"); - - size_t read_bytes = 0; - while (1) { - ssize_t ret = fread(buffer+read_bytes, sizeof(char), BUFFER-read_bytes, f); - - if (ret <= 0) - break; - - read_bytes += ret; - } - - int ret = pclose(f); - - if (ret != 0) - fprintf(stderr, "script exited with status %d\n", ret); - - *length = read_bytes; - - return buffer; -} - -void join_mcast(const int sock, const struct in6_addr addr, const char *iface) { - struct ipv6_mreq mreq; - - mreq.ipv6mr_multiaddr = addr; - mreq.ipv6mr_interface = if_nametoindex(iface); - - if (mreq.ipv6mr_interface == 0) - goto error; - - if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1) - goto error; - - return; - -error: - fprintf(stderr, "Could not join multicast group on %s: ", iface); - perror(NULL); - return; -} - -#define REQUESTSIZE 64 - -char *recvrequest(const int sock, struct sockaddr *client_addr, socklen_t *clilen) { - char request_buffer[REQUESTSIZE]; - ssize_t read_bytes; - - read_bytes = recvfrom(sock, request_buffer, sizeof(request_buffer), 0, client_addr, clilen); - - if (read_bytes < 0) { - perror("recvfrom failed"); - exit(EXIT_FAILURE); - } - - char *request = strndup(request_buffer, read_bytes); - - if (request == NULL) - perror("Could not receive request"); - - return strsep(&request, "\r\n\t "); -} - -void serve(const int sock, const char *script) { - char *request; - socklen_t clilen; - struct sockaddr_in6 client_addr; - - clilen = sizeof(client_addr); - - while (1) { - request = recvrequest(sock, (struct sockaddr*)&client_addr, &clilen); - - int cmp = strcmp(request, "nodeinfo"); - free(request); - - if (cmp != 0) - continue; - - char *msg; - size_t msg_length; - msg = run_script(&msg_length, script); - - if (sendto(sock, msg, msg_length, 0, (struct sockaddr *)&client_addr, sizeof(client_addr)) < 0) { - perror("sendto failed"); - exit(EXIT_FAILURE); - } - - free(msg); - } -} - -int main(int argc, char **argv) { - int sock; - struct sockaddr_in6 server_addr = {}; - char *script = NULL; - struct in6_addr mgroup_addr; - - sock = socket(PF_INET6, SOCK_DGRAM, 0); - - if (sock < 0) { - perror("creating socket"); - exit(EXIT_FAILURE); - } - - server_addr.sin6_family = AF_INET6; - server_addr.sin6_addr = in6addr_any; - - opterr = 0; - - int group_set = 0; - - int c; - while ((c = getopt(argc, argv, "p:g:s:i:h")) != -1) - switch (c) { - case 'p': - server_addr.sin6_port = htons(atoi(optarg)); - break; - case 'g': - if (!inet_pton(AF_INET6, optarg, &mgroup_addr)) { - perror("Invalid multicast group. This message will probably confuse you"); - exit(EXIT_FAILURE); - } - - group_set = 1; - break; - case 's': - script = optarg; - - break; - case 'i': - if (!group_set) { - fprintf(stderr, "Multicast group must be given before interface.\n"); - exit(EXIT_FAILURE); - } - join_mcast(sock, mgroup_addr, optarg); - break; - case 'h': - usage(); - exit(EXIT_SUCCESS); - break; - default: - fprintf(stderr, "Invalid parameter %c ignored.\n", c); - } - - if (script == NULL) { - fprintf(stderr, "No script given\n"); - exit(EXIT_FAILURE); - } - - if (bind(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { - perror("bind failed"); - exit(EXIT_FAILURE); - } - - serve(sock, script); - - return EXIT_FAILURE; -} -- GitLab