diff options
Diffstat (limited to 'ctrl')
79 files changed, 9228 insertions, 3386 deletions
diff --git a/ctrl/facemgr/CMakeLists.txt b/ctrl/facemgr/CMakeLists.txt index f688dd2ca..377773c2d 100644 --- a/ctrl/facemgr/CMakeLists.txt +++ b/ctrl/facemgr/CMakeLists.txt @@ -20,6 +20,22 @@ endif() project(facemgr) +option(WITH_THREAD "Run library as thread" OFF) +option(WITH_EXAMPLE_DUMMY "Compile dummy example interface" OFF) +option(WITH_EXAMPLE_UPDOWN "Compile updown example interface" OFF) + +if(WITH_THREAD) + message("Building with thread support") +endif() + +if(WITH_EXAMPLE_DUMMY) + message("Building with 'dummy' example interface") +endif() + +if(WITH_EXAMPLE_UPDOWN) + message("Building with 'updown' example interface") +endif() + if (NOT CMAKE_BUILD_TYPE) message(STATUS "${PROJECT_NAME}: No build type selected, default to Release") set(CMAKE_BUILD_TYPE "Release") @@ -42,22 +58,29 @@ find_package_wrapper(Config REQUIRED) find_package_wrapper(LibEvent REQUIRED) if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) + find_package_wrapper(Libhicn REQUIRED) find_package_wrapper(Libhicnctrl REQUIRED) - set(FACE_MGR facemgr) + set(FACEMGR facemgr) + set(LIBFACEMGR facemgr) else() - if (ANDROID_API) - set(LIBHICNCTRL_LIBRARIES ${LIBHICN_CTRL_STATIC}) + if (${CMAKE_SYSTEM_NAME} STREQUAL "Android") + set(HICN_LIBRARIES ${LIBHICN_STATIC}) + set(LIBHICNCTRL_LIBRARIES ${LIBHICNCTRL_STATIC}) list(APPEND DEPENDENCIES - ${LIBHICN_CTRL_STATIC} + ${LIBHICN_STATIC} + ${LIBHICNCTRL_STATIC} ) else () - set(LIBHICNCTRL_LIBRARIES ${LIBHICN_CTRL_SHARED}) + set(HICN_LIBRARIES ${LIBHICN_SHARED}) + set(LIBHICNCTRL_LIBRARIES ${LIBHICNCTRL_SHARED}) list(APPEND DEPENDENCIES - ${LIBHICN_CTRL_SHARED} + ${LIBHICN_SHARED} + ${LIBHICNCTRL_SHARED} ) endif () endif() +add_subdirectory(includes) add_subdirectory(src) include(Packaging) diff --git a/ctrl/facemgr/README.md b/ctrl/facemgr/README.md index e1a1beb4f..0cad9bc11 100644 --- a/ctrl/facemgr/README.md +++ b/ctrl/facemgr/README.md @@ -1 +1,11 @@ # hICN Face Manager + +The bonjour interfaces uses SO_BINDTODEVICE to be able to send bonjour queries +to the right interfaces. As such facemgr has to be run as root, or with the +CAP_NET_RAW capability. + +``` +sudo getcap build-root/bin/facemgr +sudo setcap cap_net_raw+ep build-root/bin/facemgr +sudo getcap build-root/bin/facemgr +``` diff --git a/ctrl/facemgr/cmake/Modules/Packaging.cmake b/ctrl/facemgr/cmake/Modules/Packaging.cmake index 97a1b6260..3a7e5a85c 100644 --- a/ctrl/facemgr/cmake/Modules/Packaging.cmake +++ b/ctrl/facemgr/cmake/Modules/Packaging.cmake @@ -15,17 +15,17 @@ # Packages section ###################### -set(${FACE_MGR}_DESCRIPTION - "hICN face manager, lib${LIBHICN_CTRL}" +set(${FACEMGR}_DESCRIPTION + "hICN face manager, lib${LIBHICNCTRL}" CACHE STRING "Description for deb/rpm package." ) -set(${FACE_MGR}_DEB_DEPENDENCIES - "libconfig9, libevent-dev, lib${LIBHICN_CTRL} (>= stable_version)" +set(${FACEMGR}_DEB_DEPENDENCIES + "libconfig9, libevent-dev, lib${LIBHICNCTRL} (>= stable_version)" CACHE STRING "Dependencies for deb/rpm package." ) -set(${FACE_MGR}_RPM_DEPENDENCIES - "libconfig, libevent-devel, lib${LIBHICN_CTRL} >= stable_version" +set(${FACEMGR}_RPM_DEPENDENCIES + "libconfig, libevent-devel, lib${LIBHICNCTRL} >= stable_version" CACHE STRING "Dependencies for deb/rpm package." ) diff --git a/ctrl/facemgr/doc/interface.md b/ctrl/facemgr/doc/interface.md new file mode 100644 index 000000000..11c8da275 --- /dev/null +++ b/ctrl/facemgr/doc/interface.md @@ -0,0 +1,358 @@ +# Face manager : Interfaces + +## Overview + +The architecture of the face manager is built around the concept of interfaces, +which allows for a modular and extensible deployment. + +Interfaces are used to implement in isolation various sources of information +which help with the construction of faces (such as network interface and service +discovery), and with handling the heterogeneity of host platforms. + + +### Platform and supported interfaces + +Currently, Android, Linux and MacOS are supported through the following +interfaces: + +- hicn-light [Linux, Android, MacOS, iOS] + An interface to the hicn-light forwarder, and more specifically to the Face + Table and FIB data structures. This component is responsible to effectively + create, update and delete faces in the forwarder, based on the information + provided by third party interfaces, plus adding default routes for each of + the newly created face. The communication with the forwarder is based on the + hicn control library (`libhicnctrl`). + +- netlink [Linux, Android] + The default interface on Linux systems (including Android) to communicate + with the kernel and receive information from various sources, including link + and address information (both IPv4 and IPv6) about network interfaces. + +- android\_utility [Android only] + Information available through Netlink is limited with respect to cellular + interfaces. This component allows querying the Android layer through SDK + functions to get the type of a given network interface (Wired, WiFi or + Cellular). + +- bonjour [Linux, Android] + This component performs remote service discovery based on the bonjour + protocol to discover a remote hICN forwarder that might be needed to + establish overlay faces. + +- network\_framework [MacOS, iOS] + + This component uses the recommended Network framework on Apple devices, + which provided all required information to query faces in a unified API: + link and address information, interface types, and bonjour service + discovery. + + +### Architectural overview + +#### Facelets + +TODO: +- Key attributes (netdevice and protocol family) +- Facelet API + +#### Events + +TODO + +#### Facelet cache & event scheduling + +TODO: + - Facelet cache + - Joins + - How synchronization work + +### Interface API + +TODO + +## Developing a new interface + +### Dummy template + +The face manager source code includes a template that can be used as a skeleton +to develop new faces. It can be found in `src/interface/dummy/dummy.{h,c}`. Both +include guard and specific interface functions are prefixed by a (short) +identifier which acts as a namespace for interface specific code (in our case +the string 'dummy\_'). + +Registration and instanciation of the different interfaces is currently done at +compile time in the file `src/api.c`, and the appropriate hooks to use the dummy +interface are avaialble in the code between `#if 0/#endif` tags. + +#### Interface template header; configuration parameters + +All interfaces have a standard interface defined in `src/interface.{h,c}`, and +as such the header file is only used to specify the configuration parameters of +the interface, if any. + +In the template, these configuration options are empty: +``` +/* + * Configuration data + */ +typedef struct { + /* ... */ +} dummy_cfg_t; +``` + +#### Overview of the interface template + +The file starts with useful includes: +- the global include `<hicn/facemgr.h>` : this provides public facing elements + of the face manager, such the standard definition of faces (`face_t` from + `libhicnctrl`), helper classes (such as `ip_address_t` from `libhicn`), etc. +- common.h +- facelet.h : facelets are the basic unit of communication between the face +manager and the different interfaces. They are used to construct the faces +incrementally. +- interface.h : the parent class of interfaces, such as the current dummy +interface. + +Each interface can hold a pointer to an internal data structure, which is +declared as follows: +``` +/* + * Internal data + */ +typedef struct { + /* The configuration data will likely be allocated on the stack (or should + * be freed) by the caller, we recommend to make a copy of this data. + * This copy can further be altered with default values. + */ + dummy_cfg_t cfg; + + /* ... */ + + int fd; /* Sample internal data: file descriptor */ +} dummy_data_t; +``` + +We find here a copy of the configuration settings (which allows the called to +instanciate the structure on the stack), as well as a file descriptor +(assuming most interfaces will react on events on a file descriptor). + +The rest of the file consists in the implementation of the interface, in +particular the different function required by the registration of a new +interface to the system. They are grouped as part of the `interface_ops_t` data +structure declared at the end of the file: + +``` +interface\_ops\_t dummy\_ops = { + .type = "dummy", + .initialize = dummy_initialize, + .finalize = dummy_finalize, + .callback = dummy_callback, + .on_event = dummy_on_event, +}; +``` + +The structure itself is declared and documented in `src/interface.h` +``` +/** + * \brief Interface operations + */ +typedef struct { + /** The type given to the interfaces */ + char * type; + /* Constructor */ + int (*initialize)(struct interface\_s * interface, void * cfg); + /* Destructor */ + int (*finalize)(struct interface_s * interface); + /* Callback upon file descriptor event (iif previously registered) */ + int (*callback)(struct interface_s * interface); + /* Callback upon facelet events coming from the face manager */ + int (*on_event)(struct interface_s * interface, const struct facelet_s * facelet); +} interface\_ops\_t; +``` + +Such an interface has to be registered first, then one (or multiple) instance(s) +can be created (see `src/interface.c` for the function prototypes, and +`src/api.c` for their usage). + +- interface registration: + +``` +extern interface\_ops\_t dummy\_ops; + +/* [...] */ + +rc = interface\_register(&dummy\_ops); +if (rc < 0) + goto ERR_REGISTER; +``` + +- interface instanciation: + +``` +#include "interfaces/dummy/dummy.h" + +/* [...] */ + +rc = facemgr_create_interface(facemgr, "dummy0", "dummy", &facemgr->dummy); +if (rc < 0) { + ERROR("Error creating 'Dummy' interface\n"); + goto ERR_DUMMY_CREATE; +} +``` + +#### Implementation of the interface API + +We now quickly go other the different functions, but their usage will be better +understood through the hands-on example treated in the following section. + +In the template, the constructor is the most involved as it need to: + +- initialize the internal data structure: + +``` + dummy_data_t * data = malloc(sizeof(dummy_data_t)); + if (!data) + goto ERR_MALLOC; + interface->data = data; +``` + +- process configuration parameters, eventually setting some default values: + +``` + /* Use default values for unspecified configuration parameters */ + if (cfg) { + data->cfg = *(dummy_cfg_t *)cfg; + } else { + memset(&data->cfg, 0, sizeof(data->cfg)); + } +``` + +- open an eventually required file descriptor + +For the sake of simplicity, the current API only supports a single file +descriptor per-interface, and it has to be created in the constructor, and +set as the return value so as to be registered by the system, and added to the +event loop for read events. A return value of 0 means the interface does not +require any file descriptor. As usual, a negative return value indicates an +error. + +``` + data->fd = 0; + + /* ... */ + + /* + * We should return a negative value in case of error, and a positive value + * otherwise: + * - a file descriptor (>0) will be added to the event loop; or + * - 0 if we don't use any file descriptor + */ + return data->fd; +``` + +While support for multiple file descriptors might be added in the future, an +alternative short-term implementation might consider the instanciation of +multiple interface, as is done for Bonjour in the current codebase, in +`src/api.c`. + +Data reception on the file descriptor will get the callback function called, in +our case `dummy_callback`. Finally, the destructor `dummy_finalize` should close +an eventual open file descriptor. + +In order to retrieve the internal data structure, that should in particular +store such a file descriptor, all other function but the constructor can +dereference it from the interface pointer they receive as parameter: + +``` +dummy\_data\_t * data = (dummy\_data\_t*)interface->data; +``` + +#### Raising and receiving events + +An interface will receive events in the form of a facelet through the `*_on_event` +function. It can then use the facelet API we have describe above to read +information about the face. + +As this information is declared const, the interface can either create a new +facelet (identified by the same netdevice and protocol family), or eventually +clone it. + +The facelet event can then be defined and raised to the face maanger for further +processing through the following code: +``` + facelet_set_event(facelet, EVENT_TYPE_CREATE); + facelet_raise_event(facelet, interface); +``` + +Here the event is a facelet creation (`EVENT_TYPE_CREATE`). The full facelet API +and the list of possible event types is available in `src/facelet.h` + + +#### Integration in the build system + +The build system is based on CMake. Each interface should declare its source +files, private and public header files, as well as link dependencies in the +local `CMakeLists.txt` file. + +TODO: detail the structure of the file + + +### Hands-on example + +#### Overview + +In order to better illustrate the development of a new interface, we will +consider the integration of a sample server providing a signal instructing the +face manager to alternatively use either the WiFi or the LTE interface. The code +of this server is available in the folder `examples/updownsrv/`, and the +corresponding client code in `examples/updowncli`. + +Communication between client and server is done through unix sockets over an +abstract namespace (thereby not using the file system, which would cause issues +on Android). The server listens for client connections, and periodically +broadcast a binary information to all connected clients, in the form of one byte +equal to either \0 (which we might interpret as enable LTE, disable WiFi), or \1 +(enable WiFi, disable LTE). + +Our objective is to develop a new face manager interface that would listen to +such event in order to update the administrative status of the current faces. +This would thus alternatively set the different interfaces admnistratively up +and down (which takes precedence over the actual status of the interface when +the forwarder establishes the set of available next hops for a given prefix). +The actual realization of such queries will be ultimately performed by the +hicn-light interface. + +#### Sample server and client + +In the folder containing the source code of hICN, the following commands allow +to run the sample server: + +``` +cd ctrl/facemgr/examples/updownsrv +make +./updownsrv +``` + +The server should display "Waiting for clients..." + +Similar commands allow to run the sample client: +``` +cd ctrl/facemgr/examples/updowncli +make +./updowncli +``` + +The client should display "Waiting for server data...", then every couple of +seconds display either "WiFi" or "LTE". + +#### Facemanager interface + +An example illustrating how to connect to the dummy service from `updownsrv` is +provided as the `updown` interface in the facemgr source code. + +This interface periodically swaps the status of the LTE interface up and down. +It is instanciated as part of the facemgr codebase when the code is compiled +with the ``-DWITH_EXAMPLE_UPDOWN` cmake option. + + + 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); +} diff --git a/ctrl/facemgr/includes/CMakeLists.txt b/ctrl/facemgr/includes/CMakeLists.txt new file mode 100644 index 000000000..566424c67 --- /dev/null +++ b/ctrl/facemgr/includes/CMakeLists.txt @@ -0,0 +1,44 @@ +# Copyright (c) 2017-2019 Cisco and/or its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# XXX + +set(LIBFACEMGR_INCLUDE_DIRS + ${CMAKE_CURRENT_SOURCE_DIR} "" + CACHE INTERNAL + "" FORCE +) +if (${CMAKE_SYSTEM_NAME} STREQUAL "Android") + + set(TO_INSTALL_HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/facemgr.h + ${CMAKE_CURRENT_SOURCE_DIR}/hicn/facemgr/api.h + ${CMAKE_CURRENT_SOURCE_DIR}/hicn/facemgr/cfg.h + ${CMAKE_CURRENT_SOURCE_DIR}/hicn/util/log.h + ${CMAKE_CURRENT_SOURCE_DIR}/hicn/android_utility/android_utility.h + PARENT_SCOPE + ) + +else () + + set(TO_INSTALL_HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/facemgr.h + ${CMAKE_CURRENT_SOURCE_DIR}/hicn/facemgr/api.h + ${CMAKE_CURRENT_SOURCE_DIR}/hicn/facemgr/cfg.h + ${CMAKE_CURRENT_SOURCE_DIR}/hicn/util/log.h + PARENT_SCOPE + ) + +endif () + + diff --git a/ctrl/facemgr/src/netdevice.c b/ctrl/facemgr/includes/facemgr.h index 817b0e47b..b322e7b1f 100644 --- a/ctrl/facemgr/src/netdevice.c +++ b/ctrl/facemgr/includes/facemgr.h @@ -14,15 +14,15 @@ */ /** - * \file netdevice.c - * \brief Implementation of Netdevice abstraction + * \file facemgr.h + * \brief Main interface for hICN face manager library */ +#ifndef HICN_FACEMGR_H +#define HICN_FACEMGR_H -#include "common.h" -#include "netdevice.h" +#include <hicn/policy.h> +#include <hicn/facemgr/api.h> +#include <hicn/facemgr/cfg.h> + +#endif /* HICN_FACEMGR_H */ -const char * netdevice_type_str[] = { -#define _(x) [NETDEVICE_TYPE_ ## x] = STRINGIZE(x), -foreach_netdevice_type -#undef _ -} diff --git a/ctrl/facemgr/includes/hicn/android_utility/android_utility.h b/ctrl/facemgr/includes/hicn/android_utility/android_utility.h new file mode 100644 index 000000000..53adfedf6 --- /dev/null +++ b/ctrl/facemgr/includes/hicn/android_utility/android_utility.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file android_utility/android_utility.h + * \brief Android utility. + * + * This class relies on a small utility wrapper shipped with the Android + * application to access to Java SDK APIs for information not available to + * native code. + * + * For instance, we currently don't have on Linux any mean to get the type + * associated to an interface, especially for cellular interfaces. WiFi and + * Bluetooth information is for instance available through specific netlink + * subsystems, or by means of a support library, but cellular detection mostly + * relies on heuristics based on interface names (eg. in network manager). + * + * Android ship a Radio Interface Layer (RIL) daemon that exposes a control + * socket to the Java API to control the radio layer, but there is no working + * code exploiting it and no proper documentation. + */ + +#ifndef FACEMGR_INTERFACE_ANDROID_UTILITY_H +#define FACEMGR_INTERFACE_ANDROID_UTILITY_H + +#ifdef __ANDROID__ + +#include <jni.h> + +typedef struct { + JavaVM *jvm; +} android_utility_cfg_t; + +#endif /* __ANDROID__ */ + +#endif /* FACEMGR_INTERFACE_ANDROID_UTILITY_H */ diff --git a/ctrl/facemgr/src/interface_map.h b/ctrl/facemgr/includes/hicn/facemgr.h index 5930b3001..4165a8fc4 100644 --- a/ctrl/facemgr/src/interface_map.h +++ b/ctrl/facemgr/includes/hicn/facemgr.h @@ -13,12 +13,15 @@ * limitations under the License. */ -#ifndef INTERFACE_MAP_H -#define INTERFACE_MAP_H +/** + * \file facemgr.h + * \brief Main interface for hICN face manager library + */ +#ifndef HICN_FACEMGR_H +#define HICN_FACEMGR_H -#include "interface.h" -#include "util/map.h" +#include <hicn/policy.h> +#include <hicn/facemgr/api.h> -TYPEDEF_MAP_H(interface_map, const char *, interface_t *); +#endif /* HICN_FACEMGR_H */ -#endif /* INTERFACE_MAP_H */ diff --git a/ctrl/facemgr/includes/hicn/facemgr/api.h b/ctrl/facemgr/includes/hicn/facemgr/api.h new file mode 100644 index 000000000..c5c29c219 --- /dev/null +++ b/ctrl/facemgr/includes/hicn/facemgr/api.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file facemgr.h + * \brief Face manager library interface + */ +#ifndef FACEMGR_H +#define FACEMGR_H + +#include <hicn/facemgr/cfg.h> +#include <hicn/util/ip_address.h> +#ifdef __ANDROID__ +#include <hicn/android_utility/android_utility.h> +#endif + +/* + * \brief Manual overlay settings (alternative to service discovery) + */ + +typedef struct { + uint16_t local_port; + ip_address_t remote_addr; + uint16_t remote_port; +} facemgr_overlay_setting_t; + +#define FACEMGR_OVERLAY_SETTING_EMPTY (facemgr_overlay_setting_t) { \ + .local_port = 0, \ + .remote_addr = IP_ADDRESS_EMPTY, \ + .remote_port = 0, \ +} + +typedef struct { + facemgr_overlay_setting_t v4; + facemgr_overlay_setting_t v6; +} facemgr_overlay_t; + +#define FACEMGR_OVERLAY_EMPTY (facemgr_overlay_t) { \ + .v4 = FACEMGR_OVERLAY_SETTING_EMPTY, \ + .v6 = FACEMGR_OVERLAY_SETTING_EMPTY, \ +} + +/* + * \brief Face manager context + */ +typedef struct facemgr_s facemgr_t; + +int facemgr_initialize(facemgr_t *); +int facemgr_finalize(facemgr_t *); +facemgr_t * facemgr_create(); +facemgr_t * facemgr_create_with_config(facemgr_cfg_t * cfg); +void facemgr_stop(facemgr_t *); +void facemgr_free(facemgr_t *); + +int facemgr_set_config(facemgr_t * facemgr, facemgr_cfg_t * cfg); +int facemgr_reset_config(facemgr_t * facemgr); +void facemgr_set_event_loop_handler(facemgr_t * facemgr, void * loop, + void * loop_register_fd, + void * loop_unregister_event); +int facemgr_bootstrap(facemgr_t * facemgr); +#ifdef __ANDROID__ +void facemgr_set_jvm(facemgr_t * facemgr, JavaVM *jvm); +#endif /* __ANDROID__ */ + +typedef int (*facemgr_list_faces_cb_t)(face_t * face, void * user_data); + +void facemgr_list_faces(facemgr_t * facemgr, facemgr_list_faces_cb_t cb, void * user_data); + +#endif /* FACEMGR_H */ diff --git a/ctrl/facemgr/includes/hicn/facemgr/cfg.h b/ctrl/facemgr/includes/hicn/facemgr/cfg.h new file mode 100644 index 000000000..c121c687f --- /dev/null +++ b/ctrl/facemgr/includes/hicn/facemgr/cfg.h @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file cfg.h + * \brief Face manager configuration + */ +#ifndef FACEMGR_CFG_H +#define FACEMGR_CFG_H + +#include <hicn/ctrl/face.h> +#include <hicn/util/log.h> + +/* Face type */ + +#define foreach_face_type_layer \ + _(UNDEFINED) \ + _(3) \ + _(4) \ + _(N) + +typedef enum { +#define _(x) FACE_TYPE_LAYER_ ## x, + foreach_face_type_layer +#undef _ +} face_type_layer_t; + +#define foreach_face_type_encap \ + _(UNDEFINED) \ + _(TCP) \ + _(UDP) \ + _(N) + +typedef enum { +#define _(x) FACE_TYPE_ENCAP_ ## x, + foreach_face_type_encap +#undef _ +} face_type_encap_t; + +typedef struct { + face_type_layer_t layer; + face_type_encap_t encap; +} facemgr_face_type_t; + +#define FACEMGR_FACE_TYPE_UNDEFINED (facemgr_face_type_t) { \ + .layer = FACE_TYPE_LAYER_UNDEFINED, \ + .encap = FACE_TYPE_ENCAP_UNDEFINED, \ +} + +#define FACEMGR_FACE_TYPE_NATIVE_UDP (facemgr_face_type_t) { \ + .layer = FACE_TYPE_LAYER_3, \ + .encap = FACE_TYPE_ENCAP_UDP, \ +} + +#define FACEMGR_FACE_TYPE_NATIVE_TCP (facemgr_face_type_t) { \ + .layer = FACE_TYPE_LAYER_3, \ + .encap = FACE_TYPE_ENCAP_TCP, \ +} + +#define FACEMGR_FACE_TYPE_OVERLAY_UDP (facemgr_face_type_t) { \ + .layer = FACE_TYPE_LAYER_4, \ + .encap = FACE_TYPE_ENCAP_UDP, \ +} + +#define FACEMGR_FACE_TYPE_OVERLAY_TCP (facemgr_face_type_t) { \ + .layer = FACE_TYPE_LAYER_4, \ + .encap = FACE_TYPE_ENCAP_TCP, \ +} + +/* Face manager configuration */ + +#ifdef __ANDROID__ +#define FACEMGR_FACE_TYPE_DEFAULT FACEMGR_FACE_TYPE_OVERLAY_UDP +#else +#define FACEMGR_FACE_TYPE_DEFAULT FACEMGR_FACE_TYPE_NATIVE_TCP +#endif /* __ANDROID__ */ + +#define DEFAULT_FACE_TYPE FACE_TYPE_AUTO +#define FACEMGR_CFG_DEFAULT_DISCOVERY true +//#define DEFAULT_IGNORE "lo" +#define FACEMGR_CFG_DEFAULT_IPV4 true +#define FACEMGR_CFG_DEFAULT_IPV6 true + + + +typedef struct facemgr_cfg_s facemgr_cfg_t; + +facemgr_cfg_t * facemgr_cfg_create(); +void facemgr_cfg_free(facemgr_cfg_t * cfg); +int facemgr_cfg_initialize(facemgr_cfg_t * cfg); +int facemgr_cfg_finalize(facemgr_cfg_t * cfg); +void facemgr_cfg_dump(facemgr_cfg_t * cfg); + +/* Rules */ + +typedef struct facemgr_cfg_rule_s facemgr_cfg_rule_t; + +facemgr_cfg_rule_t * facemgr_cfg_rule_create(); +void facemgr_cfg_rule_free(facemgr_cfg_rule_t * rule); +int facemgr_cfg_rule_initialize(facemgr_cfg_rule_t * rule); +int facemgr_cfg_rule_finalize(facemgr_cfg_rule_t * rule); + +int facemgr_cfg_rule_set_match(facemgr_cfg_rule_t * rule, + const char * interface_name, netdevice_type_t interface_type); + +int facemgr_cfg_rule_set_face_type(facemgr_cfg_rule_t * cfg_rule, facemgr_face_type_t * face_type); +int facemgr_cfg_rule_unset_face_type(facemgr_cfg_rule_t * cfg_rule); + +int facemgr_cfg_rule_set_discovery(facemgr_cfg_rule_t * cfg_rule, bool status); +int facemgr_cfg_rule_unset_discovery(facemgr_cfg_rule_t * cfg_rule); + +int facemgr_cfg_rule_set_ignore(facemgr_cfg_rule_t * cfg_rule, bool status); +int facemgr_cfg_rule_unset_ignore(facemgr_cfg_rule_t * cfg_rule); + +int facemgr_cfg_rule_set_ipv4(facemgr_cfg_rule_t * cfg_rule, bool status); +int facemgr_cfg_rule_unset_ipv4(facemgr_cfg_rule_t * cfg_rule); + +int facemgr_cfg_rule_set_ipv6(facemgr_cfg_rule_t * cfg_rule, bool status); +int facemgr_cfg_rule_unset_ipv6(facemgr_cfg_rule_t * cfg_rule); + +int facemgr_cfg_rule_set_overlay(facemgr_cfg_rule_t * rule, int family, + ip_address_t * local_addr, uint16_t local_port, + ip_address_t * remote_addr, uint16_t remote_port); +int facemgr_rule_unset_overlay(facemgr_cfg_rule_t * rule, int family); + +/* General */ +int facemgr_cfg_set_face_type(facemgr_cfg_t * cfg, facemgr_face_type_t * face_type); +int facemgr_cfg_unset_face_type(facemgr_cfg_t * cfg); +int facemgr_cfg_set_discovery(facemgr_cfg_t * cfg, bool status); +int facemgr_cfg_unset_discovery(facemgr_cfg_t * cfg); + +int facemgr_cfg_set_overlay(facemgr_cfg_t * cfg, int family, + ip_address_t * local_addr, uint16_t local_port, + ip_address_t * remote_addr, uint16_t remote_port); +int facemgr_cfg_unset_overlay(facemgr_cfg_t * cfg, int family); + + +int facemgr_cfg_add_rule(facemgr_cfg_t * cfg, facemgr_cfg_rule_t * rule); +int facemgr_cfg_del_rule(facemgr_cfg_t * cfg, facemgr_cfg_rule_t * rule); +int facemgr_cfg_get_rule(const facemgr_cfg_t * cfg, const char * interface_name, + netdevice_type_t interface_type, facemgr_cfg_rule_t ** rule); + +/* Log */ + +/* + * Query API + * + * Takes the overrides into account + * + * TODO : interface_types are currently not taken into account by this API + */ + +int facemgr_cfg_get_face_type(const facemgr_cfg_t * cfg, + const netdevice_t * netdevice, netdevice_type_t netdevice_type, + facemgr_face_type_t * face_type); +int facemgr_cfg_get_discovery(const facemgr_cfg_t * cfg, + const netdevice_t * netdevice, netdevice_type_t netdevice_type, + bool * discovery); +int facemgr_cfg_get_ignore(const facemgr_cfg_t * cfg, + const netdevice_t * netdevice, netdevice_type_t netdevice_type, + bool * ignore); +int facemgr_cfg_get_ipv4(const facemgr_cfg_t * cfg, + const netdevice_t * netdevice, netdevice_type_t netdevice_type, + bool * ipv4); +int facemgr_cfg_get_ipv6(const facemgr_cfg_t * cfg, + const netdevice_t * netdevice, netdevice_type_t netdevice_type, + bool * ipv6); +int facemgr_cfg_get_overlay_local_addr(const facemgr_cfg_t * cfg, + const netdevice_t * netdevice, netdevice_type_t netdevice_type, + int family, ip_address_t * addr); +int facemgr_cfg_get_overlay_local_port(const facemgr_cfg_t * cfg, + const netdevice_t * netdevice, netdevice_type_t netdevice_type, + int family, u16 * port); +int facemgr_cfg_get_overlay_remote_addr(const facemgr_cfg_t * cfg, + const netdevice_t * netdevice, netdevice_type_t netdevice_type, + int family, ip_address_t * addr); +int facemgr_cfg_get_overlay_remote_port(const facemgr_cfg_t * cfg, + const netdevice_t * netdevice, netdevice_type_t netdevice_type, + int family, u16 * port); + +#endif /* FACEMGR_CFG_H */ diff --git a/ctrl/facemgr/src/util/log.h b/ctrl/facemgr/includes/hicn/util/log.h index f1cafba47..f1cafba47 100644 --- a/ctrl/facemgr/src/util/log.h +++ b/ctrl/facemgr/includes/hicn/util/log.h diff --git a/ctrl/facemgr/src/CMakeLists.txt b/ctrl/facemgr/src/CMakeLists.txt index e7dbda5c1..f99e57e07 100644 --- a/ctrl/facemgr/src/CMakeLists.txt +++ b/ctrl/facemgr/src/CMakeLists.txt @@ -20,40 +20,22 @@ set(COMPILER_DEFINITIONS ) set(HEADER_FILES -#cache.h common.h error.h - event.h - face.h - face_cache.h - face_rules.h + facelet.h interface.h - interface_map.h - interface_ops_map.h util/hash.h - util/ip_address.h - util/log.h util/map.h - util/policy.h util/set.h - util/token.h - util/types.h - ) set(SOURCE_FILES -# cache.c + api.c + cfg.c error.c - event.c - face.c - face_cache.c - face_rules.c + facelet.c interface.c - interface_map.c - interface_ops_map.c - facemgr.c util/log.c - util/policy.c ) set(INCLUDE_DIRS @@ -61,51 +43,82 @@ set(INCLUDE_DIRS ../includes/ ${CONFIG_INCLUDE_DIR} ${LIBEVENT_INCLUDE_DIR} + ${HICN_INCLUDE_DIRS} ${LIBHICNCTRL_INCLUDE_DIRS} ) set(LIBRARIES ${CONFIG_LIBRARY} ${LIBEVENT_LIBRARY} + ${HICN_LIBRARIES} ${LIBHICNCTRL_LIBRARIES} ) + add_subdirectory(interfaces) -if (ANDROID_API) - build_library(${FACE_MGR} +if(WITH_THREAD) + set(LIBRARIES + ${LIBRARIES} + "pthread" + "event_pthreads" + ) + set(COMPILER_DEFINITIONS + ${COMPILER_DEFINITIONS} + "-DWITH_THREAD" + ) +endif() + +if(WITH_EXAMPLE_DUMMY) + set(COMPILER_DEFINITIONS + ${COMPILER_DEFINITIONS} + "-DWITH_EXAMPLE_DUMMY" + ) +endif() + +if(WITH_EXAMPLE_UPDOWN) + set(COMPILER_DEFINITIONS + ${COMPILER_DEFINITIONS} + "-DWITH_EXAMPLE_UPDOWN" + ) +endif() + +if (${CMAKE_SYSTEM_NAME} STREQUAL "Android") + build_library(${LIBFACEMGR} STATIC SOURCES ${SOURCE_FILES} INSTALL_HEADERS ${TO_INSTALL_HEADER_FILES} DEPENDS ${DEPENDENCIES} - COMPONENT ${FACE_MGR} + LINK_LIBRARIES ${LIBRARIES} + COMPONENT ${FACEMGR} INCLUDE_DIRS ${INCLUDE_DIRS} INSTALL_ROOT_DIR hicn DEFINITIONS ${COMPILER_DEFINITIONS} ) else () - build_library(${FACE_MGR} - STATIC NO_DEV + build_library(${LIBFACEMGR} + SHARED STATIC NO_DEV SOURCES ${SOURCE_FILES} INSTALL_HEADERS ${TO_INSTALL_HEADER_FILES} DEPENDS ${DEPENDENCIES} - COMPONENT ${FACE_MGR} + LINK_LIBRARIES ${LIBRARIES} + COMPONENT ${FACEMGR} INCLUDE_DIRS ${INCLUDE_DIRS} INSTALL_ROOT_DIR hicn DEFINITIONS ${COMPILER_DEFINITIONS} ) endif () -if(NOT ANDROID_API AND NOT COMPILE_FOR_IOS) +if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Android" AND NOT COMPILE_FOR_IOS) list(APPEND DAEMON_SRC main.c ) - build_executable(${FACE_MGR} + build_executable(${FACEMGR} SOURCES ${DAEMON_SRC} - LINK_LIBRARIES ${FACE_MGR}.static ${LIBRARIES} - DEPENDS ${FACE_MGR}.static - COMPONENT ${FACE_MGR} + LINK_LIBRARIES ${LIBFACEMGR}.static ${LIBRARIES} + DEPENDS ${LIBFACEMGR}.static + COMPONENT ${FACEMGR} INCLUDE_DIRS ${INCLUDE_DIRS} DEFINITIONS ${COMPILER_DEFINITIONS} ) diff --git a/ctrl/facemgr/src/api.c b/ctrl/facemgr/src/api.c new file mode 100644 index 000000000..f630792c4 --- /dev/null +++ b/ctrl/facemgr/src/api.c @@ -0,0 +1,1421 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file facemgr.c + * \brief Implementation of Face manager library interface + */ + +#include <assert.h> +#include <stdio.h> +#include <string.h> + +#include <hicn/facemgr/api.h> +#include <hicn/facemgr/cfg.h> +#include <hicn/util/log.h> + +#ifdef __APPLE__ +#include "interfaces/network_framework/network_framework.h" +#endif /* __APPLE__ */ + +#ifdef __linux__ +#include "interfaces/bonjour/bonjour.h" +#endif /* __linux__ */ + +#ifdef __ANDROID__ +#include <hicn/android_utility/android_utility.h> +#endif /* __ANDROID__ */ + +#include <hicn/ctrl/face.h> +#include "common.h" +#include "facelet.h" +#include "interface.h" +#include "util/map.h" +#include "util/set.h" + +#define RAND_NAME_LEN 5 + +#define DEFAULT_PORT 9695 + +typedef struct { + interface_t * interface; + void * event; +} interface_map_data_t; + +TYPEDEF_SET_H(facelet_cache, facelet_t *); +TYPEDEF_SET(facelet_cache, facelet_t *, facelet_cmp, facelet_snprintf); + +TYPEDEF_MAP_H(interface_map, const char *, interface_map_data_t *); +TYPEDEF_MAP(interface_map, const char *, interface_map_data_t *, strcmp, string_snprintf, generic_snprintf); + +int int_cmp(int x, int y) { return x - y; } + +TYPEDEF_MAP_H(bonjour_map, netdevice_t *, interface_t *); +TYPEDEF_MAP(bonjour_map, netdevice_t *, interface_t *, netdevice_cmp, generic_snprintf, generic_snprintf); + +/* TODO automatically register interfaces */ + +#ifdef __APPLE__ +extern interface_ops_t network_framework_ops; +#endif +#ifdef __linux__ +extern interface_ops_t netlink_ops; +extern interface_ops_t bonjour_ops; +#endif +#ifdef __ANDROID__ +extern interface_ops_t android_utility_ops; +#endif /* __ANDROID__ */ +#ifdef WITH_EXAMPLE_DUMMY +extern interface_ops_t dummy_ops; +#endif +#ifdef WITH_EXAMPLE_UPDOWN +extern interface_ops_t updown_ops; +#endif +extern interface_ops_t hicn_light_ops; + + +int +facemgr_overlay_snprintf(char * s, size_t size, const facemgr_overlay_t * overlay) +{ + return -1; +} + +struct facemgr_s { + /**************************************************/ + /* Configuration parameters (exposed through API) */ + + facemgr_cfg_t * cfg; + +#ifdef __ANDROID__ + /* + * Those two pointers are needed to call java functions from the face + * manager. + */ + JavaVM *jvm; +#endif /* __ANDROID__ */ + + /* Event loop support */ + void * loop; + void * (*loop_register_fd)(void * loop, int fd, void * cb, void * cb_args); + int (*loop_unregister_event)(void * loop, void * event); + + /****************************/ + /* Internal data structures */ + + /* Map of interfaces index by name */ + interface_map_t interface_map; + + /* Faces under construction */ + facelet_cache_t facelet_cache; + + /********************************************************/ + /* Interfaces - Those should be fully replaced by a map */ + + interface_t * hl; + +#ifdef __ANDROID__ + interface_t * au; /* android_utility */ +#endif /* __ANDROID__ */ + +#ifdef __APPLE__ + interface_t * nf; /* network_framework */ +#endif /* __APPLE__ */ + +#ifdef __linux__ + interface_t * nl; /* netlink */ + + /* + * We maintain a map of dynamically created bonjour interfaces, one for each + * found netdevice + */ + bonjour_map_t bonjour_map; +#endif /* __linux__ */ + +#ifdef WITH_EXAMPLE_DUMMY + interface_t * dummy; +#endif +#ifdef WITH_EXAMPLE_UPDOWN + interface_t * updown; +#endif +}; + +int +facemgr_initialize(facemgr_t * facemgr) +{ + int rc; + + rc = interface_map_initialize(&facemgr->interface_map); + if (rc < 0) + goto ERR_INTERFACE_MAP; + + rc = facelet_cache_initialize(&facemgr->facelet_cache); + if (rc < 0) + goto ERR_FACE_CACHE_PENDING; + +#ifdef __linux__ + rc = bonjour_map_initialize(&facemgr->bonjour_map); + if (rc < 0) + goto ERR_BJ; +#endif /* __linux */ + + facemgr->cfg = facemgr_cfg_create(); + if (!facemgr->cfg) + goto ERR_CFG; + + return 0; + +ERR_CFG: +#ifdef __linux__ + bonjour_map_finalize(&facemgr->bonjour_map); +ERR_BJ: +#endif /* __linux__ */ + facelet_cache_finalize(&facemgr->facelet_cache); +ERR_FACE_CACHE_PENDING: + interface_map_finalize(&facemgr->interface_map); +ERR_INTERFACE_MAP: + return -1; +} + +int +facemgr_finalize(facemgr_t * facemgr) +{ + int rc; + + /* TODO Free all interfaces: pass free to map */ + + rc = interface_map_finalize(&facemgr->interface_map); + if (rc < 0) + goto ERR; + + rc = facelet_cache_finalize(&facemgr->facelet_cache); + if (rc < 0) + goto ERR; + +#ifdef __linux__ + rc = bonjour_map_finalize(&facemgr->bonjour_map); + if (rc < 0) + goto ERR; +#endif /* __linux__ */ + + return 0; + +ERR: + return -1; +} + +AUTOGENERATE_CREATE_FREE(facemgr); + +int +facemgr_set_config(facemgr_t * facemgr, facemgr_cfg_t * cfg) +{ + if (facemgr->cfg) { + facemgr_cfg_free(facemgr->cfg); + } + facemgr->cfg = cfg; + return 0; +} + +int facemgr_reset_config(facemgr_t * facemgr) +{ + assert(facemgr->cfg); + facemgr_cfg_free(facemgr->cfg); + facemgr->cfg = facemgr_cfg_create(); + if (!facemgr->cfg) + return -1; + return 0; +} + +facemgr_t * +facemgr_create_with_config(facemgr_cfg_t * cfg) +{ + facemgr_t * facemgr = facemgr_create(); + if (!facemgr) + return NULL; + int rc = facemgr_set_config(facemgr, cfg); + if (rc < 0) { + free(facemgr); + return NULL; + } + return facemgr; +} + +int facemgr_on_event(facemgr_t * facemgr, facelet_t * facelet); + +int +facemgr_create_interface(facemgr_t * facemgr, const char * name, const char * type, void * cfg, interface_t ** pinterface) +{ + int fd, rc; + void * event = NULL; + char rand_name[RAND_NAME_LEN+1]; + interface_t * interface; + + if (!name) { + /* + * We can manipulate the name on the stack as it will be strdup'ed by + * interface_create + */ + rand_str(rand_name, RAND_NAME_LEN); + name = rand_name; + } + + INFO("Creating interface %s [%s]...", name, type); + interface = interface_create(name, type); + if (!interface) { + ERROR("Error creating interface %s [%s]", name, type); + goto ERR_CREATE; + } + interface_set_callback(interface, facemgr_on_event, facemgr); + + fd = interface_initialize(interface, cfg); + if (fd < 0) + goto ERR_INIT; + if (fd != 0) { + event = facemgr->loop_register_fd(facemgr->loop, fd, interface->ops->callback, interface); + if (event == NULL) + goto ERR_FD; + } + + interface_map_data_t * interface_map_data = malloc(sizeof(interface_map_data_t)); + if (!interface_map_data) + goto ERR_MAP_DATA; + + + *interface_map_data = (interface_map_data_t) { + .interface = interface, + .event = event, + }; + + rc = interface_map_add(&facemgr->interface_map, interface->name, interface_map_data); + if (rc < 0) + goto ERR_MAP_ADD; + + DEBUG("Interface %s created successfully.", name); + if (pinterface) + *pinterface = interface; + return 0; + +ERR_MAP_ADD: + free(interface_map_data); +ERR_MAP_DATA: + if (fd > 0) + facemgr->loop_unregister_event(facemgr->loop, interface_map_data->event); +ERR_FD: + interface_finalize(interface); +ERR_INIT: + interface_free(interface); +ERR_CREATE: + if (pinterface) + *pinterface = NULL; + return -1; +} + +int +facemgr_delete_interface(facemgr_t * facemgr, interface_t * interface) +{ + int rc; + + interface_map_data_t * interface_map_data = NULL; + + DEBUG("Removing interface %s\n", interface->name); + rc = interface_map_remove(&facemgr->interface_map, interface->name, &interface_map_data); + if (rc < 0) + return -1; + + if (!interface_map_data) + return -1; + + free(interface_map_data); + + rc = facemgr->loop_unregister_event(facemgr->loop, interface_map_data->event); + if (rc < 0) + return -1; + + + interface_finalize(interface); + interface_free(interface); + + return 0; +} + +#ifdef __linux__ +int facemgr_query_bonjour(facemgr_t * facemgr, netdevice_t * netdevice) +{ + interface_t * bj = NULL; + + int rc = bonjour_map_get(&facemgr->bonjour_map, netdevice, &bj); + if (rc < 0) + return rc; + + if (!bj) { + /* Create a new bonjour interface */ + bonjour_cfg_t bj_cfg = { + .netdevice = *netdevice, + }; + rc = facemgr_create_interface(facemgr, NULL, "bonjour", &bj_cfg, &bj); + if (rc < 0) { + ERROR("Error creating 'Bonjour' interface for '%s'\n", netdevice->name); + return -1; + } + } + + DEBUG("sending event to bonjour interface"); + + /* Send an event to the interface (GET ?) */ + return interface_on_event(bj, NULL); +} +#endif /* __linux__ */ + +#ifdef __ANDROID__ +int facemgr_query_android_utility(facemgr_t * facemgr, netdevice_t netdevice) +{ + /* Send an event to the interface */ + facelet_t * facelet = facelet_create(); + if (!facelet) + goto ERR_MALLOC; + + int rc = facelet_set_netdevice(facelet, netdevice); + if (rc < 0) + goto ERR_ND; + + rc = interface_on_event(facemgr->au, facelet); + if (rc < 0) + goto ERR_EVENT; + + return 0; + +ERR_EVENT: +ERR_ND: + facelet_free(facelet); +ERR_MALLOC: + return -1; +} +#endif /* __ANDROID__ */ + + +/** + * \brief Performs a cache lookup to find matching facelets + * \param [in] facelet_cache - Facelet cache on which to perform lookup + * \param [in] facelet - Facelet to lookup + * \param [out] cached_facelet - Pointer used to return a newly allocated + * facelet array corresponding to the result of the cache lookup. + * \return The number of entries in the array in case of success (positive + * value), or -1 in case of error. + */ +int +facelet_cache_lookup(const facelet_cache_t * facelet_cache, facelet_t * facelet, + facelet_t ***cached_facelets) +{ + /* + * If the facelet is uniquely identified by its key, it is used to perform + * an efficient lookup directly... + */ + if (facelet_has_key(facelet)) { + facelet_t * found = NULL; + if (facelet_cache_get(facelet_cache, facelet, &found) < 0) { + ERROR("[facelet_cache_lookup] Error during cache lookup"); + return -1; + } + if (!found) + return 0; + *cached_facelets = malloc(sizeof(facelet_t*)); + *cached_facelets[0] = found; + return 1; + } + + /* ...otherwise, we iterate over the facelet + * cache to find matching elements. + */ + facelet_t ** facelet_array; + int n = facelet_cache_get_array(facelet_cache, &facelet_array); + if (n < 0) { + ERROR("[facelet_cache_lookup] Error during cache match"); + return -1; + } + *cached_facelets = malloc(n * sizeof(facelet_t*)); + + DEBUG("cache match n = %d", n); + + int num_match = 0; + for (unsigned i = 0; i < n; i++) { + char buf[128]; + facelet_snprintf(buf, 128, facelet_array[i]); + DEBUG("- facelet_array[%d] %s", i, buf); + facelet_snprintf(buf, 128, facelet); + DEBUG(" facelet %s", buf); + + DEBUG("match ?"); + if (!facelet_match(facelet_array[i], facelet)) { + DEBUG("no match"); + continue; + } + DEBUG("match!"); + (*cached_facelets)[num_match++] = facelet_array[i]; + } + free(facelet_array); + DEBUG("return nummatch=%d", num_match); + return num_match; +} + + +/** + * \brief Checks whether the facelet satisfies face creation rules + * \param [in] facemgr - Pointer to the face manager instance + * \param [in] facelet - Pointer to the facelet to process + * \return 0 in case of success, -2 if we don't have enough information to + * decide, -3 if the face does not satisfy rules, and -1 in case of error + */ +int +facemgr_facelet_satisfy_rules(facemgr_t * facemgr, facelet_t * facelet) +{ + /* As key, netdevice and family should always be present */ + netdevice_t netdevice = NETDEVICE_EMPTY; + int rc = facelet_get_netdevice(facelet, &netdevice); + if (rc < 0) { + ERROR("[facemgr_facelet_satisfy_rules] Error retrieving netdevice from facelet"); + return -1; + } + + int family = AF_UNSPEC; + if (facelet_has_family(facelet)) { + if (facelet_get_family(facelet, &family) < 0) { + ERROR("[facemgr_facelet_satisfy_rules] Error retrieving family from facelet"); + return -1; + } + } + + netdevice_type_t netdevice_type = NETDEVICE_TYPE_UNDEFINED; +#ifdef __ANDROID__ + /* + * In addition to netdevice, netdevice_type should be present to correctly + * apply rules + */ + rc = facelet_get_netdevice_type(facelet, &netdevice_type); + if (rc < 0) { + ERROR("[facemgr_facelet_satisfy_rules] Error retrieving netdevice_type from facelet"); + return -2; + } +#endif /* __ANDROID__ */ + + /* Ignore */ + bool ignore; + if (facemgr_cfg_get_ignore(facemgr->cfg, &netdevice, netdevice_type, + &ignore) < 0) + return -1; + if (ignore) { + DEBUG("Ignored interface '%s/%s'...", netdevice.name, + netdevice_type_str[netdevice_type]); + return -3; + } + + /* IPv4 */ + bool ipv4; + if (facemgr_cfg_get_ipv4(facemgr->cfg, &netdevice, netdevice_type, + &ipv4) < 0) + return -1; + if (!ipv4) { + DEBUG("Ignored IPv4..."); + return -3; + } + + /* IPv6 */ + bool ipv6; + if (facemgr_cfg_get_ipv6(facemgr->cfg, &netdevice, netdevice_type, + &ipv6) < 0) + return -1; + if (!ipv6) { + DEBUG("Ignored IPv6..."); + return -3; + } + + return 0; +} + +#ifdef __ANDROID__ +/** + * \brief Complements facelet information through Android Utility interface + * \return 0 if request was successful, -1 in case of error, and -2 if the + * interface is not applicable + * + * This function returnds _after_ completion. + */ +int +facemgr_complement_facelet_au(facemgr_t * facemgr, facelet_t * facelet) +{ + + if (facelet_has_netdevice_type(facelet)) + return -2; + + if (facelet_is_au_done(facelet)) + return -2; + + netdevice_t netdevice = NETDEVICE_EMPTY; + int rc = facelet_get_netdevice(facelet, &netdevice); + if (rc < 0) { + ERROR("[facemgr_complement_facelet_bj] Error retrieving netdevice from facelet"); + return -1; + } + + DEBUG("Querying android utility..."); + facelet_set_au_done(facelet); + + /* /!\ Synchronous code here /!\ */ + if (facemgr_query_android_utility(facemgr, netdevice) < 0) + return -1; + return 0; +} +#endif /* __ANDROID__ */ + +#ifdef __linux__ +/** + * \brief Complements facelet information through Bonjour interface. + * \return 0 if request was successful, -1 in case of error, and -2 if the + * interface is not applicable + * + * This function returnds _before_ completion as bonjour querying is + * asynchronous. + */ +int +facemgr_complement_facelet_bj(facemgr_t * facemgr, facelet_t * facelet) +{ + netdevice_t netdevice = NETDEVICE_EMPTY; + int rc = facelet_get_netdevice(facelet, &netdevice); + if (rc < 0) { + ERROR("[facemgr_complement_facelet_bj] Error retrieving netdevice from facelet"); + return -1; + } + + netdevice_type_t netdevice_type = NETDEVICE_TYPE_UNDEFINED; +#ifdef __ANDROID__ + /* + * In addition to netdevice, netdevice_type should be present to correctly + * apply rules + */ + rc = facelet_get_netdevice_type(facelet, &netdevice_type); + if (rc < 0) { + ERROR("[facemgr_complement_facelet_bj] Error retrieving netdevice_type from facelet"); + return -2; + } +#endif /* __ANDROID__ */ + + bool discovery; + if (facemgr_cfg_get_discovery(facemgr->cfg, &netdevice, netdevice_type, + &discovery) < 0) + return -2; + + DEBUG("Discovery: %s", discovery ? "ON" : "OFF"); + + if (!discovery) + return -2; + + facemgr_face_type_t face_type = FACEMGR_FACE_TYPE_UNDEFINED; + if (facelet_get_face_type(facelet, &face_type) < 0) { + ERROR("[facemgr_complement_facelet_bj] Error retrieving face type from facelet"); + return -1; + } + + bool discovery_needed = (face_type.layer == FACE_TYPE_LAYER_4) && + ((!facelet_has_remote_addr(facelet)) || (!facelet_has_remote_port(facelet))); + + DEBUG("Discovery needed: %s", discovery ? "ON" : "OFF"); + + if (!discovery_needed) { + return -2; + } + + if (!facelet_has_local_addr(facelet)) { + DEBUG("No discovery possible without local address"); + return -2; + } + + if (facelet_is_bj_done(facelet)) { + DEBUG("Bonjour already queried"); + return -2; + } + + facelet_set_bj_done(facelet); + return facemgr_query_bonjour(facemgr, &netdevice); +} +#endif /* __linux__ */ + +/** + * \brief Complements facelet information through Manual settings. + * \return 0 if request was successful, -1 in case of error, and -2 if the + * interface is not applicable + * + * This function returnds _before_ completion as bonjour querying is + * asynchronous. + */ +int +facemgr_complement_facelet_manual(facemgr_t * facemgr, facelet_t * facelet) +{ + + netdevice_t netdevice = NETDEVICE_EMPTY; + int rc = facelet_get_netdevice(facelet, &netdevice); + if (rc < 0) { + ERROR("[facemgr_complement_facelet_manual] Error retrieving netdevice from facelet"); + return -1; + } + + netdevice_type_t netdevice_type = NETDEVICE_TYPE_UNDEFINED; +#ifdef __ANDROID__ + /* + * In addition to netdevice, netdevice_type should be present to correctly + * apply rules + */ + rc = facelet_get_netdevice_type(facelet, &netdevice_type); + if (rc < 0) { + ERROR("[facemgr_complement_facelet_manual] Error retrieving netdevice_type from facelet"); + return -2; + } +#endif /* __ANDROID__ */ + + int family = AF_UNSPEC; + if (facelet_has_family(facelet)) { + if (facelet_get_family(facelet, &family) < 0) { + ERROR("[facemgr_complement_facelet_manual] Error retrieving family from facelet"); + return -1; + } + } + + /* Do not query manual is there is a change to go through bonjour */ + bool discovery; + if (facemgr_cfg_get_discovery(facemgr->cfg, &netdevice, netdevice_type, + &discovery) < 0) + return -2; + + facemgr_face_type_t face_type = FACEMGR_FACE_TYPE_UNDEFINED; + if (facelet_get_face_type(facelet, &face_type) < 0) { + ERROR("[facemgr_complement_facelet_manual] Error retrieving face type from facelet"); + return -1; + } + + bool discovery_needed = (face_type.layer == FACE_TYPE_LAYER_4) && + ((!facelet_has_remote_addr(facelet)) || (!facelet_has_remote_port(facelet))); + + if (!discovery_needed) { + DEBUG("manual settings not considered as no discovery is needed"); + return -2; + } + + if (discovery && !facelet_is_bj_done(facelet)) { + DEBUG("manual settings not considered as discovery is enabled and Bonjour has not yet been done"); + return -2; + } + + DEBUG("Applying manual settings..."); + /* + * Manual overlay specification (remote addr/port) + * We never override a result we have obtained through bonjour + */ + if (!facelet_has_remote_addr(facelet)) { + ip_address_t remote_addr; + if (facemgr_cfg_get_overlay_remote_addr(facemgr->cfg, + &netdevice, netdevice_type, family, &remote_addr) < 0) { + ERROR("[facemgr_complement_facelet_manual] Error getting remote addr information from cfg"); + return -1; + } + if (ip_address_empty(&remote_addr)) { + ERROR("[facemgr_complement_facelet_manual] Got empty remote addr information from cfg"); + } else { + DEBUG(" - remote address"); + facelet_set_remote_addr(facelet, remote_addr); + } + } + + if (!facelet_has_remote_port(facelet)) { + uint16_t remote_port; + int rc = facemgr_cfg_get_overlay_remote_port(facemgr->cfg, + &netdevice, netdevice_type, family, &remote_port); + if (rc < 0) { + ERROR("[facemgr_complement_facelet_manual] Error getting remote port information from cfg"); + return -1; + } + DEBUG(" - remote port"); + facelet_set_remote_port(facelet, remote_port); + } + + /* + * Complementing local addr/port XXX this should be done somewhere + * else : manual settings have the lowest priority + * + * Local IP address is specific as it allows to override the source + * address just before creating the face... we would need to check + * whether this is an address that belong to us... it might be used + * to arbitrate amongst several IP addresses instead... + */ + ip_address_t local_addr; + if (facemgr_cfg_get_overlay_local_addr(facemgr->cfg, &netdevice, + netdevice_type, family, &local_addr) < 0) { + ERROR("[facemgr_complement_facelet_manual] Error getting local addr information from cfg"); + return -1; + } + if (ip_address_empty(&local_addr)) { + ERROR("[facemgr_complement_facelet_manual] Got empty local addr information from cfg"); + } else { + DEBUG(" - local addres"); + facelet_set_local_addr(facelet, local_addr); + } + + /* Sets a default local port, so far nobody sets it */ + uint16_t local_port; + if (facemgr_cfg_get_overlay_local_port(facemgr->cfg, + &netdevice, netdevice_type, family, &local_port) < 0) { + ERROR("[facemgr_complement_facelet_manual] Error getting local port information from cfg"); + return -1; + } + DEBUG(" - local port"); + facelet_set_local_port(facelet, local_port); + return 0; +} + +int +facemgr_complement_facelet(facemgr_t * facemgr, facelet_t * facelet) +{ + int rc; + + if (!facelet_has_key(facelet)) + return -2; + +#ifdef __ANDROID__ + rc = facemgr_complement_facelet_au(facemgr, facelet); + if (rc != -2) + return rc; +#endif /* __ANDROID__ */ + + /* We continue only if the current call was not applicable. In the current + * setting we have no interface that can be requested in parallel, and no + * need to. This might evolve in future releases. + */ + +#ifdef __linux__ + rc = facemgr_complement_facelet_bj(facemgr, facelet); + if (rc != -2) + return rc; +#endif /* __linux__ */ + + DEBUG("Complement manual"); + + rc = facemgr_complement_facelet_manual(facemgr, facelet); + if (rc != -2) + return rc; + + INFO("[facemgr_complement_facelet] No more interfaces to query... incomplete face"); + return 0; +} + +/** + * \brief Process facelet CREATE event + * \param [in] facemgr - Pointer to the face manager instance + * \param [in] facelet - Pointer to the facelet event to process + * \return 0 if everything went correctly, or -1 in case of error. + */ +int +facemgr_process_create(facemgr_t * facemgr, facelet_t * facelet) +{ + /* + * We create an interface locally, which does not means it should not exist + * remotely. Once such codepath is enabled, the two facelets will have been + * merged and we need to handle an eventual update on our side. + * + * In the same way, we need to check for the equivalence of face types etc. + */ + int rc; + + if (facelet_cache_add(&facemgr->facelet_cache, facelet) < 0) { + ERROR("[facemgr_process_create] Error adding facelet to cache"); + return -1; + } + DEBUG("Facelet added to cache"); + + /* + * If the facelet does not satisfy filters, we do not lose any information + * but do not take any action to complement the face + */ + rc = facemgr_facelet_satisfy_rules(facemgr, facelet); + if (rc == -3) { + /* Does not satisfy rules */ + return 0; + } + + // FIXME: we should complement a part of the facelet, so that we don't + // necessarily keep this information if we get more locally. Or at least we + // should remember that. + if (rc == -2) { + /* + * We don't have equivalent for linux right now, heuristic is only used + * at the end... might change. + */ +#ifdef __ANDROID__ + /* Priority is given to information that complements a face */ + if (facemgr_complement_facelet_au(facemgr, facelet) < 0) { + ERROR("[facemgr_process_create] Error while attempting to complement face for fields required by rule application"); + return -1; + } + return 0; +#endif /* __ANDROID__ */ + } + if (rc < 0) + return -1; + +// netdevice_t netdevice = NETDEVICE_EMPTY; +// if (facelet_get_netdevice(facelet, &netdevice) < 0) { +// ERROR("[facemgr_process_create] Error retrieving netdevice from facelet"); +// return -1; +// } +// +// netdevice_type_t netdevice_type = NETDEVICE_TYPE_UNDEFINED; +//#ifdef __ANDROID__ +// /* +// * In addition to netdevice, netdevice_type should be present to correctly +// * apply rules +// */ +// if (facelet_get_netdevice_type(facelet, &netdevice_type) < 0) { +// ERROR("[facemgr_process_create] Error retrieving netdevice_type from facelet"); +// return -2; +// } +//#endif /* __ANDROID__ */ + + + char facelet_s[MAXSZ_FACELET]; + facelet_snprintf(facelet_s, MAXSZ_FACELET, facelet); + DEBUG("---[ FACELET CREATE : %s ] ---", facelet_s); + + /* Do we have enough information about the facelet ? */ + if (!facelet_validate_face(facelet)) { + if (facemgr_complement_facelet(facemgr, facelet) < 0) { + ERROR("[facemgr_process_create] Error while attempting to complement face for fields required by face creation"); + return -1; + } + // we should not stop after complement_manual but create a face if + // possible... so we add a second validation + } + + if (!facelet_validate_face(facelet)) + return 0; + + /* + * Is the forwarder connected, and has the facelet cache already sync'ed the + * remote faces ? + */ + // TODO + + /* + * Actually create the face on the forwarder + * + * FIXME Currently hicn-light is hardcoded + */ + if (interface_on_event(facemgr->hl, facelet) < 0) + return -1; + facelet_set_status(facelet, FACELET_STATUS_CLEAN); + return 0; +} + +/** + * \brief Process facelet GET event + * \param [in] facemgr - Pointer to the face manager instance + * \param [in] facelet - Pointer to the facelet event to process + * \return 0 if everything went correctly, or -1 in case of error. + */ +int +facemgr_process_get(facemgr_t * facemgr, facelet_t * facelet) +{ + facelet_set_status(facelet, FACELET_STATUS_CLEAN); + if (facelet_has_netdevice(facelet)) { + netdevice_t netdevice; + if (facelet_get_netdevice(facelet, &netdevice) < 0) + return -1; + if (!IS_VALID_NETDEVICE(netdevice)) + return 0; + return facelet_cache_add(&facemgr->facelet_cache, facelet); + } + return 0; +} + +/** + * \brief Process facelet UPDATE event + * \param [in] facemgr - Pointer to the face manager instance + * \param [in] facelet - Pointer to the facelet event to process + * \return 0 if everything went correctly, or -1 in case of error. + */ +int +facemgr_process_update(facemgr_t * facemgr, facelet_t * facelet) +{ + /* This is the most complex operation since we have the same problems as in + * CREATE + the need to manage changes... + * + * This might eventually trigger a face deletion... + */ + + /* + * Update in local does not mean the face should not be created remotely as + * it might be the first time we have enough information to create it + */ + + char facelet_s[MAXSZ_FACELET]; + facelet_snprintf(facelet_s, MAXSZ_FACELET, facelet); + DEBUG("---[ FACELET UPDATE : %s ] ---", facelet_s); + + /* Sets face type */ + if (!facelet_has_face_type(facelet)) { + + /* As key, netdevice and family should always be present */ + netdevice_t netdevice = NETDEVICE_EMPTY; + int rc = facelet_get_netdevice(facelet, &netdevice); + if (rc < 0) { + ERROR("[facemgr_facelet_satisfy_rules] Error retrieving netdevice from facelet"); + return -1; + } + + netdevice_type_t netdevice_type = NETDEVICE_TYPE_UNDEFINED; +#ifdef __ANDROID__ + /* + * In addition to netdevice, netdevice_type should be present to correctly + * apply rules + */ + rc = facelet_get_netdevice_type(facelet, &netdevice_type); + if (rc < 0) { + ERROR("[facemgr_facelet_satisfy_rules] Error retrieving netdevice_type from facelet"); + return -2; + } +#endif /* __ANDROID__ */ + + facemgr_face_type_t face_type = FACEMGR_FACE_TYPE_UNDEFINED; + if (facemgr_cfg_get_face_type(facemgr->cfg, &netdevice, netdevice_type, &face_type) < 0) + return rc; + facelet_set_face_type(facelet, face_type); + } + + /* Process GET/UDPATE... */ + switch(facelet_get_status(facelet)) { + case FACELET_STATUS_UNDEFINED: + ERROR("[facemgr_process_update] Unexpected facelet status"); + return -1; + + case FACELET_STATUS_DELETED: + case FACELET_STATUS_NEW: + /* + * If the remote action should be a CREATE, then we need to check + * whether we have enough information about the face... + */ + if (!facelet_validate_face(facelet)) { + if (facemgr_complement_facelet(facemgr, facelet) < 0) { + ERROR("[facemgr_process_update] Error while attempting to complement face for fields required by face creation"); + return -1; + } + } + if (!facelet_validate_face(facelet)) + return 0; + + facelet_set_event(facelet, FACELET_EVENT_CREATE); + interface_on_event(facemgr->hl, facelet); + + /* This works assuming the call to hicn-light is blocking */ + facelet_set_status(facelet, FACELET_STATUS_CLEAN); + break; + + case FACELET_STATUS_CLEAN: + /* Nothing to do */ + break; + + case FACELET_STATUS_DIRTY: + /* + * For now we assume only local changes, and proceed to try and + * update the hICN forwarder. + * + * In case of update, the face exists which means we should already + * have enough information + */ + if (!facelet_validate_face(facelet)) { + if (facemgr_complement_facelet(facemgr, facelet) < 0) { + ERROR("[facemgr_process_create] Error while attempting to complement face for fields required by face creation"); + return -1; + } + } + + if (!facelet_validate_face(facelet)) + return 0; + + facelet_set_event(facelet, FACELET_EVENT_UPDATE); + if (interface_on_event(facemgr->hl, facelet) < 0) + return -1; + + /* This works assuming the call to hicn-light is blocking and we + * have proceeded to all udpates */ + facelet_set_status(facelet, FACELET_STATUS_CLEAN); + break; + + case FACELET_STATUS_CONFLICT: + ERROR("[facemgr_process_update] Conflict resolution (not) yet implemented"); + return -1; + case FACELET_STATUS_N: + ERROR("[facemgr_process_update] Facelet in error"); + return -1; + } + return 0; +} + +/** + * \brief Process facelet DELETE event + * \param [in] facemgr - Pointer to the face manager instance + * \param [in] facelet - Pointer to the facelet event to process + * \return 0 if everything went correctly, or -1 in case of error. + */ +int +facemgr_process_delete(facemgr_t * facemgr, facelet_t * facelet) +{ + if (interface_on_event(facemgr->hl, facelet) < 0) + return -1; + + facelet_set_status(facelet, FACELET_STATUS_DELETED); + //facelet_set_bj_done(facelet, false); + + return 0; +} + +/** + * \brief Process incoming events from interfaces + * + * Implementation notes: + * - Any event or timeout due to an interface triggers either a local cache + * update, as well a face operations needed to resync the state. + */ +int +facemgr_on_event(facemgr_t * facemgr, facelet_t * facelet_in) +{ + int ret = 0; + assert(facelet_in); + + char facelet_s[MAXSZ_FACELET]; + facelet_snprintf(facelet_s, MAXSZ_FACELET, facelet_in); + DEBUG("----------------------------------"); + DEBUG("EVENT %s\n", facelet_s); + + facelet_t ** cached_facelets = NULL; + int n = facelet_cache_lookup(&facemgr->facelet_cache, facelet_in, &cached_facelets); + if (n < 0) { + ERROR("[facemgr_on_event] Error during cache lookup"); + goto ERR; + } + DEBUG("num matches n=%d", n); + if (n == 0) { + /* This is a new facelet... we expect a CREATE event. */ + switch(facelet_get_event(facelet_in)) { + case FACELET_EVENT_CREATE: + if (facemgr_process_create(facemgr, facelet_in) < 0) { + ERROR("[facemgr_process_cached_facelet] Error processing CREATE event"); + goto ERR; + } + break; + + case FACELET_EVENT_GET: + /* Insert new facelet in cached */ + if (facemgr_process_get(facemgr, facelet_in) < 0) { + ERROR("[facemgr_process_cached_facelet] Error processing GET event"); + goto ERR; + } + break; + + case FACELET_EVENT_UPDATE: + /* Might be because we previously ignored the facelet... */ + //ERROR("[facemgr_on_event] Unexpected UPDATE... face does not exist"); + //goto ERR; + INFO("Ignored UPDATE for non-existing face"); + break; + + case FACELET_EVENT_DELETE: + ERROR("[facemgr_on_event] Unexpected DELETE... face does not exist"); + goto ERR; + + case FACELET_EVENT_UNDEFINED: + ERROR("[facemgr_on_event] Unexpected UNDEFINED event."); + goto ERR; + + default: /* XXX Some events should be deprecated */ + ERROR("[facemgr_on_event] Deprecated event"); + goto ERR; + } + goto DUMP_CACHE; + } + + /* + * From now on, it should not make any difference whether we have one or + * more facelet. + */ + for (unsigned i = 0; i < n; i ++) { + /* + * We merge each cached facelet with incoming one, and perform state + * reconciliation by sending appropriate updates to the forwarder + */ + facelet_t * facelet = cached_facelets[i]; + DEBUG("... match #%d", i); + switch(facelet_get_event(facelet_in)) { + case FACELET_EVENT_CREATE: + // FIXME, this might occur if the facemgr restarts and we try to + // re-create existing faces + ERROR("[facemgr_on_event] CREATE event for a face that already exists..."); + ret = -1; + continue; + + case FACELET_EVENT_GET: /* should be an INFORM message */ + // FIXME, this might occur if the forwarder restarts and we + // resync faces... + ERROR("[facemgr_on_event] GET event for a face that already exists..."); + ret = -1; + continue; + + case FACELET_EVENT_UPDATE: + { + DEBUG("FACELET_EVENT_UPDATE"); + char buf[128]; + facelet_snprintf(buf, 128, facelet_in); + DEBUG("MERGE %s", buf); + facelet_snprintf(buf, 128, facelet); + DEBUG(" ON %s", buf); + } + if (facelet_merge(facelet, facelet_in) < 0) { + ERROR("[facemgr_on_event] Error merging facelets"); + continue; + } + if (facemgr_process_update(facemgr, facelet) < 0) { + ERROR("[facemgr_on_event] Error processing UPDATE event"); + ret = -1; + } + continue; + + case FACELET_EVENT_DELETE: + if (facelet_merge(facelet, facelet_in) < 0) { + ERROR("[facemgr_on_event] Error merging facelets"); + continue; + } + if (facemgr_process_delete(facemgr, facelet) < 0) { + ERROR("[facemgr_on_event] Error processing DELETE event"); + ret = -1; + } + continue; + + default: /* XXX Some events should be deprecated */ + ERROR("[facemgr_on_event] Deprecated event"); + ret = -1; + } + + } + free(cached_facelets); + goto DUMP_CACHE; + +ERR: + ret = -1; + +DUMP_CACHE: + DEBUG(" <CACHE>"); + facelet_cache_dump(&facemgr->facelet_cache); + DEBUG(" </CACHE>"); + DEBUG("</EVENT ret=%d>", ret); + DEBUG("----------------------------------"); + return ret; +} + +int +facemgr_bootstrap(facemgr_t * facemgr) +{ + int rc; + + DEBUG("Registering interfaces..."); + rc = interface_register(&hicn_light_ops); + if (rc < 0) { + ERROR("Could not register interfaces"); + goto ERR_REGISTER; + } + +#ifdef __APPLE__ + rc = interface_register(&network_framework_ops); + if (rc < 0) + goto ERR_REGISTER; +#endif /* __APPLE__ */ + +#ifdef __linux__ + rc = interface_register(&netlink_ops); + if (rc < 0) + goto ERR_REGISTER; + rc = interface_register(&bonjour_ops); + if (rc < 0) + goto ERR_REGISTER; +#endif /* __linux__ */ + +#ifdef __ANDROID__ + rc = interface_register(&android_utility_ops); + if (rc < 0) + goto ERR_REGISTER; +#endif /* __ANDROID__ */ + +#ifdef WITH_EXAMPLE_DUMMY + rc = interface_register(&dummy_ops); + if (rc < 0) + goto ERR_REGISTER; +#endif + +#ifdef WITH_EXAMPLE_UPDOWN + rc = interface_register(&updown_ops); + if (rc < 0) + goto ERR_REGISTER; +#endif + + rc = facemgr_create_interface(facemgr, "hl", "hicn_light", NULL, &facemgr->hl); + if (rc < 0) { + ERROR("Error creating 'hICN forwarder (hicn-light)' interface\n"); + goto ERR_HL_CREATE; + } + +#ifdef __APPLE__ + network_framework_cfg_t nf_cfg = { + .rules = &facemgr->rules, + }; + rc = facemgr_create_interface(facemgr, "nf", "network_framework", &nf_cfg, &facemgr->nf); + if (rc < 0) { + ERROR("Error creating 'Apple Network Framework' interface\n"); + goto ERR_NF_CREATE; + } +#endif /* __APPLE__ */ + +#ifdef __linux__ + rc = facemgr_create_interface(facemgr, "nl", "netlink", NULL, &facemgr->nl); + if (rc < 0) { + ERROR("Error creating 'Netlink' interface\n"); + goto ERR_NL_CREATE; + } +#endif /* __linux__ */ + +#ifdef __ANDROID__ + android_utility_cfg_t au_cfg = { + .jvm = facemgr->jvm, + }; + rc = facemgr_create_interface(facemgr, "au", "android_utility", &au_cfg, &facemgr->au); + if (rc < 0) { + ERROR("Error creating 'Android Utility' interface\n"); + goto ERR_AU_CREATE; + } +#endif /* __ANDROID__ */ + +#ifdef WITH_EXAMPLE_DUMMY + rc = facemgr_create_interface(facemgr, "dummy0", "dummy", NULL, &facemgr->dummy); + if (rc < 0) { + ERROR("Error creating 'dummy' interface\n"); + goto ERR_DUMMY_CREATE; + } +#endif + +#ifdef WITH_EXAMPLE_UPDOWN + rc = facemgr_create_interface(facemgr, "updown0", "updown", NULL, &facemgr->updown); + if (rc < 0) { + ERROR("Error creating 'updown' interface\n"); + goto ERR_UPDOWN_CREATE; + } +#endif + + DEBUG("Facemgr successfully initialized..."); + + return 0; + + /* FIXME facemgr_delete_interface */ +#ifdef WITH_EXAMPLE_UPDOWN + interface_free(facemgr->updown); +ERR_UPDOWN_CREATE: +#endif +#ifdef WITH_EXAMPLE_DUMMY + interface_free(facemgr->dummy); +ERR_DUMMY_CREATE: +#endif +#ifdef __ANDROID__ + interface_free(facemgr->au); +ERR_AU_CREATE: +#endif /* __ANDROID__ */ +#ifdef __linux__ + interface_free(facemgr->nl); +ERR_NL_CREATE: +#endif /* __linux__ */ +#ifdef __APPLE__ + interface_free(facemgr->nf); +ERR_NF_CREATE: +#endif /* __APPLE__ */ + interface_free(facemgr->hl); +ERR_HL_CREATE: +ERR_REGISTER: + return -1; +} + +void facemgr_stop(facemgr_t * facemgr) +{ + // FIXME we should iterate on interface map + +#ifdef __APPLE__ + facemgr_delete_interface(facemgr, facemgr->nf); +#endif /* __APPLE__ */ + + +#ifdef __linux__ + facemgr_delete_interface(facemgr, facemgr->nl); + + /* Delete all bonjour interfaces */ + interface_t ** bonjour_array;// = NULL; // NOTE: would allow avoiding tests + int n = bonjour_map_get_value_array(&facemgr->bonjour_map, &bonjour_array); + if (n > 0) { + netdevice_t ** netdevice_array; // = NULL; + int m = bonjour_map_get_key_array(&facemgr->bonjour_map, &netdevice_array); + if (m > 0) { + assert(m == n); + for (int i = 0; i < n; i++) { /* Fail silently */ + DEBUG("Deleting bonjour interface associated to %s (%p)\n", + netdevice_array[i]->name, bonjour_array[i]); + facemgr_delete_interface(facemgr, bonjour_array[i]); + } + free(netdevice_array); + } + free(bonjour_array); + } +#endif /* __linux__ */ + +#ifdef __ANDROID__ + facemgr_delete_interface(facemgr, facemgr->au); +#endif /* __ANDROID__ */ + + facemgr_delete_interface(facemgr, facemgr->hl); + +#ifdef WITH_EXAMPLE_DUMMY + facemgr_delete_interface(facemgr, facemgr->dummy); +#endif + +#ifdef WITH_EXAMPLE_UPDOWN + facemgr_delete_interface(facemgr, facemgr->updown); +#endif +} + +#ifdef __ANDROID__ +void facemgr_set_jvm(facemgr_t * facemgr, JavaVM *jvm) +{ + facemgr->jvm = jvm; +} +#endif /* __ANDROID__ */ + +void facemgr_set_event_loop_handler(facemgr_t * facemgr, void * loop, void * loop_register_fd, void * loop_unregister_event) +{ + facemgr->loop = loop; + facemgr->loop_register_fd = loop_register_fd; + facemgr->loop_unregister_event = loop_unregister_event; +} + +void facemgr_list_faces(facemgr_t * facemgr, facemgr_list_faces_cb_t cb, void * user_data) +{ + //face_cache_iter(&facemgr->face_cache, cb, user_data); + facelet_cache_dump(&facemgr->facelet_cache); +} diff --git a/ctrl/facemgr/src/cfg.c b/ctrl/facemgr/src/cfg.c new file mode 100644 index 000000000..6b04208bb --- /dev/null +++ b/ctrl/facemgr/src/cfg.c @@ -0,0 +1,991 @@ +/** + * \file cfg.c + * \brief Implementation of Face manager configuration + */ + +#include <assert.h> +#include <hicn/ctrl.h> // HICN_DEFAULT_PORT +#include <hicn/facemgr/cfg.h> +#include <hicn/policy.h> +#include <hicn/util/ip_address.h> +#include "util/set.h" + +/* Overlay */ + +typedef struct { + bool is_local_port; + uint16_t local_port; + bool is_local_addr; + ip_address_t local_addr; + bool is_remote_port; + uint16_t remote_port; + bool is_remote_addr; + ip_address_t remote_addr; +} facemgr_cfg_overlay_t; + +int +facemgr_cfg_overlay_initialize(facemgr_cfg_overlay_t * overlay) +{ + overlay->is_local_port = false; + overlay->local_port = 0; + overlay->is_local_addr = false; + overlay->local_addr = IP_ADDRESS_EMPTY; + + overlay->is_remote_port = false; + overlay->remote_port = 0; + overlay->is_remote_addr = false; + overlay->remote_addr = IP_ADDRESS_EMPTY; + + return 0; +} + +int +facemgr_cfg_overlay_finalize(facemgr_cfg_overlay_t * overlay) +{ + return 0; +} + +facemgr_cfg_overlay_t * facemgr_cfg_overlay_create() +{ + facemgr_cfg_overlay_t * overlay = malloc(sizeof(facemgr_cfg_overlay_t)); + if (!overlay) + return NULL; + + int rc = facemgr_cfg_overlay_initialize(overlay); + if (rc < 0) { + free(overlay); + return NULL; + } + + return overlay; +} + +void facemgr_cfg_overlay_free(facemgr_cfg_overlay_t * overlay) +{ + facemgr_cfg_overlay_finalize(overlay); + free(overlay); +} + +typedef struct { + facemgr_cfg_overlay_t * v4; + facemgr_cfg_overlay_t * v6; +} facemgr_cfg_overlays_t; + +typedef struct { + const char * interface_name; + netdevice_type_t interface_type; +} facemgr_cfg_match_t; + + +typedef struct { + /* Interface specific */ + bool is_face_type; // default is auto + facemgr_face_type_t face_type; + + /* This should be defaut for the global settings */ + bool is_ignore; + bool ignore; + bool is_discovery; + bool discovery; + bool is_ipv4; + bool ipv4; + bool is_ipv6; + bool ipv6; + + facemgr_cfg_overlays_t overlays; // fallback unless discovery is disabled +} facemgr_cfg_override_t; + +struct facemgr_cfg_rule_s { + facemgr_cfg_match_t match; + facemgr_cfg_override_t override; +}; + +int +facemgr_cfg_override_initialize(facemgr_cfg_override_t * override) +{ + override->is_face_type = false; + override->face_type = FACEMGR_FACE_TYPE_UNDEFINED; + + override->is_ignore = false; + override->ignore = false; + + override->is_discovery = false; + override->discovery = false; + + override->overlays.v4 = NULL; + override->overlays.v6 = NULL; + + return 0; +} + +int +facemgr_cfg_override_finalize(facemgr_cfg_override_t * override) +{ + if (override->overlays.v4) { + facemgr_cfg_overlay_free(override->overlays.v4); + override->overlays.v4 = NULL; + } + if (override->overlays.v6) { + facemgr_cfg_overlay_free(override->overlays.v6); + override->overlays.v6 = NULL; + } + + return 0; +} + + +/* Rule */ +facemgr_cfg_rule_t * facemgr_cfg_rule_create() +{ + facemgr_cfg_rule_t * rule = malloc(sizeof(facemgr_cfg_rule_t)); + if (!rule) + return NULL; + + int rc = facemgr_cfg_rule_initialize(rule); + if (rc < 0) + return NULL; + + return rule; +} + +void facemgr_cfg_rule_free(facemgr_cfg_rule_t * rule) +{ + facemgr_cfg_rule_finalize(rule); + free(rule); +} + +int +facemgr_cfg_rule_initialize(facemgr_cfg_rule_t * rule) +{ + rule->match.interface_name = NULL; + rule->match.interface_type = NETDEVICE_TYPE_UNDEFINED; + + int rc = facemgr_cfg_override_initialize(&rule->override); + if (rc < 0) + return -1; + + return 0; +} + +int +facemgr_cfg_rule_finalize(facemgr_cfg_rule_t * rule) +{ + if (rule->match.interface_name) { + free((void*)rule->match.interface_name); + rule->match.interface_name = NULL; + } + return facemgr_cfg_override_finalize(&rule->override); +} + +void +facemgr_cfg_rule_dump(facemgr_cfg_rule_t * rule) +{ + DEBUG(" <rule>"); + DEBUG(" <match interface_name=%s interface_type=%s>", + rule->match.interface_name, + netdevice_type_str[rule->match.interface_type]); + DEBUG(" <override>"); + if (rule->override.is_face_type) { + DEBUG(" <face_type>%d</face_type>", rule->override.face_type); + } + if (rule->override.is_ignore) { + DEBUG(" <ignore>%d</ignore>", rule->override.ignore); + } + if (rule->override.is_discovery) { + DEBUG(" <discovery>%d</discovery>", rule->override.discovery); + } + if (rule->override.is_ipv4) { + DEBUG(" <ipv4>%d</ipv4>", rule->override.ipv4); + } + if (rule->override.is_ipv6) { + DEBUG(" <ipv6>%d</ipv6>", rule->override.ipv6); + } + DEBUG(" <overlays>"); + if (rule->override.overlays.v4) { + DEBUG(" <ipv4>"); + if (rule->override.overlays.v4->is_local_addr) { + char buf[MAXSZ_IP_ADDRESS]; + ip_address_snprintf(buf, MAXSZ_IP_ADDRESS, + &rule->override.overlays.v4->local_addr, AF_INET); + DEBUG(" <local_addr>%s</local_addr>", buf); + } + if (rule->override.overlays.v4->is_local_port) { + DEBUG(" <local_port>%d</local_port>", + rule->override.overlays.v4->local_port); + } + if (rule->override.overlays.v4->is_remote_addr) { + char buf[MAXSZ_IP_ADDRESS]; + ip_address_snprintf(buf, MAXSZ_IP_ADDRESS, + &rule->override.overlays.v4->remote_addr, AF_INET); + DEBUG(" <remote_addr>%s</remote_addr>", buf); + } + if (rule->override.overlays.v4->is_remote_port) { + DEBUG(" <remote_port>%d</remote_port>", + rule->override.overlays.v4->remote_port); + } + DEBUG(" </ipv4>"); + } + if (rule->override.overlays.v6) { + DEBUG(" <ipv6>"); + if (rule->override.overlays.v6->is_local_addr) { + char buf[MAXSZ_IP_ADDRESS]; + ip_address_snprintf(buf, MAXSZ_IP_ADDRESS, + &rule->override.overlays.v6->local_addr, AF_INET6); + DEBUG(" <local_addr>%s</local_addr>", buf); + } + if (rule->override.overlays.v6->is_local_port) { + DEBUG(" <local_port>%d</local_port>", + rule->override.overlays.v6->local_port); + } + if (rule->override.overlays.v6->is_remote_addr) { + char buf[MAXSZ_IP_ADDRESS]; + ip_address_snprintf(buf, MAXSZ_IP_ADDRESS, + &rule->override.overlays.v6->remote_addr, AF_INET6); + DEBUG(" <remote_addr>%s</remote_addr>", buf); + } + if (rule->override.overlays.v6->is_remote_port) { + DEBUG(" <remote_port>%d</remote_port>", + rule->override.overlays.v6->remote_port); + } + DEBUG(" </ipv6>"); + } + DEBUG(" </overlays>"); + DEBUG(" </override>"); + DEBUG(" </rule>"); +} + +int +facemgr_cfg_rule_set_match(facemgr_cfg_rule_t * rule, const char * interface_name, + netdevice_type_t interface_type) +{ + rule->match.interface_name = interface_name ? strdup(interface_name) : NULL; + rule->match.interface_type = interface_type; + return 0; +} + +int +facemgr_cfg_rule_set_face_type(facemgr_cfg_rule_t * rule, facemgr_face_type_t * face_type) +{ + rule->override.is_face_type = true; + rule->override.face_type = *face_type; + return 0; +} + +int +facemgr_cfg_rule_unset_face_type(facemgr_cfg_rule_t * rule) +{ + rule->override.is_face_type = false; + rule->override.face_type = FACEMGR_FACE_TYPE_UNDEFINED; /* optional */ + return 0; +} + +int +facemgr_cfg_rule_set_discovery(facemgr_cfg_rule_t * rule, bool status) +{ + rule->override.is_discovery = true; + rule->override.discovery = status; + return 0; +} + +int +facemgr_cfg_rule_unset_discovery(facemgr_cfg_rule_t * rule) +{ + rule->override.is_discovery = false; + return 0; +} + +int +facemgr_cfg_rule_set_ignore(facemgr_cfg_rule_t * rule, bool status) +{ + rule->override.is_ignore = true; + rule->override.ignore = status; + return 0; +} + +int +facemgr_cfg_rule_unset_ignore(facemgr_cfg_rule_t * rule) +{ + rule->override.is_ignore = false; + return 0; +} + +int +facemgr_cfg_rule_set_ipv4(facemgr_cfg_rule_t * rule, bool status) +{ + rule->override.is_ipv4 = true; + rule->override.ipv4 = status; + return 0; +} + +int +facemgr_cfg_rule_unset_ipv4(facemgr_cfg_rule_t * rule) +{ + rule->override.is_ipv4 = false; + return 0; +} + +int +facemgr_cfg_rule_set_ipv6(facemgr_cfg_rule_t * rule, bool status) +{ + rule->override.is_ipv6 = true; + rule->override.ipv6 = status; + return 0; +} + +int +facemgr_cfg_rule_unset_ipv6(facemgr_cfg_rule_t * rule) +{ + rule->override.is_ipv6 = false; + return 0; +} + +int +facemgr_cfg_rule_set_overlay(facemgr_cfg_rule_t * rule, int family, + ip_address_t * local_addr, uint16_t local_port, + ip_address_t * remote_addr, uint16_t remote_port) { + if ((family != AF_INET) && (family != AF_INET6)) + return -1; + + facemgr_cfg_overlay_t * overlay = facemgr_cfg_overlay_create(); + if (local_addr) { + overlay->is_local_addr = true; + overlay->local_addr = *local_addr; + } + if (IS_VALID_PORT(local_port)) { + overlay->is_local_port = true; + overlay->local_port = local_port; + } + if (remote_addr) { + overlay->is_remote_addr = true; + overlay->remote_addr = *remote_addr; + } + if (IS_VALID_PORT(remote_port)) { + overlay->is_remote_port = true; + overlay->remote_port = remote_port; + } + + switch(family) { + case AF_INET: + rule->override.overlays.v4 = overlay; + break; + + case AF_INET6: + rule->override.overlays.v6 = overlay; + break; + + default: + return -1; + } + + return 0; +} + +int +facemgr_rule_unset_overlay(facemgr_cfg_rule_t * rule, int family) +{ + if ((family != AF_INET) && (family != AF_INET6) && (family != AF_UNSPEC)) + return -1; + + if ((family == AF_UNSPEC) || (family == AF_INET)) { + if (rule->override.overlays.v4) { + facemgr_cfg_overlay_free(rule->override.overlays.v4); + rule->override.overlays.v4 = NULL; + } + } + if ((family == AF_UNSPEC) || (family == AF_INET6)) { + if (rule->override.overlays.v6) { + facemgr_cfg_overlay_free(rule->override.overlays.v6); + rule->override.overlays.v6 = NULL; + } + } + return 0; +} + +int +facemgr_cfg_rule_cmp(const facemgr_cfg_rule_t * r1, const facemgr_cfg_rule_t * r2) +{ + /* + * We implement a lexicographic order on the tuple (interface_name, + * interface_type) + */ + + /* We need to handle NULL cases out of strcmp */ + if (!r1->match.interface_name) { + if (r2->match.interface_name) + return 1; + else + goto BOTH_NULL; + } else { + if (!r2->match.interface_name) + return -1; + } + + + /* Only if both are non-NULL, we proceed to strcmp */ + int rc = strcmp(r1->match.interface_name, r2->match.interface_name); + if (rc != 0) + return rc; + +BOTH_NULL: + return r1->match.interface_type - r2->match.interface_type; +} + +/* General */ + +TYPEDEF_SET_H(facemgr_cfg_rule_set, facemgr_cfg_rule_t *); +TYPEDEF_SET(facemgr_cfg_rule_set, facemgr_cfg_rule_t *, facemgr_cfg_rule_cmp, generic_snprintf); + +struct facemgr_cfg_s { + facemgr_cfg_override_t global; + facemgr_cfg_rule_set_t * rule_set; + //log_cfg_t log; +}; + +facemgr_cfg_t * facemgr_cfg_create() +{ + facemgr_cfg_t * cfg = malloc(sizeof(facemgr_cfg_t)); + if (!cfg) + return NULL; + + int rc = facemgr_cfg_initialize(cfg); + if (rc < 0) { + free(cfg); + return NULL; + } + + return cfg; +} + +void facemgr_cfg_free(facemgr_cfg_t * cfg) +{ + facemgr_cfg_finalize(cfg); + free(cfg); +} + +int +facemgr_cfg_initialize(facemgr_cfg_t * cfg) +{ + int rc = facemgr_cfg_override_initialize(&cfg->global); + if (rc < 0) + goto ERR_OVERRIDE; + + cfg->rule_set = facemgr_cfg_rule_set_create(); + if (!cfg->rule_set) + goto ERR_RULE_SET; + + return 0; + +ERR_RULE_SET: + facemgr_cfg_override_finalize(&cfg->global); +ERR_OVERRIDE: + return -1; +} + +int +facemgr_cfg_finalize(facemgr_cfg_t * cfg) +{ + /* TODO Free all rules */ + facemgr_cfg_rule_set_free(cfg->rule_set); + return facemgr_cfg_override_finalize(&cfg->global); +} + +void facemgr_cfg_dump(facemgr_cfg_t * cfg) +{ + return; /* NOT IMPLEMENTED */ +} + +/* General */ +int +facemgr_cfg_set_face_type(facemgr_cfg_t * cfg, facemgr_face_type_t * face_type) +{ + cfg->global.is_face_type = true; + cfg->global.face_type = *face_type; + return 0; +} + +int +facemgr_cfg_unset_face_type(facemgr_cfg_t * cfg) +{ + cfg->global.is_face_type = false; + cfg->global.face_type = FACEMGR_FACE_TYPE_UNDEFINED; /* optional */ + return 0; +} + +int +facemgr_cfg_set_discovery(facemgr_cfg_t * cfg, bool status) +{ + cfg->global.is_discovery = true; + cfg->global.discovery = status; + return 0; +} + +int +facemgr_cfg_unset_discovery(facemgr_cfg_t * cfg) +{ + cfg->global.is_discovery = false; + return 0; +} + +int +facemgr_cfg_set_overlay(facemgr_cfg_t * cfg, int family, + ip_address_t * local_addr, uint16_t local_port, + ip_address_t * remote_addr, uint16_t remote_port) +{ + if ((family != AF_INET) && (family != AF_INET6)) + return -1; + + facemgr_cfg_overlay_t * overlay = facemgr_cfg_overlay_create(); + if (local_addr) { + overlay->is_local_addr = true; + overlay->local_addr = *local_addr; + } + if (IS_VALID_PORT(local_port)) { + overlay->is_local_port = true; + overlay->local_port = local_port; + } + if (remote_addr) { + overlay->is_remote_addr = true; + overlay->remote_addr = *remote_addr; + } + if (IS_VALID_PORT(remote_port)) { + overlay->is_remote_port = true; + overlay->remote_port = remote_port; + } + + DEBUG("facemgr_cfg_set_overlay"); + + switch(family) { + case AF_INET: + cfg->global.overlays.v4 = overlay; + break; + + case AF_INET6: + cfg->global.overlays.v6 = overlay; + break; + + default: + return -1; + } + + DEBUG("<global>"); + DEBUG(" <overlay>"); + if (overlay) { + DEBUG(" <ipv4>"); + if (overlay->is_local_addr) { + char buf[MAXSZ_IP_ADDRESS]; + ip_address_snprintf(buf, MAXSZ_IP_ADDRESS, + &overlay->local_addr, AF_INET); + DEBUG(" <local_addr>%s</local_addr>", buf); + } + if (overlay->is_local_port) { + DEBUG(" <local_port>%d</local_port>", + overlay->local_port); + } + if (overlay->is_remote_addr) { + char buf[MAXSZ_IP_ADDRESS]; + ip_address_snprintf(buf, MAXSZ_IP_ADDRESS, + &overlay->remote_addr, AF_INET); + DEBUG(" <remote_addr>%s</remote_addr>", buf); + } + if (overlay->is_remote_port) { + DEBUG(" <remote_port>%d</remote_port>", + overlay->remote_port); + } + DEBUG(" </ipv4>"); + } + DEBUG(" </overlay>"); + DEBUG("</global>"); + + return 0; +} + +int +facemgr_cfg_unset_overlay(facemgr_cfg_t * cfg, int family) +{ + if ((family != AF_INET) && (family != AF_INET6) && (family != AF_UNSPEC)) + return -1; + + if ((family == AF_UNSPEC) || (family == AF_INET)) { + if (cfg->global.overlays.v4) { + facemgr_cfg_overlay_free(cfg->global.overlays.v4); + cfg->global.overlays.v4 = NULL; + } + } + if ((family == AF_UNSPEC) || (family == AF_INET6)) { + if (cfg->global.overlays.v6) { + facemgr_cfg_overlay_free(cfg->global.overlays.v6); + cfg->global.overlays.v6 = NULL; + } + } + return 0; +} + +int +facemgr_cfg_add_rule(facemgr_cfg_t * cfg, facemgr_cfg_rule_t * rule) +{ + facemgr_cfg_rule_dump(rule); + return facemgr_cfg_rule_set_add(cfg->rule_set, rule); +} + +int +facemgr_cfg_del_rule(facemgr_cfg_t * cfg, facemgr_cfg_rule_t * rule) +{ + return facemgr_cfg_rule_set_remove(cfg->rule_set, rule, NULL); +} + +int facemgr_cfg_get_rule(const facemgr_cfg_t * cfg, const char * interface_name, + netdevice_type_t interface_type, facemgr_cfg_rule_t ** rule) { + facemgr_cfg_rule_t rule_search = { + .match = { + .interface_name = interface_name, + .interface_type = interface_type, + }, + }; + return facemgr_cfg_rule_set_get(cfg->rule_set, &rule_search, rule); +} + +/* Query API */ + +/* + * Check whether there are override rules for the given netdevice + * + * TODO: + * - until we have proper indexes we loop through the whole structure + */ +int +facemgr_cfg_get_override(const facemgr_cfg_t * cfg, + const netdevice_t * netdevice, netdevice_type_t netdevice_type, + facemgr_cfg_override_t ** override) +{ + if (!netdevice) { + *override = NULL; + return 0; + } + + facemgr_cfg_rule_t **rule_array; + int rc = facemgr_cfg_rule_set_get_array(cfg->rule_set, &rule_array); + if (rc < 0) { + ERROR("facemgr_cfg_rule_set_get_array failed"); + return rc; + } + for (unsigned i = 0; i < rc; i++) { + const char * interface_name = rule_array[i]->match.interface_name; + /* Check match for interface name */ + if (interface_name && (strcmp(interface_name, netdevice->name) != 0)) + continue; + /* Check match for interface type */ + if (rule_array[i]->match.interface_type != NETDEVICE_TYPE_UNDEFINED) { +#ifdef __ANDROID__ + if (netdevice_type != rule_array[i]->match.interface_type) + continue; +#else + ERROR("Match on interface type is currently not implemented"); + goto ERR_ARRAY; +#endif /* __ANDROID__ */ + } + /* Found match... do we have an override for face_type */ + DEBUG("override found nd=%s, ndt=%s", rule_array[i]->match.interface_name, netdevice_type_str[rule_array[i]->match.interface_type]); + *override = &rule_array[i]->override; + goto FOUND; + } + + DEBUG("override not found"); + *override = NULL; + +FOUND: + free(rule_array); + return 0; + +#ifndef __ANDROID__ +ERR_ARRAY: + free(rule_array); + return -1; +#endif /* __ANDROID__ */ +} + +int +facemgr_cfg_get_face_type(const facemgr_cfg_t * cfg, + const netdevice_t * netdevice, netdevice_type_t netdevice_type, + facemgr_face_type_t * face_type) +{ + facemgr_cfg_override_t * override; + int rc = facemgr_cfg_get_override(cfg, netdevice, netdevice_type, + &override); + if (rc < 0) { + ERROR("get override failed"); + return rc; + } + + if ((override) && (override->is_face_type)) { + *face_type = override->face_type; + return 0; + } + + *face_type = cfg->global.is_face_type + ? cfg->global.face_type + : FACEMGR_FACE_TYPE_DEFAULT; + + return 0; +} + +int +facemgr_cfg_get_discovery(const facemgr_cfg_t * cfg, + const netdevice_t * netdevice, netdevice_type_t netdevice_type, + bool * discovery) +{ + facemgr_cfg_override_t * override; + int rc = facemgr_cfg_get_override(cfg, netdevice, netdevice_type, + &override); + if (rc < 0) + return rc; + + if ((override) && (override->is_discovery)) { + *discovery = override->discovery; + return 0; + } + + *discovery = cfg->global.is_discovery + ? cfg->global.discovery + : FACEMGR_CFG_DEFAULT_DISCOVERY; + return 0; +} + +int +facemgr_cfg_get_ipv4(const facemgr_cfg_t * cfg, + const netdevice_t * netdevice, netdevice_type_t netdevice_type, + bool * ipv4) +{ + facemgr_cfg_override_t * override; + int rc = facemgr_cfg_get_override(cfg, netdevice, netdevice_type, + &override); + if (rc < 0) + return rc; + + if ((override) && (override->is_ipv4)) { + *ipv4 = override->ipv4; + return 0; + } + + *ipv4 = cfg->global.is_ipv4 + ? cfg->global.ipv4 + : FACEMGR_CFG_DEFAULT_IPV4; + return 0; +} + +int +facemgr_cfg_get_ipv6(const facemgr_cfg_t * cfg, + const netdevice_t * netdevice, netdevice_type_t netdevice_type, + bool * ipv6) +{ + facemgr_cfg_override_t * override; + int rc = facemgr_cfg_get_override(cfg, netdevice, netdevice_type, + &override); + if (rc < 0) + return rc; + + if ((override) && (override->is_ipv6)) { + *ipv6 = override->ipv6; + return 0; + } + + *ipv6 = cfg->global.is_ipv6 + ? cfg->global.ipv6 + : FACEMGR_CFG_DEFAULT_IPV6; + return 0; +} + +int +facemgr_cfg_get_ignore(const facemgr_cfg_t * cfg, + const netdevice_t * netdevice, netdevice_type_t netdevice_type, + bool * ignore) +{ + facemgr_cfg_override_t * override; + int rc = facemgr_cfg_get_override(cfg, netdevice, netdevice_type, + &override); + if (rc < 0) + return rc; + + if ((override) && (override->is_ignore)) { + *ignore = override->ignore; + return 0; + } + + assert (!cfg->global.is_ignore); + + *ignore = (netdevice && (netdevice->name[0] != '\0') && strcmp(netdevice->name, "lo") == 0); + + return 0; +} + +int +facemgr_cfg_get_overlay_local_addr(const facemgr_cfg_t * cfg, + const netdevice_t * netdevice, netdevice_type_t netdevice_type, + int family, ip_address_t * addr) +{ + facemgr_cfg_override_t * override; + int rc = facemgr_cfg_get_override(cfg, netdevice, netdevice_type, + &override); + if (rc < 0) + return rc; + + switch (family) { + case AF_INET: + if ((override) && (override->overlays.v4) && (override->overlays.v4->is_local_addr)) { + *addr = override->overlays.v4->local_addr; + return 0; + } + if ((cfg->global.overlays.v4) && (cfg->global.overlays.v4->is_local_addr)) { + *addr = cfg->global.overlays.v4->local_addr; + return 0; + } + break; + case AF_INET6: + if ((override) && (override->overlays.v6) && (override->overlays.v6->is_local_addr)) { + *addr = override->overlays.v6->local_addr; + return 0; + } + if ((cfg->global.overlays.v6) && (cfg->global.overlays.v6->is_local_addr)) { + *addr = cfg->global.overlays.v6->local_addr; + return 0; + } + break; + case AF_UNSPEC: + break; + default: + return -1; + } + + *addr = IP_ADDRESS_EMPTY; + return 0; +} + +int +facemgr_cfg_get_overlay_local_port(const facemgr_cfg_t * cfg, + const netdevice_t * netdevice, netdevice_type_t netdevice_type, + int family, u16 * port) +{ + facemgr_cfg_override_t * override; + int rc = facemgr_cfg_get_override(cfg, netdevice, netdevice_type, + &override); + if (rc < 0) + return rc; + + switch (family) { + case AF_INET: + if ((override) && (override->overlays.v4) && (override->overlays.v4->is_local_port)) { + *port = override->overlays.v4->local_port; + return 0; + } + if ((cfg->global.overlays.v4) && (cfg->global.overlays.v4->is_local_port)) { + *port = cfg->global.overlays.v4->local_port; + return 0; + } + break; + case AF_INET6: + if ((override) && (override->overlays.v6) && (override->overlays.v6->is_local_port)) { + *port = override->overlays.v6->local_port; + return 0; + } + if ((cfg->global.overlays.v6) && (cfg->global.overlays.v6->is_local_port)) { + *port = cfg->global.overlays.v6->local_port; + return 0; + } + break; + case AF_UNSPEC: + break; + default: + return -1; + } + + *port = HICN_DEFAULT_PORT; + return 0; +} + +int +facemgr_cfg_get_overlay_remote_addr(const facemgr_cfg_t * cfg, + const netdevice_t * netdevice, netdevice_type_t netdevice_type, + int family, ip_address_t * addr) +{ + facemgr_cfg_override_t * override; + int rc = facemgr_cfg_get_override(cfg, netdevice, netdevice_type, + &override); + if (rc < 0) + return rc; + + switch (family) { + case AF_INET: + if ((override) && (override->overlays.v4) && (override->overlays.v4->is_remote_addr)) { + DEBUG("remote addr v4 from override"); + *addr = override->overlays.v4->remote_addr; + return 0; + } + if ((cfg->global.overlays.v4) && (cfg->global.overlays.v4->is_remote_addr)) { + DEBUG("remote addr v4 from global"); + *addr = cfg->global.overlays.v4->remote_addr; + return 0; + } + break; + case AF_INET6: + if ((override) && (override->overlays.v6) && (override->overlays.v6->is_remote_addr)) { + DEBUG("remote addr v6 from override"); + *addr = override->overlays.v6->remote_addr; + return 0; + } + if ((cfg->global.overlays.v6) && (cfg->global.overlays.v6->is_remote_addr)) { + DEBUG("remote addr v6 from global"); + *addr = cfg->global.overlays.v6->remote_addr; + return 0; + } + break; + case AF_UNSPEC: + break; + default: + return -1; + } + + DEBUG("remote addr empty"); + *addr = IP_ADDRESS_EMPTY; + return 0; +} + +int +facemgr_cfg_get_overlay_remote_port(const facemgr_cfg_t * cfg, + const netdevice_t * netdevice, netdevice_type_t netdevice_type, + int family, u16 * port) +{ + facemgr_cfg_override_t * override; + int rc = facemgr_cfg_get_override(cfg, netdevice, netdevice_type, + &override); + if (rc < 0) + return rc; + + switch (family) { + case AF_INET: + if ((override) && (override->overlays.v4) && (override->overlays.v4->is_remote_port)) { + *port = override->overlays.v4->remote_port; + return 0; + } + if ((cfg->global.overlays.v4) && (cfg->global.overlays.v4->is_remote_port)) { + *port = cfg->global.overlays.v4->remote_port; + return 0; + } + break; + case AF_INET6: + if ((override) && (override->overlays.v6) && (override->overlays.v6->is_remote_port)) { + *port = override->overlays.v6->remote_port; + return 0; + } + if ((cfg->global.overlays.v6) && (cfg->global.overlays.v6->is_remote_port)) { + *port = cfg->global.overlays.v6->remote_port; + return 0; + } + break; + case AF_UNSPEC: + break; + default: + return -1; + } + + *port = HICN_DEFAULT_PORT; + return 0; +} diff --git a/ctrl/facemgr/src/common.h b/ctrl/facemgr/src/common.h index a73964b6d..9d6e8ca87 100644 --- a/ctrl/facemgr/src/common.h +++ b/ctrl/facemgr/src/common.h @@ -22,18 +22,12 @@ #include <stdbool.h> #include <stdint.h> +#include <stdlib.h> -#include "util/types.h" -#include "util/ip_address.h" -#include "util/token.h" // XXX debug +#include <hicn/util/ip_address.h> //#define DEBUG -/* Return value conventions */ -#define FACEMGR_SUCCESS 0 -#define FACEMGR_FAILURE -1 -#define FACEMGR_IS_ERROR(rc) (rc < 0) - /* Useful types and macros for comparisons */ typedef int(*cmp_t)(const void * x, const void * y); @@ -43,18 +37,35 @@ typedef int(*cmp_t)(const void * x, const void * y); #define INDENT(n, fmt) "%*s" fmt, n, "" #define printfi(n, fmt, ...) printf(INDENT(n*4, fmt), ##__VA_ARGS__) +#define _unused(x) ((void)(x)) + +/* Random strings */ + +static inline +void rand_str(char *dest, size_t length) { + char charset[] = "0123456789" + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + while (length-- > 0) { + size_t index = (double) rand() / RAND_MAX * (sizeof charset - 1); + *dest++ = charset[index]; + } + *dest = '\0'; +} + /* Boilerplate code */ #define NO_INITIALIZE(NAME) \ int \ NAME ## _initialize(NAME ## _t * obj) { \ - return FACEMGR_SUCCESS; \ + return 0; \ } #define NO_FINALIZE(NAME) \ int \ NAME ## _finalize(NAME ## _t * obj) { \ - return FACEMGR_SUCCESS; \ + return 0; \ } #define AUTOGENERATE_CREATE_FREE(NAME) \ @@ -66,7 +77,7 @@ NAME ## _create() \ if (!obj) \ goto ERR_MALLOC; \ \ - if (FACEMGR_IS_ERROR(NAME ## _initialize(obj))) \ + if (NAME ## _initialize(obj) < 0) \ goto ERR_INIT; \ \ return obj; \ @@ -80,7 +91,7 @@ ERR_MALLOC: \ void \ NAME ## _free(NAME ## _t * obj) \ { \ - if (FACEMGR_IS_ERROR(NAME ## _finalize(obj))) \ + if (NAME ## _finalize(obj) < 0) \ (void)0; /* XXX */ \ free(obj); \ } \ diff --git a/ctrl/facemgr/src/event.c b/ctrl/facemgr/src/event.c deleted file mode 100644 index 446c51c22..000000000 --- a/ctrl/facemgr/src/event.c +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * \file event.h - * \brief Implementatino of face events - */ - -#include "common.h" -#include "event.h" -#include "interface.h" -#include "util/token.h" - -const char * event_type_str[] = { -#define _(x) [EVENT_TYPE_ ## x] = STRINGIZE(x), -foreach_event_type -#undef _ -}; - -int -event_raise(event_type_t type, const face_t * face, const interface_t * interface) -{ - event_t event = { .type = type, .face = face }; - if (interface->callback) - interface->callback(interface->callback_data, &event); - return FACEMGR_SUCCESS; -} diff --git a/ctrl/facemgr/src/event.h b/ctrl/facemgr/src/event.h deleted file mode 100644 index 53295d009..000000000 --- a/ctrl/facemgr/src/event.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * \file event.h - * \brief Face event - */ -#ifndef FACEMGR_EVENT_H -#define FACEMGR_EVENT_H - -#include "face.h" -#include "interface.h" - -#define foreach_event_type \ - _(UNDEFINED) \ - _(CREATE) \ - _(UPDATE) \ - _(DELETE) \ - _(SET_PARAMS) \ - _(SET_UP) \ - _(SET_DOWN) \ - _(SET_TAGS) \ - _(CLEAR_TAGS) \ - _(ADD_TAG) \ - _(REMOVE_TAG) \ - _(N) - -#define MAXSZ_EVENT_TYPE_ 10 -#define MAXSZ_EVENT_TYPE MAXSZ_EVENT_TYPE_ + 1 - -typedef enum { -#define _(x) EVENT_TYPE_ ## x, -foreach_event_type -#undef _ -} event_type_t; - -extern const char * event_type_str[]; - -typedef struct event_s { - event_type_t type; - const face_t * face; /* + bitfield for face fields ? */ -} event_t; - -int -event_raise(event_type_t type, const face_t * face, const interface_t * interface); - -#endif /* FACEMGR_EVENT_H */ diff --git a/ctrl/facemgr/src/face.c b/ctrl/facemgr/src/face.c deleted file mode 100644 index 270a6fa9f..000000000 --- a/ctrl/facemgr/src/face.c +++ /dev/null @@ -1,262 +0,0 @@ -/* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * \file face.c - * \brief Implementation of face abstraction - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "face.h" -#include "util/hash.h" -#include "util/token.h" - -#ifndef bzero -#define bzero(b,len) (memset((b), '\0', (len)), (void) 0) -#endif - -#define member_size(type, member) sizeof(((type *)0)->member) - - -/* Netdevice */ - -const char * netdevice_type_str[] = { -#define _(x) [NETDEVICE_TYPE_ ## x] = STRINGIZE(x), -foreach_netdevice_type -#undef _ -}; - - -/* Face state */ - -const char * face_state_str[] = { -#define _(x) [FACE_STATE_ ## x] = STRINGIZE(x), -foreach_face_state -#undef _ -}; - - -/* Face type */ - -const char * face_type_str[] = { -#define _(x) [FACE_TYPE_ ## x] = STRINGIZE(x), -foreach_face_type -#undef _ -}; - - -/* Face */ - -int -face_initialize(face_t * face) -{ - bzero(face, sizeof(face_t)); /* 0'ed for hash */ - return 1; -} - -int -face_initialize_udp(face_t * face, const ip_address_t * local_addr, - u16 local_port, const ip_address_t * remote_addr, u16 remote_port, - int family) -{ - if (!local_addr) - return -1; - - *face = (face_t) { - .type = FACE_TYPE_UDP, - .params.tunnel = { - .family = family, - .local_addr = *local_addr, - .local_port = local_port, - .remote_addr = remote_addr ? *remote_addr : IP_ADDRESS_EMPTY, - .remote_port = remote_port, - }, - }; - return 1; -} - -int -face_initialize_udp_sa(face_t * face, const struct sockaddr * local_addr, - const struct sockaddr * remote_addr) -{ - if (!local_addr) - return -1; - - if (remote_addr && (local_addr->sa_family != remote_addr->sa_family)) - return -1; - - switch (local_addr->sa_family) { - case AF_INET: - { - struct sockaddr_in *lsai = (struct sockaddr_in *)local_addr; - struct sockaddr_in *rsai = (struct sockaddr_in *)remote_addr; - *face = (face_t) { - .type = FACE_TYPE_UDP, - .params.tunnel = { - .family = AF_INET, - .local_addr.v4.as_inaddr = lsai->sin_addr, - .local_port = lsai ? ntohs(lsai->sin_port) : 0, - .remote_addr = IP_ADDRESS_EMPTY, - .remote_port = rsai ? ntohs(rsai->sin_port) : 0, - }, - }; - if (rsai) - face->params.tunnel.remote_addr.v4.as_inaddr = rsai->sin_addr; - } - break; - case AF_INET6: - { - struct sockaddr_in6 *lsai = (struct sockaddr_in6 *)local_addr; - struct sockaddr_in6 *rsai = (struct sockaddr_in6 *)remote_addr; - *face = (face_t) { - .type = FACE_TYPE_UDP, - .params.tunnel = { - .family = AF_INET6, - .local_addr.v6.as_in6addr = lsai->sin6_addr, - .local_port = lsai ? ntohs(lsai->sin6_port) : 0, - .remote_addr = IP_ADDRESS_EMPTY, - .remote_port = rsai ? ntohs(rsai->sin6_port) : 0, - }, - }; - if (rsai) - face->params.tunnel.remote_addr.v6.as_in6addr = rsai->sin6_addr; - } - break; - default: - return -1; - } - return 1; -} - -face_t * face_create() -{ - face_t * face = calloc(1, sizeof(face_t)); /* 0'ed for hash */ - return face; -} - -face_t * face_create_udp(const ip_address_t * local_addr, u16 local_port, - const ip_address_t * remote_addr, u16 remote_port, int family) -{ - face_t * face = face_create(); - if (face_initialize_udp(face, local_addr, local_port, remote_addr, remote_port, family) < 0) - goto ERR_INIT; - return face; - -ERR_INIT: - free(face); - return NULL; -} - -face_t * face_create_udp_sa(const struct sockaddr * local_addr, - const struct sockaddr * remote_addr) -{ - face_t * face = face_create(); - if (face_initialize_udp_sa(face, local_addr, remote_addr) < 0) - goto ERR_INIT; - return face; - -ERR_INIT: - free(face); - return NULL; -} - -void face_free(face_t * face) -{ - free(face); -} - -#define face_param_cmp(f1, f2, face_param_type) \ - memcmp(&f1->type, &f2->type, \ - member_size(face_params_t, face_param_type)); - -/** - * \brief Compare two faces - * \param [in] f1 - First face - * \param [in] f2 - Second face - * \return whether faces are equal, ie both their types are parameters are - * equal. - * - * NOTE: this function implements a partial order. - */ -int -face_cmp(const face_t * f1, const face_t * f2) -{ - if (f1->type != f2->type) - return false; - - switch(f1->type) { - case FACE_TYPE_HICN: - return face_param_cmp(f1, f2, hicn); - case FACE_TYPE_TCP: - case FACE_TYPE_UDP: - return face_param_cmp(f1, f2, tunnel); - default: - return false; - } -} - -hash_t -face_hash(const face_t * face) -{ - /* Assuming the unused part of the struct is set to zero */ - return hash_struct(face); -} - -/* /!\ Please update constants in header file upon changes */ -size_t -face_snprintf(char * s, size_t size, const face_t * face) -{ - switch(face->type) { - case FACE_TYPE_HICN: - return 0; // XXX Not implemented - case FACE_TYPE_TCP: - case FACE_TYPE_UDP: - { - char local[MAXSZ_IP_ADDRESS]; - char remote[MAXSZ_IP_ADDRESS]; - char tags[MAXSZ_POLICY_TAGS]; - - ip_address_snprintf(local, MAXSZ_IP_ADDRESS, - &face->params.tunnel.local_addr, - face->params.tunnel.family); - ip_address_snprintf(remote, MAXSZ_IP_ADDRESS, - &face->params.tunnel.remote_addr, - face->params.tunnel.family); - policy_tags_snprintf(tags, MAXSZ_POLICY_TAGS, face->tags); - - return snprintf(s, size, "%s [%s:%d -> %s:%d] [%s]", - face_type_str[face->type], - local, - face->params.tunnel.local_port, - remote, - face->params.tunnel.remote_port, - tags); - } - break; - default: - return 0; - } - -} - -int -face_set_tags(face_t * face, policy_tags_t tags) -{ - face->tags = tags; - return 1; -} diff --git a/ctrl/facemgr/src/face.h b/ctrl/facemgr/src/face.h deleted file mode 100644 index 8b553f685..000000000 --- a/ctrl/facemgr/src/face.h +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * \file face.h - * \brief Face abstraction - */ -#ifndef HICN_FACE_H -#define HICN_FACE_H - -#ifndef SPACES -#define SPACES(x) x -#endif -#ifndef SPACE -#define SPACE 1 -#endif -#ifndef NULLTERM -#define NULLTERM 1 -#endif - -#include "util/ip_address.h" -#include "util/policy.h" -#include "util/types.h" - - -/* Netdevice type */ - -#include <net/if.h> // IFNAMSIZ - -#define foreach_netdevice_type \ - _(UNDEFINED) \ - _(WIRED) \ - _(WIFI) \ - _(CELLULAR) \ - _(VPN) \ - _(N) - -#define MAXSZ_NETDEVICE_TYPE_ 9 -#define MAXSZ_NETDEVICE_TYPE MAXSZ_NETDEVICE_TYPE_ + NULLTERM - -typedef enum { -#define _(x) NETDEVICE_TYPE_ ## x, -foreach_netdevice_type -#undef _ -} netdevice_type_t; - -extern const char * netdevice_type_str[]; - - -/* Netdevice */ - -typedef struct { - u32 index; - char name[IFNAMSIZ]; -} netdevice_t; - -#define NETDEVICE_UNDEFINED_INDEX 0 - -/* Face state */ - -#define foreach_face_state \ - _(UNDEFINED) \ - _(PENDING_UP) \ - _(UP) \ - _(PENDING_DOWN) \ - _(DOWN) \ - _(ERROR) \ - _(N) - -#define MAXSZ_FACE_STATE_ 12 -#define MAXSZ_FACE_STATE MAXSZ_FACE_STATE_ + 1 - -typedef enum { -#define _(x) FACE_STATE_ ## x, -foreach_face_state -#undef _ -} face_state_t; - -extern const char * face_state_str[]; - - -/* Face type */ - -#define foreach_face_type \ - _(UNDEFINED) \ - _(HICN) \ - _(HICN_LISTENER) \ - _(TCP) \ - _(TCP_LISTENER) \ - _(UDP) \ - _(UDP_LISTENER) \ - _(N) - -#define MAXSZ_FACE_TYPE_ 13 -#define MAXSZ_FACE_TYPE MAXSZ_FACE_TYPE_ + 1 - -typedef enum { -#define _(x) FACE_TYPE_ ## x, -foreach_face_type -#undef _ -} face_type_t; - -extern const char * face_type_str[]; - -#define MAXSZ_FACE_ MAXSZ_FACE_TYPE_ + 2 * MAXSZ_IP_ADDRESS_ + 2 * MAXSZ_PORT_ + 9 + MAXSZ_POLICY_TAGS_ -#define MAXSZ_FACE MAXSZ_FACE_ + 1 - -/* Face */ - -typedef union { - int family; /* To access family independently of face type */ - struct { - int family; - netdevice_t netdevice; - ip_address_t local_addr; - ip_address_t remote_addr; - } hicn; - struct { - int family; - ip_address_t local_addr; - u16 local_port; - ip_address_t remote_addr; - u16 remote_port; - } tunnel; -} face_params_t; - -typedef struct { - face_type_t type; - face_params_t params; - face_state_t admin_state; - face_state_t state; -#ifdef WITH_POLICY - policy_tags_t tags; /**< \see policy_tag_t */ -#endif /* WITH_POLICY */ -} face_t; - -int face_initialize(face_t * face); -int face_initialize_udp(face_t * face, const ip_address_t * local_addr, - u16 local_port, const ip_address_t * remote_addr, u16 remote_port, - int family); -int face_initialize_udp_sa(face_t * face, - const struct sockaddr * local_addr, const struct sockaddr * remote_addr); - -face_t * face_create(); -face_t * face_create_udp(const ip_address_t * local_addr, u16 local_port, - const ip_address_t * remote_addr, u16 remote_port, int family); -face_t * face_create_udp_sa(const struct sockaddr * local_addr, - const struct sockaddr * remote_addr); - -int face_finalize(face_t * face); - -void face_free(face_t * face); - -typedef int (*face_cmp_t)(const face_t * f1, const face_t * f2); - -int face_cmp(const face_t * f1, const face_t * f2); -hash_t face_hash(const face_t * face); - -size_t -face_snprintf(char * s, size_t size, const face_t * face); - -int face_set_tags(face_t * face, policy_tags_t tags); - -#endif /* HICN_FACE_H */ - diff --git a/ctrl/facemgr/src/face_cache.h b/ctrl/facemgr/src/face_cache.h deleted file mode 100644 index caefb7e22..000000000 --- a/ctrl/facemgr/src/face_cache.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef FACE_CACHE_H -#define FACE_CACHE_H - -#include "face.h" -#include "util/set.h" - -TYPEDEF_SET_H(face_cache, face_t *); - -#endif /* FACE_CACHE_H */ diff --git a/ctrl/facemgr/src/face_rules.c b/ctrl/facemgr/src/face_rules.c deleted file mode 100644 index ddefc15f9..000000000 --- a/ctrl/facemgr/src/face_rules.c +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "face_rules.h" - -#include <string.h> -#include "util/policy.h" - -TYPEDEF_MAP(face_rules, const char *, policy_tags_t, strcmp, string_snprintf, policy_tags_snprintf); diff --git a/ctrl/facemgr/src/facelet.c b/ctrl/facemgr/src/facelet.c new file mode 100644 index 000000000..8a3074d2a --- /dev/null +++ b/ctrl/facemgr/src/facelet.c @@ -0,0 +1,1008 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file facelet.c + * \brief Implementation of facelet + */ + +#include <assert.h> +#include <stdbool.h> +#include <hicn/ctrl/face.h> +#include <hicn/facemgr/cfg.h> +#include <hicn/util/log.h> + +#include "facelet.h" + +const char * face_type_layer_str[] = { +#define _(x) [FACE_TYPE_LAYER_ ## x] = STRINGIZE(x), + foreach_face_type_layer +#undef _ +}; + +const char * face_type_encap_str[] = { +#define _(x) [FACE_TYPE_ENCAP_ ## x] = STRINGIZE(x), + foreach_face_type_encap +#undef _ +}; + +#define FACEMGR_FACE_TYPE_STR(x) \ + face_type_layer_str[x.layer], face_type_encap_str[x.encap] + + +const char * facelet_status_str[] = { +#define _(x) [FACELET_STATUS_ ## x] = STRINGIZE(x), + foreach_facelet_status +#undef _ +}; + +/* Facelet attribute status */ + + +const char * facelet_attr_status_str[] = { +#define _(x, str) [FACELET_ATTR_STATUS_ ## x] = STRINGIZE(x), + foreach_facelet_attr_status +#undef _ +}; + +const char * facelet_attr_status_str_short[] = { +#define _(x, str) [FACELET_ATTR_STATUS_ ## x] = STRINGIZE(str), + foreach_facelet_attr_status +#undef _ +}; + + +/* Facelet */ + +struct facelet_s { +#define _(TYPE, NAME) TYPE NAME; + foreach_facelet_attr +#undef _ +#define _(TYPE, NAME) facelet_attr_status_t NAME ## _status; + foreach_facelet_attr +#undef _ + + facelet_status_t status; + facelet_event_t event; + + /* Joins */ + bool bj_done; + bool au_done; + int num_pending; +}; + +const char * facelet_event_str[] = { +#define _(x) [FACELET_EVENT_ ## x] = STRINGIZE(x), +foreach_facelet_event +#undef _ +}; + +facelet_t * +facelet_create() +{ + facelet_t * facelet = calloc(1, sizeof(facelet_t)); + if (!facelet) + goto ERR_MALLOC; + + facelet->netdevice_status = FACELET_ATTR_STATUS_UNSET; + facelet->netdevice_type_status = FACELET_ATTR_STATUS_UNSET; + facelet->family_status = FACELET_ATTR_STATUS_UNSET; + facelet->local_addr_status = FACELET_ATTR_STATUS_UNSET; + facelet->local_port_status = FACELET_ATTR_STATUS_UNSET; + facelet->remote_addr_status = FACELET_ATTR_STATUS_UNSET; + facelet->remote_port_status = FACELET_ATTR_STATUS_UNSET; + facelet->admin_state_status = FACELET_ATTR_STATUS_UNSET; + facelet->state_status = FACELET_ATTR_STATUS_UNSET; + facelet->face_type_status = FACELET_ATTR_STATUS_UNSET; + + facelet->status = FACELET_STATUS_NEW; + + facelet->bj_done = false; + facelet->au_done = false; + facelet->num_pending = 0; + + facelet->event = FACELET_EVENT_UNDEFINED; + + return facelet; + +ERR_MALLOC: + return NULL; +} + +facelet_t * +facelet_create_from_netdevice(netdevice_t * netdevice) +{ + facelet_t * facelet = facelet_create(); + if (!facelet) + goto ERR_FACELET; + + int rc = facelet_set_netdevice(facelet, *netdevice); + if (rc < 0) + goto ERR_NETDEV; + + return facelet; + +ERR_NETDEV: + facelet_free(facelet); +ERR_FACELET: + return NULL; +} + +/** + * \brief Validate whether the facelet has all required fields to construct a + * face of the given type + * \param [in) facelet - Pointer to the facelet to verify + * \return 0 in case of success, -1 otherwise + */ +int +facelet_validate_face(const facelet_t * facelet) +{ + if (!facelet_has_face_type(facelet)) + return false; + switch(facelet->face_type.layer) { + case FACE_TYPE_LAYER_4: + if (!facelet_has_remote_port(facelet)) + return false; + if (!facelet_has_remote_addr(facelet)) + return false; + case FACE_TYPE_LAYER_3: + if (!facelet_has_local_addr(facelet)) + return false; + if (!facelet_has_netdevice(facelet)) + return false; + return true; + + default: + return false; /* Error */ + } + // FIXME Not implemented + return 0; +} + + +netdevice_type_t +netdevice_type_from_face_tags(const face_t * face) +{ + policy_tags_t tags = face->tags; + if (policy_tags_has(tags, POLICY_TAG_WIRED)) + return NETDEVICE_TYPE_WIRED; + else if (policy_tags_has(tags, POLICY_TAG_WIFI)) + return NETDEVICE_TYPE_WIFI; + else if (policy_tags_has(tags, POLICY_TAG_CELLULAR)) + return NETDEVICE_TYPE_CELLULAR; + return NETDEVICE_TYPE_UNDEFINED; +} + +facelet_t * +facelet_create_from_face(face_t * face) +{ + facelet_t * facelet = malloc(sizeof(facelet_t)); + if (!facelet) + goto ERR_MALLOC; + + /* Go through the face attributes to update the local representation */ + + /* Attribute : netdevice */ + /* NOTE index is not set */ + if (IS_VALID_NETDEVICE(face->netdevice)) { + facelet->netdevice = face->netdevice; + facelet->netdevice_status = FACELET_ATTR_STATUS_CLEAN; + } else { + facelet->netdevice_status = FACELET_ATTR_STATUS_UNSET; + } + + /* Attribute : netdevice_type */ + facelet->netdevice_type = netdevice_type_from_face_tags(face); + if (facelet->netdevice_type != NETDEVICE_TYPE_UNDEFINED) { + facelet->netdevice_type_status = FACELET_ATTR_STATUS_CLEAN; + } else { + facelet->netdevice = NETDEVICE_EMPTY; + facelet->netdevice_type_status = FACELET_ATTR_STATUS_UNSET; + } + + /* Attribute : family */ + if (IS_VALID_FAMILY(face->family)) { + facelet->family = face->family; + facelet->family_status = FACELET_ATTR_STATUS_CLEAN; + + /* Attribute : local_addr */ + if (ip_address_cmp(&face->local_addr, &IP_ADDRESS_EMPTY, face->family) != 0) { + facelet->local_addr = face->local_addr; + facelet->local_addr_status = FACELET_ATTR_STATUS_CLEAN; + } else { + facelet->local_addr_status = FACELET_ATTR_STATUS_UNSET; + } + + /* Attribute : local_port */ + if (IS_VALID_PORT(face->local_port)) { + facelet->local_port = face->local_port; + facelet->local_port_status = FACELET_ATTR_STATUS_CLEAN; + } else { + facelet->local_port_status = FACELET_ATTR_STATUS_UNSET; + } + + /* Attribute : remote_addr */ + if (ip_address_cmp(&face->remote_addr, &IP_ADDRESS_EMPTY, face->family) != 0) { + facelet->remote_addr = face->remote_addr; + facelet->remote_addr_status = FACELET_ATTR_STATUS_CLEAN; + } else { + facelet->remote_addr_status = FACELET_ATTR_STATUS_UNSET; + } + + /* Attribute : remote_port */ + if (IS_VALID_PORT(face->remote_port)) { + facelet->remote_port = face->remote_port; + facelet->remote_port_status = FACELET_ATTR_STATUS_CLEAN; + } else { + facelet->remote_port_status = FACELET_ATTR_STATUS_UNSET; + } + + } else { + facelet->family_status = FACELET_ATTR_STATUS_UNSET; + facelet->local_addr_status = FACELET_ATTR_STATUS_UNSET; + facelet->local_port_status = FACELET_ATTR_STATUS_UNSET; + facelet->remote_addr_status = FACELET_ATTR_STATUS_UNSET; + facelet->remote_port_status = FACELET_ATTR_STATUS_UNSET; + } + + /* Attribute : admin_state */ + if ((face->admin_state == FACE_STATE_UP) || + (face->admin_state == FACE_STATE_DOWN)) { + facelet->admin_state = face->admin_state; + facelet->admin_state_status = FACELET_ATTR_STATUS_CLEAN; + } else { + facelet->admin_state_status = FACELET_ATTR_STATUS_UNSET; + } + + /* Attribute : state */ + if ((face->state == FACE_STATE_UP) || + (face->state == FACE_STATE_DOWN)) { + facelet->state = face->state; + facelet->state_status = FACELET_ATTR_STATUS_CLEAN; + } else { + facelet->state_status = FACELET_ATTR_STATUS_UNSET; + } + + /* Attribute : face_type */ + if ((face->type != FACE_TYPE_UNDEFINED) && (face->type != FACE_TYPE_N)) { + switch(face->type) { + case FACE_TYPE_UDP: + facelet->face_type = FACEMGR_FACE_TYPE_OVERLAY_UDP; + break; + case FACE_TYPE_TCP: + facelet->face_type = FACEMGR_FACE_TYPE_OVERLAY_TCP; + break; + case FACE_TYPE_HICN: + facelet->face_type = FACEMGR_FACE_TYPE_NATIVE_TCP; + break; + default: + ERROR("[facelet_create_from_face] Face type not (yet) implemented"); + goto ERR_FACE; + } + facelet->face_type_status = FACELET_ATTR_STATUS_CLEAN; + } else { + facelet->face_type_status = FACELET_ATTR_STATUS_UNSET; + } + + /* Status */ + facelet->status = FACELET_STATUS_CLEAN; + + /* TODO Consistency check between face type and found attributes */ + if (facelet_validate_face(facelet) < 0) + goto ERR_FACE; + + facelet->bj_done = false; + facelet->au_done = false; + facelet->num_pending = 0; + + facelet->event = FACELET_EVENT_UNDEFINED; + + return facelet; + +ERR_FACE: + free(facelet); +ERR_MALLOC: + return NULL; +} + + +void +facelet_free(facelet_t * facelet) +{ + free(facelet); +} + +facelet_t * +facelet_dup(const facelet_t * current_facelet) +{ + facelet_t * facelet = facelet_create(); + if (!facelet) + goto ERR_CREATE; + +#define _(TYPE, NAME) facelet-> NAME = current_facelet-> NAME; + foreach_facelet_attr +#undef _ +#define _(TYPE, NAME) facelet-> NAME ## _status = current_facelet-> NAME ## _status; + foreach_facelet_attr +#undef _ + + facelet->status = current_facelet->status; + facelet->event = current_facelet->event; + + facelet->bj_done = current_facelet->bj_done; + facelet->au_done = current_facelet->au_done; + facelet->num_pending = current_facelet->num_pending; + + return facelet; + +ERR_CREATE: + return NULL; +} + +int +facelet_cmp(const facelet_t * f1, const facelet_t * f2) +{ + /* + * Under the assumption we only create a face per physical interface, a + * facelet is uniquely identified by its netdevice attribute, and address + * family if any. + * + * This function is mostly used for lookups into the cache, and the face + * thus needs to have a netdevice associated, and optionally, an address + * family. + * + * For other situations, the `facelet_match` function is more appropriate. + */ + + if ((f1->netdevice_status != FACELET_ATTR_STATUS_UNSET) && + (f2->netdevice_status != FACELET_ATTR_STATUS_UNSET)) { + int rc = netdevice_cmp(&f1->netdevice, &f2->netdevice); + if (rc != 0) + return rc; + + } else { + /* Both unset : we might have the face without netdevice due to hicn + * light not returning it currently, but we cannot skip it in the match + * otherwise we cannot distinguish with other faces except matching on + * other fields which might unfortunately not be determined yet... + */ + return (f1->netdevice_status == FACELET_ATTR_STATUS_UNSET) ? -1 : 1; + } + + assert(f1->family_status != FACELET_ATTR_STATUS_UNSET); + assert(f2->family_status != FACELET_ATTR_STATUS_UNSET); + + if ((f1->family == AF_UNSPEC) || (f2->family == AF_UNSPEC)) + return 0; + int diff = f1->family - f2->family; + return (diff > 0) ? 1 : + (diff < 0) ? -1 : 0; +} + +/* + * If the match has a field set, then the facelet only matches iif it has the + * same field set, and both values are equal + */ +#define MATCH_ATTRIBUTE(TYPE, NAME) \ +do { \ + if (facelet_match->NAME ## _status == FACELET_ATTR_STATUS_CLEAN) { \ + if (facelet_has_ ## NAME(facelet_match)) { \ + TYPE NAME; \ + TYPE NAME ## _match; \ + if (!facelet_has_ ## NAME(facelet)) \ + return false; \ + if (facelet_get_ ## NAME (facelet, & NAME) < 0) \ + return false; \ + if (facelet_get_ ## NAME (facelet_match, & NAME ## _match) < 0) \ + return false; \ + if (memcmp(& NAME, & NAME ## _match, sizeof(NAME)) != 0) \ + return false; \ + } \ + } \ +} while(0) + +/* facelet_match is the incoming one */ +bool +facelet_match(const facelet_t * facelet, const facelet_t * facelet_match) +{ +#define _(TYPE, NAME) MATCH_ATTRIBUTE(TYPE, NAME); + foreach_facelet_attr +#undef _ + return true; +} + +bool facelet_has_key(const facelet_t * facelet) { + return (facelet_has_netdevice(facelet) && facelet_has_family(facelet)); +} + +/* + * Implementation note: + * - facelet_set_* is equivalent to merge with a CLEAN remote attribute + */ +#define FACELET_ACCESSORS(TYPE, NAME) \ +bool \ +facelet_has_ ## NAME(const facelet_t * facelet) \ +{ \ + assert(facelet); \ + assert(facelet->NAME ## _status != FACELET_ATTR_STATUS_UNDEFINED); \ + assert(facelet->NAME ## _status != FACELET_ATTR_STATUS_N); \ + return ((facelet-> NAME ## _status != FACELET_ATTR_STATUS_UNSET)); \ +} \ + \ +facelet_attr_status_t \ +facelet_get_ ## NAME ## _status(const facelet_t * facelet) \ +{ \ + return (facelet->NAME ## _status); \ +} \ + \ +int \ +facelet_get_ ## NAME(const facelet_t * facelet, TYPE * NAME) \ +{ \ + assert(facelet); \ + if (!facelet_has_ ## NAME(facelet)) \ + return -1; \ + *NAME = facelet-> NAME; \ + return 0; \ +} \ + \ +int \ +facelet_set_local_ ## NAME(facelet_t * facelet, TYPE NAME) \ +{ \ + assert(facelet); \ + switch(facelet->NAME ## _status) { \ + case FACELET_ATTR_STATUS_UNSET: \ + case FACELET_ATTR_STATUS_CLEAN: \ + case FACELET_ATTR_STATUS_DIRTY: \ + case FACELET_ATTR_STATUS_PENDING: \ + facelet-> NAME = NAME; \ + facelet->NAME ## _status = FACELET_ATTR_STATUS_DIRTY; \ + if (facelet->status == FACELET_STATUS_CLEAN) \ + facelet->status = FACELET_STATUS_DIRTY; \ + break; \ + case FACELET_ATTR_STATUS_CONFLICT: \ + break; \ + case FACELET_ATTR_STATUS_UNDEFINED: \ + case FACELET_ATTR_STATUS_N: \ + ERROR("Unexpected attribute status value"); \ + return -1; \ + } \ + return 0; \ +} \ + \ +int \ +facelet_set_remote_ ## NAME(facelet_t * facelet, TYPE NAME) \ +{ \ + assert(facelet); \ + switch(facelet->NAME ## _status) { \ + case FACELET_ATTR_STATUS_UNSET: \ + facelet-> NAME = NAME; \ + facelet->NAME ## _status = FACELET_ATTR_STATUS_CLEAN; \ + break; \ + case FACELET_ATTR_STATUS_CLEAN: \ + facelet->NAME = NAME; \ + break; \ + case FACELET_ATTR_STATUS_DIRTY: \ + ERROR("Discarded remote value for status reasons"); \ + break; \ + case FACELET_ATTR_STATUS_PENDING: \ + ERROR("Received remote value on pending attribute"); \ + facelet->NAME ## _status = FACELET_ATTR_STATUS_CONFLICT; \ + if (facelet->status != FACELET_STATUS_CONFLICT) \ + facelet->status = FACELET_STATUS_CONFLICT; \ + break; \ + case FACELET_ATTR_STATUS_CONFLICT: \ + return -1; \ + case FACELET_ATTR_STATUS_UNDEFINED: \ + case FACELET_ATTR_STATUS_N: \ + ERROR("Unexpected attribute status value"); \ + return -1; \ + } \ + return 0; \ +} \ + \ +int \ +facelet_set_ ## NAME(facelet_t * facelet, TYPE NAME) \ +{ \ + return facelet_set_local_ ## NAME(facelet, NAME); \ +} \ + \ + +#define _(TYPE, NAME) FACELET_ACCESSORS(TYPE, NAME) +foreach_facelet_attr +#undef _ + +/* + * This function is called for every facelet attribute. It is responsible for + * comparing both the current and new value, and set the attribute and facelet + * status appropriately. + */ + +// FIXME CLEAN for key fields, dirty for fields to update. + +#define MERGE_ATTRIBUTE(TYPE, NAME) \ +do { \ + switch(facelet_to_merge->NAME ## _status) { \ + case FACELET_ATTR_STATUS_UNDEFINED: \ + case FACELET_ATTR_STATUS_N: \ + case FACELET_ATTR_STATUS_PENDING: \ + case FACELET_ATTR_STATUS_CONFLICT: \ + ERROR("Unexpected facelet attribute status"); \ + return -1; \ + case FACELET_ATTR_STATUS_UNSET: \ + break; \ + case FACELET_ATTR_STATUS_CLEAN: \ + case FACELET_ATTR_STATUS_DIRTY: \ + facelet_set_ ## NAME(facelet, facelet_to_merge-> NAME); \ + break; \ + } \ +} while (0) + +int facelet_merge(facelet_t * facelet, const facelet_t * facelet_to_merge) +{ + assert(facelet && facelet_to_merge); +#define _(TYPE, NAME) MERGE_ATTRIBUTE(TYPE, NAME); + foreach_facelet_attr +#undef _ + facelet->event = facelet_to_merge->event; + return 0; +} + +#define MERGE_ATTRIBUTE_REMOTE(TYPE, NAME) \ +do { \ + switch(facelet_to_merge->NAME ## _status) { \ + case FACELET_ATTR_STATUS_UNDEFINED: \ + case FACELET_ATTR_STATUS_N: \ + case FACELET_ATTR_STATUS_DIRTY: \ + case FACELET_ATTR_STATUS_PENDING: \ + case FACELET_ATTR_STATUS_CONFLICT: \ + ERROR("Unexpected facelet attribute status"); \ + return -1; \ + case FACELET_ATTR_STATUS_UNSET: \ + break; \ + case FACELET_ATTR_STATUS_CLEAN: \ + facelet_set_ ## NAME(facelet, facelet_to_merge-> NAME); \ + break; \ + \ + } \ +} while (0) + +int facelet_merge_remote(facelet_t * facelet, const facelet_t * facelet_to_merge) +{ + assert(facelet && facelet_to_merge); +#define _(TYPE, NAME) MERGE_ATTRIBUTE_REMOTE(TYPE, NAME); + foreach_facelet_attr +#undef _ + facelet->event = facelet_to_merge->event; + return 0; +} + +int +facelet_get_face(const facelet_t * facelet, face_t ** pface) +{ + assert(pface); + + /* Facelet has all the required information to create a face */ + if (facelet_validate_face(facelet) < 0) + return 0; + + face_t * face = face_create(); + if (!face) + goto ERR_CREATE; + + assert(facelet_has_netdevice(facelet)); + face->netdevice = facelet->netdevice; + + /* Face type */ + switch(facelet->face_type.layer) { + case FACE_TYPE_LAYER_4: + switch(facelet->face_type.encap) { + case FACE_TYPE_ENCAP_UDP: + face->type = FACE_TYPE_UDP; + break; + case FACE_TYPE_ENCAP_TCP: + face->type = FACE_TYPE_TCP; + break; + case FACE_TYPE_ENCAP_UNDEFINED: + case FACE_TYPE_ENCAP_N: + ERROR("[facelet_get_face] Unsupported face encapsulation"); + goto ERR; + } + + if (facelet_get_family(facelet, &face->family) < 0) + goto ERR; + if (facelet_get_local_addr(facelet, &face->local_addr) < 0) + goto ERR; + if (facelet_get_local_port(facelet, &face->local_port) < 0) + goto ERR; + if (facelet_get_remote_addr(facelet, &face->remote_addr) < 0) + goto ERR; + if (facelet_get_remote_port(facelet, &face->remote_port) < 0) + goto ERR; + break; + + case FACE_TYPE_LAYER_3: + ERROR("{facelet_get_face] hICN face not (yet) implemented"); + goto ERR; + + case FACE_TYPE_LAYER_UNDEFINED: + case FACE_TYPE_LAYER_N: + ERROR("[facelet_get_face] Unsupported face type"); + goto ERR; + } + + if (facelet_has_admin_state(facelet)) { + if (facelet_get_admin_state(facelet, &face->admin_state) < 0) + goto ERR; + } else { + face->admin_state = FACE_STATE_UP; + } + + if (facelet_has_state(facelet)) { + if (facelet_get_state(facelet, &face->state) < 0) + goto ERR; + } else { + face->state = FACE_STATE_UP; + } + + /* Tags */ + + /* - based on netdevice type */ + policy_tags_t tags = POLICY_TAGS_EMPTY; + if (facelet_has_netdevice_type(facelet)) { + netdevice_type_t netdevice_type; + if (facelet_get_netdevice_type(facelet, &netdevice_type) < 0) { + ERROR("error getting netdevice_type"); + goto ERR; + } + + + switch(netdevice_type) { + case NETDEVICE_TYPE_UNDEFINED: + case NETDEVICE_TYPE_LOOPBACK: + break; + case NETDEVICE_TYPE_WIRED: + policy_tags_add(&tags, POLICY_TAG_WIRED); + break; + case NETDEVICE_TYPE_WIFI: + policy_tags_add(&tags, POLICY_TAG_WIFI); + break; + case NETDEVICE_TYPE_CELLULAR: + policy_tags_add(&tags, POLICY_TAG_CELLULAR); + break; + default: + goto ERR; + } + } +#ifdef __linux__ +#ifndef __ANDROID__ + else { + /* + * Heuristics to determine face type based on name, until a better + * solution is found + */ + if (strncmp(facelet->netdevice.name, "eth", 3) == 0) { + policy_tags_add(&tags, POLICY_TAG_WIRED); + goto DONE; + } + if (strncmp(facelet->netdevice.name, "en", 2) == 0) { + policy_tags_add(&tags, POLICY_TAG_WIRED); + goto DONE; + } + if (strncmp(facelet->netdevice.name, "wl", 2) == 0) { + /* wlan* wlp* wlx* */ + policy_tags_add(&tags, POLICY_TAG_WIFI); + goto DONE; + } + +DONE: + ; + } +#endif /* ! __ANDROID__ */ +#endif /* __linux__ */ + face->tags = tags; + + *pface = face; + + return 0; + +ERR: + free(face); +ERR_CREATE: + *pface = NULL; + return -1; +} + +facelet_status_t +facelet_get_status(const facelet_t * facelet) +{ + return facelet->status; +} + +#define SET_ATTR_STATUS_CLEAN(TYPE, NAME) \ +do { \ + if (facelet->NAME ## _status == FACELET_ATTR_STATUS_DIRTY) \ + facelet->NAME ## _status = FACELET_ATTR_STATUS_CLEAN; \ +} while (0) + +void +facelet_set_status(facelet_t * facelet, facelet_status_t status) +{ + if (status == FACELET_STATUS_CLEAN) { +#define _(TYPE, NAME) SET_ATTR_STATUS_CLEAN(TYPE, NAME); + foreach_facelet_attr +#undef _ + } + facelet->status = status; +} + +int +facelet_add_pending(facelet_t * facelet) +{ + assert(facelet); + facelet->num_pending++; + return 0; +} + +int +facelet_remove_pending(facelet_t * facelet) +{ + assert(facelet); + if (facelet->num_pending == 0) + return -1; + facelet->num_pending--; + return 0; +} + +bool +facelet_has_pending(const facelet_t * facelet) +{ + assert(facelet); + DEBUG("num pending=%d\n", facelet->num_pending); + return (facelet->num_pending > 0); +} + +void +facelet_set_bj_done(facelet_t * facelet) +{ + facelet->bj_done = true; +} + +bool +facelet_is_bj_done(const facelet_t * facelet) +{ + return facelet->bj_done; +} + +void +facelet_set_au_done(facelet_t * facelet) +{ + facelet->au_done = true; +} + +bool +facelet_is_au_done(const facelet_t * facelet) +{ + return facelet->au_done; +} + +facelet_event_t +facelet_get_event(const facelet_t * facelet) +{ + return facelet->event; +} + +void +facelet_set_event(facelet_t * facelet, facelet_event_t event) +{ + facelet->event = event; +} + +int +facelet_raise_event(facelet_t * facelet, const interface_t * interface) +{ + if (interface->callback) + interface->callback(interface->callback_data, facelet); + return 0; +} + +int +facelet_snprintf(char * s, size_t size, facelet_t * facelet) +{ + char * cur = s; + int rc; + + assert(facelet); + + /* Header + key attributes (netdevice + family) */ + rc = snprintf(cur, s + size - cur, "<Facelet %s (%s) [%d]", + // FIXME, better than the event would be the action to be performed next + facelet_event_str[facelet->event], + (facelet->family == AF_INET) ? "AF_INET" : + (facelet->family == AF_INET6) ? "AF_INET6" : + (facelet->family == AF_UNSPEC) ? "AF_UNSPEC" : + "unknown", + facelet->num_pending); + if (rc < 0) + return rc; + cur += rc; + if (size != 0 && cur >= s + size) + return cur - s; + + /* Netdevice */ + if (facelet_has_netdevice(facelet)) { + rc = snprintf(cur, s + size - cur, " netdevice=%s", + facelet->netdevice.name[0] ? facelet->netdevice.name : "*"); + if (rc < 0) + return rc; + cur += rc; + if (size != 0 && cur >= s + size) + return cur - s; + + rc = snprintf(cur, s + size - cur, "/%d", facelet->netdevice.index); + if (rc < 0) + return rc; + cur += rc; + if (size != 0 && cur >= s + size) + return cur - s; + + } else { + rc = snprintf(cur, s + size - cur, " netdevice=*/*"); + if (rc < 0) + return rc; + cur += rc; + if (size != 0 && cur >= s + size) + return cur - s; + } + + /* Netdevice type */ + if (facelet_has_netdevice_type(facelet)) { + rc = snprintf(cur, s + size - cur, " type=%s", + netdevice_type_str[facelet->netdevice_type]); + if (rc < 0) + return rc; + cur += rc; + if (size != 0 && cur >= s + size) + return cur - s; + } +#ifdef __linux__ +#ifndef __ANDROID__ + else { + /* + * Heuristics to determine face type based on name, until a better + * solution is found + */ + if ((strncmp(facelet->netdevice.name, "eth", 3) == 0) || + (strncmp(facelet->netdevice.name, "en", 2) == 0)) { + rc = snprintf(cur, s + size - cur, " [type=WIRED]"); + goto HEURISTIC_DONE; + } + if (strncmp(facelet->netdevice.name, "wl", 2) == 0) { + /* wlan* wlp* wlx* */ + rc = snprintf(cur, s + size - cur, " [type=WIFI]"); + goto HEURISTIC_DONE; + } + goto HEURISTIC_END; + +HEURISTIC_DONE: + if (rc < 0) + return rc; + cur += rc; + if (size != 0 && cur >= s + size) + return cur - s; +HEURISTIC_END: + ; + } +#endif /* ! __ANDROID__ */ +#endif /* __linux__ */ + + /* Local ip address */ + if (facelet_has_local_addr(facelet)) { + rc = snprintf(cur, s + size - cur, " local_addr="); + if (rc < 0) + return rc; + cur += rc; + if (size != 0 && cur >= s + size) + return cur - s; + + rc = ip_address_snprintf(cur, s + size - cur, &facelet->local_addr, + facelet->family); + if (rc < 0) + return rc; + cur += rc; + if (size != 0 && cur >= s + size) + return cur - s; + } + + /* Local port */ + if (facelet_has_local_port(facelet)) { + rc = snprintf(cur, s + size - cur, " local_port=%d", + facelet->local_port); + if (rc < 0) + return rc; + cur += rc; + if (size != 0 && cur >= s + size) + return cur - s; + } + + /* Remote ip address */ + if (facelet_has_remote_addr(facelet)) { + rc = snprintf(cur, s + size - cur, " remote_addr="); + if (rc < 0) + return rc; + cur += rc; + if (size != 0 && cur >= s + size) + return cur - s; + + rc = ip_address_snprintf(cur, s + size - cur, &facelet->remote_addr, + facelet->family); + if (rc < 0) + return rc; + cur += rc; + if (size != 0 && cur >= s + size) + return cur - s; + } + + /* Remote port */ + if (facelet_has_remote_port(facelet)) { + rc = snprintf(cur, s + size - cur, " remote_port=%d", + facelet->remote_port); + if (rc < 0) + return rc; + cur += rc; + if (size != 0 && cur >= s + size) + return cur - s; + } + + /* Admin state */ + if (facelet_has_admin_state(facelet)) { + rc = snprintf(cur, s + size - cur, " admin_state=%s", + face_state_str[facelet->admin_state]); + if (rc < 0) + return rc; + cur += rc; + if (size != 0 && cur >= s + size) + return cur - s; + } + + /* State */ + if (facelet_has_state(facelet)) { + rc = snprintf(cur, s + size - cur, " state=%s", + face_state_str[facelet->state]); + if (rc < 0) + return rc; + cur += rc; + if (size != 0 && cur >= s + size) + return cur - s; + } + + if (facelet_has_face_type(facelet)) { + rc = snprintf(cur, s + size - cur, " face_type=IP%s/%s", + FACEMGR_FACE_TYPE_STR(facelet->face_type)); + if (rc < 0) + return rc; + cur += rc; + if (size != 0 && cur >= s + size) + return cur - s; + } + + rc = snprintf(cur, s + size - cur, ">"); + if (rc < 0) + return rc; + cur += rc; + if (size != 0 && cur >= s + size) + return cur - s; + + return cur - s; +} diff --git a/ctrl/facemgr/src/facelet.h b/ctrl/facemgr/src/facelet.h new file mode 100644 index 000000000..fecee8641 --- /dev/null +++ b/ctrl/facemgr/src/facelet.h @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file facelet.h + * \brief Facelet + * + * A facelet consists in partial information and annotations collected towards + * the contruction of the final face that will be sent to the forwarder. + * + * It might also consist in a pattern allowing the deletion of a group of face + * for instance. + */ +#ifndef FACEMGR_FACELET_H +#define FACEMGR_FACELET_H + +#include <stdbool.h> + +#include <hicn/ctrl/face.h> +#include <hicn/facemgr.h> + +#include "interface.h" + +/* NOTE: Any test should be sufficient */ +#define IS_VALID_NETDEVICE(netdevice) ((netdevice.index != 0) && (netdevice.name[0] != '\0')) + +typedef struct facelet_s facelet_t; + +/* Facelet status */ +#define foreach_facelet_status \ + _(UNDEFINED) \ + _(NEW) \ + _(CLEAN) \ + _(DIRTY) \ + _(CONFLICT) \ + _(DELETED) \ + _(N) + +typedef enum { +#define _(x) FACELET_STATUS_ ## x, + foreach_facelet_status +#undef _ +} facelet_status_t; + +extern const char * facelet_status_str[]; + +/* Facelet attribute status */ + +/* + * We expect an attribute in the cache to be able to take any value but + * UNDEFINED and N, which facelet events should either be UNSET or CLEAN + */ +#define foreach_facelet_attr_status \ + _(UNDEFINED, '?') \ + _(UNSET, 'X') \ + _(CLEAN, ' ') \ + _(DIRTY, '*') \ + _(PENDING, 'P') \ + _(CONFLICT, '!') \ + _(N, '-') + +typedef enum { +#define _(x, y) FACELET_ATTR_STATUS_ ## x, + foreach_facelet_attr_status +#undef _ +} facelet_attr_status_t; + +extern const char * facelet_attr_status_str[]; +extern const char * facelet_attr_status_str_short[]; + +/* Facelet attribute */ + +#define foreach_facelet_attr \ + _(netdevice_type_t, netdevice_type) \ + _(netdevice_t, netdevice) \ + _(int, family) \ + _(ip_address_t, local_addr) \ + _(u16, local_port) \ + _(ip_address_t, remote_addr) \ + _(u16, remote_port) \ + _(face_state_t, admin_state) \ + _(face_state_t, state) \ + _(facemgr_face_type_t, face_type) + +#define foreach_facelet_event \ + _(UNDEFINED) \ + _(GET) \ + _(CREATE) \ + _(UPDATE) \ + _(DELETE) \ + _(SET_PARAMS) \ + _(SET_UP) \ + _(SET_DOWN) \ + _(SET_TAGS) \ + _(CLEAR_TAGS) \ + _(ADD_TAG) \ + _(REMOVE_TAG) \ + _(N) + +#define MAXSZ_EVENT__ 10 +#define MAXSZ_EVENT_ MAXSZ_EVENT_ + 1 + +/** + * \brief Enumeration of the possible types of event + */ +typedef enum { +#define _(x) FACELET_EVENT_ ## x, +foreach_facelet_event +#undef _ +} facelet_event_t; + +extern const char * facelet_event_str[]; + +/** + * \brief Create a facelet. + */ +facelet_t * facelet_create(); + +facelet_t * facelet_create_from_netdevice(netdevice_t * netdevice); + +int facelet_validate_face(const facelet_t * facelet); + +facelet_t * facelet_create_from_face(face_t * face); + +void facelet_free(facelet_t * facelet); + +facelet_t * facelet_dup(const facelet_t * current_facelet); + +int facelet_cmp(const facelet_t * f1, const facelet_t * f2); + +/* NOTE: only clean attributes are matched */ +bool facelet_match(const facelet_t * facelet, const facelet_t * facelet_match); + +/** + * \brief Returns whether the specified facelet has all key attributes defined. + * + * Key attributes are netdevice and family. If both are present, this allows to + * uniquely identify a facelet, otherwise it is a 'wildcard' facelet + * specification and might match several facelets. + */ +bool facelet_has_key(const facelet_t * facelet); + + +#define FACELET_ACCESSORS_H(TYPE, NAME) \ +bool facelet_has_ ## NAME(const facelet_t * facelet); \ +facelet_attr_status_t facelet_get_ ## NAME ## _status(const facelet_t * facelet);\ +int facelet_get_ ## NAME(const facelet_t * facelet, TYPE * NAME); \ +int facelet_set_ ## NAME(facelet_t * facelet, TYPE NAME); + +#define _(TYPE, NAME) FACELET_ACCESSORS_H(TYPE, NAME) +foreach_facelet_attr +#undef _ + +int facelet_get_face(const facelet_t * facelet, face_t ** pface); + +int facelet_merge(facelet_t * facelet, const facelet_t * facelet_to_merge); + +facelet_status_t facelet_get_status(const facelet_t * facelet); +void facelet_set_status(facelet_t * facelet, facelet_status_t status); + +int facelet_add_pending(facelet_t * facelet); +int facelet_remove_pending(facelet_t * facelet); +bool facelet_has_pending(const facelet_t * facelet); + +void facelet_set_bj_done(facelet_t * facelet); +bool facelet_is_bj_done(const facelet_t * facelet); +void facelet_set_au_done(facelet_t * facelet); +bool facelet_is_au_done(const facelet_t * facelet); + +facelet_event_t facelet_get_event(const facelet_t * facelet); +void facelet_set_event(facelet_t * facelet, facelet_event_t event); + +/** + * \brief Create and raises an event to the face manager + * \param [in] event_type - Type of the event to create + * \param [in] facelet - Facelet to communicate with the event + * \param [in] interface - Interface that raised the event (or NULL if it was + * created but the face manager itself, or is a joined event) + */ +int facelet_raise_event(facelet_t * facelet, const interface_t * interface); + +int facelet_snprintf(char * buf, size_t size, facelet_t * facelet); + +#define MAXSZ_FACELET 1024 + +#endif /* FACEMGR_FACELET_H */ diff --git a/ctrl/facemgr/src/facemgr.c b/ctrl/facemgr/src/facemgr.c deleted file mode 100644 index 41e30de56..000000000 --- a/ctrl/facemgr/src/facemgr.c +++ /dev/null @@ -1,298 +0,0 @@ -/* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * \file facemgr.c - * \brief Implementation of Face manager library interface - */ - -#include <stdio.h> - -#include "common.h" -#include "event.h" -#include "facemgr.h" -#include "interface.h" -#include "util/log.h" - -#ifdef __APPLE__ -extern interface_ops_t network_framework_ops; -#endif -#ifdef __linux__ -extern interface_ops_t netlink_ops; -#endif -#if 0 -extern interface_ops_t dummy_ops; -#endif -extern interface_ops_t hicn_light_ops; - -int -facemgr_initialize(facemgr_t * facemgr) -{ - int rc; - - rc = interface_map_initialize(&facemgr->interface_map); - if (FACEMGR_IS_ERROR(rc)) - goto ERR_INTERFACE_MAP; - - rc = face_cache_initialize(&facemgr->face_cache); - if (FACEMGR_IS_ERROR(rc)) - goto ERR_FACE_SET; - - rc = face_rules_initialize(&facemgr->rules); - if (FACEMGR_IS_ERROR(rc)) - goto ERR_FACE_SET; - - return FACEMGR_SUCCESS; - -ERR_FACE_SET: - interface_map_finalize(&facemgr->interface_map); - -ERR_INTERFACE_MAP: - return FACEMGR_FAILURE; -} - -int -facemgr_finalize(facemgr_t * facemgr) -{ - int rc; - - /* XXX Free all interfaces: pass free to map */ - rc = interface_map_finalize(&facemgr->interface_map); - if (FACEMGR_IS_ERROR(rc)) - goto ERR; - - rc = face_cache_finalize(&facemgr->face_cache); - if (FACEMGR_IS_ERROR(rc)) - goto ERR; - - rc = face_rules_finalize(&facemgr->rules); - if (FACEMGR_IS_ERROR(rc)) - goto ERR; - - return FACEMGR_SUCCESS; - -ERR: - return FACEMGR_FAILURE; -} - -AUTOGENERATE_CREATE_FREE(facemgr); - -int -facemgr_on_event(facemgr_t * facemgr, event_t * event) -{ - int rc; - char face_s[MAXSZ_FACE]; - face_t * cached_face; - - if (!event->face) { - printf("Event with empty face\n"); - return -1; - } - - face_t face = *event->face; - - /* Complement unbound UDP faces */ - switch(face.type) { - case FACE_TYPE_TCP: - case FACE_TYPE_UDP: - switch (face.params.tunnel.family) { - case AF_INET: - if ((ip_address_empty(&face.params.tunnel.remote_addr)) && - (!ip_address_empty(&facemgr->overlay_v4_remote_addr))) - face.params.tunnel.remote_addr = facemgr->overlay_v4_remote_addr; - if ((face.params.tunnel.local_port == 0) && (facemgr->overlay_v4_local_port != 0)) - face.params.tunnel.local_port = facemgr->overlay_v4_local_port; - if ((face.params.tunnel.remote_port == 0) && (facemgr->overlay_v4_remote_port != 0)) - face.params.tunnel.remote_port = facemgr->overlay_v4_remote_port; - break; - case AF_INET6: - if ((ip_address_empty(&face.params.tunnel.remote_addr)) && - (!ip_address_empty(&facemgr->overlay_v6_remote_addr))) - face.params.tunnel.remote_addr = facemgr->overlay_v6_remote_addr; - if ((face.params.tunnel.local_port == 0) && (facemgr->overlay_v6_local_port != 0)) - face.params.tunnel.local_port = facemgr->overlay_v6_local_port; - if ((face.params.tunnel.remote_port == 0) && (facemgr->overlay_v6_remote_port != 0)) - face.params.tunnel.remote_port = facemgr->overlay_v6_remote_port; - default: - break; - } - break; - default: - break; - } - - face_snprintf(face_s, MAXSZ_FACE, &face); - - /* TODO Here, we need to filter events based on our cache, and update the cache - * based on our actions if they are successful */ - - switch(event->type) { - case EVENT_TYPE_CREATE: - rc = face_cache_get(&facemgr->face_cache, &face, &cached_face); - if (!FACEMGR_IS_ERROR(rc)) { - DEBUG("Face found in cache"); - goto IGNORE_EVENT; - } - rc = face_cache_add(&facemgr->face_cache, &face); - if (FACEMGR_IS_ERROR(rc)) - WARN("Failed to add face to cache"); - break; - case EVENT_TYPE_DELETE: - rc = face_cache_remove(&facemgr->face_cache, &face, &cached_face); - if (FACEMGR_IS_ERROR(rc)) - WARN("Face not found in cache"); - break; - case EVENT_TYPE_SET_UP: - case EVENT_TYPE_SET_DOWN: - /* TODO We need a return code to update the cache */ - break; - default: - printf("Not implemented!\n"); - break; - } - - /* Process event */ - printf("[ FACE %s ] %s\n", event_type_str[event->type], face_s); - /* Hardcoded hicn-light */ - rc = interface_on_event(facemgr->hl, event); - if (FACEMGR_IS_ERROR(rc)) - goto ERR; - -IGNORE_EVENT: - return FACEMGR_SUCCESS; - -ERR: - return FACEMGR_FAILURE; -} - -#ifdef __linux__ -void interface_callback(evutil_socket_t fd, short what, void * arg) { - interface_t * interface = (interface_t *)arg; - interface->ops->callback(interface); -} -#endif /* __linux__ */ - -int -facemgr_create_interface(facemgr_t * facemgr, const char * name, const char * type, interface_t ** interface) -{ - int fd, rc; - - INFO("Creating interface %s [%s]...\n", name, type); - *interface = interface_create(name, type); - if (!*interface) { - ERROR("Error creating interface %s [%s]\n", name, type); - return -1; - } - interface_set_callback(*interface, facemgr_on_event, facemgr); - - fd = interface_initialize(*interface, &facemgr->rules); - if (fd < 0) - return -2; - if (fd != 0) { -#ifdef __linux__ - evutil_make_socket_nonblocking(fd); - struct event * event = event_new(facemgr->loop, fd, EV_READ | EV_PERSIST, interface_callback, *interface); - if (!event) { - return -3; - } - - if (event_add(event, NULL) < 0) { - return -4; - } -#else - ERROR("Not implemented\n"); - return FACEMGR_FAILURE; -#endif /* __linux__ */ - } - - rc = interface_map_add(&facemgr->interface_map, (*interface)->name, *interface); - if (FACEMGR_IS_ERROR(rc)) - return -5; - - DEBUG("Interface created successfully.\n"); - return FACEMGR_SUCCESS; -} - -int -facemgr_bootstrap(facemgr_t * facemgr) -{ - int rc; - - DEBUG("Registering interfaces..."); - rc = interface_register(&hicn_light_ops); - if (FACEMGR_IS_ERROR(rc)) { - ERROR("Could not register interfaces"); - goto ERR_REGISTER; - } - -#ifdef __APPLE__ - rc = interface_register(&network_framework_ops); - if (FACEMGR_IS_ERROR(rc)) - goto ERR_REGISTER; -#endif /* __APPLE__ */ - -#ifdef __linux__ - rc = interface_register(&netlink_ops); - if (FACEMGR_IS_ERROR(rc)) - goto ERR_REGISTER; -#endif /* __linux__ */ - -#if 0 - rc = interface_register(&dummy_ops); - if (FACEMGR_IS_ERROR(rc)) - goto ERR_REGISTER; -#endif - - rc = facemgr_create_interface(facemgr, "hl", "hicn_light", &facemgr->hl); - if (rc < 0) { - ERROR("Error creating 'hICN forwarder (hicn-light)' interface\n"); - goto ERR_HL_CREATE; - } - -#ifdef __APPLE__ - rc = facemgr_create_interface(facemgr, "nf", "network_framework", &facemgr->nf); - if (rc < 0) { - ERROR("Error creating 'Apple Network Framework' interface\n"); - goto ERR_NF_CREATE; - } -#endif /* __APPLE__ */ - -#ifdef __linux__ - rc = facemgr_create_interface(facemgr, "nl", "netlink", &facemgr->nl); - if (rc < 0) { - ERROR("Error creating 'Netlink' interface\n"); - goto ERR_NF_CREATE; - } -#endif /* __linux__ */ - -#if 0 - rc = facemgr_create_interface(facemgr, "dummy", "dummy", &facemgr->dummy); - if (rc < 0) { - ERROR("Error creating 'Dummy' interface\n"); - goto ERR_NF_CREATE; - } -#endif - - DEBUG("Facemgr successfully initialized..."); - - return FACEMGR_SUCCESS; - -ERR_NF_CREATE: - interface_free(facemgr->hl); -ERR_HL_CREATE: - //interface_map_remove(&facemgr->interface_map, data->nf->name); -ERR_REGISTER: - return FACEMGR_FAILURE; -} diff --git a/ctrl/facemgr/src/facemgr.h b/ctrl/facemgr/src/facemgr.h deleted file mode 100644 index 6505a1bd8..000000000 --- a/ctrl/facemgr/src/facemgr.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * \file facemgr.h - * \brief Face manager library interface - */ -#ifndef FACEMGR_H -#define FACEMGR_H - -#include <string.h> -#include "common.h" -#include "face.h" -#include "face_cache.h" -#include "face_rules.h" -#include "interface.h" -#include "interface_map.h" -#include "util/ip_address.h" -#include "util/map.h" -#include "util/policy.h" -#ifndef __APPLE__ -#include <event2/event.h> -#endif /* __APPLE__ */ - -/* - * \brief Face manager context - */ -typedef struct { -#ifndef APPLE - /* Event loop */ - struct event_base * loop; -#endif /* APPLE */ - - interface_map_t interface_map; - interface_t * hl; - -#ifdef __APPLE__ - interface_t * nf; -#endif /* __APPLE__ */ - -#ifdef __linux__ - interface_t * nl; -#endif /* __linux__ */ - -#if 0 - interface_t * dummy; -#endif - - /* Overlay management */ - uint16_t overlay_v4_local_port; - ip_address_t overlay_v4_remote_addr; - uint16_t overlay_v4_remote_port; - uint16_t overlay_v6_local_port; - ip_address_t overlay_v6_remote_addr; - uint16_t overlay_v6_remote_port; - - face_rules_t rules; - face_cache_t face_cache; -} facemgr_t; - -AUTOGENERATE_DEFS(facemgr); - -int facemgr_bootstrap(facemgr_t * facemgr); - -#endif /* FACEMGR_H */ diff --git a/ctrl/facemgr/src/interface.c b/ctrl/facemgr/src/interface.c index af9f666a7..3e6bc0854 100644 --- a/ctrl/facemgr/src/interface.c +++ b/ctrl/facemgr/src/interface.c @@ -20,12 +20,13 @@ #include <stdlib.h> #include <string.h> -#include "event.h" -#include "face_rules.h" +#include "facelet.h" #include "interface.h" -#include "interface_ops_map.h" #include "util/map.h" +TYPEDEF_MAP_H(interface_ops_map, const char *, const interface_ops_t *); +TYPEDEF_MAP(interface_ops_map, const char *, const interface_ops_t *, strcmp, string_snprintf, generic_snprintf); + static interface_ops_map_t * interface_ops_map = NULL; int @@ -34,19 +35,19 @@ interface_register(const interface_ops_t * ops) if (!interface_ops_map) { interface_ops_map = interface_ops_map_create(); if (!interface_ops_map) - return FACEMGR_FAILURE; + return -1; } interface_ops_map_add(interface_ops_map, ops->type, ops); - return FACEMGR_SUCCESS; + return 0; } interface_t * interface_create(const char * name, const char * type) { - interface_ops_t * ops; + const interface_ops_t * ops = NULL; int rc = interface_ops_map_get(interface_ops_map, type, &ops); - if (FACEMGR_IS_ERROR(rc)) { + if (rc < 0) { printf("Interface type not found %s\n", type); return NULL; } @@ -80,25 +81,25 @@ _interface_set_callback(interface_t * interface, callback_t callback, void * cal } int -interface_initialize(interface_t * interface, struct face_rules_s * rules) +interface_initialize(interface_t * interface, void * cfg) { if (!interface->ops->initialize) - return FACEMGR_FAILURE; - return interface->ops->initialize(interface, rules, &interface->data); + return -1; + return interface->ops->initialize(interface, cfg); } int interface_finalize(interface_t * interface) { if (!interface->ops->finalize) - return FACEMGR_FAILURE; + return -1; return interface->ops->finalize(interface); } int -interface_on_event(interface_t * interface, const event_t * event) +interface_on_event(interface_t * interface, const facelet_t * facelet) { if (!interface->ops->on_event) - return FACEMGR_FAILURE; - return interface->ops->on_event(interface, event); + return -1; + return interface->ops->on_event(interface, facelet); } diff --git a/ctrl/facemgr/src/interface.h b/ctrl/facemgr/src/interface.h index f38313182..331312bde 100644 --- a/ctrl/facemgr/src/interface.h +++ b/ctrl/facemgr/src/interface.h @@ -30,27 +30,30 @@ #include <stdbool.h> -struct event_s; -typedef int (*callback_t)(struct event_s * event, void * callback_data); +struct facelet_s; +typedef int (*callback_t)(struct facelet_s * facelet, void * callback_data); struct interface_s; -struct face_rules_s; /** * \brief Interface operations */ typedef struct { + /** The type given to the interfaces */ char * type; - bool is_singleton; - int (*initialize)(struct interface_s * interface, struct face_rules_s * rules, void ** pdata); + /* Constructor */ + int (*initialize)(struct interface_s * interface, void * cfg); + /* Destructor */ int (*finalize)(struct interface_s * interface); + /* Callback upon file descriptor event (iif previously registered) */ int (*callback)(struct interface_s * interface); - int (*on_event)(struct interface_s * interface, const struct event_s * event); + /* Callback upon face events coming from the face manager */ + int (*on_event)(struct interface_s * interface, const struct facelet_s * facelet); } interface_ops_t; typedef struct interface_s { char * name; - interface_ops_t * ops; + const interface_ops_t * ops; callback_t callback; void * callback_data; void * data; @@ -90,9 +93,9 @@ void _interface_set_callback(interface_t * interface, callback_t callback, void #define interface_set_callback(interface, callback, callback_data) \ _interface_set_callback(interface, (callback_t)callback, (void*)callback_data) -int interface_initialize(interface_t * interface, struct face_rules_s * rules); +int interface_initialize(interface_t * interface, void * cfg); int interface_finalize(interface_t * interface); -int interface_on_event(interface_t * interface, const struct event_s * event); +int interface_on_event(interface_t * interface, const struct facelet_s * facelet); #endif /* FACEMGR_INTERFACE_H */ diff --git a/ctrl/facemgr/src/interface_map.c b/ctrl/facemgr/src/interface_map.c deleted file mode 100644 index 9f7c20cab..000000000 --- a/ctrl/facemgr/src/interface_map.c +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "interface_map.h" - -#include <string.h> -#include "interface.h" - -TYPEDEF_MAP(interface_map, const char *, interface_t *, strcmp, string_snprintf, generic_snprintf); diff --git a/ctrl/facemgr/src/interface_ops_map.c b/ctrl/facemgr/src/interface_ops_map.c deleted file mode 100644 index 373f5d22f..000000000 --- a/ctrl/facemgr/src/interface_ops_map.c +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "interface_ops_map.h" - -#include <string.h> -#include "util/map.h" - -TYPEDEF_MAP(interface_ops_map, const char *, interface_ops_t *, strcmp, string_snprintf, generic_snprintf); diff --git a/ctrl/facemgr/src/interfaces/CMakeLists.txt b/ctrl/facemgr/src/interfaces/CMakeLists.txt index e5a26177a..8d079612a 100644 --- a/ctrl/facemgr/src/interfaces/CMakeLists.txt +++ b/ctrl/facemgr/src/interfaces/CMakeLists.txt @@ -24,12 +24,21 @@ endif() if(LINUX) add_subdirectory(netlink) +add_subdirectory(bonjour) endif() -if(false) +if(ANDROID) +add_subdirectory(android_utility) +endif() + +if(WITH_EXAMPLE_DUMMY) add_subdirectory(dummy) endif() +if(WITH_EXAMPLE_UPDOWN) +add_subdirectory(updown) +endif() + set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE) set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE) set(INCLUDE_DIRS ${INCLUDE_DIRS} PARENT_SCOPE) diff --git a/ctrl/facemgr/src/interfaces/android_utility/CMakeLists.txt b/ctrl/facemgr/src/interfaces/android_utility/CMakeLists.txt new file mode 100644 index 000000000..0ebe87745 --- /dev/null +++ b/ctrl/facemgr/src/interfaces/android_utility/CMakeLists.txt @@ -0,0 +1,27 @@ +# Copyright (c) 2017-2019 Cisco and/or its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +list(APPEND SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/android_utility.c +) + +list(APPEND INCLUDE_DIRS +) + +list(APPEND LIBRARIES +) + +set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE) +set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE) +set(INCLUDE_DIRS ${INCLUDE_DIRS} PARENT_SCOPE) +set(LIBRARIES ${LIBRARIES} PARENT_SCOPE) diff --git a/ctrl/facemgr/src/interfaces/android_utility/android_utility.c b/ctrl/facemgr/src/interfaces/android_utility/android_utility.c new file mode 100644 index 000000000..bb612507f --- /dev/null +++ b/ctrl/facemgr/src/interfaces/android_utility/android_utility.c @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file interfaces/android_utility/android_utility.c + * \brief Implementation of Android utility. + */ + +#include <assert.h> + +#include <hicn/facemgr.h> +#include <hicn/ctrl/face.h> +#include <hicn/util/log.h> +#include "../../common.h" +#include "../../facelet.h" +#include "../../interface.h" +#include <hicn/android_utility/android_utility.h> + +#define FACEMGR_ANDROID_UTILITY_CLASS "com/cisco/hicn/forwarder/supportlibrary/AndroidUtility" + +#define AU_INTERFACE_TYPE_UNDEFINED 0 +#define AU_INTERFACE_TYPE_WIRED 1 +#define AU_INTERFACE_TYPE_WIFI 2 +#define AU_INTERFACE_TYPE_CELLULAR 3 +#define AU_INTERFACE_TYPE_LOOPBACK 4 /* not supported yet */ + +#define ERR_STR_JAVA "Java VM parameters are required in the interface configuration." + +typedef struct { + android_utility_cfg_t cfg; +} au_data_t; + +int au_initialize(interface_t * interface, void * cfg) +{ + au_data_t * data = malloc(sizeof(au_data_t)); + if (!data) + return -1; + interface->data = data; + + if (!cfg) + goto ERR_CFG; + + data->cfg = * (android_utility_cfg_t *) cfg; + + if (!data->cfg.jvm) + goto ERR_CFG; + + return 0; + +ERR_CFG: + fprintf(stderr, ERR_STR_JAVA); + return -1; +} + +int au_finalize(interface_t * interface) +{ + /* Nothing to do */ + return 0; +} + +int au_on_event(interface_t * interface, const facelet_t * facelet) +{ + /* + * This function is responsible to annotate every face we receive with the + * correct interface type, based on the value returned by the Android + * utility shipped with the Android forwarder. + */ + DEBUG("Android utility received request"); + au_data_t * data = (au_data_t*)interface->data; + + netdevice_t netdevice = NETDEVICE_EMPTY; + int rc = facelet_get_netdevice(facelet, &netdevice); + if (rc < 0) + return -1; + DEBUG("[au_on_event] netdevice=%s", netdevice.name); + + JNIEnv *env; + JavaVM *jvm = data->cfg.jvm; + (*jvm)->AttachCurrentThread(jvm, &env, NULL); + jclass cls = (*env)->FindClass(env, FACEMGR_ANDROID_UTILITY_CLASS); + jmethodID getNetworkType = (*env)->GetStaticMethodID(env, cls, + "getNetworkType", "(Ljava/lang/String;)I"); + jint interface_type = (*env)->CallStaticIntMethod(env, cls, getNetworkType, + (*env)->NewStringUTF(env, netdevice.name)); + + DEBUG("Processing results for interface %s", netdevice.name); + + netdevice_type_t netdevice_type = AU_INTERFACE_TYPE_UNDEFINED; + switch(interface_type) { + case AU_INTERFACE_TYPE_UNDEFINED: + break; + case AU_INTERFACE_TYPE_WIRED: + netdevice_type = NETDEVICE_TYPE_WIRED; + break; + case AU_INTERFACE_TYPE_WIFI: + netdevice_type = NETDEVICE_TYPE_WIFI; + break; + case AU_INTERFACE_TYPE_CELLULAR: + netdevice_type = NETDEVICE_TYPE_CELLULAR; + break; + case AU_INTERFACE_TYPE_LOOPBACK: + netdevice_type = NETDEVICE_TYPE_LOOPBACK; + break; + default: + return -1; + } + + facelet_t * facelet_new = facelet_create(); + facelet_set_netdevice(facelet_new, netdevice); + facelet_set_status(facelet_new, FACELET_STATUS_CLEAN); + facelet_set_netdevice_type(facelet_new, netdevice_type); + + DEBUG("sending AU udpate"); + facelet_set_event(facelet_new, FACELET_EVENT_UPDATE); + facelet_raise_event(facelet_new, interface); + + return 0; +} + +const interface_ops_t android_utility_ops = { + .type = "android_utility", + .initialize = au_initialize, + .finalize = au_finalize, + .callback = NULL, + .on_event = au_on_event, +}; diff --git a/ctrl/facemgr/src/interfaces/bonjour/CMakeLists.txt b/ctrl/facemgr/src/interfaces/bonjour/CMakeLists.txt new file mode 100644 index 000000000..8a0ddc888 --- /dev/null +++ b/ctrl/facemgr/src/interfaces/bonjour/CMakeLists.txt @@ -0,0 +1,32 @@ +# Copyright (c) 2017-2019 Cisco and/or its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +list(APPEND HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/bonjour.h + ${CMAKE_CURRENT_SOURCE_DIR}/mdns/mdns.h +) + +list(APPEND SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/bonjour.c +) + +list(APPEND LIBRARIES +) + +list(APPEND INCLUDE_DIRS +) + +set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE) +set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE) +set(INCLUDE_DIRS ${INCLUDE_DIRS} PARENT_SCOPE) +set(LIBRARIES ${LIBRARIES} PARENT_SCOPE) diff --git a/ctrl/facemgr/src/interfaces/bonjour/bonjour.c b/ctrl/facemgr/src/interfaces/bonjour/bonjour.c new file mode 100644 index 000000000..d7b27b995 --- /dev/null +++ b/ctrl/facemgr/src/interfaces/bonjour/bonjour.c @@ -0,0 +1,408 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file interfaces/bonjour/bonjour.c + * \brief Implementation of Bonjour interface + * + * TODO: + * - concurrent queries + * - interface binding + */ + +#include <hicn/facemgr.h> +#include <hicn/util/log.h> + +#include "../../common.h" +#include "../../facelet.h" +#include "../../interface.h" +#include "../../util/map.h" +#include "mdns/mdns.h" + +#include "bonjour.h" + +#define DEFAULT_BUFFER_SIZE 2048 +#define SERVICE_STRING_SIZE 256 + +#define DEFAULT_SERVICE_NAME "hicn" +#define DEFAULT_SERVICE_PROTOCOL "udp" +#define DEFAULT_SERVICE_DOMAIN "local" + +typedef struct { + bonjour_cfg_t cfg; + int sock; + size_t buffer_size; + void* buffer; + + /* The face being resolved, non-NULL values indicate interface is busy... */ + face_t * face; +} bj_data_t; + +int bj_initialize(interface_t * interface, void * cfg) +{ + bj_data_t * data = malloc(sizeof(bj_data_t)); + if (!data) + goto ERR_MALLOC; + interface->data = data; + + if (cfg) { +#ifndef __linux__ + if (cfg->netdevice) + WARN("Binding to interface is (currently) only supported on Linux"); +#endif /* ! __linux__ */ + data->cfg = * (bonjour_cfg_t *) cfg; + } else { + memset(&data->cfg, 0, sizeof(bonjour_cfg_t)); + } + + if (!data->cfg.service_name) + data->cfg.service_name = DEFAULT_SERVICE_NAME; + + if (!data->cfg.service_protocol) + data->cfg.service_protocol = DEFAULT_SERVICE_PROTOCOL; + + if (!data->cfg.service_domain) + data->cfg.service_domain = DEFAULT_SERVICE_DOMAIN; + + data->sock = mdns_socket_open_ipv4(); + if (data->sock < 0) { + printf("Failed to open socket: %s\n", strerror(errno)); + goto ERR_SOCK; + } + + /* Netdevice configuration */ +#ifdef __linux__ +#ifndef __ANDROID__ + if (IS_VALID_NETDEVICE(data->cfg.netdevice)) { + int rc = setsockopt(data->sock, SOL_SOCKET, SO_BINDTODEVICE, + &data->cfg.netdevice.name, strlen(data->cfg.netdevice.name) + 1); + if (rc == -1) { + ERROR("setsockopt"); + goto ERR_SOCK_OPT; + } + } +#endif +#endif /* __linux__ */ + + data->buffer_size = DEFAULT_BUFFER_SIZE; + data->buffer = malloc(data->buffer_size); + if (!data->buffer) + goto ERR_BUFFER; + +#ifdef _WIN32 + WORD versionWanted = MAKEWORD(1, 1); + WSADATA wsaData; + WSAStartup(versionWanted, &wsaData); +#endif + + return data->sock; + +ERR_BUFFER: +#ifndef __ANDROID__ +ERR_SOCK_OPT: +#endif + mdns_socket_close(data->sock); +#ifdef _WIN32 + WSACleanup(); +#endif +ERR_SOCK: + free(data); +ERR_MALLOC: + return -1; +} + +/* + * We reuse the callback to be triggered upon external events + * TODO: move to a cleaner interface architecture later... + */ +int bj_on_event(interface_t * interface, const facelet_t * facelet) +{ + bj_data_t * data = (bj_data_t*)interface->data; + + /* + printf("Sending DNS-SD discovery\n"); + if (mdns_discovery_send(sock)) { + printf("Failed to send DNS-DS discovery: %s\n", strerror(errno)); + goto quit; + } + + printf("Reading DNS-SD replies\n"); + for (int i = 0; i < 10; ++i) { + records = mdns_discovery_recv(sock, buffer, capacity, callback, + user_data); + sleep(1); + } + */ + + DEBUG("Sending mDNS query"); + char service_string[SERVICE_STRING_SIZE]; + + int rc = snprintf(service_string, SERVICE_STRING_SIZE, "_%s._%s.%s.", + data->cfg.service_name, data->cfg.service_protocol, + data->cfg.service_domain); + if (rc < 0) + ; // error + else if (rc >= SERVICE_STRING_SIZE) + ; //truncated + + if (mdns_query_send(data->sock, MDNS_RECORDTYPE_PTR, + service_string, + strlen(service_string), + data->buffer, data->buffer_size)) { + printf("Failed to send mDNS query: %s\n", strerror(errno)); + return -1; + } + return 0; +} + +static char addrbuffer[64]; +static char namebuffer[256]; +static mdns_record_txt_t txtbuffer[128]; + +static mdns_string_t +ipv4_address_to_string(char* buffer, size_t capacity, const struct sockaddr_in* addr) { + char host[NI_MAXHOST] = {0}; + char service[NI_MAXSERV] = {0}; + int ret = getnameinfo((const struct sockaddr*)addr, sizeof(struct sockaddr_in), + host, NI_MAXHOST, service, NI_MAXSERV, + NI_NUMERICSERV | NI_NUMERICHOST); + int len = 0; + if (ret == 0) { + if (addr->sin_port != 0) + len = snprintf(buffer, capacity, "%s:%s", host, service); + else + len = snprintf(buffer, capacity, "%s", host); + } + if (len >= (int)capacity) + len = (int)capacity - 1; + mdns_string_t str = {buffer, len}; + return str; +} + +static mdns_string_t +ipv6_address_to_string(char* buffer, size_t capacity, const struct sockaddr_in6* addr) { + char host[NI_MAXHOST] = {0}; + char service[NI_MAXSERV] = {0}; + int ret = getnameinfo((const struct sockaddr*)addr, sizeof(struct sockaddr_in6), + host, NI_MAXHOST, service, NI_MAXSERV, + NI_NUMERICSERV | NI_NUMERICHOST); + int len = 0; + if (ret == 0) { + if (addr->sin6_port != 0) + len = snprintf(buffer, capacity, "[%s]:%s", host, service); + else + len = snprintf(buffer, capacity, "%s", host); + } + if (len >= (int)capacity) + len = (int)capacity - 1; + mdns_string_t str = {buffer, len}; + return str; +} + +static mdns_string_t +ip_address_to_string(char* buffer, size_t capacity, const struct sockaddr* addr) { + if (addr->sa_family == AF_INET6) + return ipv6_address_to_string(buffer, capacity, (const struct sockaddr_in6*)addr); + return ipv4_address_to_string(buffer, capacity, (const struct sockaddr_in*)addr); +} + +int +ip_address_set_sockaddr(ip_address_t * ip_address, struct sockaddr * sa) +{ + switch(sa->sa_family) { + case AF_INET: + ip_address->v4.as_inaddr = ((struct sockaddr_in *)sa)->sin_addr; + break; + case AF_INET6: + ip_address->v6.as_in6addr = ((struct sockaddr_in6 *)sa)->sin6_addr; + break; + default: + return -1; + } + + return 0; +} + +static int +callback(const struct sockaddr* from, mdns_entry_type_t entry, uint16_t type, + uint16_t rclass, uint32_t ttl, const void* data, size_t size, size_t + offset, size_t length, void* user_data) +{ + interface_t * interface = (interface_t*)user_data; + bj_data_t * bj_data = (bj_data_t *)interface->data; + + struct sockaddr_storage addr; + + mdns_string_t fromaddrstr = ip_address_to_string(addrbuffer, sizeof(addrbuffer), from); + const char* entrytype = (entry == MDNS_ENTRYTYPE_ANSWER) ? "answer" : + ((entry == MDNS_ENTRYTYPE_AUTHORITY) ? "authority" : "additional"); + + switch(type) { + case MDNS_RECORDTYPE_A: + { + ip_address_t ip_address; + mdns_record_parse_a(data, size, offset, length, (struct sockaddr_in*)&addr); + ip_address_set_sockaddr(&ip_address, (struct sockaddr *)&addr); + + mdns_string_t addrstr = ipv4_address_to_string(namebuffer, sizeof(namebuffer), (struct sockaddr_in *)&addr); + DEBUG("%.*s : %s A %.*s", + MDNS_STRING_FORMAT(fromaddrstr), entrytype, + MDNS_STRING_FORMAT(addrstr)); + + facelet_t * facelet = facelet_create(); + facelet_set_netdevice(facelet, bj_data->cfg.netdevice); + facelet_set_family(facelet, AF_INET); + facelet_set_remote_addr(facelet, ip_address); + //facelet_set_remote_port(facelet, ((struct sockaddr_in*)&addr)->sin_port); + + facelet_set_event(facelet, FACELET_EVENT_UPDATE); + facelet_raise_event(facelet, interface); + break; + } + + case MDNS_RECORDTYPE_AAAA: + { + ip_address_t ip_address; + mdns_record_parse_aaaa(data, size, offset, length, (struct sockaddr_in6*)&addr); + ip_address_set_sockaddr(&ip_address, (struct sockaddr *)&addr); + + mdns_string_t addrstr = ipv6_address_to_string(namebuffer, + sizeof(namebuffer), (struct sockaddr_in6*)&addr); + DEBUG("%.*s : %s AAAA %.*s", + MDNS_STRING_FORMAT(fromaddrstr), entrytype, + MDNS_STRING_FORMAT(addrstr)); + + facelet_t * facelet = facelet_create(); + facelet_set_netdevice(facelet, bj_data->cfg.netdevice); + facelet_set_family(facelet, AF_INET6); + facelet_set_remote_addr(facelet, ip_address); + //facelet_set_remote_port(facelet, ((struct sockaddr_in6*)&addr)->sin6_port); + + facelet_set_event(facelet, FACELET_EVENT_UPDATE); + facelet_raise_event(facelet, interface); + break; + } + + case MDNS_RECORDTYPE_SRV: /* same port for both v4 and v6 */ + { + mdns_record_srv_t srv = mdns_record_parse_srv(data, size, offset, length, + namebuffer, sizeof(namebuffer)); + + DEBUG("%.*s : %s SRV %.*s priority %d weight %d port %d", + MDNS_STRING_FORMAT(fromaddrstr), entrytype, + MDNS_STRING_FORMAT(srv.name), srv.priority, srv.weight, srv.port); + + /* We raise both v4 and v6 + * + * Unless we choose whether we query A and/or AAAA, this might leave + * us with an unused pending facelet, eg. we might not have an IPv6 + * but we raise an IPv6 bonjour event... + */ + + facelet_t * facelet = facelet_create(); + facelet_set_netdevice(facelet, bj_data->cfg.netdevice); + facelet_set_family(facelet, AF_INET); + facelet_set_remote_port(facelet, srv.port); + + facelet_set_event(facelet, FACELET_EVENT_UPDATE); + facelet_raise_event(facelet, interface); + + facelet = facelet_create(); + facelet_set_netdevice(facelet, bj_data->cfg.netdevice); + facelet_set_family(facelet, AF_INET6); + facelet_set_remote_port(facelet, srv.port); + + facelet_set_event(facelet, FACELET_EVENT_UPDATE); + facelet_raise_event(facelet, interface); + break; + } + + case MDNS_RECORDTYPE_PTR: + { + mdns_string_t namestr = mdns_record_parse_ptr(data, size, offset, length, + namebuffer, sizeof(namebuffer)); + DEBUG("%.*s : %s PTR %.*s type %u rclass 0x%x ttl %u length %d", + MDNS_STRING_FORMAT(fromaddrstr), entrytype, + MDNS_STRING_FORMAT(namestr), type, rclass, ttl, (int)length); + break; + } + + case MDNS_RECORDTYPE_TXT: + { + size_t parsed = mdns_record_parse_txt(data, size, offset, length, + txtbuffer, sizeof(txtbuffer) / sizeof(mdns_record_txt_t)); + for (size_t itxt = 0; itxt < parsed; ++itxt) { + if (txtbuffer[itxt].value.length) { + DEBUG("%.*s : %s TXT %.*s = %.*s", + MDNS_STRING_FORMAT(fromaddrstr), entrytype, + MDNS_STRING_FORMAT(txtbuffer[itxt].key), + MDNS_STRING_FORMAT(txtbuffer[itxt].value)); + } + else { + DEBUG("%.*s : %s TXT %.*s", + MDNS_STRING_FORMAT(fromaddrstr), entrytype, + MDNS_STRING_FORMAT(txtbuffer[itxt].key)); + } + } + break; + } + + default: + /* Silently ignore the received record */ + DEBUG("%.*s : %s type %u rclass 0x%x ttl %u length %d", + MDNS_STRING_FORMAT(fromaddrstr), entrytype, + type, rclass, ttl, (int)length); + return 0; + } + return 0; + +} + +/* + * The fact we use a single fd does not allow us to get user_data associated to + * the query. + */ +int bj_callback(interface_t * interface) +{ + bj_data_t * data = (bj_data_t*)interface->data; + DEBUG("Got an mDNS reply"); + /* size_t records = */ mdns_query_recv(data->sock, data->buffer, data->buffer_size, callback, interface, 1); + + return 0; +} + +int bj_finalize(interface_t * interface) +{ + bj_data_t * data = (bj_data_t*)interface->data; + + free(data->buffer); + mdns_socket_close(data->sock); + +#ifdef _WIN32 + WSACleanup(); +#endif + + return 0; + +} + +const interface_ops_t bonjour_ops = { + .type = "bonjour", + .initialize = bj_initialize, + .on_event = bj_on_event, + .callback = bj_callback, + .finalize = bj_finalize, + // .on_event = NULL, +}; diff --git a/ctrl/facemgr/src/face_rules.h b/ctrl/facemgr/src/interfaces/bonjour/bonjour.h index 28f5391a0..fe053079d 100644 --- a/ctrl/facemgr/src/face_rules.h +++ b/ctrl/facemgr/src/interfaces/bonjour/bonjour.h @@ -13,19 +13,23 @@ * limitations under the License. */ -#ifndef FACE_RULES_H -#define FACE_RULES_H - -#include "util/map.h" -#include "util/policy.h" - -/* - * Face creation rules +/** + * \file interfaces/bonjour/bonjour.h + * \brief Bonjour interface * - * For now, face creations rules are very simple and consist in a map between - * the physical interface name, and the associated list of tags that will - * preempt those assigned by the system. + * NOTES: + * - shall we support multiple service names, or instanciate multiple instances + * of the interface ? + * - interface list ? + * - ideally we should register here events that will trigger bonjour + * queries... */ -TYPEDEF_MAP_H(face_rules, const char *, policy_tags_t); -#endif /* FACE_RULES_H */ +#include <hicn/ctrl/face.h> /* netdevice_t */ + +typedef struct { + netdevice_t netdevice; + char * service_name; + char * service_protocol; + char * service_domain; +} bonjour_cfg_t; diff --git a/ctrl/facemgr/src/interfaces/bonjour/mdns/LICENSE b/ctrl/facemgr/src/interfaces/bonjour/mdns/LICENSE new file mode 100644 index 000000000..cf1ab25da --- /dev/null +++ b/ctrl/facemgr/src/interfaces/bonjour/mdns/LICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to <http://unlicense.org> diff --git a/ctrl/facemgr/src/interfaces/bonjour/mdns/README.md b/ctrl/facemgr/src/interfaces/bonjour/mdns/README.md new file mode 100644 index 000000000..1bee49c08 --- /dev/null +++ b/ctrl/facemgr/src/interfaces/bonjour/mdns/README.md @@ -0,0 +1,9 @@ +# Public domain mDNS/DNS-SD library in C + +This library provides a cross-platform mDNS and DNS-DS library in C. The latest source code is always available at + +https://github.com/mjansson/mdns + +This library is put in the public domain; you can redistribute it and/or modify it without any restrictions. + +Created by Mattias Jansson ([@maniccoder](https://twitter.com/maniccoder)) diff --git a/ctrl/facemgr/src/interfaces/bonjour/mdns/mdns.c b/ctrl/facemgr/src/interfaces/bonjour/mdns/mdns.c new file mode 100644 index 000000000..a8e97e8e0 --- /dev/null +++ b/ctrl/facemgr/src/interfaces/bonjour/mdns/mdns.c @@ -0,0 +1,192 @@ + +#ifdef _WIN32 +# define _CRT_SECURE_NO_WARNINGS 1 +#endif + +#include "mdns.h" + +#include <stdio.h> +#include <errno.h> + +#ifdef _WIN32 +# define sleep(x) Sleep(x * 1000) +#else +# include <netdb.h> +#endif + +static char addrbuffer[64]; +static char namebuffer[256]; +static mdns_record_txt_t txtbuffer[128]; + +static mdns_string_t +ipv4_address_to_string(char* buffer, size_t capacity, const struct sockaddr_in* addr) { + char host[NI_MAXHOST] = {0}; + char service[NI_MAXSERV] = {0}; + int ret = getnameinfo((const struct sockaddr*)addr, sizeof(struct sockaddr_in), + host, NI_MAXHOST, service, NI_MAXSERV, + NI_NUMERICSERV | NI_NUMERICHOST); + int len = 0; + if (ret == 0) { + if (addr->sin_port != 0) + len = snprintf(buffer, capacity, "%s:%s", host, service); + else + len = snprintf(buffer, capacity, "%s", host); + } + if (len >= (int)capacity) + len = (int)capacity - 1; + mdns_string_t str = {buffer, len}; + return str; +} + +static mdns_string_t +ipv6_address_to_string(char* buffer, size_t capacity, const struct sockaddr_in6* addr) { + char host[NI_MAXHOST] = {0}; + char service[NI_MAXSERV] = {0}; + int ret = getnameinfo((const struct sockaddr*)addr, sizeof(struct sockaddr_in6), + host, NI_MAXHOST, service, NI_MAXSERV, + NI_NUMERICSERV | NI_NUMERICHOST); + int len = 0; + if (ret == 0) { + if (addr->sin6_port != 0) + len = snprintf(buffer, capacity, "[%s]:%s", host, service); + else + len = snprintf(buffer, capacity, "%s", host); + } + if (len >= (int)capacity) + len = (int)capacity - 1; + mdns_string_t str = {buffer, len}; + return str; +} + +static mdns_string_t +ip_address_to_string(char* buffer, size_t capacity, const struct sockaddr* addr) { + if (addr->sa_family == AF_INET6) + return ipv6_address_to_string(buffer, capacity, (const struct sockaddr_in6*)addr); + return ipv4_address_to_string(buffer, capacity, (const struct sockaddr_in*)addr); +} + +static int +callback(const struct sockaddr* from, + mdns_entry_type_t entry, uint16_t type, + uint16_t rclass, uint32_t ttl, + const void* data, size_t size, size_t offset, size_t length, + void* user_data) { + mdns_string_t fromaddrstr = ip_address_to_string(addrbuffer, sizeof(addrbuffer), from); + const char* entrytype = (entry == MDNS_ENTRYTYPE_ANSWER) ? "answer" : + ((entry == MDNS_ENTRYTYPE_AUTHORITY) ? "authority" : "additional"); + if (type == MDNS_RECORDTYPE_PTR) { + mdns_string_t namestr = mdns_record_parse_ptr(data, size, offset, length, + namebuffer, sizeof(namebuffer)); + INFO("%.*s : %s PTR %.*s type %u rclass 0x%x ttl %u length %d\n", + MDNS_STRING_FORMAT(fromaddrstr), entrytype, + MDNS_STRING_FORMAT(namestr), type, rclass, ttl, (int)length); + } + else if (type == MDNS_RECORDTYPE_SRV) { + mdns_record_srv_t srv = mdns_record_parse_srv(data, size, offset, length, + namebuffer, sizeof(namebuffer)); + INFO("%.*s : %s SRV %.*s priority %d weight %d port %d\n", + MDNS_STRING_FORMAT(fromaddrstr), entrytype, + MDNS_STRING_FORMAT(srv.name), srv.priority, srv.weight, srv.port); + } + else if (type == MDNS_RECORDTYPE_A) { + struct sockaddr_in addr; + mdns_record_parse_a(data, size, offset, length, &addr); + mdns_string_t addrstr = ipv4_address_to_string(namebuffer, sizeof(namebuffer), &addr); + INFO("%.*s : %s A %.*s\n", + MDNS_STRING_FORMAT(fromaddrstr), entrytype, + MDNS_STRING_FORMAT(addrstr)); + } + else if (type == MDNS_RECORDTYPE_AAAA) { + struct sockaddr_in6 addr; + mdns_record_parse_aaaa(data, size, offset, length, &addr); + mdns_string_t addrstr = ipv6_address_to_string(namebuffer, sizeof(namebuffer), &addr); + INFO("%.*s : %s AAAA %.*s\n", + MDNS_STRING_FORMAT(fromaddrstr), entrytype, + MDNS_STRING_FORMAT(addrstr)); + } + else if (type == MDNS_RECORDTYPE_TXT) { + size_t parsed = mdns_record_parse_txt(data, size, offset, length, + txtbuffer, sizeof(txtbuffer) / sizeof(mdns_record_txt_t)); + for (size_t itxt = 0; itxt < parsed; ++itxt) { + if (txtbuffer[itxt].value.length) { + INFO("%.*s : %s TXT %.*s = %.*s\n", + MDNS_STRING_FORMAT(fromaddrstr), entrytype, + MDNS_STRING_FORMAT(txtbuffer[itxt].key), + MDNS_STRING_FORMAT(txtbuffer[itxt].value)); + } + else { + INFO("%.*s : %s TXT %.*s\n", + MDNS_STRING_FORMAT(fromaddrstr), entrytype, + MDNS_STRING_FORMAT(txtbuffer[itxt].key)); + } + } + } + else { + INFO("%.*s : %s type %u rclass 0x%x ttl %u length %d\n", + MDNS_STRING_FORMAT(fromaddrstr), entrytype, + type, rclass, ttl, (int)length); + } + return 0; +} + +int +main() { + size_t capacity = 2048; + void* buffer = 0; + void* user_data = 0; + size_t records; + +#ifdef _WIN32 + WORD versionWanted = MAKEWORD(1, 1); + WSADATA wsaData; + WSAStartup(versionWanted, &wsaData); +#endif + + int sock = mdns_socket_open_ipv4(); + if (sock < 0) { + INFO("Failed to open socket: %s\n", strerror(errno)); + return -1; + } + INFO("Opened IPv4 socket for mDNS/DNS-SD\n"); + buffer = malloc(capacity); +/* + INFO("Sending DNS-SD discovery\n"); + if (mdns_discovery_send(sock)) { + INFO("Failed to send DNS-DS discovery: %s\n", strerror(errno)); + goto quit; + } + + INFO("Reading DNS-SD replies\n"); + for (int i = 0; i < 10; ++i) { + records = mdns_discovery_recv(sock, buffer, capacity, callback, + user_data); + sleep(1); + } + */ + + INFO("Sending mDNS query\n"); + if (mdns_query_send(sock, MDNS_RECORDTYPE_PTR, + MDNS_STRING_CONST("_hicn._udp.local."), + buffer, capacity)) { + INFO("Failed to send mDNS query: %s\n", strerror(errno)); + goto quit; + } + + INFO("Reading mDNS replies\n"); + for (int i = 0; i < 10; ++i) { + records = mdns_query_recv(sock, buffer, capacity, callback, user_data, 1); + sleep(1); + } + +quit: + free(buffer); + + mdns_socket_close(sock); + INFO("Closed socket\n"); + +#ifdef _WIN32 + WSACleanup(); +#endif + + return 0; +} diff --git a/ctrl/facemgr/src/interfaces/bonjour/mdns/mdns.h b/ctrl/facemgr/src/interfaces/bonjour/mdns/mdns.h new file mode 100644 index 000000000..ff04b5d72 --- /dev/null +++ b/ctrl/facemgr/src/interfaces/bonjour/mdns/mdns.h @@ -0,0 +1,879 @@ +/* mdns.h - mDNS/DNS-SD library - Public Domain - 2017 Mattias Jansson + * + * This library provides a cross-platform mDNS and DNS-SD library in C. + * The implementation is based on RFC 6762 and RFC 6763. + * + * The latest source code is always available at + * + * https://github.com/mjansson/mdns + * + * This library is put in the public domain; you can redistribute it and/or modify it without any restrictions. + * + */ + +#pragma once + +#include <stdint.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + +#include <fcntl.h> +#ifdef _WIN32 +#include <Winsock2.h> +#include <Ws2tcpip.h> +#define strncasecmp _strnicmp +#else +#include <unistd.h> +#include <sys/socket.h> +#include <netinet/in.h> +#endif + +#define MDNS_INVALID_POS ((size_t)-1) + +#define MDNS_STRING_CONST(s) (s), (sizeof((s))-1) +#define MDNS_STRING_FORMAT(s) (int)((s).length), s.str + +enum mdns_record_type { + MDNS_RECORDTYPE_IGNORE = 0, + //Address + MDNS_RECORDTYPE_A = 1, + //Domain Name pointer + MDNS_RECORDTYPE_PTR = 12, + //Arbitrary text string + MDNS_RECORDTYPE_TXT = 16, + //IP6 Address [Thomson] + MDNS_RECORDTYPE_AAAA = 28, + //Server Selection [RFC2782] + MDNS_RECORDTYPE_SRV = 33 +}; + +enum mdns_entry_type { + MDNS_ENTRYTYPE_ANSWER = 1, + MDNS_ENTRYTYPE_AUTHORITY = 2, + MDNS_ENTRYTYPE_ADDITIONAL = 3 +}; + +enum mdns_class { + MDNS_CLASS_IN = 1 +}; + +typedef enum mdns_record_type mdns_record_type_t; +typedef enum mdns_entry_type mdns_entry_type_t; +typedef enum mdns_class mdns_class_t; + +typedef int (* mdns_record_callback_fn)(const struct sockaddr* from, + mdns_entry_type_t entry, uint16_t type, + uint16_t rclass, uint32_t ttl, + const void* data, size_t size, size_t offset, size_t length, + void* user_data); + +typedef struct mdns_string_t mdns_string_t; +typedef struct mdns_string_pair_t mdns_string_pair_t; +typedef struct mdns_record_srv_t mdns_record_srv_t; +typedef struct mdns_record_txt_t mdns_record_txt_t; + +struct mdns_string_t { + const char* str; + size_t length; +}; + +struct mdns_string_pair_t { + size_t offset; + size_t length; + int ref; +}; + +struct mdns_record_srv_t { + uint16_t priority; + uint16_t weight; + uint16_t port; + mdns_string_t name; +}; + +struct mdns_record_txt_t { + mdns_string_t key; + mdns_string_t value; +}; + +static int +mdns_socket_open_ipv4(void); + +static int +mdns_socket_setup_ipv4(int sock); + +#if 0 +static int +mdns_socket_open_ipv6(void); + + + +static int +mdns_socket_setup_ipv6(int sock); +#endif + +static void +mdns_socket_close(int sock); + +#if 0 +static int +mdns_discovery_send(int sock); + + +static size_t +mdns_discovery_recv(int sock, void* buffer, size_t capacity, + mdns_record_callback_fn callback, void* user_data); +#endif + +static int +mdns_query_send(int sock, mdns_record_type_t type, const char* name, size_t length, + void* buffer, size_t capacity); + +static size_t +mdns_query_recv(int sock, void* buffer, size_t capacity, + mdns_record_callback_fn callback, void* user_data, + uint8_t one_shot); + +static mdns_string_t +mdns_string_extract(const void* buffer, size_t size, size_t* offset, + char* str, size_t capacity); + +static int +mdns_string_skip(const void* buffer, size_t size, size_t* offset); + +#if 0 +static int +mdns_string_equal(const void* buffer_lhs, size_t size_lhs, size_t* ofs_lhs, + const void* buffer_rhs, size_t size_rhs, size_t* ofs_rhs); +#endif + +static void* +mdns_string_make(void* data, size_t capacity, const char* name, size_t length); + +static mdns_string_t +mdns_record_parse_ptr(const void* buffer, size_t size, size_t offset, size_t length, + char* strbuffer, size_t capacity); + +static mdns_record_srv_t +mdns_record_parse_srv(const void* buffer, size_t size, size_t offset, size_t length, + char* strbuffer, size_t capacity); + +static struct sockaddr_in* +mdns_record_parse_a(const void* buffer, size_t size, size_t offset, size_t length, + struct sockaddr_in* addr); + +static struct sockaddr_in6* +mdns_record_parse_aaaa(const void* buffer, size_t size, size_t offset, size_t length, + struct sockaddr_in6* addr); + +static size_t +mdns_record_parse_txt(const void* buffer, size_t size, size_t offset, size_t length, + mdns_record_txt_t* records, size_t capacity); + +// Implementations + +static int +mdns_socket_open_ipv4(void) { + int sock = (int)socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (sock < 0) + return -1; + if (mdns_socket_setup_ipv4(sock)) { + mdns_socket_close(sock); + return -1; + } + return sock; +} + +static int +mdns_socket_setup_ipv4(int sock) { + struct sockaddr_in saddr; + memset(&saddr, 0, sizeof(saddr)); + saddr.sin_family = AF_INET; + saddr.sin_addr.s_addr = INADDR_ANY; +#ifdef __APPLE__ + saddr.sin_len = sizeof(saddr); +#endif + + if (bind(sock, (struct sockaddr*)&saddr, sizeof(saddr))) + return -1; + +#ifdef _WIN32 + unsigned long param = 1; + ioctlsocket(sock, FIONBIO, ¶m); +#else + const int flags = fcntl(sock, F_GETFL, 0); + fcntl(sock, F_SETFL, flags | O_NONBLOCK); +#endif + + unsigned char ttl = 1; + unsigned char loopback = 1; + struct ip_mreq req; + + setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, (const char*)&ttl, sizeof(ttl)); + setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP, (const char*)&loopback, sizeof(loopback)); + + memset(&req, 0, sizeof(req)); + req.imr_multiaddr.s_addr = htonl((((uint32_t)224U) << 24U) | ((uint32_t)251U)); + req.imr_interface.s_addr = INADDR_ANY; + if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&req, sizeof(req))) + return -1; + + return 0; +} + +#if 0 +static int +mdns_socket_open_ipv6(void) { + int sock = (int)socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); + if (sock < 0) + return -1; + if (mdns_socket_setup_ipv6(sock)) { + mdns_socket_close(sock); + return -1; + } + return sock; +} + + +static int +mdns_socket_setup_ipv6(int sock) { + struct sockaddr_in6 saddr; + memset(&saddr, 0, sizeof(saddr)); + saddr.sin6_family = AF_INET6; + saddr.sin6_addr = in6addr_any; +#ifdef __APPLE__ + saddr.sin6_len = sizeof(saddr); +#endif + + if (bind(sock, (struct sockaddr*)&saddr, sizeof(saddr))) + return -1; + +#ifdef _WIN32 + unsigned long param = 1; + ioctlsocket(sock, FIONBIO, ¶m); +#else + const int flags = fcntl(sock, F_GETFL, 0); + fcntl(sock, F_SETFL, flags | O_NONBLOCK); +#endif + + int hops = 1; + unsigned int loopback = 1; + struct ipv6_mreq req; + + setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (const char*)&hops, sizeof(hops)); + setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (const char*)&loopback, sizeof(loopback)); + + memset(&req, 0, sizeof(req)); + req.ipv6mr_multiaddr.s6_addr[0] = 0xFF; + req.ipv6mr_multiaddr.s6_addr[1] = 0x02; + req.ipv6mr_multiaddr.s6_addr[15] = 0xFB; + if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char*)&req, sizeof(req))) + return -1; + + return 0; +} +#endif + +static void +mdns_socket_close(int sock) { +#ifdef _WIN32 + closesocket(sock); +#else + close(sock); +#endif +} + +static int +mdns_is_string_ref(uint8_t val) { + return (0xC0 == (val & 0xC0)); +} + +static mdns_string_pair_t +mdns_get_next_substring(const void* rawdata, size_t size, size_t offset) { + const uint8_t* buffer = rawdata; + mdns_string_pair_t pair = {MDNS_INVALID_POS, 0, 0}; + if (!buffer[offset]) { + pair.offset = offset; + return pair; + } + if (mdns_is_string_ref(buffer[offset])) { + if (size < offset + 2) + return pair; + + offset = (((size_t)(0x3f & buffer[offset]) << 8) | (size_t)buffer[offset + 1]); + if (offset >= size) + return pair; + + pair.ref = 1; + } + + size_t length = (size_t)buffer[offset++]; + if (size < offset + length) + return pair; + + pair.offset = offset; + pair.length = length; + + return pair; +} + +static int +mdns_string_skip(const void* buffer, size_t size, size_t* offset) { + size_t cur = *offset; + mdns_string_pair_t substr; + do { + substr = mdns_get_next_substring(buffer, size, cur); + if (substr.offset == MDNS_INVALID_POS) + return 0; + if (substr.ref) { + *offset = cur + 2; + return 1; + } + cur = substr.offset + substr.length; + } + while (substr.length); + + *offset = cur + 1; + return 1; +} + +#if 0 +static int +mdns_string_equal(const void* buffer_lhs, size_t size_lhs, size_t* ofs_lhs, + const void* buffer_rhs, size_t size_rhs, size_t* ofs_rhs) { + size_t lhs_cur = *ofs_lhs; + size_t rhs_cur = *ofs_rhs; + size_t lhs_end = MDNS_INVALID_POS; + size_t rhs_end = MDNS_INVALID_POS; + mdns_string_pair_t lhs_substr; + mdns_string_pair_t rhs_substr; + do { + lhs_substr = mdns_get_next_substring(buffer_lhs, size_lhs, lhs_cur); + rhs_substr = mdns_get_next_substring(buffer_rhs, size_rhs, rhs_cur); + if ((lhs_substr.offset == MDNS_INVALID_POS) || (rhs_substr.offset == MDNS_INVALID_POS)) + return 0; + if (lhs_substr.length != rhs_substr.length) + return 0; + if (strncasecmp((const char*)buffer_rhs + rhs_substr.offset, + (const char*)buffer_lhs + lhs_substr.offset, rhs_substr.length)) + return 0; + if (lhs_substr.ref && (lhs_end == MDNS_INVALID_POS)) + lhs_end = lhs_cur + 2; + if (rhs_substr.ref && (rhs_end == MDNS_INVALID_POS)) + rhs_end = rhs_cur + 2; + lhs_cur = lhs_substr.offset + lhs_substr.length; + rhs_cur = rhs_substr.offset + rhs_substr.length; + } + while (lhs_substr.length); + + if (lhs_end == MDNS_INVALID_POS) + lhs_end = lhs_cur + 1; + *ofs_lhs = lhs_end; + + if (rhs_end == MDNS_INVALID_POS) + rhs_end = rhs_cur + 1; + *ofs_rhs = rhs_end; + + return 1; +} +#endif + +static mdns_string_t +mdns_string_extract(const void* buffer, size_t size, size_t* offset, + char* str, size_t capacity) { + size_t cur = *offset; + size_t end = MDNS_INVALID_POS; + mdns_string_pair_t substr; + mdns_string_t result = {str, 0}; + char* dst = str; + size_t remain = capacity; + do { + substr = mdns_get_next_substring(buffer, size, cur); + if (substr.offset == MDNS_INVALID_POS) + return result; + if (substr.ref && (end == MDNS_INVALID_POS)) + end = cur + 2; + if (substr.length) { + size_t to_copy = (substr.length < remain) ? substr.length : remain; + memcpy(dst, (const char*)buffer + substr.offset, to_copy); + dst += to_copy; + remain -= to_copy; + if (remain) { + *dst++ = '.'; + --remain; + } + } + cur = substr.offset + substr.length; + } + while (substr.length); + + if (end == MDNS_INVALID_POS) + end = cur + 1; + *offset = end; + + result.length = capacity - remain; + return result; +} + +static size_t +mdns_string_find(const char* str, size_t length, char c, size_t offset) { + const void* found; + if (offset >= length) + return MDNS_INVALID_POS; + found = memchr(str + offset, c, length - offset); + if (found) + return (size_t)((const char*)found - str); + return MDNS_INVALID_POS; +} + +static void* +mdns_string_make(void* data, size_t capacity, const char* name, size_t length) { + size_t pos = 0; + size_t last_pos = 0; + size_t remain = capacity; + unsigned char* dest = data; + while ((last_pos < length) && ((pos = mdns_string_find(name, length, '.', last_pos)) != MDNS_INVALID_POS)) { + size_t sublength = pos - last_pos; + if (sublength < remain) { + *dest = (unsigned char)sublength; + memcpy(dest + 1, name + last_pos, sublength); + dest += sublength + 1; + remain -= sublength + 1; + } + else { + return 0; + } + last_pos = pos + 1; + } + if (last_pos < length) { + size_t sublength = length - last_pos; + if (sublength < capacity) { + *dest = (unsigned char)sublength; + memcpy(dest + 1, name + last_pos, sublength); + dest += sublength + 1; + remain -= sublength + 1; + } + else { + return 0; + } + } + if (!remain) + return 0; + *dest++ = 0; + return dest; +} + +static size_t +mdns_records_parse(const struct sockaddr* from, const void* buffer, size_t size, size_t* offset, + mdns_entry_type_t type, size_t records, mdns_record_callback_fn callback, + void* user_data) { + size_t parsed = 0; + int do_callback = 1; + for (size_t i = 0; i < records; ++i) { + mdns_string_skip(buffer, size, offset); + const uint16_t* data = (const uint16_t*)((const char*)buffer + (*offset)); + + uint16_t rtype = ntohs(*data++); + uint16_t rclass = ntohs(*data++); + uint32_t ttl = ntohs(*(const uint32_t*)(const void*)data); data += 2; + uint16_t length = ntohs(*data++); + + *offset += 10; + + if (do_callback) { + ++parsed; + if (callback(from, type, rtype, rclass, ttl, buffer, size, *offset, length, + user_data)) + do_callback = 0; + } + + *offset += length; + } + return parsed; +} + +static const uint8_t mdns_services_query[] = { + // Transaction ID + 0x00, 0x00, + // Flags + 0x00, 0x00, + // 1 question + 0x00, 0x01, + // No answer, authority or additional RRs + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // _services._dns-sd._udp.local. + 0x09, '_', 's', 'e', 'r', 'v', 'i', 'c', 'e', 's', + 0x07, '_', 'd', 'n', 's', '-', 's', 'd', + 0x04, '_', 'u', 'd', 'p', + 0x05, 'l', 'o', 'c', 'a', 'l', + 0x00, + // PTR record + 0x00, MDNS_RECORDTYPE_PTR, + // QU (unicast response) and class IN + 0x80, MDNS_CLASS_IN +}; + +#if 0 +static int +mdns_discovery_send(int sock) { + struct sockaddr_storage addr_storage; + struct sockaddr_in addr; + struct sockaddr_in6 addr6; + struct sockaddr* saddr = (struct sockaddr*)&addr_storage; + socklen_t saddrlen = sizeof(struct sockaddr_storage); + if (getsockname(sock, saddr, &saddrlen)) + return -1; + if (saddr->sa_family == AF_INET6) { + memset(&addr6, 0, sizeof(struct sockaddr_in6)); + addr6.sin6_family = AF_INET6; +#ifdef __APPLE__ + addr6.sin6_len = sizeof(struct sockaddr_in6); +#endif + addr6.sin6_addr.s6_addr[0] = 0xFF; + addr6.sin6_addr.s6_addr[1] = 0x02; + addr6.sin6_addr.s6_addr[15] = 0xFB; + addr6.sin6_port = htons((unsigned short)5353); + saddr = (struct sockaddr*)&addr6; + saddrlen = sizeof(struct sockaddr_in6); + } + else { + memset(&addr, 0, sizeof(struct sockaddr_in)); + addr.sin_family = AF_INET; +#ifdef __APPLE__ + addr.sin_len = sizeof(struct sockaddr_in); +#endif + addr.sin_addr.s_addr = htonl((((uint32_t)224U) << 24U) | ((uint32_t)251U)); + addr.sin_port = htons((unsigned short)5353); + saddr = (struct sockaddr*)&addr; + saddrlen = sizeof(struct sockaddr_in); + } + + if (sendto(sock, mdns_services_query, sizeof(mdns_services_query), 0, + saddr, saddrlen) < 0) + return -1; + return 0; +} + +static size_t +mdns_discovery_recv(int sock, void* buffer, size_t capacity, + mdns_record_callback_fn callback, void* user_data) { + struct sockaddr_in6 addr; + struct sockaddr* saddr = (struct sockaddr*)&addr; + memset(&addr, 0, sizeof(addr)); + saddr->sa_family = AF_INET; +#ifdef __APPLE__ + saddr->sa_len = sizeof(addr); +#endif + socklen_t addrlen = sizeof(addr); + int ret = recvfrom(sock, buffer, capacity, 0, + saddr, &addrlen); + if (ret <= 0) + return 0; + + size_t data_size = (size_t)ret; + size_t records = 0; + uint16_t* data = (uint16_t*)buffer; + + uint16_t transaction_id = ntohs(*data++); + uint16_t flags = ntohs(*data++); + uint16_t questions = ntohs(*data++); + uint16_t answer_rrs = ntohs(*data++); + uint16_t authority_rrs = ntohs(*data++); + uint16_t additional_rrs = ntohs(*data++); + + if (transaction_id || (flags != 0x8400)) + return 0; //Not a reply to our question + + if (questions > 1) + return 0; + + int i; + for (i = 0; i < questions; ++i) { + size_t ofs = (size_t)((char*)data - (char*)buffer); + size_t verify_ofs = 12; + //Verify it's our question, _services._dns-sd._udp.local. + if (!mdns_string_equal(buffer, data_size, &ofs, + mdns_services_query, sizeof(mdns_services_query), &verify_ofs)) + return 0; + data = (uint16_t*)((char*)buffer + ofs); + + uint16_t type = ntohs(*data++); + uint16_t rclass = ntohs(*data++); + + //Make sure we get a reply based on our PTR question for class IN + if ((type != MDNS_RECORDTYPE_PTR) || ((rclass & 0x7FFF) != MDNS_CLASS_IN)) + return 0; + } + + int do_callback = 1; + for (i = 0; i < answer_rrs; ++i) { + size_t ofs = (size_t)((char*)data - (char*)buffer); + size_t verify_ofs = 12; + //Verify it's an answer to our question, _services._dns-sd._udp.local. + int is_answer = mdns_string_equal(buffer, data_size, &ofs, + mdns_services_query, sizeof(mdns_services_query), &verify_ofs); + data = (uint16_t*)((char*)buffer + ofs); + + uint16_t type = ntohs(*data++); + uint16_t rclass = ntohs(*data++); + uint32_t ttl = ntohl(*(uint32_t*)(void*)data); data += 2; + uint16_t length = ntohs(*data++); + + if (is_answer && do_callback) { + ++records; + if (callback(saddr, MDNS_ENTRYTYPE_ANSWER, type, rclass, ttl, buffer, + data_size, (size_t)((char*)data - (char*)buffer), length, + user_data)) + do_callback = 0; + } + data = (void*)((char*)data + length); + } + + size_t offset = (size_t)((char*)data - (char*)buffer); + records += mdns_records_parse(saddr, buffer, data_size, &offset, + MDNS_ENTRYTYPE_AUTHORITY, authority_rrs, + callback, user_data); + records += mdns_records_parse(saddr, buffer, data_size, &offset, + MDNS_ENTRYTYPE_ADDITIONAL, additional_rrs, + callback, user_data); + + return records; +} +#endif + +static uint16_t mdns_transaction_id = 0; + +static int +mdns_query_send(int sock, mdns_record_type_t type, const char* name, size_t length, + void* buffer, size_t capacity) { + if (capacity < (17 + length)) + return -1; + + uint16_t* data = buffer; + //Transaction ID + *data++ = htons(++mdns_transaction_id); + //Flags + *data++ = 0; + //Questions + *data++ = htons(1); + //No answer, authority or additional RRs + *data++ = 0; + *data++ = 0; + *data++ = 0; + //Name string + data = mdns_string_make(data, capacity - 17, name, length); + if (!data) + return -1; + //Record type + *data++ = htons(type); + //! Unicast response, class IN + *data++ = htons(0x8000U | MDNS_CLASS_IN); + + struct sockaddr_storage addr_storage; + struct sockaddr_in addr; + struct sockaddr_in6 addr6; + struct sockaddr* saddr = (struct sockaddr*)&addr_storage; + socklen_t saddrlen = sizeof(struct sockaddr_storage); + if (getsockname(sock, saddr, &saddrlen)) + return -1; + if (saddr->sa_family == AF_INET6) { + memset(&addr6, 0, sizeof(struct sockaddr_in6)); + addr6.sin6_family = AF_INET6; +#ifdef __APPLE__ + addr6.sin6_len = sizeof(struct sockaddr_in6); +#endif + addr6.sin6_addr.s6_addr[0] = 0xFF; + addr6.sin6_addr.s6_addr[1] = 0x02; + addr6.sin6_addr.s6_addr[15] = 0xFB; + addr6.sin6_port = htons((unsigned short)5353); + saddr = (struct sockaddr*)&addr6; + saddrlen = sizeof(struct sockaddr_in6); + } + else { + memset(&addr, 0, sizeof(struct sockaddr_in)); + addr.sin_family = AF_INET; +#ifdef __APPLE__ + addr.sin_len = sizeof(struct sockaddr_in); +#endif + addr.sin_addr.s_addr = htonl((((uint32_t)224U) << 24U) | ((uint32_t)251U)); + addr.sin_port = htons((unsigned short)5353); + saddr = (struct sockaddr*)&addr; + saddrlen = sizeof(struct sockaddr_in); + } + + if (sendto(sock, buffer, (char*)data - (char*)buffer, 0, + saddr, saddrlen) < 0) + return -1; + return 0; +} + +static size_t +mdns_query_recv(int sock, void* buffer, size_t capacity, + mdns_record_callback_fn callback, void* user_data, + uint8_t one_shot) { + struct sockaddr_in6 addr; + struct sockaddr* saddr = (struct sockaddr*)&addr; + memset(&addr, 0, sizeof(addr)); + saddr->sa_family = AF_INET; +#ifdef __APPLE__ + saddr->sa_len = sizeof(addr); +#endif + socklen_t addrlen = sizeof(addr); + int ret = recvfrom(sock, buffer, capacity, 0, + saddr, &addrlen); + if (ret <= 0) + return 0; + + size_t data_size = (size_t)ret; + uint16_t* data = (uint16_t*)buffer; + + uint16_t transaction_id = ntohs(*data++); + ++data;// uint16_t flags = ntohs(*data++); + uint16_t questions = ntohs(*data++); + uint16_t answer_rrs = ntohs(*data++); + uint16_t authority_rrs = ntohs(*data++); + uint16_t additional_rrs = ntohs(*data++); + + if (one_shot && transaction_id != mdns_transaction_id)// || (flags != 0x8400)) + return 0; //Not a reply to our last question + + if (questions > 1) + return 0; + + //Skip questions part + int i; + for (i = 0; i < questions; ++i) { + size_t ofs = (size_t)((char*)data - (char*)buffer); + if (!mdns_string_skip(buffer, data_size, &ofs)) + return 0; + data = (void*)((char*)buffer + ofs); + ++data; + ++data; + } + + size_t records = 0; + size_t offset = (size_t)((char*)data - (char*)buffer); + records += mdns_records_parse(saddr, buffer, data_size, &offset, + MDNS_ENTRYTYPE_ANSWER, answer_rrs, + callback, user_data); + records += mdns_records_parse(saddr, buffer, data_size, &offset, + MDNS_ENTRYTYPE_AUTHORITY, authority_rrs, + callback, user_data); + records += mdns_records_parse(saddr, buffer, data_size, &offset, + MDNS_ENTRYTYPE_ADDITIONAL, additional_rrs, + callback, user_data); + return records; +} + +static mdns_string_t +mdns_record_parse_ptr(const void* buffer, size_t size, size_t offset, size_t length, + char* strbuffer, size_t capacity) { + //PTR record is just a string + if ((size >= offset + length) && (length >= 2)) + return mdns_string_extract(buffer, size, &offset, strbuffer, capacity); + mdns_string_t empty = {0, 0}; + return empty; +} + +static mdns_record_srv_t +mdns_record_parse_srv(const void* buffer, size_t size, size_t offset, size_t length, + char* strbuffer, size_t capacity) { + mdns_record_srv_t srv; + memset(&srv, 0, sizeof(mdns_record_srv_t)); + // Read the priority, weight, port number and the discovery name + // SRV record format (http://www.ietf.org/rfc/rfc2782.txt): + // 2 bytes network-order unsigned priority + // 2 bytes network-order unsigned weight + // 2 bytes network-order unsigned port + // string: discovery (domain) name, minimum 2 bytes when compressed + if ((size >= offset + length) && (length >= 8)) { + const uint16_t* recorddata = (const uint16_t*)((const char*)buffer + offset); + srv.priority = ntohs(*recorddata++); + srv.weight = ntohs(*recorddata++); + srv.port = ntohs(*recorddata++); + offset += 6; + srv.name = mdns_string_extract(buffer, size, &offset, strbuffer, capacity); + } + return srv; +} + +static struct sockaddr_in* +mdns_record_parse_a(const void* buffer, size_t size, size_t offset, size_t length, + struct sockaddr_in* addr) { + memset(addr, 0, sizeof(struct sockaddr_in)); + addr->sin_family = AF_INET; +#ifdef __APPLE__ + addr->sin_len = sizeof(struct sockaddr_in); +#endif + if ((size >= offset + length) && (length == 4)) + addr->sin_addr.s_addr = *(const uint32_t*)((const char*)buffer + offset); + return addr; +} + +static struct sockaddr_in6* +mdns_record_parse_aaaa(const void* buffer, size_t size, size_t offset, size_t length, + struct sockaddr_in6* addr) { + memset(addr, 0, sizeof(struct sockaddr_in6)); + addr->sin6_family = AF_INET6; +#ifdef __APPLE__ + addr->sin6_len = sizeof(struct sockaddr_in6); +#endif + if ((size >= offset + length) && (length == 16)) + addr->sin6_addr = *(const struct in6_addr*)((const char*)buffer + offset); + return addr; +} + +static size_t +mdns_record_parse_txt(const void* buffer, size_t size, size_t offset, size_t length, + mdns_record_txt_t* records, size_t capacity) { + size_t parsed = 0; + const char* strdata; + size_t separator, sublength; + size_t end = offset + length; + + if (size < end) + end = size; + + while ((offset < end) && (parsed < capacity)) { + strdata = (const char*)buffer + offset; + sublength = *(const unsigned char*)strdata; + + ++strdata; + offset += sublength + 1; + + separator = 0; + for (size_t c = 0; c < sublength; ++c) { + //DNS-SD TXT record keys MUST be printable US-ASCII, [0x20, 0x7E] + if ((strdata[c] < 0x20) || (strdata[c] > 0x7E)) + break; + if (strdata[c] == '=') { + separator = c; + break; + } + } + + if (!separator) + continue; + + if (separator < sublength) { + records[parsed].key.str = strdata; + records[parsed].key.length = separator; + records[parsed].value.str = strdata + separator + 1; + records[parsed].value.length = sublength - (separator + 1); + } + else { + records[parsed].key.str = strdata; + records[parsed].key.length = sublength; + } + + ++parsed; + } + + return parsed; +} + +#ifdef _WIN32 +#undef strncasecmp +#endif diff --git a/ctrl/facemgr/src/interfaces/dummy/CMakeLists.txt b/ctrl/facemgr/src/interfaces/dummy/CMakeLists.txt index 1af3b4b2a..05276bc5a 100644 --- a/ctrl/facemgr/src/interfaces/dummy/CMakeLists.txt +++ b/ctrl/facemgr/src/interfaces/dummy/CMakeLists.txt @@ -12,6 +12,7 @@ # limitations under the License. list(APPEND HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/dummy.h ) list(APPEND SOURCE_FILES diff --git a/ctrl/facemgr/src/interfaces/dummy/dummy.c b/ctrl/facemgr/src/interfaces/dummy/dummy.c index b0c558388..6a21792a2 100644 --- a/ctrl/facemgr/src/interfaces/dummy/dummy.c +++ b/ctrl/facemgr/src/interfaces/dummy/dummy.c @@ -19,31 +19,101 @@ */ #include <stdlib.h> +#include <unistd.h> // close + +#include <hicn/facemgr.h> -#include "../../interface.h" #include "../../common.h" -#include "../../event.h" -#include "../../face.h" -#include "../../facemgr.h" +#include "../../facelet.h" +#include "../../interface.h" + +#include "dummy.h" #define DEFAULT_PORT 9695 -int dummy_initialize(interface_t * interface, face_rules_t * rules, void **pdata) { - ip_address_t local = IPV4_LOOPBACK; - ip_address_t remote = IPV4_LOOPBACK; - face_t * face = face_create_udp(&local, DEFAULT_PORT, &remote, DEFAULT_PORT, AF_INET); - event_raise(EVENT_TYPE_CREATE, face, interface); - return FACEMGR_SUCCESS; +#define UNUSED(x) ((void)x) + +/* + * Internal data + */ +typedef struct { + /* The configuration data will likely be allocated on the stack (or should + * be freed) by the caller, we recommend to make a copy of this data. + * This copy can further be altered with default values. + */ + dummy_cfg_t cfg; + + /* ... */ + + int fd; /* Sample internal data: file descriptor */ +} dummy_data_t; + +int dummy_initialize(interface_t * interface, void * cfg) +{ + dummy_data_t * data = malloc(sizeof(dummy_data_t)); + if (!data) + goto ERR_MALLOC; + interface->data = data; + + /* Use default values for unspecified configuration parameters */ + if (cfg) { + data->cfg = *(dummy_cfg_t *)cfg; + } else { + memset(&data->cfg, 0, sizeof(data->cfg)); + } + + /* ... */ + + data->fd = 0; + + /* ... */ + + /* + * We should return a negative value in case of error, and a positive value + * otherwise: + * - a file descriptor (>0) will be added to the event loop; or + * - 0 if we don't use any file descriptor + */ + return data->fd; + +ERR_MALLOC: + return -1; +} + +int dummy_finalize(interface_t * interface) +{ + dummy_data_t * data = (dummy_data_t*)interface->data; + + if (data->fd > 0) + close(data->fd); + + return 0; } -int dummy_finalize(interface_t * interface) { - return FACEMGR_SUCCESS; +int dummy_callback(interface_t * interface) +{ + dummy_data_t * data = (dummy_data_t*)interface->data; + UNUSED(data); + + /* ... */ + + return 0; +} + +int dummy_on_event(interface_t * interface, const facelet_t * facelet) +{ + dummy_data_t * data = (dummy_data_t*)interface->data; + UNUSED(data); + + /* ... */ + + return 0; } interface_ops_t dummy_ops = { .type = "dummy", - .is_singleton = true, .initialize = dummy_initialize, .finalize = dummy_finalize, - .on_event = NULL, + .callback = dummy_callback, + .on_event = dummy_on_event, }; diff --git a/ctrl/facemgr/src/interface_ops_map.h b/ctrl/facemgr/src/interfaces/dummy/dummy.h index 2d590390a..22fe5d1a6 100644 --- a/ctrl/facemgr/src/interface_ops_map.h +++ b/ctrl/facemgr/src/interfaces/dummy/dummy.h @@ -13,12 +13,22 @@ * limitations under the License. */ -#ifndef INTERFACE_OPS_MAP_H -#define INTERFACE_OPS_MAP_H +/** + * \file dummy.h + * \brief Dummy interface + * + * This class serves as a template to implement new face maanger interfaces, and + * can be used for test purposes. + */ -#include "interface.h" -#include "util/map.h" +#ifndef FACEMGR_INTERFACE_DUMMY_H +#define FACEMGR_INTERFACE_DUMMY_H -TYPEDEF_MAP_H(interface_ops_map, const char *, interface_ops_t *); +/* + * Configuration data + */ +typedef struct { + /* ... */ +} dummy_cfg_t; -#endif /* INTERFACE_OPS_MAP_H */ +#endif /* FACEMGR_INTERFACE_DUMMY_H */ diff --git a/ctrl/facemgr/src/interfaces/hicn_light/hicn_light.c b/ctrl/facemgr/src/interfaces/hicn_light/hicn_light.c index 85694573d..e42c6c6ae 100644 --- a/ctrl/facemgr/src/interfaces/hicn_light/hicn_light.c +++ b/ctrl/facemgr/src/interfaces/hicn_light/hicn_light.c @@ -18,27 +18,70 @@ * \brief hICN light interface */ #include <stdbool.h> -#include <stdlib.h> // arc4random [random, rand] #include <stdio.h> // snprintf #include <time.h> // time #include <hicn/ctrl.h> +#include <hicn/facemgr.h> +#include <hicn/util/ip_address.h> +#include <hicn/util/log.h> -#include "../../facemgr.h" +#include "../../facelet.h" #include "../../interface.h" -#include "../../util/ip_address.h" -#include "../../util/log.h" #include "../../util/map.h" -#include "../../event.h" #define DEFAULT_ROUTE_COST 0 +typedef enum { + HL_STATE_UNDEFINED, + HL_STATE_FACES_SENT, + HL_STATE_DONE, +} hl_state_t; + typedef struct { hc_sock_t * s; - bool busy; + hl_state_t state; } hl_data_t; -int hl_initialize(interface_t * interface, face_rules_t * rules, void ** pdata) +int hl_process_state(interface_t * interface) +{ + hl_data_t * data = (hl_data_t *)interface->data; + + hc_data_t * faces; +#if 0 + char buf[MAXSZ_FACE]; +#endif + + switch(data->state) + { + case HL_STATE_UNDEFINED: + if (hc_face_list(data->s, &faces) < 0) { + /* Blocking call */ + printf("Could not retrieve face list\n"); + return -1; + } + foreach_face(f, faces) { +#if 0 + hc_face_snprintf(buf, MAXSZ_FACE, f); + printf("Face: %s\n", buf); +#endif + facelet_t * facelet = facelet_create_from_face(&f->face); + facelet_set_event(facelet, FACELET_EVENT_GET); + facelet_raise_event(facelet, interface); + } + break; + + case HL_STATE_FACES_SENT: + break; + + default: /* HL_STATE_DONE never called */ + break; + } + + return 0; +} + +int hl_initialize(interface_t * interface, void * cfg) { hl_data_t * data = malloc(sizeof(hl_data_t)); if (!data) { @@ -57,51 +100,52 @@ int hl_initialize(interface_t * interface, face_rules_t * rules, void ** pdata) goto ERR_CONNECT; } - data->busy = false; + data->state = HL_STATE_UNDEFINED; + + interface->data = data; - *pdata = data; + hl_process_state(interface); - return FACEMGR_SUCCESS; + return 0; ERR_CONNECT: hc_sock_free(data->s); ERR_SOCK: free(data); ERR_MALLOC: - return FACEMGR_FAILURE; + return -1; } int hl_finalize(interface_t * interface) { //hc_data_t * data = interface->data; //hc_sock_close(data->s); - return FACEMGR_SUCCESS; + return 0; } -int hl_on_event(interface_t * interface, const event_t * event) +int hl_on_event(interface_t * interface, const facelet_t * facelet) { - hc_face_t face; + hc_face_t hc_face; hc_route_t route; int rc; hl_data_t * data = (hl_data_t *)interface->data; - /* XXX We need a queue or a socket pool to process concurrent events */ - if (data->busy) { - ERROR("[hicn_light] Busy !"); - return FACEMGR_FAILURE; - } + face_t * face = NULL; + if (facelet_get_face(facelet, &face) < 0) + return -1; + + switch(facelet_get_event(facelet)) { - switch(event->type) { - case EVENT_TYPE_CREATE: + case FACELET_EVENT_CREATE: /* Create face */ - face.face = *event->face; - rc = hc_face_create(data->s, &face); + hc_face.face = *face; + rc = hc_face_create(data->s, &hc_face); if (rc < 0) { ERROR("Failed to create face\n"); goto ERR; } - DEBUG("Created face id=%d\n", face.id); + INFO("Created face id=%d\n", hc_face.id); #if 0 /* Add default route v4 */ @@ -134,88 +178,84 @@ int hl_on_event(interface_t * interface, const event_t * event) } #endif -#if 1 - /* We add routes based on face tags */ - - if (policy_tags_has(event->face->tags, POLICY_TAG_TRUSTED)) { - route = (hc_route_t) { - .face_id = face.id, - .family = AF_INET6, - .len = 16, - .cost = DEFAULT_ROUTE_COST, - }; - if (ip_address_pton("b001::", &route.remote_addr) < 0) { - ERROR("Failed to convert prefix"); - goto ERR; - } - if (hc_route_create(data->s, &route) < 0) { - ERROR("Failed to create hICN/IPv6 route"); - goto ERR; - } + /* Adding default route */ + route = (hc_route_t) { + .face_id = hc_face.id, + .family = AF_INET6, + .len = 0, + .cost = DEFAULT_ROUTE_COST, + }; + if (ip_address_pton("::", &route.remote_addr) < 0) { + ERROR("Failed to convert prefix"); + goto ERR; + } + if (hc_route_create(data->s, &route) < 0) { + ERROR("Failed to create hICN/IPv6 route"); + goto ERR; + } - route = (hc_route_t) { - .face_id = face.id, - .family = AF_INET6, - .len = 16, - .cost = DEFAULT_ROUTE_COST, - }; - if (ip_address_pton("d001::", &route.remote_addr) < 0) { - ERROR("Failed to convert prefix"); + break; + + case FACELET_EVENT_DELETE: + /* Removing a face should also remove associated routes */ + /* Create face */ + hc_face.face = *face; + rc = hc_face_delete(data->s, &hc_face); + if (rc < 0) { + ERROR("Failed to delete face\n"); + goto ERR; + } + INFO("Deleted face id=%d\n", hc_face.id); + break; + + case FACELET_EVENT_UPDATE: + /* Currently, only admin_state is supported */ + if (facelet_get_admin_state_status(facelet) == FACELET_ATTR_STATUS_DIRTY) { + hc_face.face = *face; + hc_face_t * face_found; + rc = hc_face_get(data->s, &hc_face, &face_found); + if (rc < 0) { + ERROR("Failed to find face\n"); goto ERR; } - if (hc_route_create(data->s, &route) < 0) { - ERROR("Failed to create hICN/IPv6 route"); + if (!face_found) { + ERROR("Face to update has not been found"); goto ERR; } + char conn_id_or_name[NAME_LEN]; + snprintf(conn_id_or_name, NAME_LEN, "%d", face_found->id); + free(face_found); + printf("Face id = %d\n", face_found->id); - } else { - - route = (hc_route_t) { - .face_id = face.id, - .family = AF_INET6, - .len = 16, - .cost = DEFAULT_ROUTE_COST, - }; - if (ip_address_pton("c001::", &route.remote_addr) < 0) { - ERROR("Failed to convert prefix"); + face_state_t admin_state; + if (facelet_get_admin_state(facelet, &admin_state) < 0) { + ERROR("Failed to retrieve facelet admin state"); goto ERR; } - if (hc_route_create(data->s, &route) < 0) { - ERROR("Failed to create hICN/IPv6 route"); + + printf("Setting admin state"); + if (hc_connection_set_admin_state(data->s, conn_id_or_name, admin_state) < 0) { + ERROR("Failed to update admin state"); goto ERR; } + INFO("Admin state updated"); } -#endif - - break; - - case EVENT_TYPE_DELETE: - /* Removing a face should also remove associated routes */ - /* Create face */ - face.face = *event->face; - rc = hc_face_delete(data->s, &face); - if (rc < 0) { - ERROR("Failed to delete face\n"); - goto ERR; - } - INFO("Deleted face id=%d\n", face.id); break; default: - ERROR("Unknown event %s\n", event_type_str[event->type]); + ERROR("Unknown event %s\n", facelet_event_str[facelet_get_event(facelet)]); /* Unsupported events */ goto ERR; } - return FACEMGR_SUCCESS; + return 0; ERR: - return FACEMGR_FAILURE; + return -1; } const interface_ops_t hicn_light_ops = { .type = "hicn_light", - .is_singleton = false, .initialize = hl_initialize, .finalize = hl_finalize, .on_event = hl_on_event, diff --git a/ctrl/facemgr/src/interfaces/netlink/netlink.c b/ctrl/facemgr/src/interfaces/netlink/netlink.c index 5bf0baf9f..08cbe4d3b 100644 --- a/ctrl/facemgr/src/interfaces/netlink/netlink.c +++ b/ctrl/facemgr/src/interfaces/netlink/netlink.c @@ -18,34 +18,120 @@ * \brief Netlink interface */ +#include <assert.h> #include <linux/rtnetlink.h> +#include <net/if_arp.h> // ARPHRD_LOOPBACK #include <sys/types.h> // getpid #include <unistd.h> // getpid -#include "../../event.h" -#include "../../facemgr.h" +#include <hicn/facemgr.h> +#include <hicn/util/ip_address.h> +#include <hicn/util/log.h> + +#include "../../common.h" +#include "../../facelet.h" #include "../../interface.h" +typedef enum { + NL_STATE_UNDEFINED, + NL_STATE_LINK_SENT, + NL_STATE_ADDR_SENT, + NL_STATE_DONE, +} nl_state_t; + /* Internal data storage */ typedef struct { int fd; + nl_state_t state; } nl_data_t; -// little helper to parsing message using netlink macroses -void parseRtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len) +static inline void parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len, + unsigned short flags) { + unsigned short type; + memset(tb, 0, sizeof(struct rtattr *) * (max + 1)); + while (RTA_OK(rta, len)) { + type = rta->rta_type & ~flags; + if (type <= max) + tb[type] = rta; + rta = RTA_NEXT(rta, len); + } +} + +int nl_process_state(interface_t * interface) +{ + nl_data_t * data = (nl_data_t*)interface->data; + int rc; + + switch(data->state) { + case NL_STATE_UNDEFINED: + { + struct { + struct nlmsghdr header; + struct rtgenmsg payload; + } msg2 = { + .header = { + .nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)), + .nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP, + .nlmsg_type = RTM_GETLINK, + .nlmsg_pid = getpid(), + .nlmsg_seq = 3, + }, + .payload = { + .rtgen_family = AF_PACKET, + } + }; + + rc = send(data->fd, &msg2, msg2.header.nlmsg_len, 0); + if (rc < 0) + printf("E: Error sending netlink query\n"); + + data->state = NL_STATE_LINK_SENT; + break; + } + + case NL_STATE_LINK_SENT: + { + /* Issue a first query to receive static state */ + struct { + struct nlmsghdr header; + struct ifaddrmsg payload; + } msg = { + .header = { + .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)), + .nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP, + .nlmsg_type = RTM_GETADDR, + .nlmsg_pid = getpid(), + .nlmsg_seq = 7, + }, + .payload = { + .ifa_family = AF_INET, + } + }; + + rc = send(data->fd, &msg, msg.header.nlmsg_len, 0); + if (rc < 0) + printf("E: Error sending netlink query\n"); + + data->state = NL_STATE_ADDR_SENT; + break; + } - while (RTA_OK(rta, len)) { // while not end of the message - if (rta->rta_type <= max) { - tb[rta->rta_type] = rta; // read attr + case NL_STATE_ADDR_SENT: + { + data->state = NL_STATE_DONE; + break; } - rta = RTA_NEXT(rta,len); // get next attr + + default: /* NL_STATE_DONE never called */ + break; } -} + return 0; +} -int nl_initialize(interface_t * interface, face_rules_t * rules, void ** pdata) +int nl_initialize(interface_t * interface, void * cfg) { nl_data_t * data = malloc(sizeof(nl_data_t)); if (!data) @@ -57,31 +143,194 @@ int nl_initialize(interface_t * interface, face_rules_t * rules, void ** pdata) goto ERR_SOCKET; } + data->state = NL_STATE_UNDEFINED; + struct sockaddr_nl local; // local addr struct memset(&local, 0, sizeof(local)); local.nl_family = AF_NETLINK; // set protocol family - local.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE; // set groups we interested in + // NOTE: RTNLGRP_LINK replaces obsolete RTMGRP_LINK, etc + local.nl_groups = 0 + | RTMGRP_LINK + | RTMGRP_IPV4_IFADDR + | RTMGRP_IPV6_IFADDR +#if 0 + | RTMGRP_IPV4_ROUTE; + | RTMGRP_IPV6_ROUTE; +#endif + ; local.nl_pid = getpid(); // set out id using current process id - if (bind(data->fd, (struct sockaddr*)&local, sizeof(local)) < 0) { // bind socket printf("Failed to bind netlink socket: %s\n", (char*)strerror(errno)); goto ERR_BIND; } - /* Issue a first query to receive static state */ + interface->data = data; + nl_process_state(interface); - *pdata = data; - return data->fd; // FACEMGR_SUCCESS; + return data->fd; // 0; ERR_BIND: close(data->fd); ERR_SOCKET: free(data); ERR_MALLOC: - *pdata = NULL; - return FACEMGR_FAILURE; + return -1; +} + +int parse_link(struct nlmsghdr * h, facelet_t ** facelet, + char * interface_name, size_t interface_name_size, + bool * up, bool * running) +{ + struct ifinfomsg *ifi; // structure for network interface info + struct rtattr *tb[IFLA_MAX + 1]; + + assert(facelet); + + ifi = (struct ifinfomsg*) NLMSG_DATA(h); // get information about changed network interface + parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), IFLA_PAYLOAD(h), 1<<15); + + if (interface_name) { + assert(tb[IFLA_IFNAME]); + snprintf(interface_name, interface_name_size, "%s", (char*)RTA_DATA(tb[IFLA_IFNAME])); + } + + if (up) + *up = ifi->ifi_flags & IFF_UP; + if (running) + *running = ifi->ifi_flags & IFF_RUNNING; + + + *facelet = facelet_create(); + netdevice_t * netdevice = netdevice_create_from_name(interface_name); + if (!netdevice) + goto ERROR; + int rc = facelet_set_netdevice(*facelet, *netdevice); + if (rc < 0) + goto ERROR; + +// FIXME Tags +#if 0 + /* This is the only opportunity to identify a loopback interface on both + * linux _and_ android, as NetworkCapabilities does not have a flag for + * LOOPBACK... */ + if (ifi->ifi_type==ARPHRD_LOOPBACK) { + DEBUG("loopback"); + } + +#ifdef IFLA_WIRELESS + /* + * This signals a wirless event, but it typically occurs _after_ a face is + * created... we might need to update an existing face by setting a tag... + * or find a way to exploit this flag before actually creating the face... + */ + if (tb[IFLA_WIRELESS]) + DEBUG("wireless!!!"); +#else +#warning "IFLA_WIRELESS not supported on this platform" +#endif /* IFLA_WIRELESS */ + +#endif + + // TODO + // - ifi_change + // - IFLA_PROTINFO + + return 0; + +ERROR: + facelet_free(*facelet); + *facelet = NULL; + + return -1; +} + +int parse_addr(struct nlmsghdr * h, facelet_t ** facelet, + char * interface_name, size_t interface_name_size, + char * interface_address, size_t interface_address_size) +{ + ip_address_t local_addr = IP_ADDRESS_EMPTY; + struct ifaddrmsg *ifa; // structure for network interface data + struct rtattr *tba[IFA_MAX+1]; + + assert(facelet); + + ifa = (struct ifaddrmsg*)NLMSG_DATA(h); // get data from the network interface + + parse_rtattr(tba, IFA_MAX, IFA_RTA(ifa), IFA_PAYLOAD(h), 0); + + /* FIXME + * + * IFA_LOCAL ok for v4, not there for v6 + * + * IFA_ADDRESS seems to work for both but with the following precaution + * + * IFA_ADDRESS is prefix address, rather than local interface address. + * It makes no difference for normally configured broadcast interfaces, + * but for point-to-point IFA_ADDRESS is DESTINATION address, + * local address is supplied in IFA_LOCAL attribute. + */ + if (!tba[IFA_ADDRESS]) { + ERROR("[netlink.parse_addr] No local address"); + return -1; + } + + switch(ifa->ifa_family) { + case AF_INET: + local_addr.v4.as_inaddr = *(struct in_addr*)RTA_DATA(tba[IFA_ADDRESS]); + break; + case AF_INET6: + local_addr.v6.as_in6addr = *(struct in6_addr*)RTA_DATA(tba[IFA_ADDRESS]); + break; + default: + return 0; + } + +#if 0 /* Not working for v6 */ + if (interface_name) { + assert(tba[IFLA_IFNAME]); + snprintf(interface_name, interface_name_size, "%s", (char*)RTA_DATA(tba[IFLA_IFNAME])); + } +#endif + + /* See comment in parse_link */ + if (interface_address) { + assert(tba[IFA_ADDRESS]); + ip_address_snprintf(interface_address, interface_address_size, &local_addr, ifa->ifa_family); + } + + netdevice_t * netdevice = netdevice_create_from_index(ifa->ifa_index); + if (!netdevice) { + ERROR("[netlink.parse_addr] error creating netdevice '%s'", interface_name); + goto ERROR; + } + + if (interface_name) { + snprintf(interface_name, interface_name_size, "%s", netdevice->name); + } + + *facelet = facelet_create(); + if (facelet_set_netdevice(*facelet, *netdevice) < 0) { + ERROR("[netlink.parse_addr] error setting netdevice"); + goto ERROR; + } + if (facelet_set_family(*facelet, ifa->ifa_family) < 0) { + ERROR("[netlink.parse_addr] error setting family"); + goto ERROR; + } + if (facelet_set_local_addr(*facelet, local_addr) < 0) { + ERROR("[netlink.parse_addr] error setting local address"); + goto ERROR; + } + + return 0; + +ERROR: + facelet_free(*facelet); + *facelet = NULL; + + return -1; } int nl_callback(interface_t * interface) @@ -97,13 +346,12 @@ int nl_callback(interface_t * interface) iov.iov_len = sizeof(buf); // set size // initialize protocol message header - struct msghdr msg; - { - msg.msg_name = &local; // local address - msg.msg_namelen = sizeof(local); // address size - msg.msg_iov = &iov; // io vector - msg.msg_iovlen = 1; // io size - } + struct msghdr msg = { + .msg_name = &local, // local address + .msg_namelen = sizeof(local), // address size + .msg_iov = &iov, // io vector + .msg_iovlen = 1, // io size + }; ssize_t status = recvmsg(data->fd, &msg, 0); @@ -115,12 +363,12 @@ int nl_callback(interface_t * interface) */ printf("Failed to read netlink: %s", (char*)strerror(errno)); - return FACEMGR_FAILURE; + return -1; } if (msg.msg_namelen != sizeof(local)) { // check message length, just in case printf("Invalid length of the sender address struct\n"); - return FACEMGR_FAILURE; + return -1; } // message parser @@ -129,103 +377,122 @@ int nl_callback(interface_t * interface) for (h = (struct nlmsghdr*)buf; status >= (ssize_t)sizeof(*h); ) { // read all messagess headers int len = h->nlmsg_len; int l = len - sizeof(*h); - char *ifName = NULL; if ((l < 0) || (len > status)) { printf("Invalid message length: %i\n", len); continue; } - // now we can check message type - if ((h->nlmsg_type == RTM_NEWROUTE) || (h->nlmsg_type == RTM_DELROUTE)) { // some changes in routing table - printf("Routing table was changed\n"); - } else { // in other case we need to go deeper - char *ifUpp; - char *ifRunn; - struct ifinfomsg *ifi; // structure for network interface info - struct rtattr *tb[IFLA_MAX + 1]; - - ifi = (struct ifinfomsg*) NLMSG_DATA(h); // get information about changed network interface - - parseRtattr(tb, IFLA_MAX, IFLA_RTA(ifi), h->nlmsg_len); // get attributes - - if (tb[IFLA_IFNAME]) { // validation - ifName = (char*)RTA_DATA(tb[IFLA_IFNAME]); // get network interface name - } - - if (ifi->ifi_flags & IFF_UP) { // get UP flag of the network interface - ifUpp = (char*)"UP"; - } else { - ifUpp = (char*)"DOWN"; - } + switch(h->nlmsg_type) { +#if 0 + case RTM_NEWROUTE: + case RTM_DELROUTE: + DEBUG("Routing table was changed"); + break; +#endif + + case RTM_DELADDR: + { + facelet_t * facelet = NULL; + char interface_name[IFNAMSIZ]; + char interface_address[MAXSZ_IP_ADDRESS] = {0}; + + if (parse_addr(h, &facelet, interface_name, IFNAMSIZ, + interface_address, MAXSZ_IP_ADDRESS) < 0) { + ERROR("Error parsing address message"); + break; + } - if (ifi->ifi_flags & IFF_RUNNING) { // get RUNNING flag of the network interface - ifRunn = (char*)"RUNNING"; - } else { - ifRunn = (char*)"NOT RUNNING"; + DEBUG("Interface %s: address was removed", interface_name); + if (facelet) { + facelet_set_event(facelet, FACELET_EVENT_DELETE); + facelet_raise_event(facelet, interface); + } + break; } - char ifAddress[256] = {0}; // network addr - struct ifaddrmsg *ifa; // structure for network interface data - struct rtattr *tba[IFA_MAX+1]; + case RTM_NEWADDR: + { + facelet_t * facelet = NULL; + char interface_name[IFNAMSIZ]; + char interface_address[MAXSZ_IP_ADDRESS] = {0}; - ifa = (struct ifaddrmsg*)NLMSG_DATA(h); // get data from the network interface + if (parse_addr(h, &facelet, interface_name, IFNAMSIZ, + interface_address, MAXSZ_IP_ADDRESS) < 0) { + ERROR("Error parsing address message"); + break; + } - parseRtattr(tba, IFA_MAX, IFA_RTA(ifa), h->nlmsg_len); + DEBUG("Interface %s: new address was assigned: %s", interface_name, interface_address); - if (tba[IFA_LOCAL]) { - inet_ntop(AF_INET, RTA_DATA(tba[IFA_LOCAL]), ifAddress, sizeof(ifAddress)); // get IP addr + if (facelet) { + facelet_set_event(facelet, FACELET_EVENT_UPDATE); + facelet_raise_event(facelet, interface); + } + break; } - face_t * face; - - if (tba[IFA_LOCAL]) { - ip_address_t local_addr = IP_ADDRESS_EMPTY; - switch(ifa->ifa_family) { - case AF_INET: - local_addr.v4.as_inaddr = *(struct in_addr*)RTA_DATA(tba[IFA_LOCAL]); - break; - case AF_INET6: - local_addr.v6.as_in6addr = *(struct in6_addr*)RTA_DATA(tba[IFA_LOCAL]); - break; - default: - continue; + case RTM_DELLINK: + { + facelet_t * facelet = NULL; + char interface_name[IFNAMSIZ]; + if (parse_link(h, &facelet, interface_name, IFNAMSIZ, + NULL, NULL) < 0) { + ERROR("Error parsing link message"); + break; + } + if (facelet) { + facelet_set_event(facelet, FACELET_EVENT_DELETE); + facelet_raise_event(facelet, interface); } - face = face_create_udp(&local_addr, 0, &IP_ADDRESS_EMPTY, 0, ifa->ifa_family); - } else { - face = NULL; + + DEBUG("Network interface %s was removed", interface_name); + break; } - switch (h->nlmsg_type) { - case RTM_DELADDR: - // DOES NOT SEEM TO BE TRIGGERED - printf("Interface %s: address was removed\n", ifName); - if (face) - event_raise(EVENT_TYPE_DELETE, face, interface); - break; + case RTM_NEWLINK: + { + facelet_t * facelet = NULL; + char interface_name[IFNAMSIZ]; + bool up, running; - case RTM_DELLINK: - printf("Network interface %s was removed\n", ifName); + if (parse_link(h, &facelet, interface_name, IFNAMSIZ, &up, &running) < 0) { + ERROR("Error parsing link message"); break; + } - case RTM_NEWLINK: - printf("New network interface %s, state: %s %s\n", ifName, ifUpp, ifRunn); - // UP RUNNING - // UP NOT RUNNING - // DOWN NOT RUNNING - if (!(ifi->ifi_flags & IFF_UP) || (!(ifi->ifi_flags & IFF_RUNNING))) { - if(face) - event_raise(EVENT_TYPE_DELETE, face, interface); + // UP RUNNING + // UP NOT RUNNING + // DOWN NOT RUNNING + DEBUG("New network interface %s, state: %s %s", interface_name, + up ? "UP" : "DOWN", + running ? "RUNNING" : "NOT_RUNNING"); + + if (facelet && up && running) { + facelet_set_event(facelet, FACELET_EVENT_CREATE); + facelet_t * facelet6 = facelet_dup(facelet); + if (!facelet6) { + ERROR("Could not duplicate face for v6"); + break; } - break; - case RTM_NEWADDR: - printf("Interface %s: new address was assigned: %s\n", ifName, ifAddress); - printf("NEW FACE\n"); - if (face) - event_raise(EVENT_TYPE_CREATE, face, interface); - break; + facelet_set_family(facelet, AF_INET); + facelet_raise_event(facelet, interface); + + facelet_set_family(facelet6, AF_INET6); + facelet_raise_event(facelet6, interface); + } + break; } + + case NLMSG_ERROR: + break; + case NLMSG_DONE: + nl_process_state(interface); + break; + default: + break; + } status -= NLMSG_ALIGN(len); // align offsets by the message length, this is important @@ -233,20 +500,19 @@ int nl_callback(interface_t * interface) h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); // get next message } - return FACEMGR_SUCCESS; + return 0; } int nl_finalize(interface_t * interface) { nl_data_t * data = (nl_data_t*)interface->data; close(data->fd); - return FACEMGR_SUCCESS; + return 0; } const interface_ops_t netlink_ops = { .type = "netlink", - .is_singleton = true, .initialize = nl_initialize, .callback = nl_callback, .finalize = nl_finalize, diff --git a/ctrl/facemgr/src/interfaces/network_framework/CMakeLists.txt b/ctrl/facemgr/src/interfaces/network_framework/CMakeLists.txt index ca6659342..e8b0144b1 100644 --- a/ctrl/facemgr/src/interfaces/network_framework/CMakeLists.txt +++ b/ctrl/facemgr/src/interfaces/network_framework/CMakeLists.txt @@ -17,6 +17,7 @@ if (NOT NETWORK_LIBRARY) endif() list(APPEND HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/network_framework.h ) list(APPEND SOURCE_FILES diff --git a/ctrl/facemgr/src/interfaces/network_framework/network_framework.c b/ctrl/facemgr/src/interfaces/network_framework/network_framework.c index 8a33129b4..4a9d24f61 100644 --- a/ctrl/facemgr/src/interfaces/network_framework/network_framework.c +++ b/ctrl/facemgr/src/interfaces/network_framework/network_framework.c @@ -24,14 +24,17 @@ #include <Network/Network.h> #include <err.h> +#include <hicn/facemgr.h> +#include <hicn/util/token.h> +#include <hicn/util/log.h> + #include "../../common.h" -#include "../../event.h" -#include "../../face.h" -#include "../../facemgr.h" +#include <hicn/ctrl/face.h> +#include "../../facelet.h" #include "../../interface.h" #include "../../util/map.h" -#include "../../util/token.h" -#include "../../util/log.h" + +#include "network_framework.h" /* * Bonjour service discovery for hICN forwarder @@ -107,7 +110,7 @@ cmp_iface(const nw_interface_t iface1, const nw_interface_t iface2) //TYPEDEF_MAP(map_cnx, nw_interface_t, nw_connection_t, cmp_iface); typedef struct { - face_rules_t * rules; /**< Face creation rules */ + network_framework_cfg_t cfg; nw_path_monitor_t pm; /**< Main path monitor */ // map_cnx_t map_cnx; /**< Map: interface -> connection for face status */ } nf_data_t; @@ -209,97 +212,90 @@ dump_connection(nw_connection_t connection, int indent) nw_release(path); } -face_t * -face_create_from_connection(nw_connection_t connection, face_rules_t * rules) +facelet_t * +facelet_create_from_connection(nw_connection_t connection) { - face_t * face; - struct sockaddr_in * sin; - struct sockaddr_in6 * sin6; + facelet_t * facelet; + ip_address_t local_addr, remote_addr; + uint16_t remote_port; nw_path_t path = nw_connection_copy_current_path(connection); nw_endpoint_t local = nw_path_copy_effective_local_endpoint(path); nw_endpoint_t remote = nw_path_copy_effective_remote_endpoint(path); __block nw_interface_t interface; - const struct sockaddr * local_addr = nw_endpoint_get_address(local); - const struct sockaddr * remote_addr = nw_endpoint_get_address(remote); + const struct sockaddr * local_sa = nw_endpoint_get_address(local); + const struct sockaddr * remote_sa = nw_endpoint_get_address(remote); - assert (local_addr->sa_family == remote_addr->sa_family); - switch(local_addr->sa_family) { + assert (local_sa->sa_family == remote_sa->sa_family); + switch(local_sa->sa_family) { case AF_INET: - sin = (struct sockaddr_in *)local_addr; - sin->sin_port = htons(DEFAULT_PORT); - sin = (struct sockaddr_in *)remote_addr; - sin->sin_port = htons(DEFAULT_PORT); + local_addr.v4.as_inaddr = ((struct sockaddr_in *)local_sa)->sin_addr; + remote_addr.v4.as_inaddr = ((struct sockaddr_in *)remote_sa)->sin_addr; + remote_port = ((struct sockaddr_in *)remote_sa)->sin_port; break; case AF_INET6: - sin6 = (struct sockaddr_in6 *)local_addr; - sin6->sin6_port = htons(DEFAULT_PORT); - sin6 = (struct sockaddr_in6 *)remote_addr; - sin6->sin6_port = htons(DEFAULT_PORT); + local_addr.v6.as_in6addr = ((struct sockaddr_in6 *)local_sa)->sin6_addr; + remote_addr.v6.as_in6addr = ((struct sockaddr_in6 *)remote_sa)->sin6_addr; + remote_port = ((struct sockaddr_in6 *)remote_sa)->sin6_port; break; default: - ERROR("Unsupported address family: %d\n", local_addr->sa_family); + ERROR("Unsupported address family: %d\n", local_sa->sa_family); return NULL; } - face = face_create_udp_sa(local_addr, remote_addr); /* Retrieving path interface type (a single one expected */ nw_path_enumerate_interfaces(path, (nw_path_enumerate_interfaces_block_t)^(nw_interface_t path_interface) { interface = path_interface; return false; }); - nw_interface_type_t type = nw_interface_get_type(interface); - const char * name = nw_interface_get_name(interface); - - policy_tags_t tags = POLICY_TAGS_EMPTY; - if (rules) { - if (!FACEMGR_IS_ERROR(face_rules_get(rules, name, &tags))) - goto SET_TAGS; + const char * name = nw_interface_get_name(interface); + netdevice_t netdevice; + snprintf(netdevice.name, IFNAMSIZ, "%s", name); + netdevice_update_index(&netdevice); - char tags[MAXSZ_POLICY_TAGS]; - policy_tags_snprintf(tags, MAXSZ_POLICY_TAGS, face->tags); - } + netdevice_type_t netdevice_type; + nw_interface_type_t type = nw_interface_get_type(interface); switch(type) { case INTERFACE_TYPE_OTHER: - policy_tags_add(&tags, POLICY_TAG_WIFI); - policy_tags_add(&tags, POLICY_TAG_TRUSTED); + netdevice_type = NETDEVICE_TYPE_UNDEFINED; break; case INTERFACE_TYPE_WIFI: - // XXX disambuiguate on interface name for now. - policy_tags_add(&tags, POLICY_TAG_WIFI); - policy_tags_add(&tags, POLICY_TAG_TRUSTED); + netdevice_type = NETDEVICE_TYPE_WIFI; break; case INTERFACE_TYPE_CELLULAR: - policy_tags_add(&tags, POLICY_TAG_CELLULAR); + netdevice_type = NETDEVICE_TYPE_CELLULAR; break; case INTERFACE_TYPE_WIRED: - /* Both VPN and USB WiFi are not well detected on MacOS. For USB - * WiFi, we currently have no solution. For VPN, until we have - * proper support of AnyC APIs, we need to have heuristics to - * determine VPN interfaces. */ - policy_tags_add(&tags, POLICY_TAG_WIRED); - policy_tags_add(&tags, POLICY_TAG_TRUSTED); + netdevice_type = NETDEVICE_TYPE_WIRED; break; case INTERFACE_TYPE_LOOPBACK: - tags = POLICY_TAGS_EMPTY; + netdevice_type = NETDEVICE_TYPE_LOOPBACK; break; default: break; } -SET_TAGS: - face_set_tags(face, tags); - nw_release(local); nw_release(remote); nw_release(path); - return face; + facelet = facelet_create(); + if (!facelet) + return NULL; + + facelet_set_netdevice(facelet, netdevice); + facelet_set_netdevice_type(facelet, netdevice_type); + facelet_set_family(facelet, local_sa->sa_family); + facelet_set_local_addr(facelet, local_addr); + facelet_set_remote_addr(facelet, remote_addr); + facelet_set_remote_port(facelet, remote_port); + + return facelet; } void @@ -340,9 +336,11 @@ on_connection_state_event(interface_t * interface, nw_interface_t iface, dump_connection(cnx, 1); }); #endif - nf_data_t * data = (nf_data_t*)interface->data; - face_t * face = face_create_from_connection(cnx, data->rules); - event_raise(EVENT_TYPE_CREATE, face, interface); + facelet_t * facelet = facelet_create_from_connection(cnx); + if (!facelet) + return; + facelet_set_event(facelet, FACELET_EVENT_CREATE); + facelet_raise_event(facelet, interface); break; } case nw_connection_state_failed: @@ -482,14 +480,11 @@ void on_interface_event(interface_t * interface, nw_interface_t iface) * This is the first time we have a connection with address and port * and thus the full identification of an hICN face */ - nf_data_t * data = (nf_data_t*)interface->data; - face_t * face = face_create_from_connection(connection, data->rules); - //event_raise(value ? EVENT_TYPE_SET_UP : EVENT_TYPE_SET_DOWN, face, interface); - if(value) { - event_raise(EVENT_TYPE_CREATE, face, interface); - } else { - event_raise(EVENT_TYPE_DELETE, face, interface); - } + facelet_t * facelet = facelet_create_from_connection(connection); + if (!facelet) + return; + facelet_set_event(facelet, value ? FACELET_EVENT_CREATE : FACELET_EVENT_DELETE); + facelet_raise_event(facelet, interface); }); @@ -528,13 +523,16 @@ void on_path_event(interface_t * interface, nw_path_t path) } -int nf_initialize(interface_t * interface, face_rules_t * rules, void ** pdata) +int nf_initialize(interface_t * interface, void * cfg) { nf_data_t * data = malloc(sizeof(nf_data_t)); if (!data) goto ERR_MALLOC; - data->rules = rules; + if (cfg) + data->cfg = * (network_framework_cfg_t *)cfg; + else + data->cfg.rules = NULL; data->pm = nw_path_monitor_create(); if (!data->pm) @@ -552,14 +550,13 @@ int nf_initialize(interface_t * interface, face_rules_t * rules, void ** pdata) DEBUG("Starting network path monitor"); nw_path_monitor_start(data->pm); - *pdata = data; - return FACEMGR_SUCCESS; + interface->data = data; + return 0; ERR_PM: free(data); ERR_MALLOC: - *pdata = NULL; - return FACEMGR_FAILURE; + return -1; } int nf_finalize(interface_t * interface) @@ -569,12 +566,11 @@ int nf_finalize(interface_t * interface) nw_path_monitor_cancel(data->pm); data->pm = NULL; } - return FACEMGR_SUCCESS; + return 0; } const interface_ops_t network_framework_ops = { .type = "network_framework", - .is_singleton = true, .initialize = nf_initialize, .finalize = nf_finalize, .on_event = NULL, diff --git a/ctrl/facemgr/src/face_cache.c b/ctrl/facemgr/src/interfaces/network_framework/network_framework.h index bee36af30..edb35e904 100644 --- a/ctrl/facemgr/src/face_cache.c +++ b/ctrl/facemgr/src/interfaces/network_framework/network_framework.h @@ -13,9 +13,10 @@ * limitations under the License. */ -#include "face_cache.h" - -#include "face.h" -#include "util/set.h" +/** + * \file network_framework.h + * \brief Network framework interface + */ -TYPEDEF_SET(face_cache, face_t *, face_cmp, face_snprintf); +typedef struct { +} network_framework_cfg_t; diff --git a/ctrl/facemgr/src/interfaces/updown/CMakeLists.txt b/ctrl/facemgr/src/interfaces/updown/CMakeLists.txt new file mode 100644 index 000000000..e5fd2167e --- /dev/null +++ b/ctrl/facemgr/src/interfaces/updown/CMakeLists.txt @@ -0,0 +1,31 @@ +# Copyright (c) 2017-2019 Cisco and/or its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +list(APPEND HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/updown.h +) + +list(APPEND SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/updown.c +) + +list(APPEND INCLUDE_DIRS +) + +list(APPEND LIBRARIES +) + +set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE) +set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE) +set(INCLUDE_DIRS ${INCLUDE_DIRS} PARENT_SCOPE) +set(LIBRARIES ${LIBRARIES} PARENT_SCOPE) diff --git a/ctrl/facemgr/src/interfaces/updown/updown.c b/ctrl/facemgr/src/interfaces/updown/updown.c new file mode 100644 index 000000000..f5a813cd4 --- /dev/null +++ b/ctrl/facemgr/src/interfaces/updown/updown.c @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file updown.c + * \brief Implementation of Example updown interface + */ + +#include <assert.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include <hicn/facemgr.h> + +#include "../../common.h" +#include "../../facelet.h" +#include "../../interface.h" + +/** + * \brief Default unix socket path (the leading \0 means using the abstract + * namespace instead of the filesystem). + */ +#define UNIX_PATH "\0updownsrv" + +typedef struct { + int fd; /* Unix client socket */ +} updown_data_t; + +int updown_initialize(interface_t * interface, void * cfg) +{ + struct sockaddr_un addr; + char * socket_path = UNIX_PATH; + + updown_data_t * data = malloc(sizeof(updown_data_t)); + if (!data) + goto ERR_MALLOC; + interface->data = data; + + data->fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (data->fd == -1) { + perror("socket error"); + return -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(data->fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) { + perror("connect error"); + return -1; + } + + return data->fd; + +ERR_MALLOC: + return -1; +} + +int updown_finalize(interface_t * interface) +{ + updown_data_t * data = (updown_data_t*)interface->data; + + if (data->fd > 0) + close(data->fd); + + return 0; +} + +int updown_callback(interface_t * interface) +{ + updown_data_t * data = (updown_data_t*)interface->data; + char buf[100]; + int rc; + + rc = read(data->fd, buf, sizeof(buf)); + if (rc < 0) + return -1; + + /* + * If the process is paused (eg. in a debugger, we might have more than one + * read. + * XXX how big is the buffer + * XXX shall we drain the queue if it exceeds buffer size ? + */ + //assert(rc == 1); + + /* Raise facelet update event */ + facelet_t * facelet = facelet_create(); + facelet_set_netdevice_type(facelet, NETDEVICE_TYPE_WIFI); //CELLULAR); + facelet_set_status(facelet, FACELET_STATUS_CLEAN); + switch(buf[0]) { + case '\0': + facelet_set_admin_state(facelet, FACE_STATE_DOWN); + break; + case '\1': + facelet_set_admin_state(facelet, FACE_STATE_UP); + break; + break; + default: + ERROR("Invalid data received from updown server. Ignoring..."); + facelet_free(facelet); + return -1; + } + + facelet_set_event(facelet, FACELET_EVENT_UPDATE); + + facelet_raise_event(facelet, interface); + + return 0; +} + +interface_ops_t updown_ops = { + .type = "updown", + .initialize = updown_initialize, + .finalize = updown_finalize, + .callback = updown_callback, +}; diff --git a/ctrl/facemgr/src/main.c b/ctrl/facemgr/src/main.c index 6a80d806b..2a336db8f 100644 --- a/ctrl/facemgr/src/main.c +++ b/ctrl/facemgr/src/main.c @@ -18,8 +18,21 @@ * \brief Face manager daemon entry point */ +#ifdef WITH_THREAD +#ifndef __linux__ +#error "Not implemented" +#endif /* __linux__ */ +#include <pthread.h> +#endif /* WITH_THREAD */ + +#ifndef __APPLE__ +#include <event2/event.h> +#include <event2/thread.h> +#endif /* __APPLE__ */ + #include <getopt.h> #include <limits.h> +#include <signal.h> #include <stdlib.h> #include <stdio.h> #include <string.h> @@ -27,20 +40,41 @@ #include <libconfig.h> -#include "util/log.h" -#include "util/policy.h" - #ifdef __APPLE__ #include <Dispatch/Dispatch.h> #else -// Note: we might want to use libevent on Apple too #include <event2/event.h> #endif -#include "facemgr.h" +#include <hicn/facemgr.h> +#include <hicn/policy.h> + +#include <hicn/util/ip_address.h> +#include <hicn/util/log.h> + +#include <hicn/facemgr/cfg.h> #define FACEMGR_TIMEOUT 3 +static struct event_base * loop; + +void facemgr_signal_handler(int signal) { + fprintf(stderr, "Received ^C... quitting !\n"); + exit(0); +#if 0 + return; + + // FIXME + + /* should be atomic */ + // FIXME Don't use loop in a static variable as we should not need it if all + // events are properly unregistered... +#endif +#ifdef __linux__ + event_base_loopbreak(loop); +#endif /* __linux__ */ + loop = NULL; +} static struct option long_options[] = { @@ -101,106 +135,305 @@ int parse_cmdline(int argc, char ** argv, facemgr_options_t * opts) return 0; } -int parse_config_file(const char * cfgpath, facemgr_t * facemgr) +int +parse_config_global(facemgr_cfg_t * cfg, config_setting_t * setting) { - /* Reading configuration file */ - config_t cfg; - config_setting_t *setting; + /* - face_type */ + + const char *face_type_str; + facemgr_face_type_t face_type; + if (config_setting_lookup_string(setting, "face_type", &face_type_str)) { + if (strcasecmp(face_type_str, "auto") == 0) { + face_type = FACEMGR_FACE_TYPE_DEFAULT; + } else + if (strcasecmp(face_type_str, "native-udp") == 0) { + face_type = FACEMGR_FACE_TYPE_NATIVE_UDP; + } else + if (strcasecmp(face_type_str, "native-tcp") == 0) { + face_type = FACEMGR_FACE_TYPE_NATIVE_TCP; + } else + if (strcasecmp(face_type_str, "overlay-udp") == 0) { + face_type = FACEMGR_FACE_TYPE_OVERLAY_UDP; + } else + if (strcasecmp(face_type_str, "overlay-tcp") == 0) { + face_type = FACEMGR_FACE_TYPE_OVERLAY_TCP; + } else { + ERROR("Invalid face type in section 'global'"); + return -1; + } - config_init(&cfg); + int rc = facemgr_cfg_set_face_type(cfg, &face_type); + if (rc < 0) + goto ERR; + } - /* Read the file. If there is an error, report it and exit. */ - if(!config_read_file(&cfg, cfgpath)) - goto ERR_FILE; + /* - disable_discovery */ - setting = config_lookup(&cfg, "log"); - if (setting) { - const char *log_level_str; - if (config_setting_lookup_string(setting, "log_level", &log_level_str)) { - if (strcmp(log_level_str, "FATAL") == 0) { - log_conf.log_level = LOG_FATAL; - } else - if (strcmp(log_level_str, "ERROR") == 0) { - log_conf.log_level = LOG_ERROR; - } else - if (strcmp(log_level_str, "WARN") == 0) { - log_conf.log_level = LOG_WARN; - } else - if (strcmp(log_level_str, "INFO") == 0) { - log_conf.log_level = LOG_INFO; - } else - if (strcmp(log_level_str, "DEBUG") == 0) { - log_conf.log_level = LOG_DEBUG; - } else - if (strcmp(log_level_str, "TRACE") == 0) { - log_conf.log_level = LOG_TRACE; - } else { - printf("Ignored unknown log level\n"); - } - } + int disable_discovery; + if (config_setting_lookup_bool(setting, "disable_discovery", + &disable_discovery)) { + int rc = facemgr_cfg_set_discovery(cfg, !disable_discovery); + if (rc < 0) + goto ERR; } - setting = config_lookup(&cfg, "faces.overlay.ipv4"); - if (setting) { - const char * ip_address; - int local_port, remote_port; - if (config_setting_lookup_int(setting, "local_port", &local_port)) { - if ((local_port < 0) || (local_port > MAX_PORT)) + /* - disable_ipv4 */ + + int disable_ipv4; + if (config_setting_lookup_bool(setting, "disable_ipv4", + &disable_ipv4)) { + INFO("Ignored setting 'disable_ipv4' in section 'global' (not implemented)."); +#if 0 + int rc = facemgr_cfg_set_ipv4(cfg, !disable_ipv4); + if (rc < 0) + goto ERR; +#endif + } + + /* - disable ipv6 */ + + int disable_ipv6; + if (config_setting_lookup_bool(setting, "disable_ipv6", + &disable_ipv6)) { + INFO("Ignored setting 'disable_ipv6' in section 'global': (not implemented)."); +#if 0 + int rc = facemgr_cfg_set_ipv6(cfg, !disable_ipv6); + if (rc < 0) + goto ERR; +#endif + } + + /* - overlay */ + config_setting_t *overlay = config_setting_get_member(setting, "overlay"); + if (overlay) { + + /* ipv4 */ + config_setting_t *overlay_v4 = config_setting_get_member(overlay, "ipv4"); + if (overlay_v4) { + const char * local_addr_str, * remote_addr_str; + ip_address_t local_addr, remote_addr; + ip_address_t * local_addr_p = NULL; + ip_address_t * remote_addr_p = NULL; + int local_port = 0; + int remote_port = 0; + + if (config_setting_lookup_string(overlay_v4, "local_addr", &local_addr_str)) { + ip_address_pton(local_addr_str, &local_addr); + local_addr_p = &local_addr; + } + + if (config_setting_lookup_int(overlay_v4, "local_port", &local_port)) { + if (!IS_VALID_PORT(local_port)) + goto ERR; + } + + if (config_setting_lookup_string(overlay_v4, "remote_addr", &remote_addr_str)) { + ip_address_pton(remote_addr_str, &remote_addr); + remote_addr_p = &remote_addr; + } + + if (config_setting_lookup_int(overlay_v4, "remote_port", &remote_port)) { + if (!IS_VALID_PORT(remote_port)) + goto ERR; + } + int rc = facemgr_cfg_set_overlay(cfg, AF_INET, + local_addr_p, local_port, + remote_addr_p, remote_port); + if (rc < 0) goto ERR; - facemgr->overlay_v4_local_port = (uint16_t)local_port; } - if (config_setting_lookup_int(setting, "remote_port", &remote_port)) { - if ((remote_port < 0) || (remote_port > MAX_PORT)) + /* ipv6 */ + config_setting_t *overlay_v6 = config_setting_get_member(overlay, "ipv6"); + if (overlay_v6) { + const char * local_addr_str, * remote_addr_str; + ip_address_t local_addr, remote_addr; + ip_address_t * local_addr_p = NULL; + ip_address_t * remote_addr_p = NULL; + int local_port = 0; + int remote_port = 0; + + if (config_setting_lookup_string(overlay_v6, "local_addr", &local_addr_str)) { + ip_address_pton(local_addr_str, &local_addr); + local_addr_p = &local_addr; + } + + if (config_setting_lookup_int(overlay_v6, "local_port", &local_port)) { + if (!IS_VALID_PORT(local_port)) + goto ERR; + } + + if (config_setting_lookup_string(overlay_v6, "remote_addr", &remote_addr_str)) { + ip_address_pton(remote_addr_str, &remote_addr); + remote_addr_p = &remote_addr; + } + + if (config_setting_lookup_int(overlay_v6, "remote_port", &remote_port)) { + if (!IS_VALID_PORT(remote_port)) + goto ERR; + } + int rc = facemgr_cfg_set_overlay(cfg, AF_INET6, + local_addr_p, local_port, + remote_addr_p, remote_port); + if (rc < 0) goto ERR; - facemgr->overlay_v4_remote_port = (uint16_t)remote_port; } - if (config_setting_lookup_string(setting, "remote_addr", &ip_address)) { - ip_address_pton(ip_address, &facemgr->overlay_v4_remote_addr); - printf("got v4 remote addr\n"); + } /* overlay */ + + return 0; + +ERR: + return -1; +} + +int +parse_config_rules(facemgr_cfg_t * cfg, config_setting_t * setting) +{ + /* List of match-override tuples */ + facemgr_cfg_rule_t * rule; + + int count = config_setting_length(setting); + for (unsigned i = 0; i < count; ++i) { + config_setting_t * rule_setting = config_setting_get_elem(setting, i); + + /* Sanity check */ + + config_setting_t * match_setting = config_setting_get_member(rule_setting, "match"); + if (!match_setting) { + ERROR("Missing match section in rule #%d", i); + goto ERR_CHECK; } - } - setting = config_lookup(&cfg, "faces.overlay.ipv6"); - if (setting) { - const char * ip_address; - int local_port, remote_port; - if (config_setting_lookup_int(setting, "local_port", &local_port)) { - if ((local_port < 0) || (local_port > MAX_PORT)) + config_setting_t * override_setting = config_setting_get_member(rule_setting, "override"); + if (!override_setting) { + ERROR("Missing override section in rule #%d", i); + goto ERR_CHECK; + } + + rule = facemgr_cfg_rule_create(); + if (!rule) + goto ERR_RULE; + + /* Parse match */ + + const char * interface_name = NULL; + config_setting_lookup_string(match_setting, "interface_name", &interface_name); + + const char * interface_type_str; + netdevice_type_t interface_type = NETDEVICE_TYPE_UNDEFINED; + if (config_setting_lookup_string(match_setting, "interface_type", &interface_type_str)) { + if (strcasecmp(interface_type_str, "wired") == 0) { + interface_type = NETDEVICE_TYPE_WIRED; + } else + if (strcasecmp(interface_type_str, "wifi") == 0) { + interface_type = NETDEVICE_TYPE_WIFI; + } else + if (strcasecmp(interface_type_str, "cellular") == 0) { + interface_type = NETDEVICE_TYPE_CELLULAR; + } else { + ERROR("Unknown interface type in rule #%d", i); goto ERR; - facemgr->overlay_v6_local_port = (uint16_t)local_port; + } } - if (config_setting_lookup_int(setting, "remote_port", &remote_port)) { - if ((remote_port < 0) || (remote_port > MAX_PORT)) + if ((!interface_name) && (interface_type == NETDEVICE_TYPE_UNDEFINED)) { + ERROR("Empty match section in rule #%d", i); + goto ERR; + } + + /* Associate match to rule */ + + int rc = facemgr_cfg_rule_set_match(rule, interface_name, interface_type); + if (rc < 0) + goto ERR; + + /* Parse override */ + + /* - face_type */ + + const char *face_type_str; + facemgr_face_type_t face_type; + if (config_setting_lookup_string(override_setting, "face_type", &face_type_str)) { + if (strcasecmp(face_type_str, "auto")) { + /* We currently hardcode different behaviours based on the OS */ +#ifdef __ANDROID__ + face_type = FACEMGR_FACE_TYPE_OVERLAY_UDP; +#else + face_type = FACEMGR_FACE_TYPE_NATIVE_TCP; +#endif + } else + if (strcasecmp(face_type_str, "native-udp") == 0) { + face_type = FACEMGR_FACE_TYPE_NATIVE_UDP; + } else + if (strcasecmp(face_type_str, "native-tcp") == 0) { + face_type = FACEMGR_FACE_TYPE_NATIVE_TCP; + } else + if (strcasecmp(face_type_str, "overlay-udp") == 0) { + face_type = FACEMGR_FACE_TYPE_OVERLAY_UDP; + } else + if (strcasecmp(face_type_str, "overlay-tcp") == 0) { + face_type = FACEMGR_FACE_TYPE_OVERLAY_TCP; + } else { + ERROR("Invalid face type in section 'global'"); + return -1; + } + + int rc = facemgr_cfg_rule_set_face_type(rule, &face_type); + if (rc < 0) goto ERR; - facemgr->overlay_v6_remote_port = (uint16_t)remote_port; } - if (config_setting_lookup_string(setting, "remote_addr", &ip_address)) - ip_address_pton(ip_address, &facemgr->overlay_v6_remote_addr); - } + /* - disable_discovery */ - setting = config_lookup(&cfg, "faces.rules"); - if (setting) { - int count = config_setting_length(setting); - for(unsigned i = 0; i < count; ++i) { - const char *interface_name; - policy_tags_t tags = POLICY_TAGS_EMPTY; + int disable_discovery; + if (config_setting_lookup_bool(override_setting, "disable_discovery", + &disable_discovery)) { + int rc = facemgr_cfg_rule_set_discovery(rule, !disable_discovery); + if (rc < 0) + goto ERR; + } - config_setting_t *rule = config_setting_get_elem(setting, i); + /* - disable_ipv4 */ - /* Interface name */ - if(!(config_setting_lookup_string(rule, "name", &interface_name))) - continue; + int disable_ipv4; + if (config_setting_lookup_bool(override_setting, "disable_ipv4", + &disable_ipv4)) { + INFO("Ignored setting 'disable_ipv4' in rule #%d (not implemented).", i); +#if 0 + int rc = facemgr_cfg_rule_set_ipv4(rule, !disable_ipv4); + if (rc < 0) + goto ERR; +#endif + } - /* Associated tags */ - config_setting_t *tag_settings = config_setting_get_member(rule, "tags"); - if (!tag_settings) + /* - disable ipv6 */ + + int disable_ipv6; + if (config_setting_lookup_bool(override_setting, "disable_ipv6", + &disable_ipv6)) { + INFO("Ignored setting 'disable_ipv6' in rule #%d (not implemented).", i); +#if 0 + int rc = facemgr_cfg_rule_set_ipv6(rule, !disable_ipv6); + if (rc < 0) goto ERR; +#endif + } + /* - ignore */ + int ignore; + if (config_setting_lookup_bool(override_setting, "ignore", &ignore)) { + int rc = facemgr_cfg_rule_set_ignore(rule, !!ignore); + if (rc < 0) + goto ERR; + } + /* - tags */ + config_setting_t *tag_settings = config_setting_get_member(override_setting, "tags"); + if (tag_settings) { + INFO("Ignored setting 'tags' in rule #%d (not implemented).", i); +#if 0 + policy_tags_t tags = POLICY_TAGS_EMPTY; for (unsigned j = 0; j < config_setting_length(tag_settings); j++) { const char * tag_str = config_setting_get_string_elem(tag_settings, j); policy_tag_t tag = policy_tag_from_str(tag_str); @@ -209,41 +442,267 @@ int parse_config_file(const char * cfgpath, facemgr_t * facemgr) policy_tags_add(&tags, tag); } - /* debug */ + int rc = facemgr_cfg_rule_set_tags(rule, tags); + if (rc < 0) + goto ERR; + +#if 0 char tags_str[MAXSZ_POLICY_TAGS]; policy_tags_snprintf(tags_str, MAXSZ_POLICY_TAGS, tags); - printf("Rule #%d interface_name=%s, tags=%s\n", i, interface_name, tags_str); - face_rules_add(&facemgr->rules, strdup(interface_name), tags); + DEBUG("Added tags tags=%s", tags_str); +#endif +#endif } + + /* - overlay */ + config_setting_t *overlay = config_setting_get_member(override_setting, "overlay"); + if (overlay) { + + /* ipv4 */ + config_setting_t *overlay_v4 = config_setting_get_member(overlay, "ipv4"); + if (overlay_v4) { + const char * local_addr_str, * remote_addr_str; + ip_address_t local_addr, remote_addr; + ip_address_t * local_addr_p = NULL; + ip_address_t * remote_addr_p = NULL; + int local_port = 0; + int remote_port = 0; + + if (config_setting_lookup_string(overlay_v4, "local_addr", &local_addr_str)) { + ip_address_pton(local_addr_str, &local_addr); + local_addr_p = &local_addr; + } + + if (config_setting_lookup_int(overlay_v4, "local_port", &local_port)) { + if (!IS_VALID_PORT(local_port)) + goto ERR; + } + + if (config_setting_lookup_string(overlay_v4, "remote_addr", &remote_addr_str)) { + ip_address_pton(remote_addr_str, &remote_addr); + remote_addr_p = &remote_addr; + } + + if (config_setting_lookup_int(overlay_v4, "remote_port", &remote_port)) { + if (!IS_VALID_PORT(remote_port)) + goto ERR; + } + int rc = facemgr_cfg_rule_set_overlay(rule, AF_INET, + local_addr_p, local_port, + remote_addr_p, remote_port); + if (rc < 0) + goto ERR; + } + + /* ipv6 */ + config_setting_t *overlay_v6 = config_setting_get_member(overlay, "ipv6"); + if (overlay_v6) { + const char * local_addr_str, * remote_addr_str; + ip_address_t local_addr, remote_addr; + ip_address_t * local_addr_p = NULL; + ip_address_t * remote_addr_p = NULL; + int local_port = 0; + int remote_port = 0; + + if (config_setting_lookup_string(overlay_v6, "local_addr", &local_addr_str)) { + ip_address_pton(local_addr_str, &local_addr); + local_addr_p = &local_addr; + } + + if (config_setting_lookup_int(overlay_v6, "local_port", &local_port)) { + if (!IS_VALID_PORT(local_port)) + goto ERR; + } + + if (config_setting_lookup_string(overlay_v6, "remote_addr", &remote_addr_str)) { + ip_address_pton(remote_addr_str, &remote_addr); + remote_addr_p = &remote_addr; + } + + if (config_setting_lookup_int(overlay_v6, "remote_port", &remote_port)) { + if (!IS_VALID_PORT(remote_port)) + goto ERR; + } + int rc = facemgr_cfg_rule_set_overlay(rule, AF_INET6, + local_addr_p, local_port, + remote_addr_p, remote_port); + if (rc < 0) + goto ERR; + } + + } /* overlay */ + + /* Add newly created rule */ + + rc = facemgr_cfg_add_rule(cfg, rule); + if (rc < 0) + goto ERR; } + return 0; + +ERR: + facemgr_cfg_rule_free(rule); +ERR_RULE: +ERR_CHECK: + return -1; +} - config_destroy(&cfg); +/* Currently not using facemgr_cfg_t */ +int +parse_config_log(facemgr_cfg_t * cfg, config_setting_t * setting) +{ + const char *log_level_str; + if (config_setting_lookup_string(setting, "log_level", &log_level_str)) { + if (strcasecmp(log_level_str, "FATAL") == 0) { + log_conf.log_level = LOG_FATAL; + } else + if (strcasecmp(log_level_str, "ERROR") == 0) { + log_conf.log_level = LOG_ERROR; + } else + if (strcasecmp(log_level_str, "WARN") == 0) { + log_conf.log_level = LOG_WARN; + } else + if (strcasecmp(log_level_str, "INFO") == 0) { + log_conf.log_level = LOG_INFO; + } else + if (strcasecmp(log_level_str, "DEBUG") == 0) { + log_conf.log_level = LOG_DEBUG; + } else + if (strcasecmp(log_level_str, "TRACE") == 0) { + log_conf.log_level = LOG_TRACE; + } else { + ERROR("Invalid log level in section 'log'"); + return -1; + } + } + return 0; +} + +int +parse_config_file(const char * cfgpath, facemgr_cfg_t * cfg) +{ + /* Reading configuration file */ + config_t cfgfile; + config_setting_t *setting; + + config_init(&cfgfile); + + /* Read the file. If there is an error, report it and exit. */ + if(!config_read_file(&cfgfile, cfgpath)) + goto ERR_FILE; + + setting = config_lookup(&cfgfile, "global"); + if (setting) { + int rc = parse_config_global(cfg, setting); + if (rc < 0) + goto ERR_PARSE; + } + + setting = config_lookup(&cfgfile, "rules"); + if (setting) { + int rc = parse_config_rules(cfg, setting); + if (rc < 0) + goto ERR_PARSE; + } + + setting = config_lookup(&cfgfile, "log"); + if (setting) { + int rc = parse_config_log(cfg, setting); + if (rc < 0) + goto ERR_PARSE; + } + + config_destroy(&cfgfile); return 0; ERR_FILE: - printf("Could not read configuration file %s\n", cfgpath); - fprintf(stderr, "%s:%d - %s\n", config_error_file(&cfg), - config_error_line(&cfg), config_error_text(&cfg)); - config_destroy(&cfg); + ERROR("Could not read configuration file %s", cfgpath); + fprintf(stderr, "%s:%d - %s\n", config_error_file(&cfgfile), + config_error_line(&cfgfile), config_error_text(&cfgfile)); + config_destroy(&cfgfile); exit(EXIT_FAILURE); return -1; -ERR: - fprintf(stderr, "%s:%d - %s\n", config_error_file(&cfg), - config_error_line(&cfg), config_error_text(&cfg)); - config_destroy(&cfg); +ERR_PARSE: + fprintf(stderr, "%s:%d - %s\n", config_error_file(&cfgfile), + config_error_line(&cfgfile), config_error_text(&cfgfile)); + config_destroy(&cfgfile); return -1; } -#ifndef APPLE -void dummy_handler(int fd, short event, void *arg) { } -#endif /* APPLE */ +#ifdef __linux__ +typedef struct { + void (*cb)(void *, ...); + void * args; +} cb_wrapper_args_t; + +void cb_wrapper(evutil_socket_t fd, short what, void * arg) { + cb_wrapper_args_t * cb_wrapper_args = arg; + cb_wrapper_args->cb(cb_wrapper_args->args); +} -int main(int argc, char **argv) +struct event * +loop_register_fd(struct event_base * loop, int fd, void * cb, void * cb_args) { - facemgr_t * facemgr = facemgr_create(); - if (!facemgr) - goto ERR_FACEMGR; + // TODO: not freed + cb_wrapper_args_t * cb_wrapper_args = malloc(sizeof(cb_wrapper_args_t)); + *cb_wrapper_args = (cb_wrapper_args_t) { + .cb = cb, + .args = cb_args, + }; + + evutil_make_socket_nonblocking(fd); + struct event * event = event_new(loop, fd, EV_READ | EV_PERSIST, cb_wrapper, cb_wrapper_args); + if (!event) + goto ERR_EVENT_NEW; + + if (event_add(event, NULL) < 0) + goto ERR_EVENT_ADD; + + return event; + +ERR_EVENT_ADD: + event_free(event); +ERR_EVENT_NEW: + return NULL; +} + +int +loop_unregister_event(struct event_base * loop, struct event * event) +{ + if (!event) + return 0; + + event_del(event); + event_free(event); + + return 0; +} + + +void * start_dispatch(void * loop_ptr) +{ + struct event_base * loop = (struct event_base *) loop_ptr; + event_base_dispatch(loop); + + return NULL; +} + +#endif /* __linux__ */ + +int main(int argc, char ** argv) +{ + facemgr_cfg_t * cfg = NULL; + facemgr_t * facemgr; +#ifdef WITH_THREAD + pthread_t facemgr_thread; +#endif /* WITH_THREAD */ + + struct sigaction sigIntHandler; + sigIntHandler.sa_handler = facemgr_signal_handler; + sigemptyset(&sigIntHandler.sa_mask); + sigIntHandler.sa_flags = 0; + sigaction(SIGINT, &sigIntHandler, NULL); char cfgfile[PATH_MAX]; @@ -252,7 +711,7 @@ int main(int argc, char **argv) /* Commandline */ facemgr_options_t cmdline_opts = {0}; if (parse_cmdline(argc, argv, &cmdline_opts) < 0) { - ERROR("Error parsing commandline\n"); + ERROR("Error parsing commandline"); goto ERR_CMDLINE; } @@ -260,7 +719,7 @@ int main(int argc, char **argv) //facemgr_options_t cfgfile_opts; if (cmdline_opts.cfgfile) { - if (strcmp(cmdline_opts.cfgfile, "none") == 0) + if (strcasecmp(cmdline_opts.cfgfile, "none") == 0) goto NO_CFGFILE; if (!realpath(cmdline_opts.cfgfile, (char*)&cfgfile)) @@ -274,76 +733,118 @@ int main(int argc, char **argv) if (probe_cfgfile(cfgfile) < 0) goto NO_CFGFILE; - printf("Using configuration file %s\n", cfgfile); - PARSE_CFGFILE: - if (parse_config_file(cfgfile, facemgr) < 0) { - ERROR("Error parsing configuration file %s\n", cfgfile); + DEBUG("Using configuration file %s", cfgfile); + cfg = facemgr_cfg_create(); + if (!cfg) + goto ERR_FACEMGR_CFG; + + if (parse_config_file(cfgfile, cfg) < 0) { + ERROR("Error parsing configuration file %s", cfgfile); goto ERR_PARSE; } + facemgr = facemgr_create_with_config(cfg); + if (!facemgr) + goto ERR_FACEMGR_CONFIG; + + goto MAIN_LOOP; + NO_CFGFILE: + facemgr = facemgr_create(); + if (!facemgr) + goto ERR_FACEMGR; + +MAIN_LOOP: + + /* Main loop */ + + +#ifdef WITH_THREAD + evthread_use_pthreads(); +#endif /* WITH_THREAD */ + #ifdef __linux__ - facemgr->loop = event_base_new(); - if (!facemgr->loop) - fatal("Could not create an event base"); - - /* Main loop - * - * To avoid the loop to exit when empty, we might either rely on an option - * introduced from versions 2.1.x: - * event_base_loop(loop->base, EVLOOP_NO_EXIT_ON_EMPTY); - * or use this workaround: - * http://archives.seul.org/libevent/users/Sep-2012/msg00056.html - * - * TODO: - * - HUP should interrupt the main loop - */ - { - struct event *ev; - struct timeval tv; - tv.tv_sec = FACEMGR_TIMEOUT; - tv.tv_usec = 0; - - ev = event_new(facemgr->loop, fileno(stdin), EV_TIMEOUT | EV_PERSIST, dummy_handler, NULL); - event_add(ev, &tv); - } + /* Event loop */ + loop = event_base_new(); + if (!loop) + goto ERR_EVENT; + + facemgr_set_event_loop_handler(facemgr, loop, loop_register_fd, loop_unregister_event); #endif /* __linux__ */ - DEBUG("Bootstrap...\n"); +#ifdef __ANDROID__ + facemgr_set_jvm(facemgr, NULL, NULL); // FIXME +#endif /* __ ANDROID__ */ + + DEBUG("Bootstrap..."); + if (facemgr_bootstrap(facemgr) < 0 ) goto ERR_BOOTSTRAP; #ifdef __linux__ event_set_log_callback(NULL); - event_base_dispatch(facemgr->loop); - event_base_free(facemgr->loop); +#ifdef WITH_THREAD + if (pthread_create(&facemgr_thread, NULL, start_dispatch, loop)) { + fprintf(stderr, "Error creating thread\n"); + return EXIT_FAILURE; + } +#else + event_base_dispatch(loop); +#endif /* WITH_THREAD */ + #endif /* __linux__ */ #ifdef __APPLE__ /* Main loop */ - facemgr->loop = NULL; dispatch_main(); #endif /* __APPLE__ */ - /* Clean up */ - //interface_delete_all(); +#ifdef __linux__ +#ifdef WITH_THREAD + for(;;) { + facemgr_list_faces(facemgr, NULL, NULL); + sleep(5); + } +#endif /* WITH_THREAD */ +#endif /* __linux__ */ + + facemgr_stop(facemgr); +#ifdef __linux__ +#ifdef WITH_THREAD + DEBUG("Waiting for loop to terminate..."); + if(pthread_join(facemgr_thread, NULL)) { + fprintf(stderr, "Error joining thread\n"); + return EXIT_FAILURE; + } + DEBUG("Loop terminated !"); +#endif /* WITH_THREAD */ +#endif /* __linux__ */ facemgr_free(facemgr); return EXIT_SUCCESS; ERR_BOOTSTRAP: +#ifdef __linux__ +ERR_EVENT: +#endif /* __linux__ */ + + facemgr_free(facemgr); +ERR_FACEMGR_CONFIG: + if (cfg) + facemgr_cfg_free(cfg); +ERR_FACEMGR: +ERR_FACEMGR_CFG: + ERR_PARSE: ERR_PATH: ERR_CMDLINE: - facemgr_free(facemgr); -ERR_FACEMGR: return EXIT_FAILURE; -} +} diff --git a/ctrl/facemgr/src/netdevice.h b/ctrl/facemgr/src/netdevice.h deleted file mode 100644 index b64ad0f9a..000000000 --- a/ctrl/facemgr/src/netdevice.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * \file netdevice.h - * \brief Netdevice abstraction - */ -#ifndef FACEMGR_NETDEVICE_H -#define FACEMGR_NETDEVICE_H - -#include <net/if.h> // IFNAMSIZ - -#include "common.h" - -#define foreach_netdevice_type \ - _(UNDEFINED) \ - _(WIRED) \ - _(WIFI) \ - _(CELLULAR) \ - _(VPN) \ - _(N) - -#define MAXSZ_NETDEVICE_TYPE 9 -#define MAXSZ_NETDEVICE_TYPE_ MAXSZ_NETDEVICE_TYPE - -typedef enum { -#define _(x) x, -foreach_netdevice_type -#undef _ -} netdevice_type_t; - -extern const char * netdevice_type_str[]; - - -typedef struct { - u32 index; - char name[IFNAMSIZ]; -} netdevice_t; - -#endif /* FACEMGR_NETDEVICE_H */ diff --git a/ctrl/facemgr/src/util/ip_address.h b/ctrl/facemgr/src/util/ip_address.h deleted file mode 100644 index 243ce048b..000000000 --- a/ctrl/facemgr/src/util/ip_address.h +++ /dev/null @@ -1,328 +0,0 @@ -/* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * \file ip_address.h - * \brief IP address type support - */ -#ifndef UTIL_IP_ADDRESS_H -#define UTIL_IP_ADDRESS_H - -#include <arpa/inet.h> // inet_ntop -#ifdef __APPLE__ -#include <libkern/OSByteOrder.h> -#define __bswap_constant_32(x) OSSwapInt32(x) -#include <machine/endian.h> -#else -#include <endian.h> -#ifdef __ANDROID__ -#include <byteswap.h> -#endif -#endif -#include <errno.h> -#include <netdb.h> // struct addrinfo -#include <netinet/in.h> // INET*_ADDRSTRLEN, IN*ADDR_LOOPBACK -#include <stdlib.h> -#include <stdio.h> // snprintf -#include <string.h> // memset - -#include "types.h" - -#define bytes_to_bits(x) (x * 8) -#define IPV6_ADDR_LEN 16 /* bytes */ -#define IPV4_ADDR_LEN 4 /* bytes */ -#define IPV6_ADDR_LEN_BITS bytes_to_bits(IPV6_ADDR_LEN) -#define IPV4_ADDR_LEN_BITS bytes_to_bits(IPV4_ADDR_LEN) - -#define IP_MAX_ADDR_LEN IPV6_ADDR_LEN - -#define DUMMY_PORT 1234 - -typedef union { - union { - struct in_addr as_inaddr; - u8 as_u8[4]; - u16 as_u16[2]; - u32 as_u32; - } v4; - union { - struct in6_addr as_in6addr; - u8 as_u8[16]; - u16 as_u16[8]; - u32 as_u32[4]; - u64 as_u64[2]; - } v6; - u8 buffer[IP_MAX_ADDR_LEN]; - u8 as_u8[IP_MAX_ADDR_LEN]; - u16 as_u16[IP_MAX_ADDR_LEN >> 1]; - u32 as_u32[IP_MAX_ADDR_LEN >> 2]; - u64 as_u64[IP_MAX_ADDR_LEN >> 3]; -} ip_address_t; - -#define MAXSZ_IP4_ADDRESS_ INET_ADDRSTRLEN - 1 -#define MAXSZ_IP6_ADDRESS_ INET6_ADDRSTRLEN - 1 -#define MAXSZ_IP_ADDRESS_ MAXSZ_IP6_ADDRESS_ -#define MAXSZ_IP4_ADDRESS MAXSZ_IP4_ADDRESS_ + 1 -#define MAXSZ_IP6_ADDRESS MAXSZ_IP6_ADDRESS_ + 1 -#define MAXSZ_IP_ADDRESS MAXSZ_IP_ADDRESS_ + 1 - -typedef struct { - int family; - ip_address_t address; - u8 len; -} ip_prefix_t; - -#define MAXSZ_PREFIX_ MAXSZ_IP_ADDRESS_ + 1 + 3 -#define MAXSZ_PREFIX MAXSZ_PREFIX_ + 1 - -/* No htonl() with const */ -static const ip_address_t IPV4_LOOPBACK = { -#if __BYTE_ORDER == __LITTLE_ENDIAN -#ifdef __ANDROID__ - .v4.as_inaddr.s_addr = bswap_32(INADDR_LOOPBACK), -#else - .v4.as_inaddr.s_addr = __bswap_constant_32(INADDR_LOOPBACK), -#endif -#else - .v4.as_inaddr.s_addr = INADDR_LOOPBACK, -#endif -}; - -static const ip_address_t IPV6_LOOPBACK = { - .v6.as_in6addr = IN6ADDR_LOOPBACK_INIT, -}; - -static const ip_address_t IPV4_ANY = { - .v4.as_inaddr.s_addr = INADDR_ANY, -}; - -static const ip_address_t IPV6_ANY = { - .v6.as_in6addr = IN6ADDR_ANY_INIT, -}; - -#define IP_ANY(family) (family == AF_INET) ? IPV4_ANY : IPV6_ANY - -static const ip_address_t IP_ADDRESS_EMPTY = { - .as_u64 = { 0 }, -}; - - -#define MAX_PORT 1 << (8 * sizeof(u16)) -#define IS_VALID_PORT(x) ((x > 0) && (x < MAX_PORT)) - -#define MAXSZ_PORT_ 5 -#define MAXSZ_PORT MAXSZ_PORT_ + 1 - -#define IS_VALID_FAMILY(x) ((x == AF_INET) || (x == AF_INET6)) - -static inline -int -ip_address_get_family (const char * ip_address) -{ - struct addrinfo hint, *res = NULL; - int rc; - - memset (&hint, '\0', sizeof hint); - - hint.ai_family = PF_UNSPEC; - hint.ai_flags = AI_NUMERICHOST; - - rc = getaddrinfo (ip_address, NULL, &hint, &res); - if (rc) - { - return -1; - } - rc = res->ai_family; - freeaddrinfo (res); - return rc; -} - -static inline -int -ip_address_len (const ip_address_t * ip_address, int family) -{ - return (family == AF_INET6) ? IPV6_ADDR_LEN : - (family == AF_INET) ? IPV4_ADDR_LEN : 0; -} - -static inline -int -ip_address_ntop (const ip_address_t * ip_address, char *dst, const size_t len, - int family) -{ - const char * s = inet_ntop (family, ip_address->buffer, dst, len); - return (s ? 1 : -1); -} - -/* - * Parse ip addresses in presentation format - */ -static inline -int -ip_address_pton (const char *ip_address_str, ip_address_t * ip_address) -{ - int pton_fd; - char *addr = strdup (ip_address_str); - int family; - - - family = ip_address_get_family (addr); - - switch (family) - { - case AF_INET6: - pton_fd = inet_pton (AF_INET6, addr, &ip_address->buffer); - break; - case AF_INET: - pton_fd = inet_pton (AF_INET, addr, &ip_address->buffer); - break; - default: - goto ERR; - } - - // 0 = not in presentation format - // < 0 = other error (use perror) - if (pton_fd <= 0) - { - goto ERR; - } - - return 1; -ERR: - free (addr); - return -1; -} - - - -static inline -int -ip_address_snprintf(char * s, size_t size, const ip_address_t * ip_address, int family) -{ - size_t len = family == AF_INET ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN; - const char * rc = inet_ntop (family, ip_address->buffer, s, len); - return rc ? strlen(rc) : -1; -} - - -static inline -int -ip_address_to_sockaddr(const ip_address_t * ip_address, - struct sockaddr *sockaddr_address, int family) -{ - struct sockaddr_in6 *tmp6 = (struct sockaddr_in6 *) sockaddr_address; - struct sockaddr_in *tmp4 = (struct sockaddr_in *) sockaddr_address; - - switch (family) - { - case AF_INET6: - tmp6->sin6_family = AF_INET6; - tmp6->sin6_port = DUMMY_PORT; - tmp6->sin6_scope_id = 0; - memcpy (&tmp6->sin6_addr, ip_address->buffer, IPV6_ADDR_LEN); - break; - case AF_INET: - tmp4->sin_family = AF_INET; - tmp4->sin_port = DUMMY_PORT; - memcpy (&tmp4->sin_addr, ip_address->buffer, IPV4_ADDR_LEN); - break; - default: - return -1; - } - - return 1; -} - -static inline -int -ip_address_cmp(const ip_address_t * ip1, const ip_address_t * ip2, int family) -{ - return memcmp(ip1, ip2, ip_address_len(ip1, family)); -} - -static inline -int -ip_address_empty(const ip_address_t * ip) -{ - return (memcmp(ip, &IP_ADDRESS_EMPTY, sizeof(IP_ADDRESS_EMPTY)) == 0); -} - -/* Parse IP Prefixes in presentation format (in bits, separated by a slash) */ -static inline -int -ip_prefix_pton (const char *ip_address_str, ip_prefix_t * ip_prefix) -{ - int pton_fd; - char *p; - char *eptr; - char *addr = strdup (ip_address_str); - - p = strchr (addr, '/'); - if (!p) - { - ip_prefix->len = 0; // until we get the ip address family - } - else - { - ip_prefix->len = strtoul (p + 1, &eptr, 10); - *p = 0; - } - - ip_prefix->family = ip_address_get_family (addr); - - switch (ip_prefix->family) - { - case AF_INET6: - if (ip_prefix->len > IPV6_ADDR_LEN_BITS) - goto ERR; - pton_fd = inet_pton (AF_INET6, addr, &ip_prefix->address.buffer); - break; - case AF_INET: - if (ip_prefix->len > IPV4_ADDR_LEN_BITS) - goto ERR; - pton_fd = inet_pton (AF_INET, addr, &ip_prefix->address.buffer); - break; - default: - goto ERR; - } - - // 0 = not in presentation format - // < 0 = other error (use perror) - if (pton_fd <= 0) - { - goto ERR; - } - - return 1; -ERR: - free (addr); - return -1; -} - -static inline -int -ip_prefix_ntop (const ip_prefix_t * ip_prefix, char *dst, size_t size) -{ - char ip_s[MAXSZ_IP_ADDRESS]; - const char * s = inet_ntop (ip_prefix->family, ip_prefix->address.buffer, ip_s, MAXSZ_IP_ADDRESS); - if (!s) - return -1; - size_t n = snprintf(dst, size, "%s/%d", ip_s, ip_prefix->len); - - return (n > 0 ? 1 : -1); -} - - -#endif /* UTIL_IP_ADDRESS_H */ diff --git a/ctrl/facemgr/src/util/log.c b/ctrl/facemgr/src/util/log.c index 54943cf45..c1fc999ad 100644 --- a/ctrl/facemgr/src/util/log.c +++ b/ctrl/facemgr/src/util/log.c @@ -13,12 +13,16 @@ * limitations under the License. */ -#include "log.h" +#include <hicn/util/log.h> #include <stdarg.h> #include <stdlib.h> #include <stdio.h> +#ifdef __ANDROID__ +#include <android/log.h> +#endif + log_conf_t log_conf = DEFAULT_LOG_CONF; #define FMT_DATETIME "%02d-%02d-%04d %02d:%02d:%02d" @@ -43,48 +47,96 @@ static char *timestamp(void) } void _log_va(int level, const char *fmt, va_list ap) -{ - char *prefix; - FILE *f = log_conf.log_file ? log_conf.log_file : stdout; +{ #if 0 if (!conf.log_system) return; #endif + char *prefix; + +#ifdef __ANDROID__ + int prio = -1; if (level > log_conf.log_level) return; switch (level) { case LOG_FATAL: + prio = ANDROID_LOG_FATAL; prefix = "FATAL: "; break; case LOG_ERROR: + prio = ANDROID_LOG_ERROR; prefix = "ERROR: "; break; case LOG_WARN: + prio = ANDROID_LOG_WARN; prefix = "WARNING: "; break; case LOG_INFO: + prio = ANDROID_LOG_INFO; prefix = ""; break; case LOG_DEBUG: + prio = ANDROID_LOG_DEBUG; prefix = "DEBUG: "; break; case LOG_TRACE: + prio = ANDROID_LOG_DEBUG; prefix = "TRACE: "; break; default: + prio = ANDROID_LOG_INFO; prefix = ""; break; } + if (log_conf.log_file) { + FILE *f = log_conf.log_file; + fprintf(f, "%s %s", timestamp(), prefix); + vfprintf(f, fmt, ap); + fprintf(f, "\n"); + } else { + __android_log_vprint(ANDROID_LOG_INFO, "HICN FACEMGR", fmt, ap); + } + +#else + + if (level > log_conf.log_level) + return; + + switch (level) { + case LOG_FATAL: + prefix = "FATAL: "; + break; + case LOG_ERROR: + prefix = "ERROR: "; + break; + case LOG_WARN: + prefix = "WARNING: "; + break; + case LOG_INFO: + prefix = ""; + break; + case LOG_DEBUG: + prefix = "DEBUG: "; + break; + case LOG_TRACE: + prefix = "TRACE: "; + break; + default: + prefix = ""; + break; + } + FILE *f = log_conf.log_file ? log_conf.log_file : stdout; fprintf(f, "%s %s", timestamp(), prefix); vfprintf(f, fmt, ap); fprintf(f, "\n"); #ifdef DEBUG fflush(f); #endif +#endif } void _log(int level, const char *fmt, ...) diff --git a/ctrl/facemgr/src/util/map.h b/ctrl/facemgr/src/util/map.h index 2694de2a7..b6773f209 100644 --- a/ctrl/facemgr/src/util/map.h +++ b/ctrl/facemgr/src/util/map.h @@ -31,6 +31,10 @@ typedef struct { VAL_T value; \ } NAME ## _pair_t; \ \ +NAME ## _pair_t * NAME ## _pair_create(KEY_T key, VAL_T value); \ + \ +void NAME ## _pair_free(NAME ## _pair_t * pair); \ + \ int NAME ## _pair_cmp(const NAME ## _pair_t * p1, const NAME ## _pair_t * p2); \ \ TYPEDEF_SET_H(NAME ## _pair_set, NAME ## _pair_t *) \ @@ -47,7 +51,7 @@ NAME ## _t * NAME ## _create(); \ void NAME ## _free(NAME ## _t * map); \ \ -int NAME ## _add(NAME ## _t * map, KEY_T key, const VAL_T value); \ +int NAME ## _add(NAME ## _t * map, KEY_T key, VAL_T value); \ \ int NAME ## _remove(NAME ## _t * map, KEY_T key, VAL_T * value); \ \ @@ -60,6 +64,24 @@ void NAME ## _dump(NAME ## _t * map); #define TYPEDEF_MAP(NAME, KEY_T, VAL_T, CMP, KEY_SNPRINTF, VALUE_SNPRINTF) \ \ +NAME ## _pair_t * NAME ## _pair_create(KEY_T key, VAL_T value) \ +{ \ + /* Create pair */ \ + NAME ## _pair_t * pair = malloc(sizeof(NAME ## _pair_t)); \ + if (!pair) \ + return NULL; \ + \ + pair->key = key; \ + pair->value = value; \ + \ + return pair; \ +} \ + \ +void NAME ## _pair_free(NAME ## _pair_t * pair) \ +{ \ + free(pair); \ +} \ + \ int \ NAME ## _pair_cmp(const NAME ## _pair_t * p1, const NAME ## _pair_t * p2) \ { \ @@ -72,7 +94,7 @@ NAME ## _pair_snprintf(char * buf, size_t size, const NAME ## _pair_t * pair) { rc = KEY_SNPRINTF(buf, BUFSIZE/2, (KEY_T)pair->key); \ if (rc < 0) \ return rc; \ - rc = VALUE_SNPRINTF(buf+rc, BUFSIZE/2, (VAL_T)pair->value); \ + rc = VALUE_SNPRINTF(buf+rc, BUFSIZE/2, (VAL_T)pair->value); \ return rc; \ } \ \ @@ -93,57 +115,98 @@ NAME ## _finalize(NAME ## _t * map) AUTOGENERATE_CREATE_FREE(NAME) \ \ int \ -NAME ## _add(NAME ## _t * map, KEY_T key, const VAL_T value) \ +NAME ## _add(NAME ## _t * map, KEY_T key, VAL_T value) \ { \ int rc; \ + NAME ## _pair_t * found = NULL; \ \ - /* Create pair */ \ - NAME ## _pair_t * pair = malloc(sizeof(NAME ## _pair_t)); \ + NAME ## _pair_t * pair = NAME ## _pair_create(key, value); \ if (!pair) \ - return FACEMGR_FAILURE; \ - \ - pair->key = key; \ - pair->value = (VAL_T)value; \ + return -1; \ \ - rc = NAME ## _pair_set_get(&map->pair_set, pair, NULL); \ - if (!FACEMGR_IS_ERROR(rc)) { \ - free(pair); \ + rc = NAME ## _pair_set_get(&map->pair_set, pair, &found); \ + if (rc < 0) \ + return -1; \ + if (found) { \ + NAME ## _pair_free(pair); \ return ERR_MAP_EXISTS; \ } \ \ rc = NAME ## _pair_set_add(&map->pair_set, pair); \ - if (FACEMGR_IS_ERROR(rc)) { \ - free(pair); \ - return FACEMGR_FAILURE; \ + if (rc < 0) { \ + NAME ## _pair_free(pair); \ + return -1; \ } \ - return FACEMGR_SUCCESS; \ + return 0; \ } \ \ int \ NAME ## _remove(NAME ## _t * map, KEY_T key, VAL_T * value) \ { \ - NAME ## _pair_t * found, search = { .key = key }; \ + NAME ## _pair_t * found = NULL; \ + NAME ## _pair_t search = { .key = key }; \ int rc = NAME ## _pair_set_remove(&map->pair_set, &search, &found); \ - if (FACEMGR_IS_ERROR(rc)) \ + if (rc < 0) \ return ERR_MAP_NOT_FOUND; \ - *value = found->value; \ - return FACEMGR_SUCCESS; \ + if (value) \ + *value = found->value; \ + NAME ## _pair_free(found); \ + return 0; \ } \ \ int \ NAME ## _get(NAME ## _t * map, KEY_T key, VAL_T * value) \ { \ - NAME ## _pair_t * found, search = { .key = key }; \ + NAME ## _pair_t * found = NULL, search = { .key = key }; \ int rc = NAME ## _pair_set_get(&map->pair_set, &search, &found); \ - if (FACEMGR_IS_ERROR(rc)) \ - return ERR_MAP_NOT_FOUND; \ - *value = found->value; \ - return FACEMGR_SUCCESS; \ + if (rc < 0) \ + return -1; \ + if (found) \ + *value = found->value; \ + return 0; \ } \ \ void \ NAME ## _dump(NAME ## _t * map) { \ NAME ## _pair_set_dump(&map->pair_set); \ +} \ + \ +int \ +NAME ## _get_key_array(NAME ## _t * map, KEY_T **array) { \ + NAME ## _pair_t ** pair_array; \ + int n = NAME ## _pair_set_get_array(&map->pair_set, &pair_array); \ + if (n < 0) \ + return -1; \ + /* Allocate result array */ \ + array = malloc(n * sizeof(KEY_T)); \ + if (!array) { \ + free(pair_array); \ + return -1; \ + } \ + /* Copy keys */ \ + for (int i = 0; i < n; i++) \ + array[i] = &pair_array[i]->key; \ + free(pair_array); \ + return 0; \ +} \ + \ +int \ +NAME ## _get_value_array(NAME ## _t * map, VAL_T **array) { \ + NAME ## _pair_t ** pair_array; \ + int n = NAME ## _pair_set_get_array(&map->pair_set, &pair_array); \ + if (n < 0) \ + return -1; \ + /* Allocate result array */ \ + array = malloc(n * sizeof(VAL_T)); \ + if (!array) { \ + free(pair_array); \ + return -1; \ + } \ + /* Copy values */ \ + for (int i = 0; i < n; i++) \ + array[i] = &pair_array[i]->value; \ + free(pair_array); \ + return 0; \ } #endif /* UTIL_MAP_H */ diff --git a/ctrl/facemgr/src/util/policy.c b/ctrl/facemgr/src/util/policy.c deleted file mode 100644 index 6c8651ee3..000000000 --- a/ctrl/facemgr/src/util/policy.c +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * \file policy.h - * \brief Implementation of policy description - */ - -#include <stdio.h> -#include "policy.h" - -const char * policy_tag_str[] = { - #define _(x, y) [POLICY_TAG_ ## x] = STRINGIZE(x), - foreach_policy_tag - #undef _ -}; - -const char policy_tag_short_str[] = { - #define _(x, y) [POLICY_TAG_ ## x] = y, - foreach_policy_tag - #undef _ -}; - -const char * policy_state_str[] = { - #define _(x) [POLICY_STATE_ ## x] = STRINGIZE(x), - foreach_policy_state - #undef _ -}; - -int -policy_tag_state_snprintf(char * s, size_t size, const policy_tag_state_t * tag_state) -{ - char *cur = s; - int rc; - - if (tag_state->disabled > 1) - return -1; - - rc = snprintf(cur, s + size - cur, "%s%s", (tag_state->disabled == 1) ? "!" : "", policy_state_str[tag_state->state]); - if (rc < 0) - return rc; - cur += rc; - if (size != 0 && cur >= s + size) - return cur - s; - - return cur - s; -} diff --git a/ctrl/facemgr/src/util/policy.h b/ctrl/facemgr/src/util/policy.h deleted file mode 100644 index e20af6560..000000000 --- a/ctrl/facemgr/src/util/policy.h +++ /dev/null @@ -1,234 +0,0 @@ -/* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * \file policy.h - * \brief Policy description - */ -#ifndef HICN_POLICY_H -#define HICN_POLICY_H - -#include <netinet/in.h> // INET*_ADDRSTRLEN -#include <string.h> // strcasecmp -#include "token.h" - -/* POLICY TAG */ - -#define foreach_policy_tag \ - /* Interface type */ \ - _(WIRED, 'E') \ - _(WIFI, 'W') \ - _(CELLULAR, 'C') \ - /* QoS */ \ - _(BEST_EFFORT, 'b') \ - _(REALTIME, 'r') \ - _(MULTIPATH, 'M') \ - /* Security */ \ - _(TRUSTED, 'T') - -typedef enum { -#define _(x, y) POLICY_TAG_ ## x, -foreach_policy_tag -#undef _ - POLICY_TAG_N -} policy_tag_t; - -#define MAXSZ_POLICY_TAG_ 11 -#define MAXSZ_POLICY_TAG MAXSZ_POLICY_TAG_ + 1 - -extern const char * policy_tag_str[]; -extern const char policy_tag_short_str[]; - -static inline -policy_tag_t -policy_tag_from_str(const char * str) -{ -#define _(x, y) if (strcasecmp(str, policy_tag_str[POLICY_TAG_ ## x] ) == 0) { return POLICY_TAG_ ## x; } else -foreach_policy_tag -#undef _ - return POLICY_TAG_N; -} - -/* POLICY_TAGS */ - -typedef int policy_tags_t; - -static inline -void policy_tags_add(policy_tags_t * tags, policy_tag_t tag) -{ - *tags |= (1 << tag); -} - -static inline -void policy_tags_remove(policy_tags_t * tags, policy_tag_t tag) -{ - *tags &= ~(1 << tag); -} - -static inline -int policy_tags_has(policy_tags_t tags, policy_tag_t tag) -{ - return tags & (1 << tag); -} - -#define POLICY_TAGS_EMPTY 0 - -static inline -int -policy_tags_snprintf(char * s, size_t size, policy_tags_t tags) -{ -#define _(x, y) s[POLICY_TAG_ ## x] = policy_tags_has(tags, POLICY_TAG_ ## x) ? y : '.'; -foreach_policy_tag -#undef _ - s[POLICY_TAG_N] = '\0'; - return POLICY_TAG_N + 1; -} - -#define MAXSZ_POLICY_TAGS_ POLICY_TAG_N -#define MAXSZ_POLICY_TAGS MAXSZ_POLICY_TAGS_ + 1 - -/* POLICY STATE */ - -/* TODO vs. weight */ - -#define foreach_policy_state \ - _(NEUTRAL) \ - _(REQUIRE) \ - _(PREFER) \ - _(AVOID) \ - _(PROHIBIT) \ - _(N) - -typedef enum { -#define _(x) POLICY_STATE_ ## x, -foreach_policy_state -#undef _ -} policy_state_t; - -#define MAXSZ_POLICY_STATE_ 8 -#define MAXSZ_POLICY_STATE MAXSZ_POLICY_STATE_ + 1 - -extern const char * policy_state_str[]; - - -/* POLICY TAG STATE */ - -typedef struct { - policy_state_t state; - uint8_t disabled; -} policy_tag_state_t; - -#define MAXSZ_POLICY_TAG_STATE_ 8 -#define MAXSZ_POLICY_TAG_STATE MAXSZ_POLICY_TAG_STATE_ + 1 - -int policy_tag_state_snprintf(char * s, size_t size, const policy_tag_state_t * tag_state); - - -/* INTERFACE STATS */ - -typedef struct { - float throughput; - float latency; - float loss_rate; -} interface_stats_t; - -#define INTERFACE_STATS_NONE { \ - .throughput = 0, \ - .latency = 0, \ - .loss_rate = 0, \ -} - - -/* POLICY STATS */ - -typedef struct { - interface_stats_t wired; - interface_stats_t wifi; - interface_stats_t cellular; - interface_stats_t all; -} policy_stats_t; - -#define POLICY_STATS_NONE { \ - .wired = INTERFACE_STATS_NONE, \ - .wifi = INTERFACE_STATS_NONE, \ - .cellular = INTERFACE_STATS_NONE, \ - .all = INTERFACE_STATS_NONE, \ -} - -typedef struct { - uint32_t num_packets; - uint32_t num_bytes; - uint32_t num_losses; - uint32_t latency_idle; -} interface_counters_t; - -#define INTERFACE_COUNTERS_NONE { \ - .num_packets = 0, \ - .num_bytes = 0, \ - .num_losses = 0, \ - .latency_idle = 0, \ -} - -typedef struct { - interface_counters_t wired; - interface_counters_t wifi; - interface_counters_t cellular; - interface_counters_t all; - uint64_t last_update; -} policy_counters_t; - -#define POLICY_COUNTERS_NONE (policy_counters_t) { \ - .wired = INTERFACE_COUNTERS_NONE, \ - .wifi = INTERFACE_COUNTERS_NONE, \ - .cellular = INTERFACE_COUNTERS_NONE, \ - .all = INTERFACE_COUNTERS_NONE, \ - .last_update = 0, \ -} - -/* POLICY */ - -#define APP_NAME_LEN 128 - -typedef struct { - char app_name[APP_NAME_LEN]; - policy_tag_state_t tags[POLICY_TAG_N]; - policy_stats_t stats; -} policy_t; - -static const policy_t POLICY_NONE = { - .app_name = { 0 }, - .tags = { -#define _(x, y) [POLICY_TAG_ ## x] = { POLICY_STATE_NEUTRAL, 0 }, -foreach_policy_tag -#undef _ - }, - .stats = POLICY_STATS_NONE, -}; - - -/* POLICY DESCRIPTION */ - -#define PFX_STRLEN 4 /* eg. /128 */ - -typedef struct { - int family; - union { - char ipv4_prefix[INET_ADDRSTRLEN + PFX_STRLEN]; - char ipv6_prefix[INET6_ADDRSTRLEN + PFX_STRLEN]; - }; - policy_t policy; -} policy_description_t; - -#endif /* HICN_POLICY_H */ diff --git a/ctrl/facemgr/src/util/set.h b/ctrl/facemgr/src/util/set.h index 47a6eeaff..61df209ab 100644 --- a/ctrl/facemgr/src/util/set.h +++ b/ctrl/facemgr/src/util/set.h @@ -16,15 +16,27 @@ #ifndef UTIL_SET_H #define UTIL_SET_H +#include <hicn/util/log.h> #include <search.h> #include <string.h> -#include "token.h" +//#if !defined(__ANDROID__) && !defined(__APPLE__) +//#include <threads.h> +//#else +#define thread_local _Thread_local +//#endif /* ! __ANDROID__ */ #include "../common.h" #define ERR_SET_EXISTS -2 #define ERR_SET_NOT_FOUND -3 -#define BUFSIZE 80 +/* FIXME: buffer overflow when this is too small... investigate */ +#define BUFSIZE 1024 + +static inline +int +int_snprintf(char * buf, size_t size, int value) { + return snprintf(buf, size, "%d", value); +} static inline int @@ -34,7 +46,7 @@ string_snprintf(char * buf, size_t size, const char * s) { static inline int -generic_snprintf(char * buf, size_t size, void * value) { +generic_snprintf(char * buf, size_t size, const void * value) { return snprintf(buf, BUFSIZE, "%p", value); } @@ -57,7 +69,9 @@ int NAME ## _add(NAME ## _t * set, const T element); \ \ int NAME ## _remove(NAME ## _t * set, const T search, T * element); \ \ -int NAME ## _get(NAME ## _t * set, const T search, T * element); \ +int NAME ## _get(const NAME ## _t * set, const T search, T * element); \ + \ +int NAME ## _get_array(const NAME ## _t * set, T ** element); \ \ void NAME ## _dump(NAME ## _t * set); @@ -70,7 +84,7 @@ NAME ## _initialize(NAME ## _t * set) \ { \ set->root = NULL; \ set->size = 0; \ - return FACEMGR_SUCCESS; \ + return 0; \ } \ \ NO_FINALIZE(NAME); \ @@ -79,49 +93,88 @@ AUTOGENERATE_CREATE_FREE(NAME); \ int \ NAME ## _add(NAME ## _t * set, const T element) \ { \ - return tsearch(element, &set->root, (cmp_t)CMP) \ - ? FACEMGR_SUCCESS : FACEMGR_FAILURE; \ + void * ptr = tsearch(element, &set->root, (cmp_t)CMP); \ + if (!ptr) \ + return -1; \ + set->size++; \ + return 0; \ } \ \ int \ NAME ## _remove(NAME ## _t * set, const T search, T * element) \ { \ - T * found = tdelete(search, &set->root, (cmp_t)CMP); \ - if (found && element) \ + T * found = tfind(search, &set->root, (cmp_t)CMP); \ + if (!found) \ + return ERR_SET_NOT_FOUND; \ + if (element) \ *element = *found; \ - return found ? FACEMGR_SUCCESS : ERR_SET_NOT_FOUND; \ + tdelete(search, &set->root, (cmp_t)CMP); \ + set->size--; \ + return 0; \ } \ \ int \ -NAME ## _get(NAME ## _t * set, const T search, T * element) \ +NAME ## _get(const NAME ## _t * set, const T search, T * element) \ { \ T * found = tfind(search, &set->root, (cmp_t)CMP); \ - if (found && element) \ - *element = *found; \ - return found ? FACEMGR_SUCCESS : ERR_SET_NOT_FOUND; \ + if (element) \ + *element = found ? *found : NULL; \ + return 0; \ } \ \ -void \ -__ ## NAME ## _dump_node(const void *nodep, const VISIT which, const int depth) \ +static void \ +NAME ## _dump_node(const void *nodep, const VISIT which, \ + const int depth) \ { \ char buf[BUFSIZE]; \ switch (which) { \ case preorder: \ - break; \ - case postorder: \ - break; \ case endorder: \ break; \ + case postorder: \ case leaf: \ SNPRINTF(buf, BUFSIZE, *(T*)nodep); \ - printf("%s\n", buf); \ + INFO("%s", buf); \ break; \ } \ } \ \ void \ NAME ## _dump(NAME ## _t * set) { \ - twalk(set->root, __ ## NAME ## _dump_node); \ + twalk(set->root, NAME ## _dump_node); \ } \ + \ +thread_local \ +T * NAME ## _array_pos = NULL; \ + \ +static void \ +NAME ## _add_node_to_array(const void *nodep, const VISIT which, \ + const int depth) \ +{ \ + if (!NAME ## _array_pos) \ + return; \ + switch (which) { \ + case preorder: \ + case endorder: \ + break; \ + case postorder: \ + case leaf: \ + *NAME ## _array_pos = *(T*)nodep; \ + NAME ## _array_pos++; \ + break; \ + } \ +} \ + \ +int \ +NAME ## _get_array(const NAME ## _t * set, T ** element) \ +{ \ + *element = malloc(set->size * sizeof(T)); \ + if (!*element) \ + return -1; \ + NAME ## _array_pos = *element; \ + twalk(set->root, NAME ## _add_node_to_array); \ + NAME ## _array_pos = NULL; \ + return set->size; \ +} #endif /* UTIL_SET_H */ diff --git a/ctrl/facemgr/src/util/token.h b/ctrl/facemgr/src/util/token.h deleted file mode 100644 index 43e0a77b2..000000000 --- a/ctrl/facemgr/src/util/token.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* Token concatenation */ - -/* - * Concatenate preprocessor tokens A and B without expanding macro definitions - * (however, if invoked from a macro, macro arguments are expanded). - */ -#define PPCAT_NX(A, B) A ## B - -/* - * Concatenate preprocessor tokens A and B after macro-expanding them. - */ -#define PPCAT(A, B) PPCAT_NX(A, B) - -/* Token stringification */ - -/* - * Turn A into a string literal without expanding macro definitions - * (however, if invoked from a macro, macro arguments are expanded). - */ -#define STRINGIZE_NX(A) #A - -/* - * Turn A into a string literal after macro-expanding it. - */ -#define STRINGIZE(A) STRINGIZE_NX(A) diff --git a/ctrl/facemgr/src/util/types.h b/ctrl/facemgr/src/util/types.h deleted file mode 100644 index 10a0bdca0..000000000 --- a/ctrl/facemgr/src/util/types.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef UTIL_TYPES -#define UTIL_TYPES - -typedef uint8_t u8; -typedef uint16_t u16; -typedef uint32_t u32; -typedef uint64_t u64; - -/* Helper for avoiding warnings about type-punning */ -#define UNION_CAST(x, destType) \ - (((union {__typeof__(x) a; destType b;})x).b) - -typedef unsigned int hash_t; - -typedef int (*cmp_t)(const void *, const void *); - -/* Enums */ - -#define IS_VALID_ENUM_TYPE(NAME, x) ((x > NAME ## _UNDEFINED) && (x < NAME ## _N)) - -#endif /* UTIL_TYPES */ diff --git a/ctrl/libhicnctrl/CMakeLists.txt b/ctrl/libhicnctrl/CMakeLists.txt index cb1bd722c..6b67544ee 100644 --- a/ctrl/libhicnctrl/CMakeLists.txt +++ b/ctrl/libhicnctrl/CMakeLists.txt @@ -26,21 +26,38 @@ set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules" ) +include(BuildMacros) + set(CMAKE_C_STANDARD 11) set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_MACOSX_RPATH ON) if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) - set(HICN_CTRL hicn-ctrl) - set(LIBHICN_CTRL hicn-ctrl) - set(LIBHICN_CTRL_SHARED ${LIBHICNCTRL}.shared) - set(LIBHICN_CTRL_STATIC ${LIBHICNCTRL}.static) -endif() -set(LIBHICNCTRL_COMPONENT lib${LIBHICN_CTRL}) + find_package_wrapper(Libhicn REQUIRED) + + set(HICNCTRL hicnctrl) + set(LIBHICNCTRL hicnctrl) + set(LIBHICNCTRL_SHARED ${LIBHICNCTRL}.shared) + set(LIBHICNCTRL_STATIC ${LIBHICNCTRL}.static) + +else() + if (${CMAKE_SYSTEM_NAME} STREQUAL "Android") + set(HICN_LIBRARIES ${LIBHICN_STATIC}) + list(APPEND DEPENDENCIES + ${LIBHICN_STATIC} + ) + else () + set(HICN_LIBRARIES ${LIBHICN_SHARED}) + list(APPEND DEPENDENCIES + ${LIBHICN_SHARED} + ) + endif () + +endif() -set(TO_INSTALL_HEADER_FILES) +set(LIBHICNCTRL_COMPONENT lib${LIBHICNCTRL}) add_subdirectory(includes) add_subdirectory(src) diff --git a/ctrl/libhicnctrl/includes/ctrl.h b/ctrl/libhicnctrl/includes/ctrl.h index 646630968..e61b7a482 120000..100644 --- a/ctrl/libhicnctrl/includes/ctrl.h +++ b/ctrl/libhicnctrl/includes/ctrl.h @@ -1 +1,25 @@ -hicn/ctrl.h
\ No newline at end of file +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file ctrl.h + * \brief Main interface for hICN control library + */ +#ifndef HICNCTRL_H +#define HICNCTRL_H + +#include <hicn/ctrl/api.h> + +#endif /* HICNCTRL_H */ diff --git a/ctrl/libhicnctrl/includes/hicn/ctrl/api.h b/ctrl/libhicnctrl/includes/hicn/ctrl/api.h index 45efb39f9..a0ee828b9 100644 --- a/ctrl/libhicnctrl/includes/hicn/ctrl/api.h +++ b/ctrl/libhicnctrl/includes/hicn/ctrl/api.h @@ -68,42 +68,19 @@ #include <stdbool.h> #include <stdint.h> +#include <hicn/util/ip_address.h> #include "face.h" -#include "util/types.h" + +#define HICN_DEFAULT_PORT 9695 #define LIBHICNCTRL_SUCCESS 0 #define LIBHICNCTRL_FAILURE -1 #define LIBHICNCTRL_NOT_IMPLEMENTED -99 #define LIBHICNCTRL_IS_ERROR(x) (x < 0) - -/** - * This allows to selectively define convenience types to avoid any collision - * when using the library in conjunction with other frameworks including similar - * defines - */ -#ifdef _HICNTRL_NO_DEFS -#define _HICNTRL_NO_DEF_TYPES -#define _HICNTRL_NO_DEF_IPADDR -#define _HICNTRL_NO_DEF_UNIONCAST -#endif - -#ifndef _HICNTRL_NO_DEF_TYPES -typedef uint8_t u8; -typedef uint16_t u16; -typedef uint32_t u32; -typedef uint64_t u64; -#endif /* _HICNTRL_NO_DEF_TYPES */ - -#ifndef _HICNTRL_NO_DEF_IPADDR -#include "util/ip_address.h" -#endif /* _HICNTRL_NO_DEF_IPADDR */ - -#ifndef _HICNTRL_NO_DEF_UNIONCAST /* Helper for avoiding warnings about type-punning */ #define UNION_CAST(x, destType) \ (((union {__typeof__(x) a; destType b;})x).b) -#endif /* _HICNTRL_NO_DEF_UNIONCAST */ /****************************************************************************** * Message helper types and aliases @@ -419,27 +396,13 @@ hc_sock_reset(hc_sock_t * s); #endif #define NAME_LEN 16 /* NULL-terminated right ? */ -#ifdef __linux__ #define INTERFACE_LEN 16 -#endif #define MAXSZ_HC_NAME_ NAME_LEN #define MAXSZ_HC_NAME MAXSZ_HC_NAME_ + NULLTERM #define MAXSZ_HC_ID_ 10 /* Number of digits for MAX_INT */ #define MAXSZ_HC_ID MAXSZ_HC_ID_ + NULLTERM -#define MAXSZ_HC_PROTO_ 8 /* inetX:// */ -#define MAXSZ_HC_PROTO MAXSZ_HC_PROTO_ + NULLTERM - -#define MAXSZ_HC_URL4_ MAXSZ_HC_PROTO_ + MAXSZ_IP4_ADDRESS_ + MAXSZ_PORT_ -#define MAXSZ_HC_URL6_ MAXSZ_HC_PROTO_ + MAXSZ_IP6_ADDRESS_ + MAXSZ_PORT_ -#define MAXSZ_HC_URL_ MAXSZ_HC_URL6_ -#define MAXSZ_HC_URL4 MAXSZ_HC_URL4_ + NULLTERM -#define MAXSZ_HC_URL6 MAXSZ_HC_URL6_ + NULLTERM -#define MAXSZ_HC_URL MAXSZ_HC_URL_ + NULLTERM - -int hc_url_snprintf(char * s, size_t size, int family, - const ip_address_t * ip_address, u16 port); #define foreach_type(TYPE, VAR, data) \ for (TYPE * VAR = (TYPE*)data->buffer; \ @@ -498,9 +461,7 @@ typedef int (*HC_PARSE)(const u8 *, u8 *); // FIXME the listener should not require any port for hICN... typedef struct { char name[NAME_LEN]; /* K.w */ // XXX clarify what used for -#ifdef __linux__ char interface_name[INTERFACE_LEN]; /* Kr. */ -#endif u32 id; hc_connection_type_t type; /* .rw */ int family; /* .rw */ @@ -509,6 +470,7 @@ typedef struct { } hc_listener_t; int hc_listener_create(hc_sock_t * s, hc_listener_t * listener); +/* listener_found might eventually be allocated, and needs to be freed */ int hc_listener_get(hc_sock_t *s, hc_listener_t * listener, hc_listener_t ** listener_found); int hc_listener_delete(hc_sock_t * s, hc_listener_t * listener); @@ -520,7 +482,7 @@ int hc_listener_parse(void * in, hc_listener_t * listener); #define foreach_listener(VAR, data) foreach_type(hc_listener_t, VAR, data) -#define MAXSZ_HC_LISTENER_ MAXSZ_HC_URL_ + SPACE + MAXSZ_HC_CONNECTION_TYPE_ +#define MAXSZ_HC_LISTENER_ INTERFACE_LEN + SPACE + MAXSZ_URL_ + SPACE + MAXSZ_HC_CONNECTION_TYPE_ #define MAXSZ_HC_LISTENER MAXSZ_HC_LISTENER_ + NULLTERM GENERATE_FIND_HEADER(listener); @@ -531,9 +493,15 @@ int hc_listener_snprintf(char * s, size_t size, hc_listener_t * listener); * Connections *----------------------------------------------------------------------------*/ +/* + * NOTE : + * - interface_name is mainly used to derive listeners from connections, but is + * not itself used to create connections. + */ typedef struct { u32 id; /* Kr. */ char name[NAME_LEN]; /* K.w */ + char interface_name[INTERFACE_LEN]; /* Kr. */ hc_connection_type_t type; /* .rw */ int family; /* .rw */ ip_address_t local_addr; /* .rw */ @@ -549,6 +517,7 @@ typedef struct { int hc_connection_create(hc_sock_t * s, hc_connection_t * connection); +/* connection_found will be allocated, and must be freed */ int hc_connection_get(hc_sock_t *s, hc_connection_t * connection, hc_connection_t ** connection_found); int hc_connection_update_by_id(hc_sock_t * s, int hc_connection_id, @@ -567,13 +536,14 @@ int hc_connection_cmp(const hc_connection_t * c1, const hc_connection_t * c2); int hc_connection_parse(void * in, hc_connection_t * connection); #ifdef WITH_POLICY -int hc_connection_set_state(hc_sock_t * s, const char * conn_id_or_name, face_state_t state); +int hc_connection_set_admin_state(hc_sock_t * s, const char * conn_id_or_name, face_state_t state); #endif /* WITH_POLICY */ #define foreach_connection(VAR, data) foreach_type(hc_connection_t, VAR, data) -#define MAXSZ_HC_CONNECTION_ MAXSZ_HC_CONNECTION_STATE_ + \ - 2 * MAXSZ_HC_URL_ + MAXSZ_HC_CONNECTION_TYPE_ + SPACES(3) +#define MAXSZ_HC_CONNECTION_ MAXSZ_HC_CONNECTION_STATE_ + \ + INTERFACE_LEN + SPACE + \ + 2 * MAXSZ_URL_ + MAXSZ_HC_CONNECTION_TYPE_ + SPACES(3) #define MAXSZ_HC_CONNECTION MAXSZ_HC_CONNECTION_ + NULLTERM GENERATE_FIND_HEADER(connection); @@ -581,38 +551,6 @@ GENERATE_FIND_HEADER(connection); int hc_connection_snprintf(char * s, size_t size, const hc_connection_t * connection); /*----------------------------------------------------------------------------* - * Routes - *----------------------------------------------------------------------------*/ - -typedef struct { - u8 face_id; /* Kr. */ - int family; /* Krw */ - ip_address_t remote_addr; /* krw */ - u8 len; /* krw */ - u16 cost; /* .rw */ -} hc_route_t; - -int hc_route_parse(void * in, hc_route_t * route); - -int hc_route_create(hc_sock_t * s, hc_route_t * route); -int hc_route_delete(hc_sock_t * s, hc_route_t * route); -int hc_route_list(hc_sock_t * s, hc_data_t ** pdata); - -#define foreach_route(VAR, data) foreach_type(hc_route_t, VAR, data) - -#define MAX_FACE_ID 255 -#define MAXSZ_FACE_ID 3 -#define MAX_COST 65535 -#define MAXSZ_COST 5 -#define MAX_LEN 255 -#define MAXSZ_LEN 3 - -#define MAXSZ_HC_ROUTE_ MAXSZ_FACE_ID + 1 + MAXSZ_COST + 1 + MAXSZ_IP_ADDRESS + 1 + MAXSZ_LEN -#define MAXSZ_HC_ROUTE MAXSZ_HC_ROUTE_ + NULLTERM - -int hc_route_snprintf(char * s, size_t size, hc_route_t * route); - -/*----------------------------------------------------------------------------* * Faces * * A face is an abstraction introduced by the control library to abstract the @@ -623,7 +561,7 @@ int hc_route_snprintf(char * s, size_t size, hc_route_t * route); *----------------------------------------------------------------------------*/ typedef struct { - u32 id; + u8 id; char name[NAME_LEN]; face_t face; // or embed ? //face_id_t parent; /* Pointer from connection to listener */ @@ -644,12 +582,47 @@ int hc_face_list(hc_sock_t * s, hc_data_t ** pdata); #define foreach_face(VAR, data) foreach_type(hc_face_t, VAR, data) -#define MAXSZ_HC_FACE_ 0 +#define MAX_FACE_ID 255 +#define MAXSZ_FACE_ID_ 3 +#define MAXSZ_FACE_ID MAXSZ_FACE_ID_ + NULLTERM +#define MAXSZ_FACE_NAME_ NAMELEN +#define MAXSZ_FACE_NAME MAXSZ_FACE_NAME_ + NULLTERM + +#define MAXSZ_HC_FACE_ MAXSZ_FACE_ID_ + MAXSZ_FACE_NAME_ + MAXSZ_FACE_ + 5 #define MAXSZ_HC_FACE MAXSZ_HC_FACE_ + NULLTERM int hc_face_snprintf(char * s, size_t size, hc_face_t * face); -/////// XXX XXX XXX XXX missing face api functions, cf punting now... +/*----------------------------------------------------------------------------* + * Routes + *----------------------------------------------------------------------------*/ + +typedef struct { + u8 face_id; /* Kr. */ + int family; /* Krw */ + ip_address_t remote_addr; /* krw */ + u8 len; /* krw */ + u16 cost; /* .rw */ +} hc_route_t; + +int hc_route_parse(void * in, hc_route_t * route); + +int hc_route_create(hc_sock_t * s, hc_route_t * route); +int hc_route_delete(hc_sock_t * s, hc_route_t * route); +int hc_route_list(hc_sock_t * s, hc_data_t ** pdata); + +#define foreach_route(VAR, data) foreach_type(hc_route_t, VAR, data) + +#define MAX_COST 65535 +#define MAXSZ_COST 5 +#define MAX_LEN 255 +#define MAXSZ_LEN 3 + +#define MAXSZ_HC_ROUTE_ MAXSZ_FACE_ID + 1 + MAXSZ_COST + 1 + MAXSZ_IP_ADDRESS + 1 + MAXSZ_LEN +#define MAXSZ_HC_ROUTE MAXSZ_HC_ROUTE_ + NULLTERM + +int hc_route_snprintf(char * s, size_t size, hc_route_t * route); + /*----------------------------------------------------------------------------* * Punting diff --git a/ctrl/libhicnctrl/includes/hicn/ctrl/commands.h b/ctrl/libhicnctrl/includes/hicn/ctrl/commands.h index 1d07c9b72..4209c6eb6 100755 --- a/ctrl/libhicnctrl/includes/hicn/ctrl/commands.h +++ b/ctrl/libhicnctrl/includes/hicn/ctrl/commands.h @@ -32,7 +32,7 @@ #include <stdlib.h> #ifdef WITH_POLICY -#include "util/policy.h" +#include <hicn/policy.h> #endif /* WITH_POLICY */ typedef struct in6_addr ipv6_addr_t; @@ -131,6 +131,7 @@ typedef struct { typedef struct { char symbolic[16]; + //char interfaceName[16]; union commandAddr remoteIp; union commandAddr localIp; uint16_t remotePort; @@ -166,9 +167,9 @@ typedef struct { add_connection_command connectionData; uint32_t connid; uint8_t state; -#ifdef WITH_UPDATE + uint8_t admin_state; char connectionName[16]; -#endif /* WITH_UPDATE */ + char interfaceName[16]; } list_connections_command; // SIZE=64 @@ -282,10 +283,8 @@ typedef struct { typedef struct { union commandAddr address; -#ifdef WITH_UPDATE char listenerName[16]; char interfaceName[16]; -#endif /* WITH_UPDATE */ uint32_t connid; uint16_t port; uint8_t addressType; @@ -310,11 +309,10 @@ typedef struct { // SIZE=1 -//========== NEW COMMANDS ========== - typedef struct { char symbolicOrConnid[16]; uint8_t admin_state; + uint8_t pad8[3]; } connection_set_admin_state_command; #ifdef WITH_POLICY diff --git a/ctrl/libhicnctrl/includes/hicn/ctrl/face.h b/ctrl/libhicnctrl/includes/hicn/ctrl/face.h index 2856ce89b..5c1fecd55 100644 --- a/ctrl/libhicnctrl/includes/hicn/ctrl/face.h +++ b/ctrl/libhicnctrl/includes/hicn/ctrl/face.h @@ -30,12 +30,11 @@ #define NULLTERM 1 #endif -#ifndef _HICNTRL_NO_DEF_IPADDR -#include "util/ip_address.h" -#endif /* _HICNTRL_NO_DEF_IPADDR */ -#include "util/policy.h" -#include "util/types.h" +#include <hicn/policy.h> +#include <hicn/util/ip_address.h> + +typedef unsigned int hash_t; /* Netdevice type */ @@ -43,6 +42,7 @@ #define foreach_netdevice_type \ _(UNDEFINED) \ + _(LOOPBACK) \ _(WIRED) \ _(WIFI) \ _(CELLULAR) \ @@ -63,25 +63,48 @@ extern const char * netdevice_type_str[]; /* Netdevice */ +/** + * \brief Netdevice type + * + * NOTE + * - This struct cannot be made opaque as it is currently part of face_t + * - We recommand using the API as to keep redundant attributes consistent + */ typedef struct { u32 index; char name[IFNAMSIZ]; } netdevice_t; +#define NETDEVICE_EMPTY (netdevice_t) { \ + .index = 0, \ + .name = {0}, \ +} + +netdevice_t * netdevice_create_from_index(u32 index); +netdevice_t * netdevice_create_from_name(const char * name); +#define netdevice_initialize_from_index netdevice_set_index +#define netdevice_initialize_from_name netdevice_set_name +void netdevice_free(netdevice_t * netdevice); +int netdevice_get_index(const netdevice_t * netdevice, u32 * index); +int netdevice_set_index(netdevice_t * netdevice, u32 index); +int netdevice_get_name(const netdevice_t * netdevice, const char ** name); +int netdevice_set_name(netdevice_t * netdevice, const char * name); +int netdevice_update_index(netdevice_t * netdevice); +int netdevice_update_name(netdevice_t * netdevice); +int netdevice_cmp(const netdevice_t * nd1, const netdevice_t * nd2); + #define NETDEVICE_UNDEFINED_INDEX 0 /* Face state */ #define foreach_face_state \ _(UNDEFINED) \ - _(PENDING_UP) \ - _(UP) \ - _(PENDING_DOWN) \ _(DOWN) \ - _(ERROR) \ + _(UP) \ _(N) -#define MAXSZ_FACE_STATE_ 12 + +#define MAXSZ_FACE_STATE_ 9 #define MAXSZ_FACE_STATE MAXSZ_FACE_STATE_ + 1 typedef enum { @@ -116,49 +139,49 @@ foreach_face_type extern const char * face_type_str[]; -#define MAXSZ_FACE_ MAXSZ_FACE_TYPE_ + 2 * MAXSZ_IP_ADDRESS + 2 * MAXSZ_PORT + 9 +#ifdef WITH_POLICY +#define MAXSZ_FACE_ MAXSZ_FACE_TYPE_ + 2 * MAXSZ_URL_ + 2 * MAXSZ_FACE_STATE_ + MAXSZ_POLICY_TAGS_ + 7 +#else +#define MAXSZ_FACE_ MAXSZ_FACE_TYPE_ + 2 * MAXSZ_URL_ + 2 * MAXSZ_FACE_STATE_ + 4 +#endif /* WITH_POLICY */ #define MAXSZ_FACE MAXSZ_FACE_ + 1 /* Face */ -typedef union { - int family; /* To access family independently of face type */ - struct { - int family; - netdevice_t netdevice; - ip_address_t local_addr; - ip_address_t remote_addr; - } hicn; - struct { - int family; - ip_address_t local_addr; - u16 local_port; - ip_address_t remote_addr; - u16 remote_port; - } tunnel; -} face_params_t; - typedef struct { face_type_t type; - face_params_t params; face_state_t admin_state; face_state_t state; #ifdef WITH_POLICY policy_tags_t tags; /**< \see policy_tag_t */ #endif /* WITH_POLICY */ + + /* + * Depending on the face type, some of the following fields will be unused + */ + netdevice_t netdevice; + int family; /* To access family independently of face type */ + ip_address_t local_addr; + ip_address_t remote_addr; + u16 local_port; + u16 remote_port; } face_t; int face_initialize(face_t * face); -int face_initialize_udp(face_t * face, const ip_address_t * local_addr, - u16 local_port, const ip_address_t * remote_addr, u16 remote_port, +int face_initialize_udp(face_t * face, const char * interface_name, + const ip_address_t * local_addr, u16 local_port, + const ip_address_t * remote_addr, u16 remote_port, int family); int face_initialize_udp_sa(face_t * face, + const char * interface_name, const struct sockaddr * local_addr, const struct sockaddr * remote_addr); face_t * face_create(); -face_t * face_create_udp(const ip_address_t * local_addr, u16 local_port, +face_t * face_create_udp(const char * interface_name, + const ip_address_t * local_addr, u16 local_port, const ip_address_t * remote_addr, u16 remote_port, int family); -face_t * face_create_udp_sa(const struct sockaddr * local_addr, +face_t * face_create_udp_sa(const char * interface_name, + const struct sockaddr * local_addr, const struct sockaddr * remote_addr); int face_finalize(face_t * face); @@ -173,6 +196,7 @@ hash_t face_hash(const face_t * face); size_t face_snprintf(char * s, size_t size, const face_t * face); +policy_tags_t face_get_tags(const face_t * face); int face_set_tags(face_t * face, policy_tags_t tags); #endif /* HICN_FACE_H */ diff --git a/ctrl/libhicnctrl/src/CMakeLists.txt b/ctrl/libhicnctrl/src/CMakeLists.txt index 204311c39..7b4413d55 100644 --- a/ctrl/libhicnctrl/src/CMakeLists.txt +++ b/ctrl/libhicnctrl/src/CMakeLists.txt @@ -11,11 +11,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -include(BuildMacros) - list(APPEND COMPILER_DEFINITIONS "-DWITH_POLICY" -# "-DWITH_UPDATE" ) set(HEADER_FILES @@ -26,34 +23,34 @@ set(HEADER_FILES set(UTIL_HEADER_FILES face.h - util/ip_address.h util/log.h - util/policy.h - util/token.h - util/types.h ) set(SOURCE_FILES api.c - util/policy.c + face.c util/log.c ) set(LIBRARIES m + ${HICN_LIBRARIES} ) set(INCLUDE_DIRS ./ ../includes/ + ${HICN_INCLUDE_DIRS} ) -if (ANDROID_API) - build_library(${LIBHICN_CTRL} +if (${CMAKE_SYSTEM_NAME} STREQUAL "Android") + set(HICN_LIBRARIES ${LIBHICN_STATIC}) + build_library(${LIBHICNCTRL} STATIC SOURCES ${SOURCE_FILES} INSTALL_HEADERS ${TO_INSTALL_HEADER_FILES} LINK_LIBRARIES ${LIBRARIES} + DEPENDS ${LIBHICN_STATIC} COMPONENT ${LIBHICNCTRL_COMPONENT} DEPENDS ${LIBHICN_STATIC} INCLUDE_DIRS ${INCLUDE_DIRS} @@ -61,11 +58,12 @@ if (ANDROID_API) DEFINITIONS ${COMPILER_DEFINITIONS} ) else () - build_library(${LIBHICN_CTRL} + build_library(${LIBHICNCTRL} SHARED STATIC SOURCES ${SOURCE_FILES} INSTALL_HEADERS ${TO_INSTALL_HEADER_FILES} LINK_LIBRARIES ${LIBRARIES} + DEPENDS ${LIBHICN_SHARED} COMPONENT ${LIBHICNCTRL_COMPONENT} DEPENDS ${LIBHICN_SHARED} INCLUDE_DIRS ${INCLUDE_DIRS} @@ -74,14 +72,14 @@ else () ) endif () -if(NOT ANDROID_API AND NOT COMPILE_FOR_IOS) +if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Android" AND NOT COMPILE_FOR_IOS) list(APPEND DAEMON_SRC cli.c ) - build_executable(${HICN_CTRL} + build_executable(${HICNCTRL} SOURCES ${DAEMON_SRC} - LINK_LIBRARIES ${LIBHICN_CTRL_SHARED} - DEPENDS ${LIBHICN_CTRL_SHARED} + LINK_LIBRARIES ${LIBHICNCTRL_SHARED} ${LIBHICN_SHARED} + DEPENDS ${LIBHICNCTRL_SHARED} ${LIBHICN_SHARED} COMPONENT ${LIBHICNCTRL_COMPONENT} INCLUDE_DIRS ${INCLUDE_DIRS} DEFINITIONS ${COMPILER_DEFINITIONS} diff --git a/ctrl/libhicnctrl/src/api.c b/ctrl/libhicnctrl/src/api.c index 3d8a2c166..769c96076 100644 --- a/ctrl/libhicnctrl/src/api.c +++ b/ctrl/libhicnctrl/src/api.c @@ -28,12 +28,21 @@ #include <hicn/ctrl/api.h> #include <hicn/ctrl/commands.h> +#include <hicn/util/token.h> #include "util/log.h" -#include "util/token.h" #include <strings.h> #define PORT 9695 +#if 0 +#ifdef __APPLE__ +#define RANDBYTE() (u8)(arc4random() & 0xFF) +#else +#define RANDBYTE() (u8)(random() & 0xFF) +#endif +#endif +#define RANDBYTE() (u8)(rand() & 0xFF) + /* * list was working with all seq set to 0, but it seems hicnLightControl uses * 1, and replies with the same seqno @@ -159,8 +168,8 @@ static const hc_connection_state_t map_from_list_connections_state[] = { }; -#define connection_state_to_face_state(x) ((face_state_t)x) -#define face_state_to_connection_state(x) ((hc_connection_state_t)x) +#define connection_state_to_face_state(x) ((face_state_t)(x)) +#define face_state_to_connection_state(x) ((hc_connection_state_t)(x)) #define IS_VALID_ADDR_TYPE(x) ((x >= ADDR_INET) && (x <= ADDR_UNIX)) @@ -342,6 +351,8 @@ hc_sock_parse_url(const char * url, struct sockaddr * sa) /* FIXME URL parsing is currently not implemented */ assert(!url); + srand(time(NULL)); + /* * A temporary solution is to inspect the sa_family fields of the passed in * sockaddr, which defaults to AF_UNSPEC (0) and thus creates an IPv4/TCP @@ -443,7 +454,13 @@ ERR_PARSE: int hc_sock_send(hc_sock_t * s, hc_msg_t * msg, size_t msglen) { - return send(s->fd, msg, msglen, 0); + int rc; + rc = send(s->fd, msg, msglen, 0); + if (rc < 0) { + perror("hc_sock_send"); + return -1; + } + return 0; } int @@ -473,6 +490,7 @@ hc_sock_recv(hc_sock_t * s, hc_data_t * data) // XXX } if (rc < 0) { + perror("hc_sock_recv"); /* Error occurred */ // XXX check for EWOULDBLOCK; // XXX @@ -647,7 +665,8 @@ hc_execute_command(hc_sock_t * s, hc_msg_t * msg, size_t msg_len, if (!data) goto ERR_DATA; - hc_sock_send(s, msg, msg_len); + if (hc_sock_send(s, msg, msg_len) < 0) + goto ERR_PROCESS; while(!data->complete) { if (hc_sock_recv(s, data) < 0) break; @@ -667,52 +686,6 @@ ERR_DATA: return LIBHICNCTRL_FAILURE; } -/* /!\ Please update constants in header file upon changes */ -int -hc_url_snprintf(char * s, size_t size, int family, - const ip_address_t * ip_address, u16 port) -{ - char * cur = s; - int rc; - - /* Other address are currently not supported */ - if (!IS_VALID_FAMILY(family)) { - ERROR("Invalid family %d for IP address", family); - return -1; - } - - rc = snprintf(cur, s + size - cur, "inet%c://", - (family == AF_INET) ? '4' : '6'); - if (rc < 0) - return rc; - cur += rc; - if (size != 0 && cur >= s + size) - return cur - s; - - rc = ip_address_snprintf(cur, s + size - cur, ip_address, family); - if (rc < 0) - return rc; - cur += rc; - if (size != 0 && cur >= s + size) - return cur - s; - - rc = snprintf(cur, s + size - cur, ":"); - if (rc < 0) - return rc; - cur += rc; - if (size != 0 && cur >= s + size) - return cur - s; - - rc = snprintf(cur, s + size - cur, "%d", port); - if (rc < 0) - return rc; - cur += rc; - if (size != 0 && cur >= s + size) - return cur - s; - - return cur - s; -} - /*----------------------------------------------------------------------------* * Listeners *----------------------------------------------------------------------------*/ @@ -750,9 +723,7 @@ hc_listener_create(hc_sock_t * s, hc_listener_t * listener) }; snprintf(msg.payload.symbolic, NAME_LEN, "%s", listener->name); -#ifdef __linux__ snprintf(msg.payload.interfaceName, INTERFACE_LEN, "%s", listener->interface_name); -#endif hc_command_params_t params = { .cmd = ACTION_CREATE, @@ -772,13 +743,25 @@ hc_listener_get(hc_sock_t *s, hc_listener_t * listener, hc_listener_t ** listener_found) { hc_data_t * listeners; + hc_listener_t * found; if (hc_listener_list(s, &listeners) < 0) return LIBHICNCTRL_FAILURE; /* Test */ - if (hc_listener_find(listeners, listener, listener_found) < 0) + if (hc_listener_find(listeners, listener, &found) < 0) { + hc_data_free(listeners); return LIBHICNCTRL_FAILURE; + } + + if (found) { + *listener_found = malloc(sizeof(hc_listener_t)); + if (!*listener_found) + return LIBHICNCTRL_FAILURE; + **listener_found = *found; + } else { + *listener_found = NULL; + } hc_data_free(listeners); @@ -818,6 +801,7 @@ hc_listener_delete(hc_sock_t * s, hc_listener_t * listener) return LIBHICNCTRL_FAILURE; printf("Delete listener ID=%d\n", listener_found->id); snprintf(msg.payload.symbolicOrListenerid, NAME_LEN, "%d", listener_found->id); + free(listener_found); } hc_command_params_t params = { @@ -879,6 +863,7 @@ hc_listener_cmp(const hc_listener_t * l1, const hc_listener_t * l2) { return ((l1->type == l2->type) && (l1->family == l2->family) && + (strncmp(l1->interface_name, l2->interface_name, INTERFACE_LEN) == 0) && (ip_address_cmp(&l1->local_addr, &l2->local_addr, l1->family) == 0) && (l1->local_port == l2->local_port)) ? LIBHICNCTRL_SUCCESS @@ -913,7 +898,8 @@ hc_listener_parse(void * in, hc_listener_t * listener) .local_addr = UNION_CAST(cmd->address, ip_address_t), .local_port = ntohs(cmd->port), }; - memset(listener->name, 0, NAME_LEN); + snprintf(listener->name, NAME_LEN, "%s", cmd->listenerName); + snprintf(listener->interface_name, INTERFACE_LEN, "%s", cmd->interfaceName); return LIBHICNCTRL_SUCCESS; } @@ -925,14 +911,15 @@ GENERATE_FIND(listener) int hc_listener_snprintf(char * s, size_t size, hc_listener_t * listener) { - char local[MAXSZ_HC_URL]; + char local[MAXSZ_URL]; int rc; - rc = hc_url_snprintf(local, MAXSZ_HC_URL, + rc = url_snprintf(local, MAXSZ_URL, listener->family, &listener->local_addr, listener->local_port); if (rc < 0) return rc; - return snprintf(s, size+17, "%s %s", + return snprintf(s, size+17, "%s %s %s", + listener->interface_name, local, connection_type_str[listener->type]); } @@ -993,13 +980,25 @@ hc_connection_get(hc_sock_t *s, hc_connection_t * connection, hc_connection_t ** connection_found) { hc_data_t * connections; + hc_connection_t * found; if (hc_connection_list(s, &connections) < 0) return LIBHICNCTRL_FAILURE; /* Test */ - if (hc_connection_find(connections, connection, connection_found) < 0) + if (hc_connection_find(connections, connection, &found) < 0) { + hc_data_free(connections); return LIBHICNCTRL_FAILURE; + } + + if (found) { + *connection_found = malloc(sizeof(hc_connection_t)); + if (!*connection_found) + return LIBHICNCTRL_FAILURE; + **connection_found = *found; + } else { + *connection_found = NULL; + } hc_data_free(connections); @@ -1039,6 +1038,7 @@ hc_connection_delete(hc_sock_t * s, hc_connection_t * connection) return LIBHICNCTRL_FAILURE; printf("Delete connection ID=%d\n", connection_found->id); snprintf(msg.payload.symbolicOrConnid, NAME_LEN, "%d", connection_found->id); + free(connection_found); } hc_command_params_t params = { @@ -1158,6 +1158,7 @@ hc_connection_parse(void * in, hc_connection_t * connection) .state = state, }; snprintf(connection->name, NAME_LEN, "%s", cmd->connectionData.symbolic); + snprintf(connection->interface_name, INTERFACE_LEN, "%s", cmd->interfaceName); return LIBHICNCTRL_SUCCESS; } @@ -1169,23 +1170,24 @@ GENERATE_FIND(connection) int hc_connection_snprintf(char * s, size_t size, const hc_connection_t * connection) { - char local[MAXSZ_HC_URL]; - char remote[MAXSZ_HC_URL]; + char local[MAXSZ_URL]; + char remote[MAXSZ_URL]; int rc; // assert(connection->connection_state) - rc = hc_url_snprintf(local, MAXSZ_HC_URL, connection->family, + rc = url_snprintf(local, MAXSZ_URL, connection->family, &connection->local_addr, connection->local_port); if (rc < 0) return rc; - rc = hc_url_snprintf(remote, MAXSZ_HC_URL, connection->family, + rc = url_snprintf(remote, MAXSZ_URL, connection->family, &connection->remote_addr, connection->remote_port); if (rc < 0) return rc; - return snprintf(s, size, "%s %s %s %s", + return snprintf(s, size, "%s %s %s %s %s", connection_state_str[connection->state], + connection->interface_name, local, remote, connection_type_str[connection->type]); @@ -1195,7 +1197,7 @@ hc_connection_snprintf(char * s, size_t size, const hc_connection_t * connection int hc_connection_set_admin_state(hc_sock_t * s, const char * conn_id_or_name, - hc_connection_state_t admin_state) + face_state_t state) { struct { header_control_message hdr; @@ -1208,7 +1210,7 @@ hc_connection_set_admin_state(hc_sock_t * s, const char * conn_id_or_name, .seqNum = s->send_seq, }, .payload = { - .admin_state = admin_state, + .admin_state = state, }, }; snprintf(msg.payload.symbolicOrConnid, NAME_LEN, "%s", conn_id_or_name); @@ -1436,13 +1438,12 @@ hc_face_to_connection(const hc_face_t * face, hc_connection_t * connection, bool switch(f->type) { case FACE_TYPE_HICN: - /* FIXME truncations, collisions, ... */ *connection = (hc_connection_t) { .type = CONNECTION_TYPE_HICN, - .family = f->params.hicn.family, - .local_addr = f->params.hicn.local_addr, + .family = f->family, + .local_addr = f->local_addr, .local_port = 0, - .remote_addr = f->params.hicn.remote_addr, + .remote_addr = f->remote_addr, .remote_port = 0, .admin_state = face_state_to_connection_state(f->admin_state), .state = face_state_to_connection_state(f->state), @@ -1451,16 +1452,18 @@ hc_face_to_connection(const hc_face_t * face, hc_connection_t * connection, bool #endif /* WITH_POLICY */ }; snprintf(connection->name, NAME_LEN, "%s", - f->params.hicn.netdevice.name); + f->netdevice.name); + snprintf(connection->interface_name, INTERFACE_LEN, "%s", + f->netdevice.name); break; case FACE_TYPE_TCP: *connection = (hc_connection_t) { .type = CONNECTION_TYPE_TCP, - .family = f->params.hicn.family, - .local_addr = f->params.tunnel.local_addr, - .local_port = f->params.tunnel.local_port, - .remote_addr = f->params.tunnel.remote_addr, - .remote_port = f->params.tunnel.remote_port, + .family = f->family, + .local_addr = f->local_addr, + .local_port = f->local_port, + .remote_addr = f->remote_addr, + .remote_port = f->remote_port, .admin_state = face_state_to_connection_state(f->admin_state), .state = face_state_to_connection_state(f->state), #ifdef WITH_POLICY @@ -1468,23 +1471,21 @@ hc_face_to_connection(const hc_face_t * face, hc_connection_t * connection, bool #endif /* WITH_POLICY */ }; if (generate_name) { -#ifdef __APPLE__ - snprintf(connection->name, NAME_LEN, "tcp%d", arc4random() & 0xFF); -#else - snprintf(connection->name, NAME_LEN, "tcp%ld", random() & 0xFF); -#endif + snprintf(connection->name, NAME_LEN, "tcp%u", RANDBYTE()); } else { memset(connection->name, 0, NAME_LEN); } + snprintf(connection->interface_name, INTERFACE_LEN, "%s", + f->netdevice.name); break; case FACE_TYPE_UDP: *connection = (hc_connection_t) { .type = CONNECTION_TYPE_UDP, .family = AF_INET, - .local_addr = f->params.tunnel.local_addr, - .local_port = f->params.tunnel.local_port, - .remote_addr = f->params.tunnel.remote_addr, - .remote_port = f->params.tunnel.remote_port, + .local_addr = f->local_addr, + .local_port = f->local_port, + .remote_addr = f->remote_addr, + .remote_port = f->remote_port, .admin_state = face_state_to_connection_state(f->admin_state), .state = face_state_to_connection_state(f->state), #ifdef WITH_POLICY @@ -1492,20 +1493,21 @@ hc_face_to_connection(const hc_face_t * face, hc_connection_t * connection, bool #endif /* WITH_POLICY */ }; if (generate_name) { -#ifdef __APPLE__ - snprintf(connection->name, NAME_LEN, "udp%d", arc4random() & 0xFF); -#else - snprintf(connection->name, NAME_LEN, "udp%ld", random() & 0xFF); -#endif + snprintf(connection->name, NAME_LEN, "udp%u", RANDBYTE()); } else { memset(connection->name, 0, NAME_LEN); } + snprintf(connection->interface_name, INTERFACE_LEN, "%s", + f->netdevice.name); break; default: return LIBHICNCTRL_FAILURE; } - return LIBHICNCTRL_SUCCESS; + snprintf(connection->interface_name, INTERFACE_LEN, "%s", + f->netdevice.name); + + return LIBHICNCTRL_SUCCESS; } /* CONNECTION -> FACE */ @@ -1519,13 +1521,11 @@ hc_connection_to_face(const hc_connection_t * connection, hc_face_t * face) .id = connection->id, .face = { .type = FACE_TYPE_TCP, - .params.tunnel = { - .family = connection->family, - .local_addr = connection->local_addr, - .local_port = connection->local_port, - .remote_addr = connection->remote_addr, - .remote_port = connection->remote_port, - }, + .family = connection->family, + .local_addr = connection->local_addr, + .local_port = connection->local_port, + .remote_addr = connection->remote_addr, + .remote_port = connection->remote_port, .admin_state = connection_state_to_face_state(connection->admin_state), .state = connection_state_to_face_state(connection->state), #ifdef WITH_POLICY @@ -1539,13 +1539,11 @@ hc_connection_to_face(const hc_connection_t * connection, hc_face_t * face) .id = connection->id, .face = { .type = FACE_TYPE_UDP, - .params.tunnel = { - .family = connection->family, - .local_addr = connection->local_addr, - .local_port = connection->local_port, - .remote_addr = connection->remote_addr, - .remote_port = connection->remote_port, - }, + .family = connection->family, + .local_addr = connection->local_addr, + .local_port = connection->local_port, + .remote_addr = connection->remote_addr, + .remote_port = connection->remote_port, .admin_state = connection_state_to_face_state(connection->admin_state), .state = connection_state_to_face_state(connection->state), #ifdef WITH_POLICY @@ -1559,12 +1557,10 @@ hc_connection_to_face(const hc_connection_t * connection, hc_face_t * face) .id = connection->id, .face = { .type = FACE_TYPE_HICN, - .params.hicn = { - .family = connection->family, - .netdevice.index = NETDEVICE_UNDEFINED_INDEX, // XXX - .local_addr = connection->local_addr, - .remote_addr = connection->remote_addr, - }, + .family = connection->family, + .netdevice.index = NETDEVICE_UNDEFINED_INDEX, // XXX + .local_addr = connection->local_addr, + .remote_addr = connection->remote_addr, .admin_state = connection_state_to_face_state(connection->admin_state), .state = connection_state_to_face_state(connection->state), #ifdef WITH_POLICY @@ -1576,7 +1572,11 @@ hc_connection_to_face(const hc_connection_t * connection, hc_face_t * face) default: return LIBHICNCTRL_FAILURE; } + face->face.netdevice.name[0] = '\0'; + face->face.netdevice.index = 0; snprintf(face->name, NAME_LEN, "%s", connection->name); + snprintf(face->face.netdevice.name, INTERFACE_LEN, "%s", connection->interface_name); + netdevice_update_index(&face->face.netdevice); return LIBHICNCTRL_SUCCESS; } @@ -1592,6 +1592,8 @@ hc_connection_to_local_listener(const hc_connection_t * connection, hc_listener_ .local_addr = connection->local_addr, .local_port = connection->local_port, }; + snprintf(listener->name, NAME_LEN, "lst%u", RANDBYTE()); // generate name + snprintf(listener->interface_name, INTERFACE_LEN, "%s", connection->interface_name); return LIBHICNCTRL_SUCCESS; } @@ -1631,8 +1633,11 @@ hc_face_create(hc_sock_t * s, hc_face_t * face) /* We need to create the listener if it does not exist */ if (hc_listener_create(s, &listener) < 0) { ERROR("[hc_face_create] Could not create listener."); + free(listener_found); return LIBHICNCTRL_FAILURE; } + } else { + free(listener_found); } /* Create corresponding connection */ @@ -1656,6 +1661,7 @@ hc_face_create(hc_sock_t * s, hc_face_t * face) } face->id = connection_found->id; + free(connection_found); break; @@ -1674,6 +1680,7 @@ hc_face_create(hc_sock_t * s, hc_face_t * face) break; default: ERROR("[hc_face_create] Unknwon face type."); + return LIBHICNCTRL_FAILURE; }; @@ -1702,7 +1709,9 @@ hc_face_get(hc_sock_t * s, hc_face_t * face, hc_face_t ** face_found) *face_found = NULL; return LIBHICNCTRL_SUCCESS; } + *face_found = malloc(sizeof(face_t)); hc_connection_to_face(connection_found, *face_found); + free(connection_found); break; case FACE_TYPE_HICN_LISTENER: @@ -1716,7 +1725,9 @@ hc_face_get(hc_sock_t * s, hc_face_t * face, hc_face_t ** face_found) *face_found = NULL; return LIBHICNCTRL_SUCCESS; } + *face_found = malloc(sizeof(face_t)); hc_listener_to_face(listener_found, *face_found); + free(listener_found); break; default: @@ -1776,6 +1787,71 @@ ERR: int hc_face_snprintf(char * s, size_t size, hc_face_t * face) { + /* URLs are also big enough to contain IP addresses in the hICN case */ + char local[MAXSZ_URL]; + char remote[MAXSZ_URL]; +#ifdef WITH_POLICY + char tags[MAXSZ_POLICY_TAGS]; +#endif /* WITH_POLICY */ + int rc; + + switch(face->face.type) { + case FACE_TYPE_HICN: + case FACE_TYPE_HICN_LISTENER: + rc = ip_address_snprintf(local, MAXSZ_URL, + &face->face.local_addr, + face->face.family); + if (rc < 0) + return rc; + rc = ip_address_snprintf(remote, MAXSZ_URL, + &face->face.remote_addr, + face->face.family); + if (rc < 0) + return rc; + break; + case FACE_TYPE_TCP: + case FACE_TYPE_UDP: + case FACE_TYPE_TCP_LISTENER: + case FACE_TYPE_UDP_LISTENER: + rc = url_snprintf(local, MAXSZ_URL, face->face.family, + &face->face.local_addr, + face->face.local_port); if (rc < 0) + return rc; + rc = url_snprintf(remote, MAXSZ_URL, face->face.family, + &face->face.remote_addr, + face->face.remote_port); if (rc < 0) + if (rc < 0) + return rc; + break; + default: + return LIBHICNCTRL_FAILURE; + } + + // [#ID NAME] TYPE LOCAL_URL REMOTE_URL STATE/ADMIN_STATE (TAGS) +#ifdef WITH_POLICY + rc = policy_tags_snprintf(tags, MAXSZ_POLICY_TAGS, face->face.tags); + if (rc < 0) + return rc; + + return snprintf(s, size, "[#%d %s] %s %s %s %s/%s (%s)", + face->id, + face->name, + face_type_str[face->face.type], + local, + remote, + face_state_str[face->face.state], + face_state_str[face->face.admin_state], + tags); +#else + return snprintf(s, size, "[#%d %s] %s %s %s %s/%s", + face->id, + face->name, + face_type_str[face->face.type], + local, + remote, + face_state_str[face->face.state], + face_state_str[face->face.admin_state]); +#endif /* WITH_POLICY */ return LIBHICNCTRL_SUCCESS; } @@ -1783,7 +1859,7 @@ int hc_face_set_admin_state(hc_sock_t * s, const char * conn_id_or_name, // XXX wrong identifier face_state_t admin_state) { - return hc_connection_set_admin_state(s, conn_id_or_name, (hc_connection_state_t)admin_state); + return hc_connection_set_admin_state(s, conn_id_or_name, admin_state); } /*----------------------------------------------------------------------------* diff --git a/ctrl/libhicnctrl/src/cli.c b/ctrl/libhicnctrl/src/cli.c index 70620a84f..6798b5aec 100644 --- a/ctrl/libhicnctrl/src/cli.c +++ b/ctrl/libhicnctrl/src/cli.c @@ -22,9 +22,8 @@ #include <unistd.h> // getopt #include <hicn/ctrl.h> - -#include "util/ip_address.h" -#include "util/token.h" +#include <hicn/util/ip_address.h> +#include <hicn/util/token.h> #define die(LABEL, MESSAGE) do { \ diff --git a/ctrl/libhicnctrl/src/face.c b/ctrl/libhicnctrl/src/face.c index 9e0fbb597..41ff58f81 100644 --- a/ctrl/libhicnctrl/src/face.c +++ b/ctrl/libhicnctrl/src/face.c @@ -21,10 +21,10 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <hicn/util/token.h> -#include "face.h" +#include <hicn/ctrl/face.h> #include "util/hash.h" -#include "util/token.h" #define member_size(type, member) sizeof(((type *)0)->member) @@ -37,6 +37,112 @@ foreach_netdevice_type #undef _ }; +netdevice_t * +netdevice_create_from_index(u32 index) +{ + netdevice_t * netdevice = malloc(sizeof(netdevice_t)); + if (!netdevice) + goto ERR_MALLOC; + + int rc = netdevice_set_index(netdevice, index); + if (rc < 0) + goto ERR_INIT; + + return netdevice; + +ERR_INIT: + free(netdevice); +ERR_MALLOC: + return NULL; +} + +netdevice_t * +netdevice_create_from_name(const char * name) +{ + netdevice_t * netdevice = malloc(sizeof(netdevice_t)); + if (!netdevice) + goto ERR_MALLOC; + + int rc = netdevice_set_name(netdevice, name); + if (rc < 0) + goto ERR_INIT; + + return netdevice; + +ERR_INIT: + free(netdevice); +ERR_MALLOC: + return NULL; +} + +/** + * \brief Update the index of the netdevice based on the name + */ +int +netdevice_update_index(netdevice_t * netdevice) +{ + netdevice->index = if_nametoindex(netdevice->name); + if (netdevice->index == 0) + return -1; + return 0; +} + +int +netdevice_update_name(netdevice_t * netdevice) +{ + if (!if_indextoname(netdevice->index, netdevice->name)) + return -1; + return 0; +} + +void +netdevice_free(netdevice_t * netdevice) +{ + free(netdevice); +} + +int +netdevice_get_index(const netdevice_t * netdevice, u32 * index) +{ + if (netdevice->index == 0) + return -1; + *index = netdevice->index; + return 0; +} + +int +netdevice_set_index(netdevice_t * netdevice, u32 index) +{ + netdevice->index = index; + return netdevice_update_name(netdevice); +} + +int +netdevice_get_name(const netdevice_t * netdevice, const char ** name) +{ + if (netdevice->name[0] == '\0') + return -1; + *name = netdevice->name; + return 0; +} + +int +netdevice_set_name(netdevice_t * netdevice, const char * name) +{ + int rc = snprintf(netdevice->name, IFNAMSIZ, "%s", name); + if (rc < 0) + return -1; + if (rc >= IFNAMSIZ) + return -2; /* truncated */ + return netdevice_update_index(netdevice); +} + +int +netdevice_cmp(const netdevice_t * nd1, const netdevice_t * nd2) +{ + return (nd1->index - nd2->index); +} + /* Face state */ @@ -61,33 +167,42 @@ foreach_face_type int face_initialize(face_t * face) { - bzero(face, sizeof(face_t)); /* 0'ed for hash */ + memset(face, 0, sizeof(face_t)); /* 0'ed for hash */ return 1; } int -face_initialize_udp(face_t * face, const ip_address_t * local_addr, - u16 local_port, const ip_address_t * remote_addr, u16 remote_port, +face_initialize_udp(face_t * face, const char * interface_name, const + ip_address_t * local_addr, u16 local_port, + const ip_address_t * remote_addr, u16 remote_port, int family) { + if (!local_addr) + return -1; + *face = (face_t) { .type = FACE_TYPE_UDP, - .params.tunnel = { - .family = family, - .local_addr = *local_addr, - .local_port = local_port, - .remote_addr = *remote_addr, - .remote_port = remote_port, - }, + .family = family, + .local_addr = *local_addr, + .local_port = local_port, + .remote_addr = remote_addr ? *remote_addr : IP_ADDRESS_EMPTY, + .remote_port = remote_port, }; + + snprintf(face->netdevice.name, IFNAMSIZ, "%s", interface_name); + return 1; } int -face_initialize_udp_sa(face_t * face, const struct sockaddr * local_addr, +face_initialize_udp_sa(face_t * face, const char * interface_name, + const struct sockaddr * local_addr, const struct sockaddr * remote_addr) { - if (local_addr->sa_family != remote_addr->sa_family) + if (!local_addr) + return -1; + + if (remote_addr && (local_addr->sa_family != remote_addr->sa_family)) return -1; switch (local_addr->sa_family) { @@ -97,14 +212,14 @@ face_initialize_udp_sa(face_t * face, const struct sockaddr * local_addr, struct sockaddr_in *rsai = (struct sockaddr_in *)remote_addr; *face = (face_t) { .type = FACE_TYPE_UDP, - .params.tunnel = { - .family = AF_INET, - .local_addr.v4.as_inaddr = lsai->sin_addr, - .local_port = ntohs(lsai->sin_port), - .remote_addr.v4.as_inaddr = rsai->sin_addr, - .remote_port = ntohs(rsai->sin_port), - }, + .family = AF_INET, + .local_addr.v4.as_inaddr = lsai->sin_addr, + .local_port = lsai ? ntohs(lsai->sin_port) : 0, + .remote_addr = IP_ADDRESS_EMPTY, + .remote_port = rsai ? ntohs(rsai->sin_port) : 0, }; + if (rsai) + face->remote_addr.v4.as_inaddr = rsai->sin_addr; } break; case AF_INET6: @@ -113,19 +228,22 @@ face_initialize_udp_sa(face_t * face, const struct sockaddr * local_addr, struct sockaddr_in6 *rsai = (struct sockaddr_in6 *)remote_addr; *face = (face_t) { .type = FACE_TYPE_UDP, - .params.tunnel = { - .family = AF_INET6, - .local_addr.v6.as_in6addr = lsai->sin6_addr, - .local_port = ntohs(lsai->sin6_port), - .remote_addr.v6.as_in6addr = rsai->sin6_addr, - .remote_port = ntohs(rsai->sin6_port), - }, + .family = AF_INET6, + .local_addr.v6.as_in6addr = lsai->sin6_addr, + .local_port = lsai ? ntohs(lsai->sin6_port) : 0, + .remote_addr = IP_ADDRESS_EMPTY, + .remote_port = rsai ? ntohs(rsai->sin6_port) : 0, }; + if (rsai) + face->remote_addr.v6.as_in6addr = rsai->sin6_addr; } break; default: return -1; } + + snprintf(face->netdevice.name, IFNAMSIZ, "%s", interface_name); + return 1; } @@ -135,11 +253,12 @@ face_t * face_create() return face; } -face_t * face_create_udp(const ip_address_t * local_addr, u16 local_port, +face_t * face_create_udp(const char * interface_name, + const ip_address_t * local_addr, u16 local_port, const ip_address_t * remote_addr, u16 remote_port, int family) { face_t * face = face_create(); - if (face_initialize_udp(face, local_addr, local_port, remote_addr, remote_port, family) < 0) + if (face_initialize_udp(face, interface_name, local_addr, local_port, remote_addr, remote_port, family) < 0) goto ERR_INIT; return face; @@ -148,11 +267,12 @@ ERR_INIT: return NULL; } -face_t * face_create_udp_sa(const struct sockaddr * local_addr, +face_t * face_create_udp_sa(const char * interface_name, + const struct sockaddr * local_addr, const struct sockaddr * remote_addr) { face_t * face = face_create(); - if (face_initialize_udp_sa(face, local_addr, remote_addr) < 0) + if (face_initialize_udp_sa(face, interface_name, local_addr, remote_addr) < 0) goto ERR_INIT; return face; @@ -166,10 +286,6 @@ void face_free(face_t * face) free(face); } -#define face_param_cmp(f1, f2, face_param_type) \ - memcmp(&f1->type, &f2->type, \ - member_size(face_params_t, face_param_type)); - /** * \brief Compare two faces * \param [in] f1 - First face @@ -182,18 +298,61 @@ void face_free(face_t * face) int face_cmp(const face_t * f1, const face_t * f2) { - if (f1->type != f2->type) - return false; + + int ret = f1->type - f2->type; + if (ret != 0) + return ret; + + ret = f1->family - f2->family; + if (ret != 0) + return ret; + + /* + * FIXME As hicn-light API might not return the netdevice, we can discard the + * comparison when one of the two is not set for now... + */ + if ((f1->netdevice.index != 0) && (f2->netdevice.index != 0)) { + ret = netdevice_cmp(&f1->netdevice, &f2->netdevice); + if (ret != 0) + return ret; + } switch(f1->type) { case FACE_TYPE_HICN: - return face_param_cmp(f1, f2, hicn); + ret = ip_address_cmp(&f1->local_addr, &f2->local_addr, f1->family); + if (ret != 0) + return ret; + + ret = ip_address_cmp(&f1->remote_addr, &f2->remote_addr, f1->family); + if (ret != 0) + return ret; + + break; + case FACE_TYPE_TCP: case FACE_TYPE_UDP: - return face_param_cmp(f1, f2, tunnel); + ret = ip_address_cmp(&f1->local_addr, &f2->local_addr, f1->family); + if (ret != 0) + return ret; + + ret = f1->local_port - f2->local_port; + if (ret != 0) + return ret; + + ret = ip_address_cmp(&f1->remote_addr, &f2->remote_addr, f1->family); + if (ret != 0) + return ret; + + ret = f1->remote_port - f2->remote_port; + if (ret != 0) + return ret; + + break; default: - return false; + break; } + + return 0; } hash_t @@ -209,34 +368,59 @@ face_snprintf(char * s, size_t size, const face_t * face) { switch(face->type) { case FACE_TYPE_HICN: - return 0; // XXX Not implemented + { + char local[MAXSZ_IP_ADDRESS]; + char remote[MAXSZ_IP_ADDRESS]; + char tags[MAXSZ_POLICY_TAGS]; + + ip_address_snprintf(local, MAXSZ_IP_ADDRESS, + &face->local_addr, + face->family); + ip_address_snprintf(remote, MAXSZ_IP_ADDRESS, + &face->remote_addr, + face->family); + policy_tags_snprintf(tags, MAXSZ_POLICY_TAGS, face->tags); + return snprintf(s, size, "%s [%s -> %s] [%s]", + face_type_str[face->type], + local, + remote, + tags); + } + case FACE_TYPE_UNDEFINED: case FACE_TYPE_TCP: case FACE_TYPE_UDP: - { - char local[MAXSZ_IP_ADDRESS]; - char remote[MAXSZ_IP_ADDRESS]; - - ip_address_snprintf(local, MAXSZ_IP_ADDRESS, - &face->params.tunnel.local_addr, - face->params.tunnel.family); - ip_address_snprintf(remote, MAXSZ_IP_ADDRESS, - &face->params.tunnel.remote_addr, - face->params.tunnel.family); - - return snprintf(s, size, "%s [%s:%d -> %s:%d]", - face_type_str[face->type], - local, - face->params.tunnel.local_port, - remote, - face->params.tunnel.remote_port); - } - break; + { + char local[MAXSZ_IP_ADDRESS]; + char remote[MAXSZ_IP_ADDRESS]; + char tags[MAXSZ_POLICY_TAGS]; + + ip_address_snprintf(local, MAXSZ_IP_ADDRESS, + &face->local_addr, + face->family); + ip_address_snprintf(remote, MAXSZ_IP_ADDRESS, + &face->remote_addr, + face->family); + policy_tags_snprintf(tags, MAXSZ_POLICY_TAGS, face->tags); + + return snprintf(s, size, "%s [%s:%d -> %s:%d] [%s]", + face_type_str[face->type], + local, + face->local_port, + remote, + face->remote_port, + tags); + } default: - return 0; + return -1; } } +policy_tags_t face_get_tags(const face_t * face) +{ + return face->tags; +} + int face_set_tags(face_t * face, policy_tags_t tags) { diff --git a/ctrl/libhicnctrl/src/util/ip_address.h b/ctrl/libhicnctrl/src/util/ip_address.h deleted file mode 100644 index 472cceeea..000000000 --- a/ctrl/libhicnctrl/src/util/ip_address.h +++ /dev/null @@ -1,316 +0,0 @@ -/* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * \file ip_address.h - * \brief IP address type support - */ -#ifndef UTIL_IP_ADDRESS_H -#define UTIL_IP_ADDRESS_H - -#include <arpa/inet.h> // inet_ntop -#ifdef __APPLE__ -#include <libkern/OSByteOrder.h> -#define __bswap_constant_32(x) OSSwapInt32(x) -#include <machine/endian.h> -#else -#ifdef __ANDROID__ -#include <byteswap.h> -#endif -#include <endian.h> -#endif -#include <errno.h> -#include <netdb.h> // struct addrinfo -#include <netinet/in.h> // INET*_ADDRSTRLEN, IN*ADDR_LOOPBACK -#include <stdlib.h> -#include <string.h> // memset - -#include "types.h" - - -#define bytes_to_bits(x) (x * 8) -#define IPV6_ADDR_LEN 16 /* bytes */ -#define IPV4_ADDR_LEN 4 /* bytes */ -#define IPV6_ADDR_LEN_BITS bytes_to_bits(IPV6_ADDR_LEN) -#define IPV4_ADDR_LEN_BITS bytes_to_bits(IPV4_ADDR_LEN) - -#define IP_MAX_ADDR_LEN IPV6_ADDR_LEN - -#define DUMMY_PORT 1234 - -typedef union { - union { - struct in_addr as_inaddr; - u8 as_u8[4]; - u16 as_u16[2]; - u32 as_u32; - } v4; - union { - struct in6_addr as_in6addr; - u8 as_u8[16]; - u16 as_u16[8]; - u32 as_u32[4]; - u64 as_u64[2]; - } v6; - u8 buffer[IP_MAX_ADDR_LEN]; - u8 as_u8[IP_MAX_ADDR_LEN]; - u16 as_u16[IP_MAX_ADDR_LEN >> 1]; - u32 as_u32[IP_MAX_ADDR_LEN >> 2]; - u64 as_u64[IP_MAX_ADDR_LEN >> 3]; -} ip_address_t; - -#define MAXSZ_IP4_ADDRESS_ INET_ADDRSTRLEN - 1 -#define MAXSZ_IP6_ADDRESS_ INET6_ADDRSTRLEN - 1 -#define MAXSZ_IP_ADDRESS_ MAXSZ_IP6_ADDRESS_ -#define MAXSZ_IP4_ADDRESS MAXSZ_IP4_ADDRESS_ + 1 -#define MAXSZ_IP6_ADDRESS MAXSZ_IP6_ADDRESS_ + 1 -#define MAXSZ_IP_ADDRESS MAXSZ_IP_ADDRESS_ + 1 - - -typedef struct { - int family; - ip_address_t address; - u8 len; -} ip_prefix_t; - -#define MAXSZ_PREFIX_ MAXSZ_IP_ADDRESS_ + 1 + 3 -#define MAXSZ_PREFIX MAXSZ_PREFIX_ + 1 - -/* No htonl() with const */ -static const ip_address_t IPV4_LOOPBACK = { -#if __BYTE_ORDER == __LITTLE_ENDIAN -#ifdef __ANDROID__ - .v4.as_inaddr.s_addr = bswap_32(INADDR_LOOPBACK), -#else - .v4.as_inaddr.s_addr = __bswap_constant_32(INADDR_LOOPBACK), -#endif -#else - .v4.as_inaddr.s_addr = INADDR_LOOPBACK, -#endif -}; - -static const ip_address_t IPV6_LOOPBACK = { - .v6.as_in6addr = IN6ADDR_LOOPBACK_INIT, -}; - -static const ip_address_t IPV4_ANY = { - .v4.as_inaddr.s_addr = INADDR_ANY, -}; - -static const ip_address_t IPV6_ANY = { - .v6.as_in6addr = IN6ADDR_ANY_INIT, -}; - -#define IP_ANY(family) (family == AF_INET) ? IPV4_ANY : IPV6_ANY - -#define MAX_PORT 1 << (8 * sizeof(u16)) -#define IS_VALID_PORT(x) ((x > 0) && (x < MAX_PORT)) - -#define MAXSZ_PORT_ 5 -#define MAXSZ_PORT MAXSZ_PORT_ + 1 - -#define IS_VALID_FAMILY(x) ((x == AF_INET) || (x == AF_INET6)) - -static inline -int -ip_address_get_family (const char * ip_address) -{ - struct addrinfo hint, *res = NULL; - int rc; - - memset (&hint, '\0', sizeof hint); - - hint.ai_family = PF_UNSPEC; - hint.ai_flags = AI_NUMERICHOST; - - rc = getaddrinfo (ip_address, NULL, &hint, &res); - if (rc) - { - return -1; - } - rc = res->ai_family; - freeaddrinfo (res); - return rc; -} - -static inline -int -ip_address_len (const ip_address_t * ip_address, int family) -{ - return (family == AF_INET6) ? IPV6_ADDR_LEN : - (family == AF_INET) ? IPV4_ADDR_LEN : 0; -} - -static inline -int -ip_address_ntop (const ip_address_t * ip_address, char *dst, const size_t len, - int family) -{ - const char * s = inet_ntop (family, ip_address->buffer, dst, len); - return (s ? 1 : -1); -} - -/* - * Parse ip addresses in presentation format - */ -static inline -int -ip_address_pton (const char *ip_address_str, ip_address_t * ip_address) -{ - int pton_fd; - char *addr = strdup (ip_address_str); - int family; - - - family = ip_address_get_family (addr); - - switch (family) - { - case AF_INET6: - pton_fd = inet_pton (AF_INET6, addr, &ip_address->buffer); - break; - case AF_INET: - pton_fd = inet_pton (AF_INET, addr, &ip_address->buffer); - break; - default: - goto ERR; - } - - // 0 = not in presentation format - // < 0 = other error (use perror) - if (pton_fd <= 0) - { - goto ERR; - } - - return 1; -ERR: - free (addr); - return -1; -} - - - -static inline -int -ip_address_snprintf(char * s, size_t size, const ip_address_t * ip_address, int family) -{ - size_t len = family == AF_INET ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN; - const char * rc = inet_ntop (family, ip_address->buffer, s, len); - return rc ? strlen(rc) : -1; -} - - -static inline -int -ip_address_to_sockaddr(const ip_address_t * ip_address, - struct sockaddr *sockaddr_address, int family) -{ - struct sockaddr_in6 *tmp6 = (struct sockaddr_in6 *) sockaddr_address; - struct sockaddr_in *tmp4 = (struct sockaddr_in *) sockaddr_address; - - switch (family) - { - case AF_INET6: - tmp6->sin6_family = AF_INET6; - tmp6->sin6_port = DUMMY_PORT; - tmp6->sin6_scope_id = 0; - memcpy (&tmp6->sin6_addr, ip_address->buffer, IPV6_ADDR_LEN); - break; - case AF_INET: - tmp4->sin_family = AF_INET; - tmp4->sin_port = DUMMY_PORT; - memcpy (&tmp4->sin_addr, ip_address->buffer, IPV4_ADDR_LEN); - break; - default: - return -1; - } - - return 1; -} - -static inline -int -ip_address_cmp(const ip_address_t * ip1, const ip_address_t * ip2, int family) -{ - return memcmp(ip1, ip2, ip_address_len(ip1, family)); -} - -/* Parse IP Prefixes in presentation format (in bits, separated by a slash) */ -static inline -int -ip_prefix_pton (const char *ip_address_str, ip_prefix_t * ip_prefix) -{ - int pton_fd; - char *p; - char *eptr; - char *addr = strdup (ip_address_str); - - p = strchr (addr, '/'); - if (!p) - { - ip_prefix->len = 0; // until we get the ip address family - } - else - { - ip_prefix->len = strtoul (p + 1, &eptr, 10); - *p = 0; - } - - ip_prefix->family = ip_address_get_family (addr); - - switch (ip_prefix->family) - { - case AF_INET6: - if (ip_prefix->len > IPV6_ADDR_LEN_BITS) - goto ERR; - pton_fd = inet_pton (AF_INET6, addr, &ip_prefix->address.buffer); - break; - case AF_INET: - if (ip_prefix->len > IPV4_ADDR_LEN_BITS) - goto ERR; - pton_fd = inet_pton (AF_INET, addr, &ip_prefix->address.buffer); - break; - default: - goto ERR; - } - - // 0 = not in presentation format - // < 0 = other error (use perror) - if (pton_fd <= 0) - { - goto ERR; - } - - return 1; -ERR: - free (addr); - return -1; -} - -static inline -int -ip_prefix_ntop (const ip_prefix_t * ip_prefix, char *dst, size_t size) -{ - char ip_s[MAXSZ_IP_ADDRESS]; - const char * s = inet_ntop (ip_prefix->family, ip_prefix->address.buffer, ip_s, MAXSZ_IP_ADDRESS); - if (!s) - return -1; - size_t n = snprintf(dst, size, "%s/%d", ip_s, ip_prefix->len); - - return (n > 0 ? 1 : -1); -} - -#endif /* UTIL_IP_ADDRESS_H */ diff --git a/ctrl/libhicnctrl/src/util/policy.c b/ctrl/libhicnctrl/src/util/policy.c deleted file mode 100644 index 90dbc72cd..000000000 --- a/ctrl/libhicnctrl/src/util/policy.c +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * \file policy.h - * \brief Implementation of policy description - */ - -#include <stdio.h> -#include "policy.h" - -const char * policy_tag_str[] = { - #define _(x) [POLICY_TAG_ ## x] = STRINGIZE(x), - foreach_policy_tag - #undef _ -}; - -const char * policy_state_str[] = { - #define _(x) [POLICY_STATE_ ## x] = STRINGIZE(x), - foreach_policy_state - #undef _ -}; - -int -policy_tag_state_snprintf(char * s, size_t size, const policy_tag_state_t * tag_state) -{ - char *cur = s; - int rc; - - if (tag_state->disabled > 1) - return -1; - - rc = snprintf(cur, s + size - cur, "%s%s", (tag_state->disabled == 1) ? "!" : "", policy_state_str[tag_state->state]); - if (rc < 0) - return rc; - cur += rc; - if (size != 0 && cur >= s + size) - return cur - s; - - return cur - s; -} diff --git a/ctrl/libhicnctrl/src/util/policy.h b/ctrl/libhicnctrl/src/util/policy.h deleted file mode 100644 index 231e53f73..000000000 --- a/ctrl/libhicnctrl/src/util/policy.h +++ /dev/null @@ -1,266 +0,0 @@ -/* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * \file policy.h - * \brief Policy description - */ -#ifndef HICN_POLICY_H -#define HICN_POLICY_H - -#include <netinet/in.h> // INET*_ADDRSTRLEN -#include "token.h" - -/* POLICY TAG */ - -#define foreach_policy_tag \ - /* Interface type */ \ - _(WIRED) \ - _(WIFI) \ - _(CELLULAR) \ - /* QoS */ \ - _(BEST_EFFORT) \ - _(REALTIME) \ - _(MULTIPATH) \ - /* Security */ \ - _(TRUSTED) - -typedef enum { -#define _(x) POLICY_TAG_ ## x, -foreach_policy_tag -#undef _ - POLICY_TAG_N -} policy_tag_t; - -#define MAXSZ_POLICY_TAG_ 11 -#define MAXSZ_POLICY_TAG MAXSZ_POLICY_TAG_ + 1 - -extern const char * policy_tag_str[]; - - -/* POLICY_TAGS */ - -typedef int policy_tags_t; - -static inline -void policy_tags_add(policy_tags_t * tags, policy_tag_t tag) -{ - *tags |= (1 << tag); -} - -static inline -void policy_tags_remove(policy_tags_t * tags, policy_tag_t tag) -{ - *tags &= ~(1 << tag); -} - -static inline -int policy_tags_has(policy_tags_t tags, policy_tag_t tag) -{ - return tags & (1 << tag); -} - -#define POLICY_TAGS_EMPTY 0 - - -/* POLICY STATE */ - -/* TODO vs. weight */ - -#define foreach_policy_state \ - _(NEUTRAL) \ - _(REQUIRE) \ - _(PREFER) \ - _(AVOID) \ - _(PROHIBIT) \ - _(N) - -typedef enum { -#define _(x) POLICY_STATE_ ## x, -foreach_policy_state -#undef _ -} policy_state_t; - -#define MAXSZ_POLICY_STATE_ 8 -#define MAXSZ_POLICY_STATE MAXSZ_POLICY_STATE_ + 1 - -extern const char * policy_state_str[]; - - -/* POLICY TAG STATE */ - -typedef struct { - policy_state_t state; - uint8_t disabled; -} policy_tag_state_t; - -#define MAXSZ_POLICY_TAG_STATE_ 8 -#define MAXSZ_POLICY_TAG_STATE MAXSZ_POLICY_TAG_STATE_ + 1 - -int policy_tag_state_snprintf(char * s, size_t size, const policy_tag_state_t * tag_state); - - -/* INTERFACE STATS */ - -typedef struct { - float throughput; - float latency; - float loss_rate; -} interface_stats_t; - -#define INTERFACE_STATS_NONE { \ - .throughput = 0, \ - .latency = 0, \ - .loss_rate = 0, \ -} - - -/* POLICY STATS */ - -typedef struct { - interface_stats_t wired; - interface_stats_t wifi; - interface_stats_t cellular; - interface_stats_t all; -} policy_stats_t; - -#define POLICY_STATS_NONE { \ - .wired = INTERFACE_STATS_NONE, \ - .wifi = INTERFACE_STATS_NONE, \ - .cellular = INTERFACE_STATS_NONE, \ - .all = INTERFACE_STATS_NONE, \ -} - -typedef struct { - uint32_t num_packets; - uint32_t num_bytes; - uint32_t num_losses; - uint32_t latency_idle; -} interface_counters_t; - -#define INTERFACE_COUNTERS_NONE { \ - .num_packets = 0, \ - .num_bytes = 0, \ - .num_losses = 0, \ - .latency_idle = 0, \ -} - -typedef struct { - interface_counters_t wired; - interface_counters_t wifi; - interface_counters_t cellular; - interface_counters_t all; - uint64_t last_update; -} policy_counters_t; - -#define POLICY_COUNTERS_NONE (policy_counters_t) { \ - .wired = INTERFACE_COUNTERS_NONE, \ - .wifi = INTERFACE_COUNTERS_NONE, \ - .cellular = INTERFACE_COUNTERS_NONE, \ - .all = INTERFACE_COUNTERS_NONE, \ - .last_update = 0, \ -} - -/* POLICY */ - -#define APP_NAME_LEN 128 - -typedef struct { - char app_name[APP_NAME_LEN]; - policy_tag_state_t tags[POLICY_TAG_N]; - policy_stats_t stats; -} policy_t; - -static const policy_t POLICY_NONE = { - .app_name = { 0 }, - .tags = { -#define _(x) [POLICY_TAG_ ## x] = { POLICY_STATE_NEUTRAL, 0 }, -foreach_policy_tag -#undef _ - }, - .stats = POLICY_STATS_NONE, -}; - - -/* POLICY DESCRIPTION */ - -#define PFX_STRLEN 4 /* eg. /128 */ - -typedef struct { - int family; - union { - char ipv4_prefix[INET_ADDRSTRLEN + PFX_STRLEN]; - char ipv6_prefix[INET6_ADDRSTRLEN + PFX_STRLEN]; - }; - policy_t policy; -} policy_description_t; - -/* DEFAULT POLICY */ - -static const policy_description_t default_policy[] = { - { - .family = AF_INET6, - .ipv6_prefix = "a001::/16", - .policy = { - .app_name = "Webex", - .tags = { - [POLICY_TAG_WIRED] = { POLICY_STATE_PREFER, 0 }, - [POLICY_TAG_WIFI] = { POLICY_STATE_NEUTRAL, 0 }, - [POLICY_TAG_CELLULAR] = { POLICY_STATE_AVOID, 1 }, - [POLICY_TAG_BEST_EFFORT] = { POLICY_STATE_PROHIBIT, 0 }, - [POLICY_TAG_REALTIME] = { POLICY_STATE_REQUIRE, 1 }, - [POLICY_TAG_MULTIPATH] = { POLICY_STATE_AVOID, 0 }, - [POLICY_TAG_TRUSTED] = { POLICY_STATE_REQUIRE, 1 }, - }, - .stats = POLICY_STATS_NONE, - }, - }, - { - .family = AF_INET6, - .ipv6_prefix = "b001::/16", - .policy = { - .app_name = "Video Streaming", - .tags = { - [POLICY_TAG_WIRED] = { POLICY_STATE_PREFER, 0 }, - [POLICY_TAG_WIFI] = { POLICY_STATE_NEUTRAL, 0 }, - [POLICY_TAG_CELLULAR] = { POLICY_STATE_NEUTRAL, 0 }, - [POLICY_TAG_BEST_EFFORT] = { POLICY_STATE_PROHIBIT, 0 }, - [POLICY_TAG_REALTIME] = { POLICY_STATE_REQUIRE, 0 }, - [POLICY_TAG_MULTIPATH] = { POLICY_STATE_AVOID, 0 }, - [POLICY_TAG_TRUSTED] = { POLICY_STATE_PREFER, 0 }, - }, - .stats = POLICY_STATS_NONE, - }, - }, - { - .family = AF_INET6, - .ipv6_prefix = "c001::/16", - .policy = { - .app_name = "*", - .tags = { - [POLICY_TAG_WIRED] = { POLICY_STATE_PREFER, 0 }, - [POLICY_TAG_WIFI] = { POLICY_STATE_NEUTRAL, 0 }, - [POLICY_TAG_CELLULAR] = { POLICY_STATE_NEUTRAL, 0 }, - [POLICY_TAG_BEST_EFFORT] = { POLICY_STATE_PROHIBIT, 0 }, - [POLICY_TAG_REALTIME] = { POLICY_STATE_REQUIRE, 0 }, - [POLICY_TAG_MULTIPATH] = { POLICY_STATE_AVOID, 0 }, - [POLICY_TAG_TRUSTED] = { POLICY_STATE_PROHIBIT, 1 }, - }, - .stats = POLICY_STATS_NONE, - }, - }, -}; - -#endif /* HICN_POLICY_H */ diff --git a/ctrl/libhicnctrl/src/util/token.h b/ctrl/libhicnctrl/src/util/token.h deleted file mode 100644 index 43e0a77b2..000000000 --- a/ctrl/libhicnctrl/src/util/token.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* Token concatenation */ - -/* - * Concatenate preprocessor tokens A and B without expanding macro definitions - * (however, if invoked from a macro, macro arguments are expanded). - */ -#define PPCAT_NX(A, B) A ## B - -/* - * Concatenate preprocessor tokens A and B after macro-expanding them. - */ -#define PPCAT(A, B) PPCAT_NX(A, B) - -/* Token stringification */ - -/* - * Turn A into a string literal without expanding macro definitions - * (however, if invoked from a macro, macro arguments are expanded). - */ -#define STRINGIZE_NX(A) #A - -/* - * Turn A into a string literal after macro-expanding it. - */ -#define STRINGIZE(A) STRINGIZE_NX(A) diff --git a/ctrl/libhicnctrl/src/util/types.h b/ctrl/libhicnctrl/src/util/types.h deleted file mode 100644 index 10a0bdca0..000000000 --- a/ctrl/libhicnctrl/src/util/types.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef UTIL_TYPES -#define UTIL_TYPES - -typedef uint8_t u8; -typedef uint16_t u16; -typedef uint32_t u32; -typedef uint64_t u64; - -/* Helper for avoiding warnings about type-punning */ -#define UNION_CAST(x, destType) \ - (((union {__typeof__(x) a; destType b;})x).b) - -typedef unsigned int hash_t; - -typedef int (*cmp_t)(const void *, const void *); - -/* Enums */ - -#define IS_VALID_ENUM_TYPE(NAME, x) ((x > NAME ## _UNDEFINED) && (x < NAME ## _N)) - -#endif /* UTIL_TYPES */ |