From 6b84ec54083da9911f5ad4816d0eb4f4745afad4 Mon Sep 17 00:00:00 2001 From: Jordan Augé Date: Mon, 7 Oct 2019 09:52:33 +0200 Subject: [HICN-298] Release new hICN app for Android MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I43adc62fadf00690b687078d739788dffdc5e566 Signed-off-by: Jordan Augé --- ctrl/facemgr/examples/facemgr.conf | 217 ++++++++++++++++++++++---- ctrl/facemgr/examples/run-bonjour.sh | 162 +++++++++++++++++++ ctrl/facemgr/examples/updowncli/Makefile | 25 +++ ctrl/facemgr/examples/updowncli/updowncli.c | 57 +++++++ ctrl/facemgr/examples/updownsrv/Makefile | 25 +++ ctrl/facemgr/examples/updownsrv/updownsrv.c | 231 ++++++++++++++++++++++++++++ 6 files changed, 687 insertions(+), 30 deletions(-) create mode 100755 ctrl/facemgr/examples/run-bonjour.sh create mode 100644 ctrl/facemgr/examples/updowncli/Makefile create mode 100644 ctrl/facemgr/examples/updowncli/updowncli.c create mode 100644 ctrl/facemgr/examples/updownsrv/Makefile create mode 100644 ctrl/facemgr/examples/updownsrv/updownsrv.c (limited to 'ctrl/facemgr/examples') diff --git a/ctrl/facemgr/examples/facemgr.conf b/ctrl/facemgr/examples/facemgr.conf index 54c212c2b..4658d13e3 100644 --- a/ctrl/facemgr/examples/facemgr.conf +++ b/ctrl/facemgr/examples/facemgr.conf @@ -1,37 +1,194 @@ +# # hICN facemgr configuration file +# -faces: -{ - # A list of interfaces to ignore - ignore = ("lo"); - - # A list of rules used to assign tags to interfaces - # Each rule follows the syntax { name = "NAME"; tags = ("TAG", ...); } - # with TAG = WIRED | WIFI | CELLULAR | TRUSTED - rules = ( - { - name = "utun1"; - tags = ("WIRED", "TRUSTED"); - } - ); - - overlay = { - ipv4 = { - local_port = 9695; - remote_port = 9695; - remote_addr = "10.60.16.14"; - }; - ipv6 = { - local_port = 9695; - remote_port = 9695; - remote_addr = "2001:420:44f1:10:20c:29ff:fef3:8f8f"; - }; - }; -} +################################################################################ +# Global settings +################################################################################ + +global = { + +# Default type for face creation +# +# Values: "auto" | "native-udp" | "native-tcp" | "overlay-udp" | "overlay-tcp" +# Default "auto" +# +#face_type = "auto"; +face_type = "overlay-udp" + +# Disable service discovery for overlay creation +# +# This is only meaningful for overlay_* face types. If service discovery is +# disabled, only manually entered overlay information will be used, if any. +# Otherwise, no face will be created. +# +# Values : true | false +# Default: false +# +#disable_discovery = true; + +# TODO Disable IPv4 face creation +# +# Values : true | false +# Default: false +# +#disable_ipv4 = true; + +# TODO Disable IPv6 face creation +# +# Values : true | false +# Default: false +# +#disable_ipv6 = true; + +# TODO overlay +# +# By default, no address is specified, and local and remote ports are set to +# the standard value for hICN (9695). +# + +}; + +################################################################################ +# Per-interface rules +################################################################################ +# +# Rules allow to override the default behaviour of the face manager. +# +# The list of rules must be specified as follows (note that the last one has no +# coma at the end) : +# +# rules = ( +# { ... }, +# { ... }, +# { ... } +# ); +# +# A rule is composed of match and override attributes, and has the following +# syntax: +# +# { +# match = { +# interface_name = STRING; +# interface_type = STRING; +# }; +# override = { +# face_type = STRING; +# disable_discovery = BOOL; +# ignore = BOOL; +# tags = (STRING, STRING, STRING); +# overlay = { +# ipv4 = { +# local_port = PORT; +# remote_addr = IP_ADDRESS; +# remote_port = PORT; +# }; +# ipv6 = { +# local_port = PORT; +# remote_addr = IP_ADDRESS; +# remote_port = PORT; +# }; +# }; +# }; +# } +# +# Match attributes: +# +# Match attributes serve to identify rules and as such defining two rules with +# similar matches is not allowed. However, overlapping match definitions are +# possible, in which case only the first matching rule is considered. +# +# A match is composed of the name of an interface and/or its type (either +# attribute is optional but at least one has to be specified). +# +# * interface_name - a string representing an interface name +# +# * interface_type - the type of interface to match +# +# Values: "wired" | "wifi" | "cellular" +# +# Override attributes: +# +# Those attributes are applied when all specified match attributes correspond, +# and override general settings or default values. +# +# * face_type - type used for face creation +# +# Values: "auto" | "native_udp" | "native_tcp" | "overlay_udp" | "overlay_tcp" +# +# * disable_discovery - disable service discovery for overlay creation +# +# Values : true | false +# +# * ignore - a boolean indicating whether that interface should be ignored +# +# * TODO tags - a (possibly empty) list of tags to be associated to the created face. +# +# Values: "wired" | "wifi" | "cellular" | "trusted" +# +# * overlay +# +# An overlay specification is used to complement any information retrieved +# through service discovery (or replace it if service discovery is +# disabled). +# +# It is possible to specify values for IPv4, IPv6 or both. +# +# Note that it is not currently possible to set different settings for IPv4 and +# IPv6 but overlay specifications. +# +# +# Here are a few example of rule definitions: +# +# rules = ( +# # Ignore localhost interface +# { +# match = { +# interface_name = "lo"; +# }; +# override = { +# ignore = true; +# }; +# }, +# # Set tags for unknown tunnnel interface +# { +# match = { +# interface_name = "utun1"; +# }; +# override = { +# tags = ("WIRED", "TRUSTED"); +# }; +# }, +# # Force cellular connections to use manually specified overlay faces +# { +# match = { +# interface_type = "cellular", +# }; +# override = { +# overlay = { +# ipv4 = { +# local_port = 9695; +# remote_addr = "10.60.16.14"; +# remote_port = 9695; +# }; +# ipv6 = { +# local_port = 9695; +# remote_addr = "2001:420:44f1:10:20c:29ff:fef3:8f8f"; +# remote_port = 9695; +# }; +# }; +# }; +# } +# ); +# +#rules = ( +#); + +################################################################################ +# Logging +################################################################################ log: { log_level = "DEBUG"; } - - diff --git a/ctrl/facemgr/examples/run-bonjour.sh b/ctrl/facemgr/examples/run-bonjour.sh new file mode 100755 index 000000000..c6c317b42 --- /dev/null +++ b/ctrl/facemgr/examples/run-bonjour.sh @@ -0,0 +1,162 @@ +#!/bin/bash + +set -e + +PORT=9695 + +#------------------------------------------------------------------------------- + +FN_AVAHI_CFG_SRC=$SCRIPT_PATH/etc_avahi_services_hicn.service +FN_AVAHI_CFG=/etc/avahi/services/hicn.service + +# https://unix.stackexchange.com/questions/265149/why-is-set-o-errexit-breaking-this-read-heredoc-expression +! read -r -d '' TPL_AVAHI_CFG <<-EOF + + + + hicn node + + _hicn._udp + $PORT + + +EOF + +#------------------------------------------------------------------------------- + +# Reliably determine script's full path +SCRIPT_PATH="$( cd "$(dirname "$0")" ; pwd -P )" + +# https://unix.stackexchange.com/questions/325594/script-a-test-for-installed-debian-package-error-handling +function pkg_is_installed() +{ + PKG="$1" + LISTF=$(mktemp) + dpkg-query -W -f '${Package} ${State}\n' >$LISTF + grep "^${PKG} " $LISTF >/dev/null + GREP_RC=$? + rm $LISTF + + # for even moar strict error handling + test $GREP_RC == 0 -o $GREP_RC == 1 + + return $GREP_RC +} + +# https://stackoverflow.com/questions/3466166/how-to-check-if-running-in-cygwin-mac-or-linux +function detect_os() +{ + unameOut="$(uname -s)" + case "${unameOut}" in + Linux*) machine=linux;; + Darwin*) machine=mac;; + CYGWIN*) machine=cygwin;; + MINGW*) machine=mingw;; + *) machine=unknown;; + esac + echo ${machine} +} + +function ensure_pkg_is_installed() +{ + PKG="$1" + pkg_is_installed $PKG && return + sudo apt install $PKG +} + +function ensure_file_installed() +{ + SRC=$1 + DST=$2 + + # Test whether destination exists and is up to date + [ -s $DST ] && cmp -s $SRC $DST && return + + sudo cp $SRC $DST +} + +function ensure_file_template() +{ + DST=$1 + TPL=$2 + + echo "$TPL" | sudo tee $DST >/dev/null +} + +function is_function() +{ + [ "$(type -t $1)" == "function" ] +} + +function os_function() +{ + FUN=$1 + shift + ARGS=$@ + + OS=$(detect_os) + if ! is_function ${FUN}_${OS}; then + echo "Platform $OS not supported for $FUN [${FUN}_${OS}]" + exit -1 + fi + ${FUN}_${OS} $ARGS +} + +#------------------------------------------------------------------------------- + +# NOTE: debian only +function run_bonjour_server_linux() +{ + ensure_pkg_is_installed avahi-daemon + #ensure_file_installed $FN_AVAHI_CFG_SRC $FN_AVAHI_CFG + ensure_file_template $FN_AVAHI_CFG "$TPL_AVAHI_CFG" + sudo service avahi-daemon restart + echo >&2, "Bonjour is now served through avahi" +} + +function run_bonjour_server_mac() +{ + dns-sd -R hicn _hicn._tcp local $PORT + # Proxy mode -P +} + +function run_bonjour_client_linux() +{ + avahi-browse -ptr _hicn._udp +} + +function run_bonjour_client_mac() +{ + dns-sd -B _hicn._udp local + +} + +# XXX function run_bonjour_proxy_linux() { } + +function run_bonjour_proxy_mac() +{ + if [[ $# != 2 ]]; then + echo "Usage: $0 proxy IP_ADDRESS" + exit -1 + fi + IP=$1 + dns-sd -P hicn _hicn._udp local $PORT hicn.local $IP path=/ +} + +#------------------------------------------------------------------------------- + +case $1 in + client) + os_function run_bonjour_client + ;; + server) + os_function run_bonjour_server + ;; + proxy) + os_function run_bonjour_proxy $@ + ;; + *) + echo "$0 [client|server]" + exit -1 + ;; +esac diff --git a/ctrl/facemgr/examples/updowncli/Makefile b/ctrl/facemgr/examples/updowncli/Makefile new file mode 100644 index 000000000..5e6111c2a --- /dev/null +++ b/ctrl/facemgr/examples/updowncli/Makefile @@ -0,0 +1,25 @@ +EXEC = $(shell basename $$(pwd)) +CC = gcc + +CFLAGS = -std=gnu11 -O3 -Wall -Wextra -Wpedantic -Wstrict-aliasing +#CFLAGS += $(shell pkg-config --cflags glib-2.0 gio-2.0) +#LDFLAGS = $(shell pkg-config --libs glib-2.0 gio-2.0) + +SRC = $(wildcard *.c) +OBJ = $(SRC:.c=.o) + +all: $(EXEC) + +${EXEC}: $(OBJ) + $(CC) -o $@ $^ $(LDFLAGS) + +%.o: %.c + $(CC) -o $@ -c $< $(CFLAGS) + +.PHONY: clean mrproper + +clean: + @rm -rf *.o + +mrproper: clean + @rm -rf $(EXEC) diff --git a/ctrl/facemgr/examples/updowncli/updowncli.c b/ctrl/facemgr/examples/updowncli/updowncli.c new file mode 100644 index 000000000..4f5a14165 --- /dev/null +++ b/ctrl/facemgr/examples/updowncli/updowncli.c @@ -0,0 +1,57 @@ +#include +#include +#include +#include +#include +#include + +/** + * \brief Default unix socket path (the leading \0 means using the abstract + * namespace instead of the filesystem). + */ +#define UNIX_PATH "\0updownsrv" + +int main() { + struct sockaddr_un addr; + char buf[100]; + int fd,rc; + + char * socket_path = UNIX_PATH; + + if ( (fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + perror("socket error"); + exit(-1); + } + + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + if (*socket_path == '\0') { + *addr.sun_path = '\0'; + strncpy(addr.sun_path+1, socket_path+1, sizeof(addr.sun_path)-2); + } else { + strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path)-1); + } + + if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) { + perror("connect error"); + exit(-1); + } + + printf("Waiting for server data...\n"); + while( (rc=read(fd, buf, sizeof(buf))) > 0) { + assert(rc == 1); + switch(buf[0]) { + case '\0': + printf("WiFi\n"); + break; + case '\1': + printf("LTE\n"); + break; + default: + printf("Unknown\n"); + break; + } + } + + return 0; +} diff --git a/ctrl/facemgr/examples/updownsrv/Makefile b/ctrl/facemgr/examples/updownsrv/Makefile new file mode 100644 index 000000000..5e6111c2a --- /dev/null +++ b/ctrl/facemgr/examples/updownsrv/Makefile @@ -0,0 +1,25 @@ +EXEC = $(shell basename $$(pwd)) +CC = gcc + +CFLAGS = -std=gnu11 -O3 -Wall -Wextra -Wpedantic -Wstrict-aliasing +#CFLAGS += $(shell pkg-config --cflags glib-2.0 gio-2.0) +#LDFLAGS = $(shell pkg-config --libs glib-2.0 gio-2.0) + +SRC = $(wildcard *.c) +OBJ = $(SRC:.c=.o) + +all: $(EXEC) + +${EXEC}: $(OBJ) + $(CC) -o $@ $^ $(LDFLAGS) + +%.o: %.c + $(CC) -o $@ -c $< $(CFLAGS) + +.PHONY: clean mrproper + +clean: + @rm -rf *.o + +mrproper: clean + @rm -rf $(EXEC) diff --git a/ctrl/facemgr/examples/updownsrv/updownsrv.c b/ctrl/facemgr/examples/updownsrv/updownsrv.c new file mode 100644 index 000000000..e10247860 --- /dev/null +++ b/ctrl/facemgr/examples/updownsrv/updownsrv.c @@ -0,0 +1,231 @@ +/* + * Dummy server sending alternating bytes to all clients. + * + * This is used by the face manager to illustrate the creation of interfaces + * using unix domains that sets a face up and down. + */ + +#include // inet_ntop +#include // EINTR,. .. +#include // INET_ADDRSTRLEN, INET6_ADDRSTRLEN +#include +#include + +#include +#include +#include +#include // sockaddr_un +#include // fcntl +#include // fcntl + + +/** + * \brief Default unix socket path (the leading \0 means using the abstract + * namespace instead of the filesystem). + */ +#define UNIX_PATH "\0updownsrv" + +/** + * \brief Default interval (in seconds) between timer events */ +#define DEFAULT_INTERVAL 100000 + +/** + * \brief Maximum allowed number of connected clients + */ +#define MAX_CLIENTS 5 + +/** + * \brief Maximum backlog of listening unix socket + */ +#define LISTEN_BACKLOG MAX_CLIENTS + + +/** + * \brief Creates a unix server socket + * \param [in] path - string representing the path on which to listen for + * connections + * \return int - fd associated to the socket + */ +int +create_unix_server(char * path) +{ + struct sockaddr_un addr; + int fd; + + fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd == -1) { + perror("socket error"); + return -1; + } + + if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { + perror("fcntl"); + return -1; + } + + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + if (*path == '\0') { + *addr.sun_path = '\0'; + strncpy(addr.sun_path+1, path+1, sizeof(addr.sun_path)-2); + } else { + strncpy(addr.sun_path, path, sizeof(addr.sun_path)-1); + unlink(path); + } + + if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) { + perror("bind error"); + return -1; + } + + if (listen(fd, LISTEN_BACKLOG) == -1) { + perror("listen error"); + return -1; + } + + return fd; +} + + +/** + * \brief Main function + */ +int main() { + int fd, tfd; + int rc; + + /* Alternating state of the server : 0 / 1 */ + unsigned state = 0; + + /* + * This server has to send a signal to all connected clients at periodic + * intervals. Since we don't expect a large number of connected clients for + * such a simple program, we simply use a statically allocated array. + */ + int clients[MAX_CLIENTS]; + size_t num_clients = 0; + + fd_set active_fd_set, read_fd_set; + FD_ZERO (&active_fd_set); + + /* Create listening unix socket */ + fd = create_unix_server(UNIX_PATH); + if (fd < 0) + exit(EXIT_FAILURE); + FD_SET (fd, &active_fd_set); + + /* Create timer */ + tfd = timerfd_create(CLOCK_MONOTONIC, 0); + if (tfd == -1) { + perror("timer error"); + exit(EXIT_FAILURE); + } + + if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { + perror("fcntl"); + exit(EXIT_FAILURE); + } + + FD_SET (tfd, &active_fd_set); + + struct itimerspec ts = { + .it_interval = { + .tv_sec = DEFAULT_INTERVAL, + .tv_nsec = 0, + }, + .it_value = { + .tv_sec = DEFAULT_INTERVAL, + .tv_nsec = 0, + } + }; + rc = timerfd_settime(tfd, 0, &ts, NULL); + if (rc == -1) { + perror("timerfd_settime"); + exit(EXIT_FAILURE); + } + + printf("Waiting for clients...\n"); + + for(;;) { + /* Block until input arrives on one or more active sockets. */ + read_fd_set = active_fd_set; + rc = select (FD_SETSIZE, &read_fd_set, NULL, NULL, NULL); + if (rc < 0) { + if (rc == EINTR) + break; + perror("select"); + exit (EXIT_FAILURE); + } + + /* Service all the sockets with input pending. */ + for (int i = 0; i < FD_SETSIZE; ++i) { + if (!FD_ISSET (i, &read_fd_set)) + continue; + if (i == fd) { + /* Connection request on original socket. */ + int client_fd = accept(fd, NULL, NULL); + if (client_fd < 0) { + perror("accept"); + continue; + } + + fprintf(stderr, "Server: connect from new client\n"); + clients[num_clients++] = client_fd; + FD_SET(client_fd, &active_fd_set); + } else if (i == tfd) { + /* Timer event */ + uint64_t res; + + read(tfd, &res, sizeof(res)); +// while (read(fd, &missed, sizeof(missed)) > 0) +// ; + for (unsigned j = 0; j < num_clients; j++) { + write(clients[j], state ? "\1" : "\0", 1); + } + printf("STATE=%d\n", state); + state = 1 - state; + } else { + char buf[1024]; + rc = read(i, buf, sizeof(buf)); + /* Client event : we close the connection on any event... */ + for (unsigned j = 0; j < num_clients; j++) { + if (i == clients[j]) { + clients[j] = clients[num_clients--]; + break; + } + } + close(i); + FD_CLR(i, &active_fd_set); + } + } + + } + + int ret = EXIT_SUCCESS; + + /* Close all active client connections */ + for (unsigned i = 0; i < num_clients; i++) { + rc = close(clients[i]); + if (rc == -1) { + perror("close"); + ret = EXIT_FAILURE; + } + } + + /* Close server */ + rc = close(fd); + if (rc == -1) { + perror("close"); + ret = EXIT_FAILURE; + } + + /* Terminate timer */ + ts.it_value.tv_sec = 0; + rc = timerfd_settime(tfd, 0, &ts, NULL); + if (rc == -1) { + perror("timerfd_settime"); + exit(EXIT_FAILURE); + } + + exit(ret); +} -- cgit 1.2.3-korg