From c87f73a07df468eccedbe1fdfa82bdd5b633a0d5 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Thu, 22 Nov 2018 22:04:48 +0100 Subject: move network type logic out of ATS code, move performance preferences into MQ --- configure.ac | 3 +- po/POTFILES.in | 2 + src/Makefile.am | 7 +- src/ats/ats_api_performance.c | 2 +- src/include/Makefile.am | 1 + src/include/gnunet_mq_lib.h | 47 ++++- src/include/gnunet_nt_lib.h | 123 +++++++++++++ src/nt/Makefile.am | 36 ++++ src/nt/nt.c | 410 ++++++++++++++++++++++++++++++++++++++++++ src/util/mq.c | 24 ++- 10 files changed, 648 insertions(+), 7 deletions(-) create mode 100644 src/include/gnunet_nt_lib.h create mode 100644 src/nt/Makefile.am create mode 100644 src/nt/nt.c diff --git a/configure.ac b/configure.ac index b43aa84be..35b2ef659 100644 --- a/configure.ac +++ b/configure.ac @@ -598,7 +598,7 @@ AC_CHECK_LIB(ogg, ogg_stream_flush_fill, PKG_CHECK_MODULES([GLIB], [glib-2.0], [# check for pbc library - pbc=0 + pbc=0 AC_CHECK_HEADER([pbc/pbc.h],pbc=1) AC_CHECK_HEADER([gabe.h],abe=1) AM_CONDITIONAL(HAVE_PBC, [test "x$pbc" = x1]) @@ -1807,6 +1807,7 @@ src/nat-auto/Makefile src/nat-auto/nat-auto.conf src/nse/Makefile src/nse/nse.conf +src/nt/Makefile src/peerinfo/Makefile src/peerinfo/peerinfo.conf src/peerinfo-tool/Makefile diff --git a/po/POTFILES.in b/po/POTFILES.in index 129c43cdd..a7d35588f 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -193,6 +193,7 @@ src/gns/w32nsp-uninstall.c src/hello/address.c src/hello/gnunet-hello.c src/hello/hello.c +src/hello/hello-ng.c src/hostlist/gnunet-daemon-hostlist.c src/hostlist/gnunet-daemon-hostlist_client.c src/hostlist/gnunet-daemon-hostlist_server.c @@ -250,6 +251,7 @@ src/nse/gnunet-nse.c src/nse/gnunet-nse-profiler.c src/nse/gnunet-service-nse.c src/nse/nse_api.c +src/nt/nt.c src/peerinfo/gnunet-service-peerinfo.c src/peerinfo/peerinfo_api.c src/peerinfo/peerinfo_api_notify.c diff --git a/src/Makefile.am b/src/Makefile.am index 39cbaa893..5e2b0e493 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -16,7 +16,7 @@ if HAVE_EXPERIMENTAL psycutil \ psycstore \ psyc \ - social + social # dv (FTBFS) if HAVE_ABE if HAVE_JSON @@ -24,7 +24,7 @@ if HAVE_JSON abe \ credential \ reclaim-attribute \ - reclaim + reclaim endif endif if HAVE_JSON @@ -80,6 +80,7 @@ else SUBDIRS = \ include $(INTLEMU_SUBDIRS) \ util \ + nt \ gnsrecord \ hello \ block \ @@ -129,6 +130,6 @@ SUBDIRS = \ $(EXP_DIR) \ $(JSON_DIR) \ $(REST_DIR) \ - integration-tests + integration-tests endif diff --git a/src/ats/ats_api_performance.c b/src/ats/ats_api_performance.c index 0c196ea43..11e71e94e 100644 --- a/src/ats/ats_api_performance.c +++ b/src/ats/ats_api_performance.c @@ -11,7 +11,7 @@ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - + You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ diff --git a/src/include/Makefile.am b/src/include/Makefile.am index 41b2b1382..185f649ac 100644 --- a/src/include/Makefile.am +++ b/src/include/Makefile.am @@ -87,6 +87,7 @@ gnunetinclude_HEADERS = \ gnunet_nc_lib.h \ gnunet_network_lib.h \ gnunet_nse_service.h \ + gnunet_nt_lib.h \ gnunet_op_lib.h \ gnunet_os_lib.h \ gnunet_peer_lib.h \ diff --git a/src/include/gnunet_mq_lib.h b/src/include/gnunet_mq_lib.h index 226b3389f..3d3a74e3b 100644 --- a/src/include/gnunet_mq_lib.h +++ b/src/include/gnunet_mq_lib.h @@ -11,7 +11,7 @@ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - + You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ @@ -875,6 +875,51 @@ const struct GNUNET_MessageHeader * GNUNET_MQ_impl_current (struct GNUNET_MQ_Handle *mq); + +/** + * Enum defining all known preference categories. + */ +enum GNUNET_MQ_PreferenceKind +{ + + /** + * No preference was expressed. + */ + GNUNET_MQ_PREFERENCE_NONE = 0, + + /** + * The preferred transmission for this envelope focuses on + * maximizing bandwidth. + */ + GNUNET_MQ_PREFERENCE_BANDWIDTH = 1, + + /** + * The preferred transmission for this envelope foces on + * minimizing latency. + */ + GNUNET_MQ_PREFERENCE_LATENCY = 2, + + /** + * The preferred transmission for this envelope foces on + * reliability. + */ + GNUNET_MQ_PREFERENCE_RELIABILITY = 3 + +}; + + +/** + * Convert an `enum GNUNET_MQ_PreferenceType` to a string + * + * @param type the preference type + * @return a string or NULL if invalid + */ +const char * +GNUNET_MQ_preference_to_string (enum GNUNET_MQ_PreferenceKind type); + + + + #endif /** @} */ /* end of group mq */ diff --git a/src/include/gnunet_nt_lib.h b/src/include/gnunet_nt_lib.h new file mode 100644 index 000000000..3d89aa7b2 --- /dev/null +++ b/src/include/gnunet_nt_lib.h @@ -0,0 +1,123 @@ +/* + This file is part of GNUnet. + Copyright (C) 2010-2015, 2018 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ +/** + * @file network type characterization + * @author Christian Grothoff + * @author Matthias Wachs + * + * @defgroup nt network type characterization + * + * @{ + */ +#ifndef GNUNET_NT_LIB_H +#define GNUNET_NT_LIB_H + +/** + * Types of networks (with separate quotas) we support. + */ +enum GNUNET_NetworkType +{ + /** + * Category of last resort. + */ + GNUNET_NT_UNSPECIFIED = 0, + + /** + * Loopback (same host). + */ + GNUNET_NT_LOOPBACK = 1, + + /** + * Local area network. + */ + GNUNET_NT_LAN = 2, + + /** + * Wide area network (i.e. Internet) + */ + GNUNET_NT_WAN = 3, + + /** + * Wireless LAN (i.e. 802.11abgn) + */ + GNUNET_NT_WLAN = 4, + + /** + * Bluetooth LAN + */ + GNUNET_NT_BT = 5 + +/** + * Number of network types supported by ATS + */ +#define GNUNET_NT_COUNT 6 + +}; + + +/** + * Convert a `enum GNUNET_NetworkType` to a string + * + * @param net the network type + * @return a string or NULL if invalid + */ +const char * +GNUNET_NT_to_string (enum GNUNET_NetworkType net); + + +/** + * Handle for the LAN Characterization library. + */ +struct GNUNET_NT_InterfaceScanner; + + +/** + * Returns where the address is located: loopback, LAN or WAN. + * + * @param is handle from #GNUNET_ATS_interface_scanner_init() + * @param addr address + * @param addrlen address length + * @return type of the network the address belongs to + */ +enum GNUNET_NetworkType +GNUNET_NT_scanner_get_type (struct GNUNET_NT_InterfaceScanner *is, + const struct sockaddr *addr, + socklen_t addrlen); + + +/** + * Initialize the address characterization client handle. + * + * @return scanner handle, NULL on error + */ +struct GNUNET_NT_InterfaceScanner * +GNUNET_NT_scanner_init (void); + + +/** + * Terminate interface scanner. + * + * @param is scanner we are done with + */ +void +GNUNET_NT_scanner_done (struct GNUNET_NT_InterfaceScanner *is); + + +#endif + +/** @} */ /* end of group */ diff --git a/src/nt/Makefile.am b/src/nt/Makefile.am new file mode 100644 index 000000000..68b6a55e7 --- /dev/null +++ b/src/nt/Makefile.am @@ -0,0 +1,36 @@ +# This Makefile.am is in the public domain +AM_CPPFLAGS = -I$(top_srcdir)/src/include + +if MINGW + WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +endif + +if USE_COVERAGE + AM_CFLAGS = --coverage +endif + +lib_LTLIBRARIES = libgnunetnt.la + +libgnunetnt_la_SOURCES = \ + nt.c + +libgnunetnt_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la +libgnunetnt_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) \ + -version-info 0:0:0 + +#if ENABLE_TEST_RUN +#TESTS = \ +# test_nt +#endif + +#check_PROGRAMS= \ +# test_nt +# +#test_nt_SOURCES = \ +# test_nt.c +#test_nt_LDADD = \ +# libgnunetnt.la \ +# $(top_builddir)/src/util/libgnunetutil.la \ +# $(XLIB) diff --git a/src/nt/nt.c b/src/nt/nt.c new file mode 100644 index 000000000..5764f8f4a --- /dev/null +++ b/src/nt/nt.c @@ -0,0 +1,410 @@ +/* + This file is part of GNUnet. + Copyright (C) 2010-2015, 2018 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ +/** + * @file nt/nt_api_scanner.c + * @brief LAN interface scanning to determine IPs in LAN + * @author Christian Grothoff + * @author Matthias Wachs + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_nt_lib.h" + +/** + * How frequently do we scan the interfaces for changes to the addresses? + */ +#define INTERFACE_PROCESSING_INTERVAL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 2) + + +/** + * Convert a `enum GNUNET_NetworkType` to a string + * + * @param net the network type + * @return a string or NULL if invalid + */ +const char * +GNUNET_NT_to_string (enum GNUNET_NetworkType net) +{ + switch (net) + { + case GNUNET_NT_UNSPECIFIED: + return "UNSPECIFIED"; + case GNUNET_NT_LOOPBACK: + return "LOOPBACK"; + case GNUNET_NT_LAN: + return "LAN"; + case GNUNET_NT_WAN: + return "WAN"; + case GNUNET_NT_WLAN: + return "WLAN"; + case GNUNET_NT_BT: + return "BLUETOOTH"; + default: + return NULL; + } +} + + +/** + * We keep a list of our local networks so we can answer + * LAN vs. WAN questions. Note: WLAN is not detected yet. + * (maybe we can do that heuristically based on interface + * name in the future?). + */ +struct NT_Network +{ + /** + * Kept in a DLL. + */ + struct NT_Network *next; + + /** + * Kept in a DLL. + */ + struct NT_Network *prev; + + /** + * Network address. + */ + struct sockaddr *network; + + /** + * Netmask to determine what is in the LAN. + */ + struct sockaddr *netmask; + + /** + * How long are @e network and @e netmask? + */ + socklen_t length; +}; + + +/** + * Handle to the interface scanner. + */ +struct GNUNET_NT_InterfaceScanner +{ + + /** + * Head of LAN networks list. + */ + struct NT_Network *net_head; + + /** + * Tail of LAN networks list. + */ + struct NT_Network *net_tail; + + /** + * Task for periodically refreshing our LAN network list. + */ + struct GNUNET_SCHEDULER_Task *interface_task; + +}; + + +/** + * Delete all entries from the current network list. + * + * @param is scanner to clean up + */ +static void +delete_networks (struct GNUNET_NT_InterfaceScanner *is) +{ + struct NT_Network *cur; + + while (NULL != (cur = is->net_head)) + { + GNUNET_CONTAINER_DLL_remove (is->net_head, + is->net_tail, + cur); + GNUNET_free (cur); + } +} + + +/** + * Function invoked for each interface found. Adds the interface's + * network addresses to the respective DLL, so we can distinguish + * between LAN and WAN. + * + * @param cls closure with the `struct GNUNET_NT_InterfaceScanner` + * @param name name of the interface (can be NULL for unknown) + * @param isDefault is this presumably the default interface + * @param addr address of this interface (can be NULL for unknown or unassigned) + * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned) + * @param netmask the network mask (can be NULL for unknown or unassigned) + * @param addrlen length of the address + * @return #GNUNET_OK to continue iteration + */ +static int +interface_proc (void *cls, + const char *name, + int isDefault, + const struct sockaddr *addr, + const struct sockaddr *broadcast_addr, + const struct sockaddr *netmask, + socklen_t addrlen) +{ + struct GNUNET_NT_InterfaceScanner *is = cls; + /* Calculate network */ + struct NT_Network *net = NULL; + + /* Skipping IPv4 loopback addresses since we have special check */ + if (addr->sa_family == AF_INET) + { + const struct sockaddr_in *a4 = (const struct sockaddr_in *) addr; + + if ((a4->sin_addr.s_addr & htonl(0xff000000)) == htonl (0x7f000000)) + return GNUNET_OK; + } + /* Skipping IPv6 loopback addresses since we have special check */ + if (addr->sa_family == AF_INET6) + { + const struct sockaddr_in6 *a6 = (const struct sockaddr_in6 *) addr; + if (IN6_IS_ADDR_LOOPBACK (&a6->sin6_addr)) + return GNUNET_OK; + } + + if (addr->sa_family == AF_INET) + { + const struct sockaddr_in *addr4 = (const struct sockaddr_in *) addr; + const struct sockaddr_in *netmask4 = (const struct sockaddr_in *) netmask; + struct sockaddr_in *tmp; + struct sockaddr_in network4; + + net = GNUNET_malloc (sizeof (struct NT_Network) + 2 * sizeof (struct sockaddr_in)); + tmp = (struct sockaddr_in *) &net[1]; + net->network = (struct sockaddr *) &tmp[0]; + net->netmask = (struct sockaddr *) &tmp[1]; + net->length = addrlen; + + memset (&network4, 0, sizeof (network4)); + network4.sin_family = AF_INET; +#if HAVE_SOCKADDR_IN_SIN_LEN + network4.sin_len = sizeof (network4); +#endif + network4.sin_addr.s_addr = (addr4->sin_addr.s_addr & netmask4->sin_addr.s_addr); + + GNUNET_memcpy (net->netmask, netmask4, sizeof (struct sockaddr_in)); + GNUNET_memcpy (net->network, &network4, sizeof (struct sockaddr_in)); + } + + if (addr->sa_family == AF_INET6) + { + const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *) addr; + const struct sockaddr_in6 *netmask6 = (const struct sockaddr_in6 *) netmask; + struct sockaddr_in6 * tmp; + struct sockaddr_in6 network6; + + net = GNUNET_malloc (sizeof (struct NT_Network) + 2 * sizeof (struct sockaddr_in6)); + tmp = (struct sockaddr_in6 *) &net[1]; + net->network = (struct sockaddr *) &tmp[0]; + net->netmask = (struct sockaddr *) &tmp[1]; + net->length = addrlen; + + memset (&network6, 0, sizeof (network6)); + network6.sin6_family = AF_INET6; +#if HAVE_SOCKADDR_IN_SIN_LEN + network6.sin6_len = sizeof (network6); +#endif + unsigned int c = 0; + uint32_t *addr_elem = (uint32_t *) &addr6->sin6_addr; + uint32_t *mask_elem = (uint32_t *) &netmask6->sin6_addr; + uint32_t *net_elem = (uint32_t *) &network6.sin6_addr; + for (c = 0; c < 4; c++) + net_elem[c] = addr_elem[c] & mask_elem[c]; + + GNUNET_memcpy (net->netmask, netmask6, sizeof (struct sockaddr_in6)); + GNUNET_memcpy (net->network, &network6, sizeof (struct sockaddr_in6)); + } + if (NULL == net) + return GNUNET_OK; /* odd / unsupported address family */ + + /* Store in list */ +#if VERBOSE_NT + char * netmask = GNUNET_strdup (GNUNET_a2s((struct sockaddr *) net->netmask, addrlen)); + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, + "nt", + "Adding network `%s', netmask `%s'\n", + GNUNET_a2s ((struct sockaddr *) net->network, + addrlen), + netmask); + GNUNET_free (netmask); +#endif + GNUNET_CONTAINER_DLL_insert (is->net_head, + is->net_tail, + net); + + return GNUNET_OK; +} + + +/** + * Periodically get list of network addresses from our interfaces. + * + * @param cls closure + */ +static void +get_addresses (void *cls) +{ + struct GNUNET_NT_InterfaceScanner *is = cls; + + is->interface_task = NULL; + delete_networks (is); + GNUNET_OS_network_interfaces_list (&interface_proc, + is); + is->interface_task = GNUNET_SCHEDULER_add_delayed (INTERFACE_PROCESSING_INTERVAL, + &get_addresses, + is); +} + + +/** + * Returns where the address is located: LAN or WAN or ... + * + * @param is the interface scanner handle + * @param addr address + * @param addrlen address length + * @return type of the network the address belongs to + */ +enum GNUNET_NetworkType +GNUNET_NT_scanner_address_get_type (struct GNUNET_NT_InterfaceScanner *is, + const struct sockaddr *addr, + socklen_t addrlen) +{ + struct NT_Network *cur = is->net_head; + enum GNUNET_NetworkType type = GNUNET_NT_UNSPECIFIED; + + switch (addr->sa_family) + { + case AF_UNIX: + type = GNUNET_NT_LOOPBACK; + break; + case AF_INET: + { + const struct sockaddr_in *a4 = (const struct sockaddr_in *) addr; + + if ((a4->sin_addr.s_addr & htonl(0xff000000)) == htonl (0x7f000000)) + type = GNUNET_NT_LOOPBACK; + break; + } + case AF_INET6: + { + const struct sockaddr_in6 *a6 = (const struct sockaddr_in6 *) addr; + + if (IN6_IS_ADDR_LOOPBACK (&a6->sin6_addr)) + type = GNUNET_NT_LOOPBACK; + break; + } + default: + GNUNET_break (0); + break; + } + + /* Check local networks */ + while ((NULL != cur) && (GNUNET_NT_UNSPECIFIED == type)) + { + if (addrlen != cur->length) + { + cur = cur->next; + continue; + } + if (addr->sa_family == AF_INET) + { + const struct sockaddr_in *a4 = (const struct sockaddr_in *) addr; + const struct sockaddr_in *net4 = (const struct sockaddr_in *) cur->network; + const struct sockaddr_in *mask4 = (const struct sockaddr_in *) cur->netmask; + + if (((a4->sin_addr.s_addr & mask4->sin_addr.s_addr)) == net4->sin_addr.s_addr) + type = GNUNET_NT_LAN; + } + if (addr->sa_family == AF_INET6) + { + const struct sockaddr_in6 *a6 = (const struct sockaddr_in6 *) addr; + const struct sockaddr_in6 *net6 = (const struct sockaddr_in6 *) cur->network; + const struct sockaddr_in6 *mask6 = (const struct sockaddr_in6 *) cur->netmask; + + int res = GNUNET_YES; + int c = 0; + uint32_t *addr_elem = (uint32_t *) &a6->sin6_addr; + uint32_t *mask_elem = (uint32_t *) &mask6->sin6_addr; + uint32_t *net_elem = (uint32_t *) &net6->sin6_addr; + for (c = 0; c < 4; c++) + if ((addr_elem[c] & mask_elem[c]) != net_elem[c]) + res = GNUNET_NO; + + if (res == GNUNET_YES) + type = GNUNET_NT_LAN; + } + cur = cur->next; + } + + /* no local network found for this address, default: WAN */ + if (type == GNUNET_NT_UNSPECIFIED) + type = GNUNET_NT_WAN; + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, + "nt-scanner-api", + "`%s' is in network `%s'\n", + GNUNET_a2s (addr, + addrlen), + GNUNET_NT_to_string (type)); + return type; +} + + +/** + * Initialize the interface scanner. + * + * @return interface scanner + */ +struct GNUNET_NT_InterfaceScanner * +GNUNET_NT_scanner_init () +{ + struct GNUNET_NT_InterfaceScanner *is; + + is = GNUNET_new (struct GNUNET_NT_InterfaceScanner); + GNUNET_OS_network_interfaces_list (&interface_proc, + is); + is->interface_task = GNUNET_SCHEDULER_add_delayed (INTERFACE_PROCESSING_INTERVAL, + &get_addresses, + is); + return is; +} + + +/** + * Client is done with the interface scanner, release resources. + * + * @param is handle to release + */ +void +GNUNET_NT_scanner_done (struct GNUNET_NT_InterfaceScanner *is) +{ + if (NULL != is->interface_task) + { + GNUNET_SCHEDULER_cancel (is->interface_task); + is->interface_task = NULL; + } + delete_networks (is); + GNUNET_free (is); +} + + +/* end of nt.c */ diff --git a/src/util/mq.c b/src/util/mq.c index eaac85575..8bf1f9752 100644 --- a/src/util/mq.c +++ b/src/util/mq.c @@ -11,7 +11,7 @@ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - + You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ @@ -1270,5 +1270,27 @@ GNUNET_MQ_count_handlers (const struct GNUNET_MQ_MessageHandler *handlers) } +/** + * Convert an `enum GNUNET_MQ_PreferenceType` to a string + * + * @param type the preference type + * @return a string or NULL if invalid + */ +const char * +GNUNET_MQ_preference_to_string (enum GNUNET_MQ_PreferenceKind type) +{ + switch (type) { + case GNUNET_MQ_PREFERENCE_NONE: + return "NONE"; + case GNUNET_MQ_PREFERENCE_BANDWIDTH: + return "BANDWIDTH"; + case GNUNET_MQ_PREFERENCE_LATENCY: + return "LATENCY"; + case GNUNET_MQ_PREFERENCE_RELIABILITY: + return "RELIABILITY"; + }; + return NULL; +} + /* end of mq.c */ -- cgit v1.2.3