aboutsummaryrefslogtreecommitdiffstats
path: root/ctrl/facemgr/examples
diff options
context:
space:
mode:
authorJordan Augé <jordan.auge+fdio@cisco.com>2019-10-07 09:52:33 +0200
committerJordan Augé <jordan.auge+fdio@cisco.com>2019-10-07 15:55:42 +0200
commit6b84ec54083da9911f5ad4816d0eb4f4745afad4 (patch)
treee4296ebb218fff02dc0bbea73ce1c8d12aba7bcc /ctrl/facemgr/examples
parent85a791ac2cdd35d79c00141e748b4c68fbdafb0d (diff)
[HICN-298] Release new hICN app for Android
Change-Id: I43adc62fadf00690b687078d739788dffdc5e566 Signed-off-by: Jordan Augé <jordan.auge+fdio@cisco.com>
Diffstat (limited to 'ctrl/facemgr/examples')
-rw-r--r--ctrl/facemgr/examples/facemgr.conf217
-rwxr-xr-xctrl/facemgr/examples/run-bonjour.sh162
-rw-r--r--ctrl/facemgr/examples/updowncli/Makefile25
-rw-r--r--ctrl/facemgr/examples/updowncli/updowncli.c57
-rw-r--r--ctrl/facemgr/examples/updownsrv/Makefile25
-rw-r--r--ctrl/facemgr/examples/updownsrv/updownsrv.c231
6 files changed, 687 insertions, 30 deletions
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
+<?xml version="1.0" standalone='no'?>
+<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
+<service-group>
+ <name>hicn node</name>
+ <service>
+ <type>_hicn._udp</type>
+ <port>$PORT</port>
+ </service>
+</service-group>
+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 <assert.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+/**
+ * \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 <arpa/inet.h> // inet_ntop
+#include <errno.h> // EINTR,. ..
+#include <netinet/in.h> // INET_ADDRSTRLEN, INET6_ADDRSTRLEN
+#include <stdio.h>
+#include <inttypes.h>
+
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/timerfd.h>
+#include <sys/un.h> // sockaddr_un
+#include <unistd.h> // fcntl
+#include <fcntl.h> // 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);
+}