diff --git a/CMakeLists.txt b/CMakeLists.txt index e69de29..bddcf46 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -0,0 +1,145 @@ +cmake_minimum_required(VERSION 2.8) + +# Define project name +project("libviface") + +# The version number +set(libviface_VERSION_STRING "1.1.0") + +# Setup project variables +set(VIFACE_TESTS ON CACHE BOOL "Enable compilation of unit tests.") +set(VIFACE_EXAMPLES ON CACHE BOOL "Enable compilation of the examples.") +set(VIFACE_FORCE_32BITS OFF CACHE BOOL "Force library compilation for 32 bits.") + +# Force C++11 compiler +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") + +# Installation variables +set(CMAKE_INSTALL_LIBDIR lib) +set(CMAKE_INSTALL_INCLUDEDIR include) +set(CMAKE_INSTALL_BINDIR bin) + +# Configure library install location +if(VIFACE_FORCE_32BITS) + set(CMAKE_INSTALL_LIBDIR lib32) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -m32") +endif(VIFACE_FORCE_32BITS) + +# Support for pkg-config file +set(pkgconfig_prefix ${CMAKE_INSTALL_PREFIX}) +set(pkgconfig_exec_prefix ${CMAKE_INSTALL_PREFIX}) +set(pkgconfig_libdir ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}) +set(pkgconfig_version ${libviface_VERSION_STRING}) +configure_file( + "${libviface_SOURCE_DIR}/libviface.pc.in" + "${CMAKE_BINARY_DIR}/libviface.pc" + @ONLY +) + +include(FindPkgConfig) + +# Check and set APR dependencies +pkg_check_modules(APR apr-1>=1.5.1) +set (LIBVIFACE_PC_REQUIRED_PACKAGES ${LIBVIFACE_PC_REQUIRED_PACKAGES} "apr-1 >= 1.5.1") +if(NOT APR_FOUND) + message(FATAL_ERROR "Apache Portable Runtime not found, please install it (>= 1.5.1)") +endif() + +pkg_check_modules(APRUTIL apr-util-1>=1.5.3) +set (LIBVIFACE_PC_REQUIRED_PACKAGES ${LIBVIFACE_PC_REQUIRED_PACKAGES} "apr-util-1 >= 1.5.3") +if(NOT APRUTIL_FOUND) + message(FATAL_ERROR "Apache Portable Runtime Utils not found, please install it (>= 1.5.3)") +endif() + +add_definitions(${APR_CFLAGS} ${APRUTIL_CFLAGS}) +include_directories(${APR_INCLUDE_DIRS} ${APRUTIL_INCLUDE_DIRS}) +link_directories(${APR_LIBRARY_DIRS} ${APRUTIL_LIBRARY_DIRS}) + +install( + FILES + "${CMAKE_BINARY_DIR}/libviface.pc" + DESTINATION + "${CMAKE_INSTALL_LIBDIR}/pkgconfig" +) + +# Configure library +configure_file( + "${libviface_SOURCE_DIR}/include/viface/config.h.in" + "${CMAKE_BINARY_DIR}/include/viface/config.h" + @ONLY +) + +# Creates custom target to build library +add_custom_target( + ${PROJECT_NAME} + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" + COMMENT "Building ${PROJECT_NAME} library..." VERBATIM +) + +# Specify include directory +include_directories("${libviface_SOURCE_DIR}/include/") +include_directories("${CMAKE_BINARY_DIR}/include/") + +# Specify source directory +add_subdirectory("${libviface_SOURCE_DIR}/src/") +if(VIFACE_TESTS) + message(STATUS "Including libviface test suite...") + add_subdirectory("${libviface_SOURCE_DIR}/test/") +endif(VIFACE_TESTS) +if(VIFACE_EXAMPLES) + message(STATUS "Including libviface examples...") + add_subdirectory("${libviface_SOURCE_DIR}/examples/") +endif(VIFACE_EXAMPLES) + +# Specify bindings directory +add_subdirectory("${libviface_SOURCE_DIR}/bindings/") + +# Specify public interface install directory +install( + FILES + "${libviface_SOURCE_DIR}/include/viface/viface.h" + "${CMAKE_BINARY_DIR}/include/viface/config.h" + DESTINATION + "${CMAKE_INSTALL_INCLUDEDIR}/viface" +) + +# Creates a symbolic link of the shared library +add_custom_command( + TARGET ${PROJECT_NAME} POST_BUILD + COMMAND ln -sf ${CMAKE_SOURCE_DIR}/build/src/libviface.so.1.1.0 /usr/lib/ + COMMENT "Generating symbolic link to ${PROJECT_NAME} library" +) + +# Add API Reference generation +find_package(Doxygen) +if(DOXYGEN_FOUND) + configure_file( + "${libviface_SOURCE_DIR}/doc/doxygen.conf.in" + "${CMAKE_BINARY_DIR}/doxygen.conf" + @ONLY + ) + add_custom_target( + doc + "${DOXYGEN_EXECUTABLE}" + "${CMAKE_BINARY_DIR}/doxygen.conf" + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" + COMMENT "Generating API Reference documentation..." VERBATIM + ) +endif(DOXYGEN_FOUND) + +# Setup Git hooks +if(EXISTS ${CMAKE_SOURCE_DIR}/.git/hooks) + + # Setup our git hooks to avoid people from checking in code against the + # Coding Standard (at least syntactically) + if(NOT EXISTS ${CMAKE_SOURCE_DIR}/.git/hooks/pre-commit) + + message(STATUS "Installing Coding Standard pre-commit hook...") + execute_process( + COMMAND ln -s ../../tools/uncrustify/pre-commit ${CMAKE_SOURCE_DIR}/.git/hooks/pre-commit + COMMAND chmod 0755 ${CMAKE_SOURCE_DIR}/.git/hooks/pre-commit + ) + endif() +endif() diff --git a/README.rst b/README.rst index 54d52eb..c38df8c 100644 --- a/README.rst +++ b/README.rst @@ -1,23 +1,45 @@ ================================================================== -libviface : C++ bindings for Linux tun/tap and netdevice interface +libviface : libviface C object oriented interface for managing and creating network interfaces. ================================================================== -``libviface`` is a small C++11 library that allows to create and configure +``libviface`` is a small C library that allows to create and configure virtual network interfaces in Linux based Operating Systems. :: - #include "viface/viface.hpp" + #include "viface/viface.h" - // Create interface - viface::VIface iface("viface%d"); + // Creates viface struct + struct viface *self; - // Configure interface - iface.setMAC("66:23:2d:28:c6:84"); - iface.setIPv4("192.168.20.21"); + // Interface configuration data + char *name = "viface0"; + char *ip = "192.168.25.46"; + char* mac = "ec:f1:f8:d5:47:6b"; + int id = 1; - // Bring-up interface - iface.up(); + apr_initialize(); + + // Creates parent pool + apr_pool_t *parent_pool; + apr_pool_create(&parent_pool, NULL); + + // Creates interface + if ((viface_create(&parent_pool, &self) == EXIT_FAILURE) || + (vifaceImpl(&self, name, true, id) == EXIT_FAILURE)) { + return EXIT_FAILURE; + } + + // Configures interface + if ((setIPv4(&self, ip) == EXIT_FAILURE) || + (setMAC(&self, mac) == EXIT_FAILURE)) { + return EXIT_FAILURE; + } + + // Brings-up interface + if (up(&self) == EXIT_FAILURE) { + return EXIT_FAILURE; + } Then you can ``send()``, ``receive()`` or setup a ``dispath()`` callback to handle virtual interfaces incoming and outgoing packets. Also, interface @@ -34,7 +56,6 @@ Features - Multiple strategies for packet reception and emission. - Interface configuration API (MAC, Ipv4, IPv6, MTU). - Interface statistics reading and clearing. -- Easily integrated with ``libtins``. Dependencies diff --git a/bindings/CMakeLists.txt b/bindings/CMakeLists.txt new file mode 100644 index 0000000..2026f52 --- /dev/null +++ b/bindings/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory("cpp") +add_subdirectory("go") diff --git a/bindings/cpp/CMakeLists.txt b/bindings/cpp/CMakeLists.txt index 82c64e5..31d33fc 100644 --- a/bindings/cpp/CMakeLists.txt +++ b/bindings/cpp/CMakeLists.txt @@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 2.8) project("libvifacecpp") # The version number -set(libviface_VERSION_STRING "1.1.0") +set(libvifacecpp_VERSION_STRING "1.1.0") # Setup project variables set(VIFACE_TESTS ON CACHE BOOL "Enable compilation of unit tests.") @@ -31,9 +31,9 @@ endif(VIFACE_FORCE_32BITS) set(pkgconfig_prefix ${CMAKE_INSTALL_PREFIX}) set(pkgconfig_exec_prefix ${CMAKE_INSTALL_PREFIX}) set(pkgconfig_libdir ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}) -set(pkgconfig_version ${libviface_VERSION_STRING}) +set(pkgconfig_version ${libvifacecpp_VERSION_STRING}) configure_file( - "${libviface_SOURCE_DIR}/libvifacecpp.pc.in" + "${libvifacecpp_SOURCE_DIR}/libvifacecpp.pc.in" "${CMAKE_BINARY_DIR}/libvifacecpp.pc" @ONLY ) @@ -46,30 +46,37 @@ install( # Configure library configure_file( - "${libviface_SOURCE_DIR}/include/viface/config.hpp.in" + "${libvifacecpp_SOURCE_DIR}/include/viface/config.hpp.in" "${CMAKE_BINARY_DIR}/include/viface/config.hpp" @ONLY ) +# Creates custom target to build library +add_custom_target( + ${PROJECT_NAME} + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" + COMMENT "Building ${PROJECT_NAME} library..." VERBATIM +) + # Specify include directory -include_directories("${libviface_SOURCE_DIR}/include/") +include_directories("${libvifacecpp_SOURCE_DIR}/include/") include_directories("${CMAKE_BINARY_DIR}/include/") # Specify source directory -add_subdirectory("${libviface_SOURCE_DIR}/src/") +add_subdirectory("${libvifacecpp_SOURCE_DIR}/src/") if(VIFACE_TESTS) - message(STATUS "Including libviface test suite...") - add_subdirectory("${libviface_SOURCE_DIR}/test/") + message(STATUS "Including libvifacecpp test suite...") + add_subdirectory("${libvifacecpp_SOURCE_DIR}/test/") endif(VIFACE_TESTS) if(VIFACE_EXAMPLES) - message(STATUS "Including libviface examples...") - add_subdirectory("${libviface_SOURCE_DIR}/examples/") + message(STATUS "Including libvifacecpp examples...") + add_subdirectory("${libvifacecpp_SOURCE_DIR}/examples/") endif(VIFACE_EXAMPLES) # Specify public interface install directory install( FILES - "${libviface_SOURCE_DIR}/include/viface/viface.hpp" + "${libvifacecpp_SOURCE_DIR}/include/viface/viface.hpp" "${CMAKE_BINARY_DIR}/include/viface/config.hpp" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/viface" @@ -79,14 +86,14 @@ install( find_package(Doxygen) if(DOXYGEN_FOUND) configure_file( - "${libviface_SOURCE_DIR}/doc/doxygen.conf.in" - "${CMAKE_BINARY_DIR}/doxygen.conf" + "${libvifacecpp_SOURCE_DIR}/doc/doxygen.conf.in" + "${CMAKE_BINARY_DIR}/bindings/cpp/doxygen.conf" @ONLY ) add_custom_target( - doc + doccpp "${DOXYGEN_EXECUTABLE}" - "${CMAKE_BINARY_DIR}/doxygen.conf" + "${CMAKE_BINARY_DIR}/bindings/cpp/doxygen.conf" WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" COMMENT "Generating API Reference documentation..." VERBATIM ) diff --git a/bindings/cpp/README.rst b/bindings/cpp/README.rst new file mode 100644 index 0000000..4c2c0d0 --- /dev/null +++ b/bindings/cpp/README.rst @@ -0,0 +1,86 @@ +================================================================== +libvifacecpp : C++ bindings for Linux tun/tap and netdevice interface +================================================================== + +``libvifacecpp`` is a small C++11 library that allows to create and configure +virtual network interfaces in Linux based Operating Systems. + +:: + + #include "viface/viface.hpp" + + // Create interface + viface::VIface iface("viface%d"); + + // Configure interface + iface.setMAC("66:23:2d:28:c6:84"); + iface.setIPv4("192.168.20.21"); + + // Bring-up interface + iface.up(); + +Then you can ``send()``, ``receive()`` or setup a ``dispath()`` callback to +handle virtual interfaces incoming and outgoing packets. Also, interface +statistics (rx/tx packets, bytes, etc) are available to read using +``readStat()`` and related functions. + +For a complete overview check the reference documentation and examples. + + +Features +======== + +- Object Oriented approach to create virtual interfaces. +- Multiple strategies for packet reception and emission. +- Interface configuration API (MAC, Ipv4, IPv6, MTU). +- Interface statistics reading and clearing. +- Easily integrated with ``libtins``. + + +Dependencies +============ + +:: + + sudo apt-get install build-essential cmake doxygen graphviz + + +Build +===== + +:: + + mkdir build + cd build + cmake .. + make + make doccpp + + +Improvements +============ + +- Improve and fix possible race conditions when up/down is issued (and thus + packet buffer based on MTU is resized) and a dispatcher is active or any + other IO is active. + + +License +======= + +:: + + Copyright (C) 2015 Hewlett Packard Enterprise Development LP + + 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. diff --git a/bindings/cpp/doc/doxygen.conf.in b/bindings/cpp/doc/doxygen.conf.in index e69de29..dd6048b 100644 --- a/bindings/cpp/doc/doxygen.conf.in +++ b/bindings/cpp/doc/doxygen.conf.in @@ -0,0 +1,1853 @@ +# Doxyfile 1.8.3.1 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" "). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or sequence of words) that should +# identify the project. Note that if you do not use Doxywizard you need +# to put quotes around the project name if it contains spaces. + +PROJECT_NAME = "libvifacecpp" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = "@libvifacecpp_VERSION_STRING@" + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer +# a quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = "C++ bindings for libviface" + +# With the PROJECT_LOGO tag one can specify an logo or icon that is +# included in the documentation. The maximum height of the logo should not +# exceed 55 pixels and the maximum width should not exceed 200 pixels. +# Doxygen will copy the logo to the output directory. + +PROJECT_LOGO = @libvifacecpp_SOURCE_DIR@/doc/hpe.png + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = @CMAKE_BINARY_DIR@/bindings/cpp/doc/ + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. Note that you specify absolute paths here, but also +# relative paths, which will be relative from the directory where doxygen is +# started. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful if your file system +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = YES + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding +# "class=itcl::class" will allow you to use the command class in the +# itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, +# and language is one of the parsers supported by doxygen: IDL, Java, +# Javascript, CSharp, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, +# C++. For instance to make doxygen treat .inc files as Fortran files (default +# is PHP), and .f files as C (default is Fortran), use: inc=Fortran f=C. Note +# that for custom extensions you also need to set FILE_PATTERNS otherwise the +# files are not read by doxygen. + +EXTENSION_MAPPING = + +# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all +# comments according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you +# can mix doxygen, HTML, and XML commands with Markdown formatting. +# Disable only in case of backward compatibilities issues. + +MARKDOWN_SUPPORT = YES + +# When enabled doxygen tries to link words that correspond to documented classes, +# or namespaces to their corresponding documentation. Such a link can be +# prevented in individual cases by by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also makes the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES (the +# default) will make doxygen replace the get and set methods by a property in +# the documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and +# unions are shown inside the group in which they are included (e.g. using +# @ingroup) instead of on a separate page (for HTML and Man pages) or +# section (for LaTeX and RTF). + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and +# unions with only public data fields will be shown inline in the documentation +# of the scope in which they are defined (i.e. file, namespace, or group +# documentation), provided this scope is documented. If set to NO (the default), +# structs, classes, and unions are shown on a separate page (for HTML and Man +# pages) or section (for LaTeX and RTF). + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be +# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given +# their name and scope. Since this can be an expensive process and often the +# same symbol appear multiple times in the code, doxygen keeps a cache of +# pre-resolved symbols. If the cache is too small doxygen will become slower. +# If the cache is too large, memory is wasted. The cache size is given by this +# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# scope will be included in the documentation. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespaces are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = NO + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to +# do proper type resolution of all parameters of a function it will reject a +# match between the prototype and the implementation of a member function even +# if there is only one candidate or it is obvious which candidate to choose +# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen +# will still accept a match between prototype and implementation in such cases. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if section-label ... \endif +# and \cond section-label ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or macro consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and macros in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. +# This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted +# DoxygenLayout.xml will be used as the name of the layout file. + +LAYOUT_FILE = @libvifacecpp_SOURCE_DIR@/doc/layout.conf + +# The CITE_BIB_FILES tag can be used to specify one or more bib files +# containing the references data. This must be a list of .bib files. The +# .bib extension is automatically appended if omitted. Using this command +# requires the bibtex tool to be installed. See also +# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style +# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this +# feature you need bibtex and perl available in the search path. Do not use +# file names with spaces, bibtex cannot handle them. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# The WARN_NO_PARAMDOC option can be enabled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = @libvifacecpp_SOURCE_DIR@/include/viface/ @CMAKE_BINARY_DIR@/include/viface/ + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh +# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py +# *.f90 *.f *.for *.vhd *.vhdl + +FILE_PATTERNS = viface.hpp config.hpp utils.hpp *.dox + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. +# If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. +# Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. +# The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty or if +# non of the patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) +# and it is also possible to disable source filtering for a specific pattern +# using *.ext= (so without naming a filter). This option only has effect when +# FILTER_SOURCE_FILES is enabled. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MD_FILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page (index.html). +# This can be useful if you have a project on for instance GitHub and want reuse +# the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C, C++ and Fortran comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. +# Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. Note that when using a custom header you are responsible +# for the proper inclusion of any scripts and style sheets that doxygen +# needs, which is dependent on the configuration options used. +# It is advised to generate a default header using "doxygen -w html +# header.html footer.html stylesheet.css YourConfigFile" and then modify +# that header. Note that the header is subject to change so you typically +# have to redo this when upgrading to a newer version of doxygen or when +# changing the value of configuration settings such as GENERATE_TREEVIEW! + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If left blank doxygen will +# generate a default style sheet. Note that it is recommended to use +# HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this +# tag will in the future become obsolete. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional +# user-defined cascading style sheet that is included after the standard +# style sheets created by doxygen. Using this option one can overrule +# certain style aspects. This is preferred over using HTML_STYLESHEET +# since it does not replace the standard style sheet and is therefor more +# robust against future updates. Doxygen will copy the style sheet file to +# the output directory. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that +# the files will be copied as-is; there are no commands or markers available. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the style sheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of +# entries shown in the various tree structured indices initially; the user +# can expand and collapse entries dynamically later on. Doxygen will expand +# the tree to such a level that at most the specified number of entries are +# visible (unless a fully collapsed tree already exceeds this amount). +# So setting the number of entries 1 will produce a full collapsed tree by +# default. 0 is a special value representing an infinite number of entries +# and will result in a full expanded tree by default. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely +# identify the documentation publisher. This should be a reverse domain-name +# style string, e.g. com.mycompany.MyDocSet.documentation. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# +# Qt Help Project / Custom Filters. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# +# Qt Help Project / Filter Attributes. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) +# at top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. Since the tabs have the same information as the +# navigation tree you can set this option to NO if you already set +# GENERATE_TREEVIEW to YES. + +DISABLE_INDEX = YES + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. +# Since the tree basically has the same information as the tab index you +# could consider to set DISABLE_INDEX to NO when enabling this option. + +GENERATE_TREEVIEW = YES + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values +# (range [0,1..20]) that doxygen will group on one line in the generated HTML +# documentation. Note that a value of 0 will completely suppress the enum +# values from appearing in the overview section. + +ENUM_VALUES_PER_LINE = 1 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax +# (see http://www.mathjax.org) which uses client side Javascript for the +# rendering instead of using prerendered bitmaps. Use this if you do not +# have LaTeX installed or if you want to formulas look prettier in the HTML +# output. When enabled you may also need to install MathJax separately and +# configure the path to it using the MATHJAX_RELPATH option. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# thA MathJax output. Supported types are HTML-CSS, NativeMML (i.e. MathML) and +# SVG. The default value is HTML-CSS, which is slower, but has the best +# compatibility. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the +# HTML output directory using the MATHJAX_RELPATH option. The destination +# directory should contain the MathJax.js script. For instance, if the mathjax +# directory is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to +# the MathJax Content Delivery Network so you can quickly see the result without +# installing MathJax. +# However, it is strongly recommended to install a local +# copy of MathJax from http://www.mathjax.org before deployment. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension +# names that should be enabled during MathJax rendering. + +MATHJAX_EXTENSIONS = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a web server instead of a web client using Javascript. +# There are two flavours of web server based search depending on the +# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for +# searching and an index file used by the script. When EXTERNAL_SEARCH is +# enabled the indexing and searching needs to be provided by external tools. +# See the manual for details. + +SERVER_BASED_SEARCH = NO + +# When EXTERNAL_SEARCH is enabled doxygen will no longer generate the PHP +# script for searching. Instead the search results are written to an XML file +# which needs to be processed by an external indexer. Doxygen will invoke an +# external search engine pointed to by the SEARCHENGINE_URL option to obtain +# the search results. Doxygen ships with an example indexer (doxyindexer) and +# search engine (doxysearch.cgi) which are based on the open source search engine +# library Xapian. See the manual for configuration details. + +EXTERNAL_SEARCH = NO + +# The SEARCHENGINE_URL should point to a search engine hosted by a web server +# which will returned the search results when EXTERNAL_SEARCH is enabled. +# Doxygen ships with an example search engine (doxysearch) which is based on +# the open source search engine library Xapian. See the manual for configuration +# details. + +SEARCHENGINE_URL = + +# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed +# search data is written to a file for indexing by an external tool. With the +# SEARCHDATA_FILE tag the name of this file can be specified. + +SEARCHDATA_FILE = searchdata.xml + +# When SERVER_BASED_SEARCH AND EXTERNAL_SEARCH are both enabled the +# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is +# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple +# projects and redirect the results back to the right project. + +EXTERNAL_SEARCH_ID = + +# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen +# projects other than the one defined by this configuration file, but that are +# all added to the same external search index. Each project needs to have a +# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id +# of to a relative location where the documentation can be found. +# The format is: EXTRA_SEARCH_MAPPINGS = id1=loc1 id2=loc2 ... + +EXTRA_SEARCH_MAPPINGS = + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4 + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for +# the generated latex document. The footer should contain everything after +# the last chapter. If it is left blank doxygen will generate a +# standard footer. Notice: only use this tag if you know what you are doing! + +LATEX_FOOTER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See +# http://en.wikipedia.org/wiki/BibTeX for more info. + +LATEX_BIB_STYLE = plain + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load style sheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. +# This is useful +# if you want to understand what is going on. +# On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# pointed to by INCLUDE_PATH will be searched when a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition that +# overrules the definition found in the source code. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all references to function-like macros +# that are alone on a line, have an all uppercase name, and do not end with a +# semicolon, because these will confuse the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. For each +# tag file the location of the external documentation should be added. The +# format of a tag file without this location is as follows: +# +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths +# or URLs. Note that each tag file must have a unique name (where the name does +# NOT include the path). If a tag file is not located in the directory in which +# doxygen is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option also works with HAVE_DOT disabled, but it is recommended to +# install and use dot, since it yields more powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = YES + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 0 + +# By default doxygen will use the Helvetica font for all dot files that +# doxygen generates. When you want a differently looking font you can specify +# the font name using DOT_FONTNAME. You need to make sure dot is able to find +# the font, which can be done by putting it in a standard location or by setting +# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the +# directory containing the font. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the Helvetica font. +# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to +# set the path where dot can find it. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = YES + +# If the UML_LOOK tag is enabled, the fields and methods are shown inside +# the class node. If there are many fields or methods and many nodes the +# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS +# threshold limits the number of items for each type to make the size more +# managable. Set this to 0 for no limit. Note that the threshold may be +# exceeded by 50% before the limit is enforced. + +UML_LIMIT_NUM_FIELDS = 10 + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will generate a graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are svg, png, jpg, or gif. +# If left blank png will be used. If you choose svg you need to set +# HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible in IE 9+ (other browsers do not have this requirement). + +DOT_IMAGE_FORMAT = svg + +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# Note that this requires a modern browser other than Internet Explorer. +# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you +# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible. Older versions of IE do not have SVG support. + +INTERACTIVE_SVG = YES + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the +# \mscfile command). + +MSCFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = YES + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES diff --git a/bindings/cpp/doc/hp.png b/bindings/cpp/doc/hp.png deleted file mode 120000 index 61a5b2f..0000000 --- a/bindings/cpp/doc/hp.png +++ /dev/null @@ -1 +0,0 @@ -../../../doc/hp.png \ No newline at end of file diff --git a/bindings/cpp/doc/hp.svg b/bindings/cpp/doc/hp.svg deleted file mode 120000 index 49756a4..0000000 --- a/bindings/cpp/doc/hp.svg +++ /dev/null @@ -1 +0,0 @@ -../../../doc/hp.svg \ No newline at end of file diff --git a/bindings/cpp/doc/hpe.png b/bindings/cpp/doc/hpe.png new file mode 120000 index 0000000..de62422 --- /dev/null +++ b/bindings/cpp/doc/hpe.png @@ -0,0 +1 @@ +../../../doc/hpe.png \ No newline at end of file diff --git a/bindings/cpp/doc/hpe.svg b/bindings/cpp/doc/hpe.svg new file mode 120000 index 0000000..30cd4ed --- /dev/null +++ b/bindings/cpp/doc/hpe.svg @@ -0,0 +1 @@ +../../../doc/hpe.svg \ No newline at end of file diff --git a/bindings/cpp/examples/basic/CMakeLists.txt b/bindings/cpp/examples/basic/CMakeLists.txt index 740815f..5ce957e 100644 --- a/bindings/cpp/examples/basic/CMakeLists.txt +++ b/bindings/cpp/examples/basic/CMakeLists.txt @@ -1,10 +1,13 @@ -set(EXEC_NAME "basic") +set(EXEC_NAME "basiccpp") # Add source to the executable add_executable( ${EXEC_NAME} - ${EXEC_NAME}.cpp + basic.cpp ) # Link the executable to the library -target_link_libraries(${EXEC_NAME} viface) +target_link_libraries(${EXEC_NAME} vifacecpp) + +# Set dependency with the library target +add_dependencies(${PROJECT_NAME} ${EXEC_NAME}) diff --git a/bindings/cpp/examples/dispatch/CMakeLists.txt b/bindings/cpp/examples/dispatch/CMakeLists.txt index 33f4ad2..c014ce6 100644 --- a/bindings/cpp/examples/dispatch/CMakeLists.txt +++ b/bindings/cpp/examples/dispatch/CMakeLists.txt @@ -1,10 +1,13 @@ -set(EXEC_NAME "dispatch") +set(EXEC_NAME "dispatchcpp") # Add source to the executable add_executable( ${EXEC_NAME} - ${EXEC_NAME}.cpp + dispatch.cpp ) # Link the executable to the library -target_link_libraries(${EXEC_NAME} viface) +target_link_libraries(${EXEC_NAME} vifacecpp) + +# Set dependency with the library target +add_dependencies(${PROJECT_NAME} ${EXEC_NAME}) diff --git a/bindings/cpp/examples/libtins/CMakeLists.txt b/bindings/cpp/examples/libtins/CMakeLists.txt index 87ce250..0c1ef41 100644 --- a/bindings/cpp/examples/libtins/CMakeLists.txt +++ b/bindings/cpp/examples/libtins/CMakeLists.txt @@ -3,7 +3,7 @@ include(FindPkgConfig) pkg_check_modules(LIBTINS "libtins") if(LIBTINS_FOUND) - set(EXEC_NAME "libtins") + set(EXEC_NAME "libtinscpp") # Allow to use libviface include_directories( @@ -16,11 +16,14 @@ if(LIBTINS_FOUND) # Add source to the executable add_executable( ${EXEC_NAME} - ${EXEC_NAME}.cpp + libtins.cpp ) # Link the executable to the library - target_link_libraries(${EXEC_NAME} ${LIBTINS_LIBRARIES} viface) + target_link_libraries(${EXEC_NAME} ${LIBTINS_LIBRARIES} vifacecpp) else() message(WARNING "libtins not found, not building libtins example...") -endif() \ No newline at end of file +endif() + +# Set dependency with the library target +add_dependencies(${PROJECT_NAME} ${EXEC_NAME}) diff --git a/bindings/cpp/examples/signal/CMakeLists.txt b/bindings/cpp/examples/signal/CMakeLists.txt index ff039f7..31589ee 100644 --- a/bindings/cpp/examples/signal/CMakeLists.txt +++ b/bindings/cpp/examples/signal/CMakeLists.txt @@ -1,10 +1,13 @@ -set(EXEC_NAME "signal") +set(EXEC_NAME "signalcpp") # Add source to the executable add_executable( ${EXEC_NAME} - ${EXEC_NAME}.cpp + signal.cpp ) # Link the executable to the library -target_link_libraries(${EXEC_NAME} viface) +target_link_libraries(${EXEC_NAME} vifacecpp) + +# Set dependency with the library target +add_dependencies(${PROJECT_NAME} ${EXEC_NAME}) diff --git a/bindings/cpp/examples/stats/CMakeLists.txt b/bindings/cpp/examples/stats/CMakeLists.txt index 7fe4c17..a218356 100644 --- a/bindings/cpp/examples/stats/CMakeLists.txt +++ b/bindings/cpp/examples/stats/CMakeLists.txt @@ -1,11 +1,14 @@ -set(EXEC_NAME "stats") +set(EXEC_NAME "statscpp") # Add source to the executable add_executable( ${EXEC_NAME} - ${EXEC_NAME}.cpp + stats.cpp ) # Link the executable to the library -target_link_libraries(${EXEC_NAME} viface) +target_link_libraries(${EXEC_NAME} vifacecpp) + +# Set dependency with the library target +add_dependencies(${PROJECT_NAME} ${EXEC_NAME}) diff --git a/bindings/cpp/examples/threads/CMakeLists.txt b/bindings/cpp/examples/threads/CMakeLists.txt index 77a9e48..9157c09 100644 --- a/bindings/cpp/examples/threads/CMakeLists.txt +++ b/bindings/cpp/examples/threads/CMakeLists.txt @@ -1,16 +1,19 @@ find_package(Threads) if(Threads_FOUND) - set(EXEC_NAME "threads") + set(EXEC_NAME "threadscpp") # Add source to the executable add_executable( ${EXEC_NAME} - ${EXEC_NAME}.cpp + threads.cpp ) # Link the executable to the library - target_link_libraries(${EXEC_NAME} viface ${CMAKE_THREAD_LIBS_INIT}) + target_link_libraries(${EXEC_NAME} vifacecpp ${CMAKE_THREAD_LIBS_INIT}) else() message(WARNING "Threads package not found, not building threads example...") -endif() \ No newline at end of file +endif() + +# Set dependency with the library target +add_dependencies(${PROJECT_NAME} ${EXEC_NAME}) diff --git a/bindings/cpp/examples/timeout/CMakeLists.txt b/bindings/cpp/examples/timeout/CMakeLists.txt index 35d548f..12a8d43 100644 --- a/bindings/cpp/examples/timeout/CMakeLists.txt +++ b/bindings/cpp/examples/timeout/CMakeLists.txt @@ -1,10 +1,13 @@ -set(EXEC_NAME "timeout") +set(EXEC_NAME "timeoutcpp") # Add source to the executable add_executable( ${EXEC_NAME} - ${EXEC_NAME}.cpp + timeout.cpp ) # Link the executable to the library -target_link_libraries(${EXEC_NAME} viface) \ No newline at end of file +target_link_libraries(${EXEC_NAME} vifacecpp) + +# Set dependency with the library target +add_dependencies(${PROJECT_NAME} ${EXEC_NAME}) diff --git a/bindings/cpp/examples/vifaced/CMakeLists.txt b/bindings/cpp/examples/vifaced/CMakeLists.txt index 139ae87..e86c5f2 100644 --- a/bindings/cpp/examples/vifaced/CMakeLists.txt +++ b/bindings/cpp/examples/vifaced/CMakeLists.txt @@ -1,10 +1,13 @@ -set(EXEC_NAME "vifaced") +set(EXEC_NAME "vifacedcpp") # Add source to the executable add_executable( ${EXEC_NAME} - ${EXEC_NAME}.cpp + vifaced.cpp ) # Link the executable to the library -target_link_libraries(${EXEC_NAME} viface) \ No newline at end of file +target_link_libraries(${EXEC_NAME} vifacecpp) + +# Set dependency with the library target +add_dependencies(${PROJECT_NAME} ${EXEC_NAME}) diff --git a/bindings/cpp/src/CMakeLists.txt b/bindings/cpp/src/CMakeLists.txt index 51a67e7..73f378c 100644 --- a/bindings/cpp/src/CMakeLists.txt +++ b/bindings/cpp/src/CMakeLists.txt @@ -1,12 +1,12 @@ # Define library name -set(LIB_NAME "viface") +set(LIB_NAME "vifacecpp") # Add libviface library to build add_library(${LIB_NAME} SHARED viface.cpp) # Set library version set_target_properties( - ${LIB_NAME} PROPERTIES VERSION ${libviface_VERSION_STRING} + ${LIB_NAME} PROPERTIES VERSION ${libvifacecpp_VERSION_STRING} ) # Specify shared library install directory @@ -16,3 +16,6 @@ install( DESTINATION "${CMAKE_INSTALL_LIBDIR}" ) + +# Set dependency with the library target +add_dependencies(${PROJECT_NAME} ${LIB_NAME}) diff --git a/bindings/cpp/test/CMakeLists.txt b/bindings/cpp/test/CMakeLists.txt index dd26baf..714aa08 100644 --- a/bindings/cpp/test/CMakeLists.txt +++ b/bindings/cpp/test/CMakeLists.txt @@ -1,4 +1,4 @@ -set(EXEC_NAME "tests") +set(EXEC_NAME "testscpp") # Add source to the executable add_executable( @@ -7,4 +7,7 @@ add_executable( ) # Link the executable to the library -target_link_libraries(${EXEC_NAME} viface) +target_link_libraries(${EXEC_NAME} vifacecpp) + +# Set dependency with the library target +add_dependencies(${PROJECT_NAME} ${EXEC_NAME}) diff --git a/bindings/cpp/tools/uncrustify/pre-commit b/bindings/cpp/tools/uncrustify/pre-commit new file mode 120000 index 0000000..3a60f25 --- /dev/null +++ b/bindings/cpp/tools/uncrustify/pre-commit @@ -0,0 +1 @@ +../../../../tools/uncrustify/pre-commit \ No newline at end of file diff --git a/bindings/cpp/tools/uncrustify/uncrustify.cfg b/bindings/cpp/tools/uncrustify/uncrustify.cfg new file mode 120000 index 0000000..ebd08c9 --- /dev/null +++ b/bindings/cpp/tools/uncrustify/uncrustify.cfg @@ -0,0 +1 @@ +../../../../tools/uncrustify/uncrustify.cfg \ No newline at end of file diff --git a/bindings/cpp/tools/uncrustify/uncrustify.sh b/bindings/cpp/tools/uncrustify/uncrustify.sh new file mode 120000 index 0000000..b70ad47 --- /dev/null +++ b/bindings/cpp/tools/uncrustify/uncrustify.sh @@ -0,0 +1 @@ +../../../../tools/uncrustify/uncrustify.sh \ No newline at end of file diff --git a/bindings/go/CMakeLists.txt b/bindings/go/CMakeLists.txt new file mode 100644 index 0000000..ca79884 --- /dev/null +++ b/bindings/go/CMakeLists.txt @@ -0,0 +1,42 @@ +cmake_minimum_required(VERSION 2.8) + +# Define project name +project("libvifacego") + +# The version number +set(libvifacego_VERSION_STRING "1.1.0") + +# Creates custom target to build library +add_custom_target( + ${PROJECT_NAME} + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" + COMMENT "Building ${PROJECT_NAME} library..." VERBATIM +) + +add_subdirectory("${libvifacego_SOURCE_DIR}/src/") + +# Moves bin GO files to cmake build directory +add_custom_command( + TARGET ${PROJECT_NAME} + COMMAND rm -rf ./bin + COMMAND rm -rf ../../../bindings/go/pkg + COMMAND mv ../../../bindings/go/bin ./ +) + + +# Creates custom target to build library +add_custom_target( + docgo + COMMAND godoc -http=:6060 -goroot=../../../build/bindings/go/ + COMMENT "${PROJECT_NAME} GO documentation available at http://localhost:6060/pkg/vifacego/" +) + + + + + + + + + + diff --git a/bindings/go/README.rst b/bindings/go/README.rst new file mode 100644 index 0000000..8f38277 --- /dev/null +++ b/bindings/go/README.rst @@ -0,0 +1,98 @@ +================================================================== +libvifacego : libviface GO wrapper for managing and creating network interfaces. +================================================================== + +``libvifacego`` is a GOlang wrapper of the libviface C library that allows to create +and configure virtual network interfaces in Linux based Operating Systems. + +:: + + import ( + "fmt" + "vifacego" + ) + + // Creates viface struct + var self = wrapper.CreateVifaceStruct() + + // Viface configuration data + var name = "viface0" + var ipv4 = "192.168.25.46" + var id = 1 + + if ((wrapper.VifaceCreateGlobalPool() == wrapper.ExitFailure) || + (wrapper.VifaceCreateViface(name, true, id, &self) == wrapper.ExitFailure) || + (wrapper.VifaceSetIpv4(self, ipv4) == wrapper.ExitFailure)) { + fmt.Printf("--- An error occurred executing basic GO example\n") + } + + +Then you can send ``VifaceSend()`` or receive ``VifaceReceive()`` to +handle virtual interfaces incoming and outgoing packets. Also, interface +statistics (rx/tx packets, bytes, etc) are available to read using +``VifaceReadStat()`` and related functions. + +For a complete overview check the reference documentation and examples. + + +Features +======== + +- Object Oriented approach to create virtual interfaces. +- Multiple strategies for packet reception and emission. +- Interface configuration API (MAC, Ipv4, IPv6, MTU). +- Interface statistics reading and clearing. + + +Dependencies +============ + +:: + + sudo apt-get install build-essential cmake golang + + +Build +===== + +:: + Set GOPATH env variable to the location where the libviface repository is + located at: + + export GOPATH="libviface_directory_path"/bindings/go + export PATH=$PATH:$GOPATH/bin + + mkdir build + cd build + cmake .. + make libvifacego + make docgo + + +Improvements +============ + +- Improve and fix possible race conditions when up/down is issued (and thus + packet buffer based on MTU is resized) and a dispatcher is active or any + other IO is active. + + +License +======= + +:: + + Copyright (C) 2015 Hewlett Packard Enterprise Development LP + + 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. diff --git a/bindings/go/src/CMakeLists.txt b/bindings/go/src/CMakeLists.txt new file mode 100644 index 0000000..99d3b25 --- /dev/null +++ b/bindings/go/src/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory("vifacego") +add_subdirectory("examples") diff --git a/bindings/go/src/examples/CMakeLists.txt b/bindings/go/src/examples/CMakeLists.txt new file mode 100644 index 0000000..bffab9f --- /dev/null +++ b/bindings/go/src/examples/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory("basic") +add_subdirectory("stats") diff --git a/bindings/go/src/examples/basic/CMakeLists.txt b/bindings/go/src/examples/basic/CMakeLists.txt new file mode 100644 index 0000000..77b03ce --- /dev/null +++ b/bindings/go/src/examples/basic/CMakeLists.txt @@ -0,0 +1,18 @@ +# Define target name +set(EXEC_NAME "basicgo") + +# Creates custom target to build basic GO example +add_custom_target( + ${EXEC_NAME} + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" +) + +# Creates custom command to install basic GO example +add_custom_command( + TARGET ${EXEC_NAME} + COMMAND go install examples/basic + COMMENT "Building ${EXEC_NAME} GO example..." +) + +# Set dependency with the library target +add_dependencies(${PROJECT_NAME} ${EXEC_NAME}) diff --git a/bindings/go/src/examples/basic/basic.go b/bindings/go/src/examples/basic/basic.go new file mode 100644 index 0000000..0da5500 --- /dev/null +++ b/bindings/go/src/examples/basic/basic.go @@ -0,0 +1,166 @@ +package main + +import ( + "fmt" + "vifacego" +) + +// Viface configuration data +var name = "viface0" +var ipv4 = "192.168.25.46" +var ipv6s = []string{"fe80::6829:26ff:fe53:4670", + "fe20::5478:93f5:fe93:4680"} +var mac = "ec:f1:f8:d5:47:6b" +var broadcast = "192.168.25.255" +var netmask = "255.255.255.0" +var id = 1 +var mtu uint = 1500 //Default value if not set + +// setInterfaceConfiguration Sets network configuration data +// (name, id, ip, mac, netmask, broadcast, mtu). +func setInterfaceConfiguration(self vifacego.Viface) int { + // Configures interface + if ((vifacego.VifaceSetIpv4(self, ipv4) == vifacego.ExitFailure) || + (vifacego.VifaceSetMac(self, mac) == vifacego.ExitFailure) || + (vifacego.VifaceSetIpv4Broadcast(self,broadcast) == + vifacego.ExitFailure) || + (vifacego.VifaceSetIpv4Netmask(self, netmask) == + vifacego.ExitFailure) || + (vifacego.VifaceSetIpv6(self, len(ipv6s), ipv6s) == + vifacego.ExitFailure)) { + return vifacego.ExitFailure + } + + return vifacego.ExitSuccess; +} + +// checkInterfaceConfiguration Checks the interface configuration data +// (name, id, ip, mac, netmask, broadcast, mtu). +func checkInterfaceConfiguration(self vifacego.Viface) int { + var idValue uint + var vifaceUp bool + var mtuValue uint + var vifaceName string + var ipValue string + var macValue string + var broadcastValue string + var netmaskValue string + var ipv6sValues []string + + // Gets interface configuration data + if ((vifacego.VifaceGetName(self, &vifaceName) == vifacego.ExitFailure) || + (vifacego.VifaceGetID(self, &idValue) == vifacego.ExitFailure) || + (vifacego.VifaceIsUp(self, &vifaceUp) == vifacego.ExitFailure) || + (vifacego.VifaceGetIpv4(self, &ipValue) == vifacego.ExitFailure) || + (vifacego.VifaceGetMac(self, &macValue) == vifacego.ExitFailure) || + (vifacego.VifaceGetIpv4Broadcast(self, &broadcastValue) == + vifacego.ExitFailure) || + (vifacego.VifaceGetIpv4Netmask(self, &netmaskValue) == + vifacego.ExitFailure) || + (vifacego.VifaceGetMtu(self, &mtuValue) == vifacego.ExitFailure) || + (vifacego.VifaceGetIpv6(self, &ipv6sValues) == vifacego.ExitFailure)) { + return vifacego.ExitFailure + } + + fmt.Printf("********** Viface Configuration Data **********\n\n"); + + // Checks interface name + fmt.Printf("--- Viface name is: %v.\n", vifaceName); + fmt.Printf(" Expected: %v.\n\n", name); + + // Checks interface ID + fmt.Printf("--- Viface ID is: %v.\n", idValue); + fmt.Printf(" Expected: %v.\n\n", id); + + // Checks if interface is Up + fmt.Printf("--- Interface isUp: %v\n", vifaceUp); + fmt.Printf(" Expected: true.\n\n"); + + // Checks interface IP + fmt.Printf("--- IP value is: %v\n", ipValue); + fmt.Printf(" Expected: %v.\n\n", ipv4); + + // Checks mac value + fmt.Printf("--- MAC value is: %v\n", macValue); + fmt.Printf(" Expected: %v.\n\n", mac); + + // Checks broadcast value + fmt.Printf("--- Broadcast value is: %v\n", broadcastValue); + fmt.Printf(" Expected: %v.\n\n", broadcast); + + // Checks netmask value + fmt.Printf("--- Netmask value is: %v\n", netmaskValue); + fmt.Printf(" Expected: %v.\n\n", netmask); + + // Checks mtu value + fmt.Printf("--- MTU value is: %v\n", mtuValue); + fmt.Printf(" Expected: %v.\n\n", mtu); + + // Checks Ipv6s values + fmt.Printf("--- Ipv6 values are:\n"); + + for i:= 0; i < len(ipv6sValues); i++ { + fmt.Printf(" %v\n", ipv6sValues[i]); + } + fmt.Printf("\n"); + + return vifacego.ExitSuccess +} + +// checkInterfaceIsDown Checks if the network interface is down +func checkInterfaceIsDown(self vifacego.Viface) int { + // Checks if interface is down + var isDown bool + + if (vifacego.VifaceIsUp(self, &isDown) == vifacego.ExitFailure) { + return vifacego.ExitFailure; + } + + fmt.Printf("--- Interface is still Up: %v\n", isDown); + fmt.Printf(" Expected: false\n\n"); + return vifacego.ExitSuccess; +} + + +// main This example shows the basics to setup a new virtual network +// interface called viface0 +// (or use the name passed as first argument). +// It will show how to: +// 1) Set interface configuration data +// (name, id, ip, ipv6, mac, netmask, broadcast, mtu). +// 2) Bring-up the network interface. +// 3) Check the interface configuration data +// (name, id, ip, ipv6, mac, netmask, broadcast, mtu). +func main() { + + fmt.Printf("\n--- Starting basic GO example...\n\n") + + // Creates viface struct + var self = vifacego.CreateVifaceStruct() + + /* These IF statements do the following: + * 1) Creates global parent APR pool + * 2) Creates interface + * 3) Sets interface configuration data + * 4) Brings-up interface + * 5) Checks interface configuration data + * 6) Brings-down interface + * 7) Checks if interface is down + * 8) Destroys viface struct + * 9) Destroys global APR pool + */ + if ((vifacego.VifaceCreateGlobalPool() == vifacego.ExitFailure) || + (vifacego.VifaceCreateViface(name, true, id, &self) == + vifacego.ExitFailure) || + (setInterfaceConfiguration(self) == vifacego.ExitFailure) || + (vifacego.VifaceUp(self) == vifacego.ExitFailure) || + (checkInterfaceConfiguration(self) == vifacego.ExitFailure) || + (vifacego.VifaceDown(self) == vifacego.ExitFailure) || + (checkInterfaceIsDown(self) == vifacego.ExitFailure) || + (vifacego.VifaceDestroyViface(self) == vifacego.ExitFailure) || + (vifacego.VifaceDestroyGlobalPool() == vifacego.ExitFailure)) { + fmt.Printf("--- An error occurred executing basic GO example\n") + } + + +} diff --git a/bindings/go/src/examples/stats/CMakeLists.txt b/bindings/go/src/examples/stats/CMakeLists.txt new file mode 100644 index 0000000..7141013 --- /dev/null +++ b/bindings/go/src/examples/stats/CMakeLists.txt @@ -0,0 +1,18 @@ +# Define target name +set(EXEC_NAME "statsgo") + +# Creates custom target to build stats GO example +add_custom_target( + ${EXEC_NAME} + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" +) + +# Creates custom command to install stats GO example +add_custom_command( + TARGET ${EXEC_NAME} + COMMAND go install examples/stats + COMMENT "Building ${EXEC_NAME} GO example..." +) + +# Set dependency with the library target +add_dependencies(${PROJECT_NAME} ${EXEC_NAME}) diff --git a/bindings/go/src/examples/stats/stats.go b/bindings/go/src/examples/stats/stats.go new file mode 100644 index 0000000..4556af8 --- /dev/null +++ b/bindings/go/src/examples/stats/stats.go @@ -0,0 +1,133 @@ +package main + +import ( + "fmt" + "vifacego" +) + +// Viface configuration data +var name = "viface1" +var id = 1 + +// Example packet. In Scapy: +// packet = Ether()/IP()/TCP()/Raw('I\'m a packet!'*3) +// len(packet) == 93 +var packet = []uint8 { + 0x5D, //This is the packet size (0x5D = 93) + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x45, 0x00, 0x00, 0x4F, 0x00, 0x01, 0x00, 0x00, 0x40, 0x06, + 0x7C, 0xA6, 0x7F, 0x00, 0x00, 0x01, 0x7F, 0x00, 0x00, 0x01, 0x00, 0x14, + 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x02, + 0x20, 0x00, 0x04, 0x91, 0x00, 0x00, 0x49, 0x27, 0x6D, 0x20, 0x61, 0x20, + 0x70, 0x61, 0x63, 0x6B, 0x65, 0x74, 0x21, 0x49, 0x27, 0x6D, 0x20, 0x61, + 0x20, 0x70, 0x61, 0x63, 0x6B, 0x65, 0x74, 0x21, 0x49, 0x27, 0x6D, 0x20, + 0x61, 0x20, 0x70, 0x61, 0x63, 0x6B, 0x65, 0x74, 0x21} + +var count = 0 + +// printStatistics Prints the network interface statistics values +func printStatistics(self vifacego.Viface, statsNames []string) int { + for i := 0; i < len(statsNames); i++ { + var resultKey uint64 + if (vifacego.VifaceReadStat(self, statsNames[i], &resultKey) == + vifacego.ExitFailure) { + return vifacego.ExitFailure + } + fmt.Printf(" %v : %v\n", statsNames[i], resultKey) + } + + fmt.Printf("\n") + return vifacego.ExitSuccess +} + +/* Shows the use of the interface statistics to read + * the number of packets and bytes sent. + */ +func checkStatistics(self vifacego.Viface) int { + var numberPackets = 100 + var crc32 uint32 + var hexDump string + var statsNames []string + + fmt.Printf("********** Viface Statistics **********\n\n"); + + // Prints statistics before sending packets + fmt.Printf("--- Statistics before sending packets:\n"); + + if ((vifacego.VifaceListStats(self, &statsNames) == vifacego.ExitFailure) || + (printStatistics(self, statsNames) == vifacego.ExitFailure) || + (vifacego.VifaceCrc32(packet, &crc32) == vifacego.ExitFailure) || + (vifacego.VifaceHexDump(self, packet, &hexDump) == + vifacego.ExitFailure)) { + return vifacego.ExitFailure + } + + fmt.Printf("--- About to send the following packet.\n") + fmt.Printf(" Size: %v\n", packet[0]) + fmt.Printf(" CRC: 0x%x\n", crc32) + fmt.Printf("%v\n\n", hexDump) + + fmt.Printf("--- Sending the packet %v times...", numberPackets) + + // Sends the packet for 'numberPackets' times + for i := 0; i < numberPackets; i++ { + if (i % 10 == 0) { + fmt.Printf("\n") + } + fmt.Printf(" #%.2d ...", i + 1) + if (vifacego.VifaceSend(self, packet) == vifacego.ExitFailure) { + return vifacego.ExitFailure + } + } + fmt.Printf("\n\n") + + // Prints statistics after sending packets + fmt.Printf("--- Statistics after sending packets:\n"); + if (printStatistics(self, statsNames) == vifacego.ExitFailure) { + return vifacego.ExitFailure; + } + + // Clears statistics + fmt.Printf("--- Clearing statistics:\n"); + + for i := 0; i < 23; i++ { + var resultKey uint64 + + if ((vifacego.VifaceClearStat(self, statsNames[i]) == + vifacego.ExitFailure) || + (vifacego.VifaceReadStat(self, statsNames[i], &resultKey) == + vifacego.ExitFailure)) { + return vifacego.ExitFailure + } + fmt.Printf(" %v : %v\n", statsNames[i], resultKey) + } + fmt.Printf("\n") + return vifacego.ExitSuccess +} + +// main This example shows the use of the interface statistics interface +// to read the number of packets and bytes sent. +func main() { + + fmt.Printf("\n--- Starting stats example...\n\n") + + // Creates viface struct + var self = vifacego.CreateVifaceStruct() + + /* These IF statements do the following: + * 1) Creates interface + * 2) Brings-up interface + * 3) Checks interface statistics + * 4) Brings-down interface + */ + if ((vifacego.VifaceCreateGlobalPool() == vifacego.ExitFailure) || + (vifacego.VifaceCreateViface(name, true, 0, &self) == + vifacego.ExitFailure) || + (vifacego.VifaceUp(self) == vifacego.ExitFailure) || + (checkStatistics(self) == vifacego.ExitFailure) || + (vifacego.VifaceDown(self) == vifacego.ExitFailure) || + (vifacego.VifaceDestroyViface(self) == vifacego.ExitFailure) || + (vifacego.VifaceDestroyGlobalPool() == vifacego.ExitFailure)) { + fmt.Printf("--- An error occurred executing stats GO example\n") + } +} diff --git a/bindings/go/src/vifacego/CMakeLists.txt b/bindings/go/src/vifacego/CMakeLists.txt new file mode 100644 index 0000000..4f1f375 --- /dev/null +++ b/bindings/go/src/vifacego/CMakeLists.txt @@ -0,0 +1,19 @@ +# Define target name +set(WRAPPER_NAME "vifacego") + +# Creates custom target to build library +add_custom_target( + ${WRAPPER_NAME} + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" + COMMENT "Building ${WRAPPER_NAME} GO wrapper..." VERBATIM +) + +# Creates custom command to install libviface GO wrapper +add_custom_command( + TARGET ${WRAPPER_NAME} + COMMAND go install vifacego + COMMENT "Building libviface GO packet..." +) + +# Set dependency with the library target +add_dependencies(${PROJECT_NAME} ${WRAPPER_NAME}) diff --git a/bindings/go/src/vifacego/vifacego.go b/bindings/go/src/vifacego/vifacego.go new file mode 100644 index 0000000..93ed287 --- /dev/null +++ b/bindings/go/src/vifacego/vifacego.go @@ -0,0 +1,409 @@ +// vifacego it's a GO packet wrapper of the libviface library +// for managing and creating network interfaces. +package vifacego + +// #cgo CFLAGS: -g -Wall -I/usr/local/apr/include/apr-1 -I/usr/lib/apr-util-1 -I. +// #cgo LDFLAGS: -L/usr/local/apr/lib -lapr-1 -laprutil-1 -L../../../../build/src -lviface +// #include "../../../../include/viface/viface.h" +import "C" +import ( + "strconv" + "unsafe" +) + +// ExitFailure status value indicating error +const ExitFailure int = 1 + +// ExitSuccess status value indicating success +const ExitSuccess int = 0 + +// Viface configuration data +var name = "viface0" +var ipv4 = "192.168.25.46" +var mac = "ec:f1:f8:d5:47:6b" +var broadcast = "192.168.25.255" +var netmask = "255.255.255.0" +var id = 1 +var mtu = 1000 + +// Viface Viface C struct +type Viface *C.struct_viface + +// CreateVifaceStruct Create a new C viface struct +func CreateVifaceStruct() *C.struct_viface { + return new(C.struct_viface) +} + +// VifaceHexDump Build a hexdump representation of a binary blob. +func VifaceHexDump(self *C.struct_viface, bytes []uint8, + result *string) int { + var hexDump *C.char + packet := (*C.uint8_t)(unsafe.Pointer(&bytes[0])) + if C.viface_hex_dump(self, packet, &hexDump) == C.int(ExitFailure) { + return ExitFailure + } + *result = C.GoString(hexDump) + return ExitSuccess +} + +// VifaceCrc32 Calculate the 32 bit CRC of the given binary blob. +func VifaceCrc32(bytes []uint8, result *uint32) int { + var crc32 C.uint32_t + packet := (*C.uint8_t)(unsafe.Pointer(&bytes[0])) + if C.viface_crc_32(packet, &crc32) == C.int(ExitFailure) { + return ExitFailure + } + *result = uint32(crc32) + return ExitSuccess +} + +// VifaceCreateGlobalPool Create an APR parent pool for memory allocation. +func VifaceCreateGlobalPool() int { + return int(C.viface_create_global_pool()) +} + +// VifaceCreateViface Create a viface struct and an +// APR subpool from a parent pool. +func VifaceCreateViface(name string, tap bool, id int, + result **C.struct_viface) int { + var nameValue = C.CString(name) + var status = int(C.viface_create_viface(nameValue, C.bool(tap), C.int(id), result)) + C.free(unsafe.Pointer(nameValue)) + return status +} + +// VifaceDestroyGlobalPool Destroy the static global APR parent pool. +func VifaceDestroyGlobalPool() int { + return int(C.viface_destroy_global_pool()) +} + +// VifaceDestroyTemporalPool Destroy the static temporal APR pool. +func VifaceDestroyTemporalPool() int { + return int(C.viface_destroy_temporal_pool()) +} + +// VifaceDestroyViface Destroy a viface struct and free +// all allocated memory from the APR subpool +func VifaceDestroyViface(self *C.struct_viface) int { + return int(C.viface_destroy_viface(&self)) +} + +// VifaceGetName Getter method for virtual interface associated name. +func VifaceGetName(self *C.struct_viface, result *string) int { + var name *C.char + if C.viface_get_name(self, &name) == C.int(ExitFailure) { + return ExitFailure + } + *result = C.GoString(name) + return ExitSuccess +} + +// VifaceGetID Getter method for virtual interface associated numeric id. +func VifaceGetID(self *C.struct_viface, result *uint) int { + + var id C.uint + if C.viface_get_id(self, &id) == C.int(ExitFailure) { + return ExitFailure + } + *result = uint(id) + return ExitSuccess +} + +// VifaceGetTx Getter method for virtual interface associated +// transmission file descriptor. +func VifaceGetTx(self *C.struct_viface, result *int) int { + + var tx C.int + if C.viface_get_tx(self, &tx) == C.int(ExitFailure) { + return ExitFailure + } + *result = int(tx) + return ExitSuccess +} + +// VifaceGetRx Getter method for virtual interface associated +// reception file descriptor. +func VifaceGetRx(self *C.struct_viface, result *int) int { + + var rx C.int + if C.viface_get_rx(self, &rx) == C.int(ExitFailure) { + return ExitFailure + } + *result = int(rx) + return ExitSuccess +} + +// VifaceSetMac Set the MAC address of the virtual interface. +// +// The format of the MAC address is verified, but is just until up() +// is called that the library will try to attempt to write it. +// If you don't provide a MAC address (the default) one will be +// automatically assigned when bringing up the interface. +func VifaceSetMac(self *C.struct_viface, mac string) int { + var macValue = C.CString(mac) + var status = int(C.viface_set_mac(self, macValue)) + C.free(unsafe.Pointer(macValue)) + return status +} + +// VifaceGetMac Getter method for virtual interface associated MAC Address. +func VifaceGetMac(self *C.struct_viface, result *string) int { + var mac *C.char + if C.viface_get_mac(self, &mac) == C.int(ExitFailure) { + return ExitFailure + } + *result = C.GoString(mac) + return ExitSuccess +} + +// VifaceSetIpv4 Set the IPv4 address of the virtual interface. +// +// The format of the IPv4 address is verified, but is just until up() +// is called that the library will try to attempt to write it. +func VifaceSetIpv4(self *C.struct_viface, ipv4 string) int { + var ipv4Value = C.CString(ipv4) + var status = int(C.viface_set_ipv4(self, ipv4Value)) + C.free(unsafe.Pointer(ipv4Value)) + return status +} + +// VifaceGetIpv4 Getter method for virtual interface associated IPv4 Address. +func VifaceGetIpv4(self *C.struct_viface, result *string) int { + var ipv4 *C.char + if C.viface_get_ipv4(self, &ipv4) == C.int(ExitFailure) { + return ExitFailure + } + *result = C.GoString(ipv4) + return ExitSuccess +} + +// VifaceSetIpv4Netmask Set the IPv4 netmask of the virtual interface. +// +// The format of the IPv4 netmask is verified, but is just until up() +// is called that the library will try to attempt to write it. +func VifaceSetIpv4Netmask(self *C.struct_viface, netmask string) int { + var netmaskValue = C.CString(netmask) + var status = int(C.viface_set_ipv4_netmask(self, netmaskValue)) + C.free(unsafe.Pointer(netmaskValue)) + return status +} + +// VifaceGetIpv4Netmask Getter method for virtual interface +// associated IPv4 netmask. +func VifaceGetIpv4Netmask(self *C.struct_viface, result *string) int { + var netmask *C.char + if C.viface_get_ipv4_netmask(self, &netmask) == C.int(ExitFailure) { + return ExitFailure + } + *result = C.GoString(netmask) + return ExitSuccess +} + +// VifaceSetIpv4Broadcast Set the IPv4 broadcast address +// of the virtual interface. +// +// The format of the IPv4 broadcast address is verified, but is just +// until up() is called that the library will try to attempt to write it. +func VifaceSetIpv4Broadcast(self *C.struct_viface, broadcast string) int { + var broadcastValue = C.CString(broadcast) + var status = int(C.viface_set_ipv4_broadcast(self, broadcastValue)) + C.free(unsafe.Pointer(broadcastValue)) + return status +} + +// VifaceGetIpv4Broadcast Getter method for virtual interface associated +// IPv4 broadcast address. +func VifaceGetIpv4Broadcast(self *C.struct_viface, result *string) int { + var broadcast *C.char + if C.viface_get_ipv4_broadcast(self, &broadcast) == C.int(ExitFailure) { + return ExitFailure + } + *result = C.GoString(broadcast) + return ExitSuccess +} + +func setIPv6(self *C.struct_viface, numIPv6s int, ipv6s []*C.char) int { + C.viface_set_ipv6(self, C.int(numIPv6s), &ipv6s[0]) + return ExitSuccess +} + +// VifaceSetIpv6 Set the IPv6 addresses of the virtual interface. +// +// The format of the IPv6 addresses are verified, but is just until +// up() is called that the library will try to attempt to write them. +func VifaceSetIpv6(self *C.struct_viface, numIPv6s int, ipv6s []string) int { + + ipv6sValues := + (*[1 << 30]*C.char)(unsafe.Pointer(&ipv6s[0]))[:numIPv6s:numIPv6s] + + for i := 0; i < numIPv6s; i++ { + var ipv6 = C.CString(ipv6s[i]) + ipv6sValues[i] = ipv6 + } + + if C.viface_set_ipv6(self, C.int(numIPv6s), &ipv6sValues[0]) == + C.int(ExitFailure) { + return ExitFailure + } + + return ExitSuccess +} + +// VifaceGetIpv6 Getter method for virtual interface associated IPv6 Addresses +// (note the plural). +func VifaceGetIpv6(self *C.struct_viface, result *[]string) int { + var ipv6sValues **C.char + + if C.viface_get_ipv6(self, &ipv6sValues) == C.int(ExitFailure) { + return ExitFailure + } + + ipv6sListC := (*[1 << 30]*C.char)(unsafe.Pointer(ipv6sValues)) + numberIpv6s, err := strconv.Atoi(C.GoString(ipv6sListC[0])) + + if err != nil { + return ExitFailure + } + + ipv6sListGO := make([]string, numberIpv6s) + + for i := 0; i < numberIpv6s; i++ { + ipv6sListGO[i] = C.GoString(ipv6sListC[i+1]) + } + + *result = ipv6sListGO + return ExitSuccess +} + +// VifaceSetMtu Set the MTU of the virtual interface. +// +// The range of the MTU is verified, but is just until up() is called +// that the library will try to attempt to write it. +func VifaceSetMtu(self *C.struct_viface, mtu uint) int { + return int(C.viface_set_mtu(self, C.uint(mtu))) +} + +// VifaceGetMtu Getter method for virtual interface associated +// maximum transmission unit (MTU). +// +// MTU is the size of the largest packet or frame that can be sent +// using this interface. +func VifaceGetMtu(self *C.struct_viface, result *uint) int { + + var mtu C.uint + if C.viface_get_mtu(self, &mtu) == C.int(ExitFailure) { + return ExitFailure + } + *result = uint(mtu) + return ExitSuccess +} + +// VifaceUp Bring up the virtual interface. +// +// This call will configure and bring up the interface. +func VifaceUp(self *C.struct_viface) int { + return int(C.viface_up(self)) +} + +// VifaceDown Bring down the virtual interface. +func VifaceDown(self *C.struct_viface) int { + return int(C.viface_down(self)) +} + +// VifaceIsUp Indicate if the virtual interface is up. +func VifaceIsUp(self *C.struct_viface, result *bool) int { + + var isUp C.bool = false + if C.viface_is_up(self, &isUp) == C.int(ExitFailure) { + return ExitFailure + } + *result = bool(isUp) + return ExitSuccess +} + +// VifaceReceive Receive a packet from the virtual interface. +// +// Note: Receive a packet from a virtual interface means that another +// userspace program (or the kernel) sent a packet to the network +// interface with the name of the instance of this class. If not packet +// was available, and empty vector is returned. +func VifaceReceive(self *C.struct_viface, result *[]uint8) int { + + var packet *C.uint8_t + if C.viface_receive(self, &packet) == C.int(ExitFailure) { + return ExitFailure + } + + packetC := (*[1 << 30]C.uint8_t)(unsafe.Pointer(packet)) + packetBytesSize := int(packetC[0]) + packetGO := make([]uint8, packetBytesSize+1) + + for i := 0; i <= packetBytesSize; i++ { + packetGO[i] = uint8(packetC[i]) + } + + *result = packetGO + return ExitSuccess +} + +// VifaceSend Send a packet to this virtual interface. +// +// Note: Sending a packet to this virtual interface means that it +// will reach any userspace program (or the kernel) listening for +// packets in the interface with the name of the instance of this +// class. +func VifaceSend(self *C.struct_viface, packet []uint8) int { + packetC := (*C.uint8_t)(unsafe.Pointer(&packet[0])) + if C.viface_send(self, packetC) == C.int(ExitFailure) { + return ExitFailure + } + return ExitSuccess +} + +// VifaceListStats List available statistics for this interface. +func VifaceListStats(self *C.struct_viface, result *[]string) int { + var stats **C.char + if C.viface_list_stats(self, &stats) == C.int(ExitFailure) { + return ExitFailure + } + + statsListC := (*[1 << 30]*C.char)(unsafe.Pointer(stats)) + numerStats, err := strconv.Atoi(C.GoString(statsListC[0])) + + if err != nil { + return ExitFailure + } + + statsListGO := make([]string, numerStats) + + for i := 0; i < numerStats; i++ { + statsListGO[i] = C.GoString(statsListC[i+1]) + } + + *result = statsListGO + return ExitSuccess +} + +// VifaceReadStat Read given statistic for this interface. +func VifaceReadStat(self *C.struct_viface, stat string, result *uint64) int { + var statValue C.uint64_t + var statName = C.CString(stat) + var status = int(C.viface_read_stat(self, statName, &statValue)) + C.free(unsafe.Pointer(statName)) + *result = uint64(statValue) + return status +} + +// VifaceClearStat Clear given statistic for this interface. +// +// Please note that this feature is implemented in library as there is +// currently no way to clear them (except by destroying the interface). +// If you clear the statistics using this method, subsequent calls to +// readStat() results will differ from, for example, those reported +// by tools like ifconfig. +func VifaceClearStat(self *C.struct_viface, stat string) int { + var statName = C.CString(stat) + var status = int(C.viface_clear_stat(self, statName)) + C.free(unsafe.Pointer(statName)) + return status +} diff --git a/doc/doxygen.conf.in b/doc/doxygen.conf.in index 5ac37da..ebf6af7 100644 --- a/doc/doxygen.conf.in +++ b/doc/doxygen.conf.in @@ -38,14 +38,14 @@ PROJECT_NUMBER = "@libviface_VERSION_STRING@" # for a project that appears at the top of each page and should give viewer # a quick idea about the purpose of the project. Keep the description short. -PROJECT_BRIEF = "C++ bindings for C Linux tun/tap Interface" +PROJECT_BRIEF = "libviface C object oriented interface for managing and creating network interfaces" # With the PROJECT_LOGO tag one can specify an logo or icon that is # included in the documentation. The maximum height of the logo should not # exceed 55 pixels and the maximum width should not exceed 200 pixels. # Doxygen will copy the logo to the output directory. -PROJECT_LOGO = @libviface_SOURCE_DIR@/doc/hp.png +PROJECT_LOGO = @libviface_SOURCE_DIR@/doc/hpe.png # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. @@ -670,7 +670,7 @@ INPUT_ENCODING = UTF-8 # *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py # *.f90 *.f *.for *.vhd *.vhdl -FILE_PATTERNS = viface.hpp config.hpp utils.hpp *.dox +FILE_PATTERNS = viface.h config.h # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. diff --git a/doc/hp.png b/doc/hp.png deleted file mode 100644 index 9e4a70a..0000000 Binary files a/doc/hp.png and /dev/null differ diff --git a/doc/hp.svg b/doc/hp.svg deleted file mode 100644 index d672cc9..0000000 --- a/doc/hp.svg +++ /dev/null @@ -1,25 +0,0 @@ - - - -image/svg+xml \ No newline at end of file diff --git a/doc/hpe.png b/doc/hpe.png new file mode 100644 index 0000000..f1d5d34 Binary files /dev/null and b/doc/hpe.png differ diff --git a/doc/hpe.svg b/doc/hpe.svg new file mode 100644 index 0000000..c474618 --- /dev/null +++ b/doc/hpe.svg @@ -0,0 +1,131 @@ + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt new file mode 100644 index 0000000..5b04d95 --- /dev/null +++ b/examples/CMakeLists.txt @@ -0,0 +1,4 @@ +add_subdirectory("basic") +add_subdirectory("dispatch") +add_subdirectory("stats") + diff --git a/examples/basic.c b/examples/basic.c deleted file mode 100644 index e69de29..0000000 diff --git a/examples/basic/CMakeLists.txt b/examples/basic/CMakeLists.txt new file mode 100644 index 0000000..97fc8f2 --- /dev/null +++ b/examples/basic/CMakeLists.txt @@ -0,0 +1,13 @@ +set(EXEC_NAME "basic") + +# Add source to the executable +add_executable( + ${EXEC_NAME} + basic.c +) + +# Link the executable to the library +target_link_libraries(${EXEC_NAME} viface) + +# Set dependency with the library target +add_dependencies(${PROJECT_NAME} ${EXEC_NAME}) diff --git a/examples/basic/basic.c b/examples/basic/basic.c new file mode 100644 index 0000000..2527f15 --- /dev/null +++ b/examples/basic/basic.c @@ -0,0 +1,168 @@ +/** + * Copyright (C) 2015 Hewlett Packard Enterprise Development LP + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use self 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 "viface/viface.h" + +// Interface configuration data +static char name[IFNAMSIZ] = "viface0"; +static char ip[INET_ADDRSTRLEN] = "192.168.25.46"; +static char mac[18] = "ec:f1:f8:d5:47:6b"; +static char broadcast[INET_ADDRSTRLEN] = "192.168.25.255"; +static char netmask[INET_ADDRSTRLEN] = "255.255.255.0"; +static uint mtu = 1000; +static int id = 1; + +/* Sets network configuration data + * (name, id, ip, mac, netmask, broadcast, mtu). + */ +int set_interface_configuration(struct viface* self) +{ + // Configures interface + if ((viface_set_ipv4(self, ip) == EXIT_FAILURE) || + (viface_set_mac(self, mac) == EXIT_FAILURE) || + (viface_set_ipv4_broadcast(self, broadcast) == EXIT_FAILURE) || + (viface_set_ipv4_netmask(self, netmask) == EXIT_FAILURE) || + (viface_set_mtu(self, mtu) == EXIT_FAILURE)) { + return EXIT_FAILURE; + } + return EXIT_SUCCESS; +} + +/* Checks the interface configuration data + * (name, id, ip, mac, netmask, broadcast, mtu). + */ +int check_interface_configuration(struct viface* self) +{ + int id_value; + bool is_viface_up; + uint mtu_value; + char* viface_name; + char* ip_value; + char* mac_value; + char* broadcast_value; + char* netmask_value; + + // Gets interface configuration data + if ((viface_get_name(self, &viface_name) == EXIT_FAILURE) || + (viface_get_id(self, &id_value) == EXIT_FAILURE) || + (viface_is_up(self, &is_viface_up) == EXIT_FAILURE) || + (viface_get_ipv4(self, &ip_value) == EXIT_FAILURE) || + (viface_get_mac(self, &mac_value) == EXIT_FAILURE) || + (viface_get_ipv4_broadcast(self, &broadcast_value) == EXIT_FAILURE) || + (viface_get_ipv4_netmask(self, &netmask_value) == EXIT_FAILURE) || + (viface_get_mtu(self, &mtu_value) == EXIT_FAILURE)) { + return EXIT_FAILURE; + } + + printf("********** Viface Configuration Data **********\n\n"); + + // Checks interface name + printf("--- Viface name is: %s.\n", viface_name); + printf(" Expected: %s.\n\n", name); + + // Checks interface ID + printf("--- Viface ID is: %d.\n", id_value); + printf(" Expected: %d.\n\n", id); + + // Checks if interface is Up + printf("--- Interface isUp: %s\n", is_viface_up ? "true" : "false"); + printf(" Expected: true.\n\n"); + + // Checks interface IP + printf("--- IP value is: %s\n", ip_value); + printf(" Expected: %s.\n\n", ip); + + // Checks mac value + printf("--- MAC value is: %s\n", mac_value); + printf(" Expected: %s.\n\n", mac); + + // Checks broadcast value + printf("--- Broadcast value is: %s\n", broadcast_value); + printf(" Expected: %s.\n\n", broadcast); + + // Checks netmask value + printf("--- Netmask value is: %s\n", netmask_value); + printf(" Expected: %s.\n\n", netmask); + + // Checks mtu value + printf("--- MTU value is: %d\n", mtu_value); + printf(" Expected: %u.\n\n", mtu); + + return EXIT_SUCCESS; +} + +// Checks if the network interface is down +int check_interface_is_down(struct viface* self) +{ + // Checks if interface is down + bool is_down; + + if (viface_is_up(self, &is_down) == EXIT_FAILURE) { + return EXIT_FAILURE; + } + + printf("--- Interface isDown: %s\n", is_down ? "false" : "true"); + printf(" Expected: true\n\n"); + return EXIT_SUCCESS; +} + +/** + * This example shows the basics to setup a new virtual network + * interface called viface0 + * (or use the name passed as first argument). + * It will show how to: + * 1) Set interface configuration data + * (name, id, ip, ipv6, mac, netmask, broadcast, mtu). + * 2) Bring-up the network interface. + * 3) Check the interface configuration data + * (name, id, ip, ipv6, mac, netmask, broadcast, mtu). + */ +main(int argc, const char* argv[]) +{ + struct viface* self; + + printf("\n--- Starting basic example...\n\n"); + + if (argc > 1) { + strcpy(name, argv[1]); + } + + /* These IF statements do the following: + * 1) Creates global parent APR pool + * 2) Creates interface + * 3) Sets interface configuration data + * 4) Brings-up interface + * 5) Checks interface configuration data + * 6) Brings-down interface + * 7) Checks if interface is down + * 8) Destroys viface struct + * 9) Destroys global APR pool + */ + if ((viface_create_global_pool() == EXIT_FAILURE) || + (viface_create_viface(name, true, id, &self) == EXIT_FAILURE) || + (set_interface_configuration(self) == EXIT_FAILURE) || + (viface_up(self) == EXIT_FAILURE) || + (check_interface_configuration(self) == EXIT_FAILURE) || + (viface_down(self) == EXIT_FAILURE) || + (check_interface_is_down(self) == EXIT_FAILURE) || + (viface_destroy_viface(&self) == EXIT_FAILURE) || + (viface_destroy_global_pool() == EXIT_FAILURE)) { + return EXIT_FAILURE; + } + + return 0; +} \ No newline at end of file diff --git a/examples/dispatch/CMakeLists.txt b/examples/dispatch/CMakeLists.txt new file mode 100644 index 0000000..0d1c426 --- /dev/null +++ b/examples/dispatch/CMakeLists.txt @@ -0,0 +1,13 @@ +set(EXEC_NAME "dispatch") + +# Add source to the executable +add_executable( + ${EXEC_NAME} + ${EXEC_NAME}.c +) + +# Link the executable to the library +target_link_libraries(${EXEC_NAME} viface) + +# Set dependency with the library target +add_dependencies(${PROJECT_NAME} ${EXEC_NAME}) diff --git a/examples/dispatch/dispatch.c b/examples/dispatch/dispatch.c new file mode 100644 index 0000000..15b4d43 --- /dev/null +++ b/examples/dispatch/dispatch.c @@ -0,0 +1,119 @@ +/** + * Copyright (C) 2015 Hewlett Packard Enterprise Development LP + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use self 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 "viface/viface.h" + +// Example packet. In Scapy: +// packet = Ether()/IP()/TCP()/Raw('I\'m a packet!'*3) +// len(packet) == 93 +static uint8_t packet[94] = { + 0x5D, //This is the packet size (0x5D = 93) + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x45, 0x00, 0x00, 0x4F, 0x00, 0x01, 0x00, 0x00, 0x40, 0x06, + 0x7C, 0xA6, 0x7F, 0x00, 0x00, 0x01, 0x7F, 0x00, 0x00, 0x01, 0x00, 0x14, + 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x02, + 0x20, 0x00, 0x04, 0x91, 0x00, 0x00, 0x49, 0x27, 0x6D, 0x20, 0x61, 0x20, + 0x70, 0x61, 0x63, 0x6B, 0x65, 0x74, 0x21, 0x49, 0x27, 0x6D, 0x20, 0x61, + 0x20, 0x70, 0x61, 0x63, 0x6B, 0x65, 0x74, 0x21, 0x49, 0x27, 0x6D, 0x20, + 0x61, 0x20, 0x70, 0x61, 0x63, 0x6B, 0x65, 0x74, 0x21 +}; + +int count = 0; + +// Prints received packet information +int print_packet(struct viface* self, uint8_t* packet) +{ + uint32_t crc_32 = 0; + char *hex_dump; + + if ((viface_crc_32(packet, &crc_32) == EXIT_FAILURE) || + (viface_hex_dump(self, packet, &hex_dump) == EXIT_FAILURE)) { + return EXIT_FAILURE; + } + + printf("+++ Received packet %d from interface", count); + printf(" %s (%d) of size", self->name, self->id); + printf(" %d and CRC of 0x%x\n%s\n", packet[0], crc_32, hex_dump); + return EXIT_SUCCESS; +} + +// Dispatch callback type to handle packet reception. +int handler(struct viface* self, uint8_t* packet, + bool* result) +{ + if (print_packet(self, packet) == EXIT_FAILURE) { + return EXIT_FAILURE; + } + count++; + *result = true; + return EXIT_SUCCESS; +} + +/** + * This example shows how to setup a dispatcher for a set of virtual interfaces. + * This uses a method for the callback in order to show this kind of + * usage, but any function using the same signature as dispatcher_cb type + * can be used. + * + * To help with the example you can send a few packets to the created virtual + * interfaces using scapy, wireshark, libtins or any other. + */ +main(int argc, const char* argv[]) +{ + struct viface* iface0; + struct viface* iface1; + dispatcher_cb callback; + + char* name_iface0 = "viface0"; + char* name_iface1 = "viface1"; + + printf("\n--- Starting dispatch example...\n\n"); + + if ((viface_create_global_pool() == EXIT_FAILURE) || + (viface_create_viface(name_iface0, true, 0, + &iface0) == EXIT_FAILURE) || + (viface_up(iface0) == EXIT_FAILURE) || + (viface_create_viface(name_iface1, true, 1, + &iface1) == EXIT_FAILURE) || + (viface_up(iface1) == EXIT_FAILURE)) { + return EXIT_FAILURE; + } + + printf("--- Interface %s is up!.\n", name_iface0); + printf("--- Interface %s is up!.\n", name_iface1); + + printf("--- Press Any Key to Receive Packet.\n"); + getchar(); + + // Creates array of viface structs + struct viface* ifaces[2] = {iface0, iface1}; + int num_ifaces = sizeof(ifaces) / sizeof(struct viface*); + + printf("--- Calling dispatch ...\n"); + callback = handler; + if ((viface_dispatch(iface0, num_ifaces, ifaces, + callback, -1) == EXIT_FAILURE) || + (viface_down(iface0) == EXIT_FAILURE) || + (viface_down(iface1) == EXIT_FAILURE) || + (viface_destroy_viface(&iface0) == EXIT_FAILURE) || + (viface_destroy_viface(&iface1) == EXIT_FAILURE) || + (viface_destroy_global_pool() == EXIT_FAILURE)) { + return EXIT_FAILURE; + } + + return 0; +} \ No newline at end of file diff --git a/examples/stats/CMakeLists.txt b/examples/stats/CMakeLists.txt new file mode 100644 index 0000000..33c7f39 --- /dev/null +++ b/examples/stats/CMakeLists.txt @@ -0,0 +1,13 @@ +set(EXEC_NAME "stats") + +# Add source to the executable +add_executable( + ${EXEC_NAME} + ${EXEC_NAME}.c +) + +# Link the executable to the library +target_link_libraries(${EXEC_NAME} viface) + +# Set dependency with the library target +add_dependencies(${PROJECT_NAME} ${EXEC_NAME}) diff --git a/examples/stats/stats.c b/examples/stats/stats.c new file mode 100644 index 0000000..af61494 --- /dev/null +++ b/examples/stats/stats.c @@ -0,0 +1,154 @@ +/** + * Copyright (C) 2015 Hewlett Packard Enterprise Development LP + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use self 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 "viface/viface.h" + +// Example packet. In Scapy: +// packet = Ether()/IP()/TCP()/Raw('I\'m a packet!'*3) +// len(packet) == 93 +static uint8_t packet[94] = { + 0x5D, //This is the packet size (0x5D = 93) + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x45, 0x00, 0x00, 0x4F, 0x00, 0x01, 0x00, 0x00, 0x40, 0x06, + 0x7C, 0xA6, 0x7F, 0x00, 0x00, 0x01, 0x7F, 0x00, 0x00, 0x01, 0x00, 0x14, + 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x02, + 0x20, 0x00, 0x04, 0x91, 0x00, 0x00, 0x49, 0x27, 0x6D, 0x20, 0x61, 0x20, + 0x70, 0x61, 0x63, 0x6B, 0x65, 0x74, 0x21, 0x49, 0x27, 0x6D, 0x20, 0x61, + 0x20, 0x70, 0x61, 0x63, 0x6B, 0x65, 0x74, 0x21, 0x49, 0x27, 0x6D, 0x20, + 0x61, 0x20, 0x70, 0x61, 0x63, 0x6B, 0x65, 0x74, 0x21 +}; + +int count = 0; + +// Prints the network interface statistics values +int print_statistics(struct viface* self, char** stats_names) +{ + int i = 1; + int number_statistics = atoi(stats_names[0]); + + for (i = 1; i <= number_statistics; i++) { + uint64_t result_key; + if (viface_read_stat(self, stats_names[i], + &result_key) == EXIT_FAILURE) { + return EXIT_FAILURE; + } + printf(" %s : %zu\n", stats_names[i], result_key); + } + printf("\n"); + return EXIT_SUCCESS; +} + +/* Shows the use of the interface statistics to read + * the number of packets and bytes sent. + */ +int check_statistics(struct viface* self) +{ + int i = 0; + int number_packets = 100; + uint32_t crc_32 = 0; + char *hex_dump; + char** stats_names; + + printf("********** Viface Statistics **********\n\n"); + + // Prints statistics before sending packets + printf("--- Statistics before sending packets:\n"); + + if ((viface_list_stats(&*self, &stats_names) == EXIT_FAILURE) || + (print_statistics(&*self, stats_names) == EXIT_FAILURE) || + (viface_crc_32(packet, &crc_32) == EXIT_FAILURE) || + (viface_hex_dump(&*self, packet, &hex_dump) == EXIT_FAILURE)) { + return EXIT_FAILURE; + } + + printf("--- About to send the following packet.\n"); + printf(" Size: %d\n", packet[0]); + printf(" CRC: 0x%x\n", crc_32); + printf("%s\n\n", hex_dump); + + printf("--- Sending the packet %d times...", number_packets); + + // Sends the packet for 'number_packets' times + for (i = 0; i < number_packets; i++) { + if (i % 10 == 0) { + printf("\n"); + } + printf(" #%.2d ...", i + 1); + if (viface_send(self, packet) == EXIT_FAILURE) { + return EXIT_FAILURE; + } + } + printf("\n\n"); + + // Prints statistics after sending packets + printf("--- Statistics after sending packets:\n"); + if (print_statistics(self, stats_names) == EXIT_FAILURE) { + return EXIT_FAILURE; + } + + // Clears statistics + printf("--- Clearing statistics:\n"); + int number_statistics = atoi(stats_names[0]); + + for (i = 1; i <= number_statistics; i++) { + uint64_t result_key; + + if ((viface_clear_stat(self, stats_names[i]) == EXIT_FAILURE) || + (viface_read_stat(self, stats_names[i], + &result_key) == EXIT_FAILURE)) { + return EXIT_FAILURE; + } + printf(" %s : %zu\n", stats_names[i], result_key); + } + printf("\n"); + return EXIT_SUCCESS; +} + +/** + * This example shows the use of the interface statistics interface to read + * the number of packets and bytes sent. + */ +main(int argc, const char* argv[]) +{ + struct viface* self; + char name[IFNAMSIZ] = "viface0"; + int id = 1; + + printf("\n--- Starting stats example...\n\n"); + + if (argc > 1) { + strcpy(name, argv[1]); + } + + /* These IF statements do the following: + * 1) Creates interface + * 2) Brings-up interface + * 3) Checks interface statistics + * 4) Brings-down interface + */ + if ((viface_create_global_pool() == EXIT_FAILURE) || + (viface_create_viface(name, true, 0, &self) == EXIT_FAILURE) || + (viface_up(self) == EXIT_FAILURE) || + (check_statistics(self) == EXIT_FAILURE) || + (viface_down(self) == EXIT_FAILURE) || + (viface_destroy_viface(&self) == EXIT_FAILURE) || + (viface_destroy_global_pool() == EXIT_FAILURE)) { + return EXIT_FAILURE; + } + + return 0; +} \ No newline at end of file diff --git a/include/viface/config.h.in b/include/viface/config.h.in new file mode 100644 index 0000000..0f30482 --- /dev/null +++ b/include/viface/config.h.in @@ -0,0 +1,43 @@ +/** + * Copyright (C) 2015 Hewlett Packard Enterprise Development LP + * + * 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 config.h + * libviface configuration header file. + * Configuration and build time defined parameters for libviface + */ + +#ifndef _VIFACE_CONFIG_H +#define _VIFACE_CONFIG_H + +namespace viface { +/** + * @defgroup libviface_private_config Library Configuration + * Library configuration parameters. + * @{ + */ + +/** + * @def VIFACE_VERSION + * libviface full version string + */ +#define VIFACE_VERSION "@libviface_VERSION_STRING@" + +/** @} */ // End of libviface_private_config +}; + +#endif // _VIFACE_CONFIG_H \ No newline at end of file diff --git a/include/viface/viface.h b/include/viface/viface.h index e69de29..748d240 100644 --- a/include/viface/viface.h +++ b/include/viface/viface.h @@ -0,0 +1,548 @@ +/** + * Copyright (C) 2015 Hewlett Packard Enterprise Development LP + * + * 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 viface.h + * Main libviface header file. + * Define the public interface for libviface. + */ + +#ifndef _VIFACE_H +#define _VIFACE_H +#define UNUSED_VAR __attribute__ ((unused)) + +#ifdef __cplusplus +extern "C" { +#endif + +// Posix +#include // open(), close() +#include // O_RDWR +#include // opendir, readdir, closedir + +// Network +#include // inet_ntop() + +// Linux TUN/TAP includes +#include +#include +#include + +// Interfaces +#include // getifaddrs + +// Standard +#include // bool +#include // EXIT_FAILURE + +// APR +#include // apr hash +#include // isprint +#include // apr ring +#include // apr_cpystrn +#define APR_WANT_STDIO +#include + + +/*= Structs Declarations =====================================================*/ + +struct in6_ifreq +{ + struct in6_addr ifr6_addr; + uint32_t ifr6_prefixlen; + int ifr6_ifindex; +}; + +struct viface_queues +{ + int rx; + int tx; +}; + +struct viface +{ + struct viface_queues queues; + int kernel_socket; + int kernel_socket_ipv6; + uint id; + uint mtu; + uint8_t* pktbuff; + char broadcast[INET_ADDRSTRLEN]; + char ipv4[INET_ADDRSTRLEN]; + char name[IFNAMSIZ]; + char netmask[INET_ADDRSTRLEN]; + char mac[18]; + char** ipv6s; + apr_hash_t* stats_cache; + apr_hash_t* stats_keys_cache; + apr_pool_t* viface_pool; +}; + +// Vifaces sequencial identifier number +UNUSED_VAR static uint ID_SEQ = 0; + +// APR parent pool +UNUSED_VAR static apr_pool_t* PARENT_POOL = NULL; + +// APR temporal pool +UNUSED_VAR static apr_pool_t* TEMPORAL_POOL = NULL; + + +/** + * Dispatch callback type to handle packet reception. + * + * @param[in] viface struct containing its state. + * @param[in] packet Packet (if tun) or frame (if tap) as a binary blob + * (array of bytes). + * @param[out] true if the dispatcher should continue processing or false to stop. + * + * @return status indicating if an error happened or not. + */ +typedef int (*dispatcher_cb)(struct viface* self, + uint8_t* packet, bool* result); + +/*= Utilities ================================================================*/ + +/** + * Parse a MAC address in string format. + * + * @param[in] viface struct containing its state. + * @param[in] mac MAC address to parse in format "56:84:7a:fe:97:99". + * @param[out] A vector of 6 bytes with the parsed MAC address. + * + * @return status indicating if an error happened or not. + */ +int viface_parse_mac(struct viface* self, char* mac, uint8_t** result); + +/** + * Build a hexdump representation of a binary blob. + * + * @param[in] viface struct containing its state. + * @param[in] bytes Binary blob (array of bytes) with the data to build + * representation. + * @param[out] string with the hexdump representation of the input binary blob. + * + * @return status indicating if an error happened or not. + */ +int viface_hex_dump(struct viface* self, uint8_t* bytes, char** result); + +/** + * Calculate the 32 bit CRC of the given binary blob. + * + * @param[in] bytes Binary blob (array of bytes) with the data to calculate + * the 32 bit CRC. + * @param[out] string with the hexdump representation of the input binary blob. + * + * @return status indicating if an error happened or not. + */ +int viface_crc_32(uint8_t* bytes, uint32_t* result); + +/*= Virtual Interface Implementation =========================================*/ + +/** + * Create an APR parent pool for memory allocation. + * + * @return status indicating if an error happened or not. + */ +int viface_create_global_pool(); + +/** + * Create a viface struct and an APR subpool from a parent pool. + * + * @param[in] name Name of the virtual interface. The placeholder %d + * can be used and a number will be assigned to it. + * @param[in] tap Tap device (default, true) or Tun device (false). + * @param[in] id Optional numeric id. If given id < 0 a sequential + * number will be given. + * @param[out] viface struct created + * + * @return status indicating if an error happened or not. + */ +int viface_create_viface(char* name, bool tap, int id, struct viface** result); + +/** + * Destroy the static global APR parent pool. + * + * @return status indicating if an error happened or not. + */ +int viface_destroy_global_pool(); + +/** + * Destroy the static temporal APR pool. + * + * @return status indicating if an error happened or not. + */ +int viface_destroy_temporal_pool(); + +/** + * Destroy a viface struct and free all allocated memory from the APR subpool + * + * @param[in] viface struct containing its state. + * + * @return status indicating if an error happened or not. + */ +int viface_destroy_viface(struct viface** self); + +/** + * Create a viface object with given name. + * + * @param[in] viface struct containing its state. + * @param[in] name Name of the virtual interface. The placeholder %d + * can be used and a number will be assigned to it. + * @param[in] tap Tap device (default, true) or Tun device (false). + * @param[in] id Optional numeric id. If given id < 0 a sequential + * number will be given. + * + * @return status indicating if an error happened or not. + */ +int viface_initialization_viface(struct viface* self, char* name, bool tap, + int id); + +/** + * Getter method for virtual interface associated name. + * + * @param[in] viface struct containing its state. + * @param[out] name of the virtual interface. + * + * @return status indicating if an error happened or not. + */ +int viface_get_name(struct viface* self, char** result); + +/** + * Getter method for virtual interface associated numeric id. + * + * @param[in] viface struct containing its state. + * @param[out] numeric id of the virtual interface. + * + * @return status indicating if an error happened or not. + */ +int viface_get_id(struct viface* self, uint* result); + +/** + * Getter method for virtual interface associated + * transmission file descriptor. + * + * @param[in] viface struct containing its state. + * @param[out] transmission file descriptor number. + * + * @return status indicating if an error happened or not. + */ +int viface_get_tx(struct viface* self, int* result); + +/** + * Getter method for virtual interface associated + * reception file descriptor. + * + * @param[in] viface struct containing its state. + * @param[out] reception file descriptor number. + * + * @return status indicating if an error happened or not. + */ +int viface_get_rx(struct viface* self, int* result); + +/** + * Set the MAC address of the virtual interface. + * + * The format of the MAC address is verified, but is just until up() + * is called that the library will try to attempt to write it. + * If you don't provide a MAC address (the default) one will be + * automatically assigned when bringing up the interface. + * + * @param[in] viface struct containing its state. + * @param[in] mac New MAC address for this virtual interface in the + * form "d8:9d:67:d3:65:1f". + * + * @return status indicating if an error happened or not. + */ +int viface_set_mac(struct viface* self, char* mac); + +/** + * Getter method for virtual interface associated MAC Address. + * + * @param[in] viface struct containing its state. + * @param[out] current MAC address of the virtual interface. + * An empty string means no associated MAC address. + * + * @return status indicating if an error happened or not. + */ +int viface_get_mac(struct viface* self, char** result); + +/** + * Auxiliar method to get IPv4 Address, Netmask and Broadcast + * of the virtual interface. + * + * @param[in] viface struct containing its state. + * @param[in] code indicating which IPv4 value to read + * (Address, Netmask, Broadcast) + * @param[out] current IPv4 address, netmask or broadcast of the virtual + * interface depending on the request value. + * An empty string means no associated IPv4 address. + * @return status indicating if an error happened or not. + */ +int viface_ioctl_get_ipv4(struct viface* self, unsigned long request, + char** result); + +/** + * Set the IPv4 address of the virtual interface. + * + * The format of the IPv4 address is verified, but is just until up() + * is called that the library will try to attempt to write it. + * + * @param[in] viface struct containing its state. + * @param[in] ipv4 New IPv4 address for this virtual interface in the + * form "172.17.42.1". + * + * @return status indicating if an error happened or not. + */ +int viface_set_ipv4(struct viface* self, char* ipv4); + +/** + * Getter method for virtual interface associated IPv4 Address. + * + * @param[in] viface struct containing its state. + * @param[out] current IPv4 address of the virtual interface. + * An empty string means no associated IPv4 address. + * + * @return status indicating if an error happened or not. + */ +int viface_get_ipv4(struct viface* self, char** result); + +/** + * Set the IPv4 netmask of the virtual interface. + * + * The format of the IPv4 netmask is verified, but is just until up() + * is called that the library will try to attempt to write it. + * + * @param[in] viface struct containing its state. + * @param[in] netmask New IPv4 netmask for this virtual interface in + * the form "255.255.255.0". + * + * @return status indicating if an error happened or not. + */ +int viface_set_ipv4_netmask(struct viface* self, char* netmask); + +/** + * Getter method for virtual interface associated IPv4 netmask. + * + * @param[in] viface struct containing its state. + * @param[out] current IPv4 netmask of the virtual interface. + * An empty string means no associated IPv4 netmask. + * + * @return status indicating if an error happened or not. + */ +int viface_get_ipv4_netmask(struct viface* self, char** result); + +/** + * Set the IPv4 broadcast address of the virtual interface. + * + * The format of the IPv4 broadcast address is verified, but is just + * until up() is called that the library will try to attempt to write + * it. + * + * @param[in] viface struct containing its state. + * @param[in] broadcast New IPv4 broadcast address for this virtual + * interface in the form "172.17.42.255". + * + * @return status indicating if an error happened or not. + */ +int viface_set_ipv4_broadcast(struct viface* self, char* broadcast); + +/** + * Getter method for virtual interface associated IPv4 broadcast + * address. + * + * @param[in] viface struct containing its state. + * @param[out] current IPv4 broadcast address of the virtual interface. + * An empty string means no associated IPv4 broadcast address. + * + * @return status indicating if an error happened or not. + */ +int viface_get_ipv4_broadcast(struct viface* self, char** result); + +/** + * Set the IPv6 addresses of the virtual interface. + * + * The format of the IPv6 addresses are verified, but is just until + * up() is called that the library will try to attempt to write them. + * + * @param[in] viface struct containing its state. + * @param[in] number of IPv6s to set + * @param[in] ipv6s New IPv6 addresses for this virtual interface in + * the form "::FFFF:204.152.189.116". + * + * @return status indicating if an error happened or not. + */ +int viface_set_ipv6(struct viface* self, int num_ipv6s, char* ipv6s[]); + +/** + * Getter method for virtual interface associated IPv6 Addresses + * (note the plural). + * + * @param[in] viface struct containing its state. + * @param[out] current IPv6 addresses of the virtual interface. + * An empty set means no associated IPv6 addresses. + * + * @return status indicating if an error happened or not. + */ +int viface_get_ipv6(struct viface* self, char** result[]); + +/** + * Set the MTU of the virtual interface. + * + * The range of the MTU is verified, but is just until up() is called + * that the library will try to attempt to write it. + * + * @param[in] viface struct containing its state. + * @param[in] mtu New MTU for this virtual interface. + * + * @return status indicating if an error happened or not. + */ +int viface_set_mtu(struct viface* self, uint mtu); + +/** + * Getter method for virtual interface associated maximum transmission + * unit (MTU). + * + * MTU is the size of the largest packet or frame that can be sent + * using this interface. + * + * @param[in] viface struct containing its state. + * @param[out] current MTU of the virtual interface. + * + * @return status indicating if an error happened or not. + */ +int viface_get_mtu(struct viface* self, uint* mtu); + +/** + * Bring up the virtual interface. + * + * This call will configure and bring up the interface. + * + * @param[in] viface struct containing its state. + * + * @return status indicating if an error happened or not. + */ +int viface_up(struct viface* self); + +/** + * Bring down the virtual interface. + * + * + * @param[in] viface struct containing its state. + * + * @return status indicating if an error happened or not. + */ +int viface_down(struct viface* self); + +/** + * Indicate if the virtual interface is up. + * + * @param[in] viface struct containing its state. + * @param[out] value indicating if the virtual interface + * is up or not. + * + * @return status indicating if an error happened or not. + */ +int viface_is_up(struct viface* self, bool* result); + +/** + * Receive a packet from the virtual interface. + * + * Note: Receive a packet from a virtual interface means that another + * userspace program (or the kernel) sent a packet to the network + * interface with the name of the instance of this class. If not packet + * was available, and empty vector is returned. + * + * @param[in] viface struct containing its state. + * @param[out] packet (if tun) or frame (if tap) as a binary blob + * (array of bytes). + * + * @return status indicating if an error happened or not. + */ +int viface_receive(struct viface* self, uint8_t** result); + +/** + * Send a packet to this virtual interface. + * + * Note: Sending a packet to this virtual interface means that it + * will reach any userspace program (or the kernel) listening for + * packets in the interface with the name of the instance of this + * class. + * + * @param[in] viface struct containing its state. + * @param[in] packet (if tun) or frame (if tap) as a binary blob + * (array of bytes). + * + * @return status indicating if an error happened or not. + */ +int viface_send(struct viface* self, uint8_t* packet); + +/** + * List available statistics for this interface. + * + * @param[in] viface struct containing its state. + * @param[out] set of statistics names. + * For example, {"rx_packets", "tx_bytes", ...} + * Exceptions can be thrown in case of generic IO errors. + * + * @return status indicating if an error happened or not. + */ +int viface_list_stats(struct viface* self, char** result[]); + +/** + * Read given statistic for this interface. + * + * @param[in] viface struct containing its state. + * @param[in] stat statistic name. See listStats(). + * @param[out] current value of the given statistic. + * + * @return status indicating if an error happened or not. + */ +int viface_read_stat_file(struct viface* self, char* stat, uint64_t* result); + +/** + * Read given statistic for this interface. + * + * @param[in] viface struct containing its state. + * @param[in] stat statistic name. See listStats(). + * @param[out] current value of the given statistic. + * + * @return status indicating if an error happened or not. + */ +int viface_read_stat(struct viface* self, char* stat, uint64_t* result); + +/** + * Clear given statistic for this interface. + * + * Please note that this feature is implemented in library as there is + * currently no way to clear them (except by destroying the interface). + * If you clear the statistics using this method, subsequent calls to + * readStat() results will differ from, for example, those reported + * by tools like ifconfig. + * + * @param[in] viface struct containing its state. + * @param[in] stat statistic name. See listStats(). + * + * @return status indicating if an error happened or not. + */ +int viface_clear_stat(struct viface* self, char* stat); + +#ifdef __cplusplus +} +#endif + +#endif // _VIFACE_H \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e69de29..341f63f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -0,0 +1,32 @@ +# Define library name +set(LIB_NAME "viface") + +# Add libviface library to build +add_library(${LIB_NAME} SHARED viface.c) + +# Add APR dependencies +if (NOT APR_FOUND) + add_dependencies(${LIB_NAME} apr_lib) +endif() +if (NOT APRUTIL_FOUND) + add_dependencies(${LIB_NAME} aprutil_lib) +endif() + +# Link target with APR libraries +target_link_libraries(${LIB_NAME} ${APR_LIBRARIES} ${APRUTIL_LIBRARIES}) + +# Set library version +set_target_properties( + ${LIB_NAME} PROPERTIES VERSION ${libviface_VERSION_STRING} +) + +# Specify shared library install directory +install( + TARGETS + ${LIB_NAME} + DESTINATION + "${CMAKE_INSTALL_LIBDIR}" +) + +# Set dependency with the library target +add_dependencies(${PROJECT_NAME} ${LIB_NAME}) diff --git a/src/viface.c b/src/viface.c index e69de29..41588fb 100644 --- a/src/viface.c +++ b/src/viface.c @@ -0,0 +1,1591 @@ +/** + * Copyright (C) 2015 Hewlett Packard Enterprise Development LP + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use self 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 "viface/viface.h" + +/*= Utilities ================================================================*/ + +int viface_parse_mac(struct viface* self, char* mac, uint8_t** result) +{ + unsigned int bytes[6]; + int scans = sscanf( + mac, + "%02x:%02x:%02x:%02x:%02x:%02x", + &bytes[0], &bytes[1], &bytes[2], &bytes[3], &bytes[4], &bytes[5] + ); + + if (scans != 6) { + fprintf(stdout, "---- Invalid MAC address %s.\n", mac); + return EXIT_FAILURE; + } + + int i = 0; + uint8_t *parsed = apr_pcalloc(TEMPORAL_POOL, 6); + + if (parsed == NULL) { + fprintf(stdout, "--- Memory could not be allocated for"); + fprintf(stdout, " parsing mac address.\n"); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + return EXIT_FAILURE; + } + + for (i = 0; i < 6; i++) { + parsed[i] = bytes[i]; + } + + *result = parsed; + return EXIT_SUCCESS; +} + +int viface_hex_dump(struct viface* self, uint8_t* bytes, char** result) +{ + const int BYTES_PER_LINE = 72; + + char buffer[10]; + int number_lines = (bytes[0] / 16) + 1; + + *result = apr_pcalloc(TEMPORAL_POOL, BYTES_PER_LINE * number_lines); + if (result == NULL) { + fprintf(stdout, "--- Memory could not be allocated for"); + fprintf(stdout, " result buffer at 'viface_hex_dump' method.\n"); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + return EXIT_FAILURE; + } + memset(*result, '\0', BYTES_PER_LINE * number_lines); + + int i; + int j; + char c; + + for (i = 0, j = 0; i < bytes[0]; i += 16) { + // Print offset + sprintf(buffer, "%.4d ", i); + strcat(*result, buffer); + + for (j = 0; j < 16; j++) { + if (i + j < bytes[0]) { + c = bytes[i + j + 1]; + sprintf(buffer, "%.2x ", ((int)c & 0xFF)); + strcat(*result, buffer); + } else { + strcat(*result, " "); + } + } + strcat(*result, " "); + + // Print printable characters + for (j = 0; j < 16; j++) { + if (i + j < bytes[0]) { + c = bytes[i + j + 1]; + if (isprint(c)) { + sprintf(buffer, "%c", c); + strcat(*result, buffer); + } else { + strcat(*result, "."); + } + } + } + strcat(*result, "\n"); + } + return EXIT_SUCCESS; +} + +int viface_crc_32(uint8_t* bytes, uint32_t* result) +{ + static uint32_t crc_table[] = { + 0x4DBDF21C, 0x500AE278, 0x76D3D2D4, 0x6B64C2B0, + 0x3B61B38C, 0x26D6A3E8, 0x000F9344, 0x1DB88320, + 0xA005713C, 0xBDB26158, 0x9B6B51F4, 0x86DC4190, + 0xD6D930AC, 0xCB6E20C8, 0xEDB71064, 0xF0000000 + }; + + uint32_t crc = 0; + uint32_t i = 0; + const uint8_t* data = &bytes[1]; + + for (i = 0; i < bytes[0]; ++i) { + crc = (crc >> 4) ^ crc_table[(crc ^ data[i]) & 0x0F]; + crc = (crc >> 4) ^ crc_table[(crc ^ (data[i] >> 4)) & 0x0F]; + } + *result = crc; + return EXIT_SUCCESS; +} + +/*= Helpers ==================================================================*/ + +static int viface_read_flags(int sock_fd, char* name, struct ifreq* ifr) +{ + // Prepare communication structure + memset(ifr, 0, sizeof(struct ifreq)); + + // Set interface name + apr_cpystrn(ifr->ifr_name, name, IFNAMSIZ - 1); + + // Read interface flags + if (ioctl(sock_fd, SIOCGIFFLAGS, ifr) != 0) { + fprintf(stdout, "--- Unable to read %s flags.\n", name); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + return EXIT_FAILURE; + } + return EXIT_SUCCESS; +} + + +static int viface_read_mtu(char* name, size_t size_bytes, uint* result) +{ + const int SIZE_BYTES_PATH = 19; + + int fd = -1; + int nread = -1; + int size_bytes_mtu_path = SIZE_BYTES_PATH + strlen(name); + char buffer[size_bytes + 1]; + + char mtu_path[size_bytes_mtu_path + 1]; + memset(&mtu_path, 0, size_bytes_mtu_path); + + snprintf(mtu_path, sizeof(mtu_path), "%s%s%s", + "/sys/class/net/", name, "/mtu"); + + mtu_path[size_bytes_mtu_path] = '\0'; + + // Opens MTU file + fd = open(mtu_path, + O_RDONLY | O_NONBLOCK); + + if (fd < 0) { + fprintf(stdout, "--- Unable to open MTU file for"); + fprintf(stdout, " '%s' network interface.\n", name); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + goto err; + } + + // Reads MTU value + nread = read(fd, &buffer, size_bytes); + buffer[size_bytes] = '\0'; + + // Handles errors + if (nread == -1) { + fprintf(stdout, "--- Unable to read MTU for"); + fprintf(stdout, " '%s' network interface.\n", name); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + goto err; + } + + if (close(fd) < 0) { + fprintf(stdout, "--- Unable to close MTU file for"); + fprintf(stdout, " '%s' network interface.\n", name); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + goto err; + } + + *result = strtoul(buffer, NULL, 10); + return EXIT_SUCCESS; + +err: + // Rollback close file descriptor + close(fd); + return EXIT_FAILURE; +} + +static int viface_alloc_viface(struct viface* self, char* name, bool tap, + struct viface_queues* queues, char* result) +{ + int i = 0; + int fd = -1; + + /* Create structure for ioctl call + * + * Flags: IFF_TAP - TAP device (layer 2, ethernet frame) + * IFF_TUN - TUN device (layer 3, IP packet) + * IFF_NO_PI - Do not provide packet information + * IFF_MULTI_QUEUE - Create a queue of multiqueue device + */ + struct ifreq ifr; + memset(&ifr, 0, sizeof(ifr)); + + ifr.ifr_flags = IFF_NO_PI | IFF_MULTI_QUEUE; + if (tap) { + ifr.ifr_flags |= IFF_TAP; + } else { + ifr.ifr_flags |= IFF_TUN; + } + + apr_cpystrn(ifr.ifr_name, name, IFNAMSIZ - 1); + + // Allocate queues + for (i = 0; i < 2; i++) { + // Open TUN/TAP device + fd = open("/dev/net/tun", O_RDWR | O_NONBLOCK); + if (fd < 0) { + fprintf(stdout, "--- Unable to open TUN/TAP device.\n"); + fprintf(stdout, " Name: %s Queue: %d.\n", name, i); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + goto err; + } + + // Register a network device with the kernel + if (ioctl(fd, TUNSETIFF, (void* )&ifr) != 0) { + fprintf(stdout, "--- Unable to register a TUN/TAP device.\n"); + fprintf(stdout, " Name: %s Queue: %d.\n", name, i); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + goto err; + + if (close(fd) < 0) { + fprintf(stdout, "--- Unable to close a TUN/TAP device.\n"); + fprintf(stdout, " Name: %s Queue: %d.\n", name, i); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + goto err; + } + goto err; + } + + ((int* )queues)[i] = fd; + } + + apr_cpystrn(result, ifr.ifr_name, strlen(ifr.ifr_name) + 1); + return EXIT_SUCCESS; + +err: + // Rollback close file descriptors + for (--i; i >= 0; i--) { + if (close(((int* )queues)[i]) < 0) { + fprintf(stdout, "--- Unable to close a TUN/TAP device.\n"); + fprintf(stdout, " Name: %s Queue: %d.\n", name, i); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + } + } + return EXIT_FAILURE; +} + +static int viface_hook_viface(char* name, struct viface_queues* queues) +{ + int i = 0; + int fd = -1; + + // Creates Tx/Rx sockets and allocates queues + for (i = 0; i < 2; i++) { + // Creates the socket + fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); + + if (fd < 0) { + fprintf(stdout, "--- Unable to create the Tx/Rx socket channel.\n"); + fprintf(stdout, " Name: %s Queue: %d.\n", name, i); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + goto err; + } + + struct ifreq ifr; + memset(&ifr, 0, sizeof(ifr)); + + apr_cpystrn(ifr.ifr_name, name, IFNAMSIZ - 1); + + // Obtains the network index number + if (ioctl(fd, SIOCGIFINDEX, &ifr) != 0) { + fprintf(stdout, "--- Unable to get network index number.\n"); + fprintf(stdout, " Name: %s Queue: %d.\n", name, i); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + goto err; + } + + struct sockaddr_ll socket_addr; + memset(&socket_addr, 0, sizeof(struct sockaddr_ll)); + + socket_addr.sll_family = AF_PACKET; + socket_addr.sll_protocol = htons(ETH_P_ALL); + socket_addr.sll_ifindex = ifr.ifr_ifindex; + + // Binds the socket to the 'socket_addr' address + if (bind(fd, (struct sockaddr*) &socket_addr, + sizeof(socket_addr)) != 0) { + fprintf(stdout, "--- Unable to bind the Tx/Rx socket channel to"); + fprintf(stdout, " the '%s' network interface.\n", name); + fprintf(stdout, " Queue: %d.\n", i); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + goto err; + } + + ((int* )queues)[i] = fd; + } + return EXIT_SUCCESS; + +err: + // Rollback close file descriptors + for (--i; i >= 0; i--) { + if (close(((int* )queues)[i]) < 0) { + fprintf(stdout, "--- Unable to close a Rx/Tx socket.\n"); + fprintf(stdout, " Name: %s Queue: %d.\n", name, i); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + } + } + return EXIT_FAILURE; +} + +static int viface_is_empty(char* buffer, bool* result) +{ + *result = true; + + if ((buffer != NULL) && (buffer[0] != '\0')) { + *result = false; + } + return EXIT_SUCCESS; +} + +/*= Virtual Interface Implementation =========================================*/ + +int viface_create_global_pool() +{ + apr_initialize(); + + // Creates parent and temporal pools + apr_pool_create(&PARENT_POOL, NULL); + apr_pool_create(&TEMPORAL_POOL, PARENT_POOL); +} + +int viface_create_viface(char* name, bool tap, int id, struct viface** result) +{ + apr_pool_t* viface_pool = NULL; + apr_pool_create(&viface_pool, PARENT_POOL); + + struct viface* self = apr_pcalloc(viface_pool, sizeof(struct viface)); + + if (self == NULL) { + fprintf(stdout, "--- Memory could not be allocated for"); + fprintf(stdout, " 'viface' struct.\n"); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + viface_destroy_viface(&self); + return EXIT_FAILURE; + } + + self->viface_pool = viface_pool; + + self->stats_keys_cache = apr_hash_make(self->viface_pool); + self->stats_cache = apr_hash_make(self->viface_pool); + + if ((self->stats_keys_cache == NULL) || + (self->stats_cache == NULL)) { + fprintf(stdout, "--- Memory could not be allocated for"); + fprintf(stdout, " APR hash table.\n"); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + viface_destroy_viface(&self); + return EXIT_FAILURE; + } + *result = self; + + if (viface_initialization_viface(self, name, tap, id) == EXIT_FAILURE) { + viface_destroy_viface(&self); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + +int viface_destroy_global_pool() +{ + apr_pool_destroy(PARENT_POOL); + apr_terminate(); + return EXIT_SUCCESS; +} + +int viface_destroy_temporal_pool() +{ + apr_pool_destroy(TEMPORAL_POOL); + return EXIT_SUCCESS; +} + +int viface_destroy_viface(struct viface** self) +{ + if (*self == NULL) { + fprintf(stdout, "--- Error destroying viface struct"); + return EXIT_FAILURE; + } + + if ((close((*self)->queues.rx)) || + (close((*self)->queues.tx)) || + (close((*self)->kernel_socket)) || + (close((*self)->kernel_socket_ipv6))) { + fprintf(stdout, "--- Unable to close file descriptors for"); + fprintf(stdout, " interface %s.\n", (*self)->name); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + return EXIT_FAILURE; + } + + apr_pool_destroy((*self)->viface_pool); + *self = NULL; + + return EXIT_SUCCESS; +} + +int viface_initialization_viface(struct viface* self, char* name, + bool tap, int id) +{ + // Check name length + if (strlen(name) >= IFNAMSIZ) { + fprintf(stdout, "--- Virtual interface name too long.\n"); + return EXIT_FAILURE; + } + + // Create queues + struct viface_queues queues; + memset(&queues, 0, sizeof(struct viface_queues)); + + int size_bytes_viface_path = strlen("/sys/class/net/") + strlen(name); + + char viface_path[size_bytes_viface_path + 1]; + memset(&viface_path, 0, size_bytes_viface_path); + + snprintf(viface_path, sizeof(viface_path), "%s%s", + "/sys/class/net/", name); + + /* Checks if the path name can be accessed. If so, + * it means that the network interface is already defined. + */ + if (access(viface_path, F_OK) == 0) { + if (viface_hook_viface(name, &queues) == EXIT_FAILURE) { + return EXIT_FAILURE; + } + apr_cpystrn(self->name, name, strlen(name) + 1); + + // Read MTU value and resize buffer + if (viface_read_mtu(name, sizeof(self->mtu), + &self->mtu) == EXIT_FAILURE) { + return EXIT_FAILURE; + } + self->pktbuff = apr_pcalloc(self->viface_pool, sizeof(self->mtu)); + + if (self->pktbuff == NULL) { + fprintf(stdout, "--- Memory could not be allocated for"); + fprintf(stdout, " pktbuff in %s interface.\n", name); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + return EXIT_FAILURE; + } + } else { + char viface_name[IFNAMSIZ]; + if (viface_alloc_viface(self, name, tap, &queues, + viface_name) == EXIT_FAILURE) { + return EXIT_FAILURE; + } + apr_cpystrn(self->name, viface_name, strlen(viface_name) + 1); + + // Other defaults + self->mtu = 1500; + } + + self->queues = queues; + + // Create socket channels to the NET kernel for later ioctl + self->kernel_socket = -1; + self->kernel_socket = socket(AF_INET, SOCK_STREAM, 0); + if (self->kernel_socket < 0) { + fprintf(stdout, "--- Unable to create IPv4 socket channel to the"); + fprintf(stdout, " NET kernel.\n"); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + return EXIT_FAILURE; + } + + self->kernel_socket_ipv6 = -1; + self->kernel_socket_ipv6 = socket(AF_INET6, SOCK_STREAM, 0); + if (self->kernel_socket_ipv6 < 0) { + fprintf(stdout, "--- Unable to create IPv6 socket channel to the"); + fprintf(stdout, " NET kernel.\n"); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + return EXIT_FAILURE; + } + + // Set id + if (id < 0) { + self->id = ID_SEQ; + } else { + self->id = id; + } + + ID_SEQ++; + return EXIT_SUCCESS; +} + +int viface_get_name(struct viface* self, char** result) +{ + *result = apr_pcalloc(TEMPORAL_POOL, IFNAMSIZ); + if (result == NULL) { + fprintf(stdout, "--- Memory could not be allocated for"); + fprintf(stdout, " result buffer at 'viface_get_name' method.\n"); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + return EXIT_FAILURE; + } + + *result = self->name; + return EXIT_SUCCESS; +} + +int viface_get_id(struct viface* self, uint* result) +{ + *result = self->id; + return EXIT_SUCCESS; +} + +int viface_get_tx(struct viface* self, int* result) +{ + *result = self->queues.tx; + return EXIT_SUCCESS; +} + +int viface_get_rx(struct viface* self, int* result) +{ + *result = self->queues.rx; + return EXIT_SUCCESS; +} + + +int viface_set_mac(struct viface* self, char* mac) +{ + uint8_t* mac_bin; + if (viface_parse_mac(self, mac, &mac_bin) == EXIT_FAILURE) { + return EXIT_FAILURE; + } + + apr_cpystrn(self->mac, mac, strlen(mac) + 1); + return EXIT_SUCCESS; +} + +int viface_get_mac(struct viface* self, char** result) +{ + // Read interface flags + struct ifreq ifr; + if (viface_read_flags(self->kernel_socket, self->name, + &ifr) == EXIT_FAILURE) { + return EXIT_FAILURE; + } + + if (ioctl(self->kernel_socket, SIOCGIFHWADDR, &ifr) != 0) { + fprintf(stdout, "--- Unable to get MAC addr for %s.\n", self->name); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + return EXIT_FAILURE; + } + + *result = apr_pcalloc(TEMPORAL_POOL, 18); + if (result == NULL) { + fprintf(stdout, "--- Memory could not be allocated for"); + fprintf(stdout, " result buffer at 'viface_get_mac' method.\n"); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + return EXIT_FAILURE; + } + + // Convert binary MAC address to string + int i = 0; + for (i = 0; i < 6; i++) { + char value[2]; + snprintf(value, 3, "%.02x", + (unsigned int) (0xFF & ifr.ifr_hwaddr.sa_data[i])); + strcat(*result, value); + + if (i != 5) { + strcat(*result, ":"); + } + } + return EXIT_SUCCESS; +} + +int viface_set_ipv4(struct viface* self, char* ipv4) +{ + // Validate format + struct in_addr addr; + + if (!inet_pton(AF_INET, ipv4, &addr)) { + fprintf(stdout, "--- Invalid IPv4 address (%s) for", ipv4); + fprintf(stdout, " %s.\n", self->name); + return EXIT_FAILURE; + } + + apr_cpystrn(self->ipv4, ipv4, strlen(ipv4) + 1); + return EXIT_SUCCESS; +} + +int viface_ioctl_get_ipv4(struct viface* self, unsigned long request, + char** result) +{ + // Read interface flags + struct ifreq ifr; + if (viface_read_flags(self->kernel_socket, self->name, + &ifr) == EXIT_FAILURE) { + return EXIT_FAILURE; + } + + if (ioctl(self->kernel_socket, request, &ifr) != 0) { + fprintf(stdout, "--- Unable to get IPv4 for %s.\n", self->name); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + return EXIT_FAILURE; + } + + // Convert binary IP address to string + char addr[INET_ADDRSTRLEN]; + memset(&addr, 0, sizeof(addr)); + + struct sockaddr_in* ipaddr = (struct sockaddr_in*) &ifr.ifr_addr; + if (inet_ntop(AF_INET, &(ipaddr->sin_addr), addr, sizeof(addr)) == NULL) { + fprintf(stdout, "--- Unable to convert IPv4 for %s.\n", self->name); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + return EXIT_FAILURE; + } + + *result = apr_pcalloc(TEMPORAL_POOL, INET_ADDRSTRLEN); + if (result == NULL) { + fprintf(stdout, "--- Memory could not be allocated for"); + fprintf(stdout, " result buffer at 'viface_ioctlGetIPv4' method.\n"); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + return EXIT_FAILURE; + } + + apr_cpystrn(*result, addr, strlen(addr) + 1); + return EXIT_SUCCESS; +} + +int viface_get_ipv4(struct viface* self, char** result) +{ + return viface_ioctl_get_ipv4(self, SIOCGIFADDR, result); +} + +int viface_set_ipv4_netmask(struct viface* self, char* netmask) +{ + // Validate format + struct in_addr addr; + + if (!inet_pton(AF_INET, netmask, &addr)) { + fprintf(stdout, "--- Invalid IPv4 netmask (%s) for", netmask); + fprintf(stdout, " %s.\n", self->name); + return EXIT_FAILURE; + } + + apr_cpystrn(self->netmask, netmask, strlen(netmask) + 1); + return EXIT_SUCCESS; +} + +int viface_get_ipv4_netmask(struct viface* self, char** result) +{ + return viface_ioctl_get_ipv4(self, SIOCGIFNETMASK, result); +} + +int viface_set_ipv4_broadcast(struct viface* self, char* broadcast) +{ + // Validate format + struct in_addr addr; + + if (!inet_pton(AF_INET, broadcast, &addr)) { + fprintf(stdout, "--- Invalid IPv4 address (%s) for", broadcast); + fprintf(stdout, " %s.\n", self->name); + return EXIT_FAILURE; + } + + apr_cpystrn(self->broadcast, broadcast, strlen(broadcast) + 1); + return EXIT_SUCCESS; +} + +int viface_get_ipv4_broadcast(struct viface* self, char** result) +{ + return viface_ioctl_get_ipv4(self, SIOCGIFBRDADDR, result); +} + +int viface_set_mtu(struct viface* self, uint mtu) +{ + // RFC 791, p. 24: "Every internet module must be able to forward a + // datagram of 68 octets without further fragmentation." + if (mtu < 68) { + fprintf(stdout, "--- MTU %d too small (< 68).\n", mtu); + return EXIT_FAILURE; + } + + // Are we sure about self upper validation? + // lo interface reports self number for its MTU + if (mtu > 65536) { + fprintf(stdout, "--- MTU %d too large (> 65536).\n", mtu); + return EXIT_FAILURE; + } + + self->mtu = mtu; + return EXIT_SUCCESS; +} + +int viface_get_mtu(struct viface* self, uint* mtu) +{ + // Read interface flags + struct ifreq ifr; + if (viface_read_flags(self->kernel_socket, self->name, + &ifr) == EXIT_FAILURE) { + return EXIT_FAILURE; + } + + if (ioctl(self->kernel_socket, SIOCGIFMTU, &ifr) != 0) { + fprintf(stdout, "--- Unable to get MTU for %s.\n", self->name); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + return EXIT_FAILURE; + } + + *mtu = ifr.ifr_mtu; + return EXIT_SUCCESS; +} + +int viface_set_ipv6(struct viface* self, int num_ipv6s, char* ipv6s[]) +{ + // Validate format + struct in6_addr addr6; + + int i = 0; + for (i = 0; i < num_ipv6s; i++) { + if (!inet_pton(AF_INET6, ipv6s[i], &addr6)) { + fprintf(stdout, "--- Invalid IPv6 address"); + fprintf(stdout, " (%s) for %s.\n", ipv6s[i], self->name); + return EXIT_FAILURE; + } + } + + self->ipv6s = apr_pcalloc(self->viface_pool, sizeof(char) * num_ipv6s + 1); + + if (self->ipv6s == NULL) { + fprintf(stdout, "--- Memory could not be allocated for"); + fprintf(stdout, " ipv6s buffer at 'viface_set_ipv6' method.\n"); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + return EXIT_FAILURE; + } + + self->ipv6s = ipv6s; + return EXIT_SUCCESS; +} + +int viface_get_ipv6(struct viface* self, char** result[]) +{ + int i = 1; + + // Creates hash table + char** ipv6s = + apr_pcalloc(TEMPORAL_POOL, sizeof(char*) * INET6_ADDRSTRLEN + 1); + + if (ipv6s == NULL) { + fprintf(stdout, "--- Memory could not be allocated for"); + fprintf(stdout, " getting IPv6s for %s interface.\n", self->name); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + return EXIT_FAILURE; + } + + // Buffer to store string representation of the address + char buff[INET6_ADDRSTRLEN]; + memset(&buff, 0, sizeof(buff)); + + // Cast pointer to ipv6 address + struct sockaddr_in6* addr; + + // Pointers to list head and current node + struct ifaddrs *head; + struct ifaddrs *node; + + // Get list of interfaces + if (getifaddrs(&head) == -1) { + fprintf(stdout, "--- Failed to get list of interface addresses.\n"); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + return EXIT_FAILURE; + } + + // Iterate list + for (node = head; node != NULL; node = node->ifa_next) { + if (node->ifa_addr == NULL) { + continue; + } + if (node->ifa_addr->sa_family != AF_INET6) { + continue; + } + + if (strcmp(node->ifa_name, self->name) != 0) { + continue; + } + + // Convert IPv6 address to string representation + addr = (struct sockaddr_in6*) node->ifa_addr; + if (inet_ntop(AF_INET6, &(addr->sin6_addr), buff, + sizeof(buff)) == NULL) { + fprintf(stdout, "--- Unable to convert IPv6 for"); + fprintf(stdout, " %s.\n", self->name); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + return EXIT_FAILURE; + } + + ipv6s[i] = apr_pcalloc(TEMPORAL_POOL, sizeof(buff) + 1); + if (ipv6s[i] == NULL) { + fprintf(stdout, "--- Memory could not be allocated for"); + fprintf(stdout, " getting IPv6 addresses.\n"); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + return EXIT_FAILURE; + } + apr_cpystrn(ipv6s[i], buff, sizeof(buff)); + i++; + } + + char *number_ipv6s = apr_pcalloc(TEMPORAL_POOL, sizeof(int)); + + if (number_ipv6s == NULL) { + fprintf(stdout, "--- Memory could not be allocated"); + fprintf(stdout, " getting Ipv6s for %s interface.\n", self->name); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + return EXIT_FAILURE; + } + + sprintf(number_ipv6s,"%d", i - 1); + ipv6s[0] = number_ipv6s; + + freeifaddrs(head); + *result = ipv6s; + return EXIT_SUCCESS; +} + +int viface_is_up(struct viface* self, bool* result) +{ + // Read interface flags + struct ifreq ifr; + + if (viface_read_flags(self->kernel_socket, self->name, + &ifr) == EXIT_FAILURE) { + return EXIT_FAILURE; + } + + *result = (ifr.ifr_flags & IFF_UP) != 0; + return EXIT_SUCCESS; +} + +int viface_up(struct viface* self) +{ + bool is_viface_up; + if (viface_is_up(self, &is_viface_up) == EXIT_FAILURE) { + return EXIT_FAILURE; + } + + if (is_viface_up) { + fprintf(stdout, "--- Virtual interface %s", self->name); + fprintf(stdout, " is already up.\n"); + fprintf(stdout, " up() Operation not permitted.\n"); + return EXIT_FAILURE; + } + + // Read interface flags + struct ifreq ifr; + if (viface_read_flags(self->kernel_socket, self->name, + &ifr) == EXIT_FAILURE) { + return EXIT_FAILURE; + } + + // Set MAC address + bool is_mac_empty; + viface_is_empty(self->mac, &is_mac_empty); + if (!is_mac_empty) { + uint8_t* mac_bin; + + if (viface_parse_mac(self, self->mac, &mac_bin) == EXIT_FAILURE) { + return EXIT_FAILURE; + } + + int i = 0; + ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER; + for (i = 0; i < 6; i++) { + ifr.ifr_hwaddr.sa_data[i] = mac_bin[i]; + } + + if (ioctl(self->kernel_socket, SIOCSIFHWADDR, &ifr) != 0) { + fprintf(stdout, "--- Unable to set MAC Address (%s)", self->mac); + fprintf(stdout, " for %s.\n", self->name); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + return EXIT_FAILURE; + } + } + + // Set IPv4 related + // FIXME: Refactor self, it's ugly :/ + struct sockaddr_in* addr = (struct sockaddr_in*) &ifr.ifr_addr; + addr->sin_family = AF_INET; + + // Address + bool is_ipv4_empty; + viface_is_empty(self->ipv4, &is_ipv4_empty); + if (!is_ipv4_empty) { + if (!inet_pton(AF_INET, self->ipv4, &addr->sin_addr)) { + fprintf(stdout, "--- Invalid cached IPv4 address"); + fprintf(stdout, " (%s) for %s.\n", self->ipv4, self->name); + fprintf(stdout, " Something really bad happened :/\n"); + return EXIT_FAILURE; + } + + if (ioctl(self->kernel_socket, SIOCSIFADDR, &ifr) != 0) { + fprintf(stdout, "--- Unable to set IPv4"); + fprintf(stdout, " (%s) for %s.\n", self->ipv4, self->name); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + return EXIT_FAILURE; + } + } + + // Netmask + bool is_netmask_empty; + viface_is_empty(self->netmask, &is_netmask_empty); + if (!is_netmask_empty) { + if (!inet_pton(AF_INET, self->netmask, &addr->sin_addr)) { + fprintf(stdout, "--- Invalid cached IPv4 netmask"); + fprintf(stdout, " (%s) for %s.\n", self->netmask, self->name); + fprintf(stdout, " Something really bad happened :/\n"); + return EXIT_FAILURE; + } + + if (ioctl(self->kernel_socket, SIOCSIFNETMASK, &ifr) != 0) { + fprintf(stdout, "--- Unable to set IPv4 netmask"); + fprintf(stdout, " (%s) for %s.\n", self->netmask, self->name); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + return EXIT_FAILURE; + } + } + + // Broadcast + bool is_broadcast_empty; + viface_is_empty(self->broadcast, &is_broadcast_empty); + if (!is_broadcast_empty) { + if (!inet_pton(AF_INET, self->broadcast, &addr->sin_addr)) { + fprintf(stdout, "--- Invalid cached IPv4 broadcast"); + fprintf(stdout, " (%s) for", self->broadcast); + fprintf(stdout, " %s.\n", self->name); + fprintf(stdout, " Something really bad happened :/\n"); + return EXIT_FAILURE; + } + + if (ioctl(self->kernel_socket, SIOCSIFBRDADDR, &ifr) != 0) { + fprintf(stdout, "--- Unable to set IPv4 broadcast"); + fprintf(stdout, " (%s) for", self->broadcast); + fprintf(stdout, " %s.\n", self->name); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + return EXIT_FAILURE; + } + } + + // Set IPv6 related + // FIXME: Refactor self, it's ugly :/ + if (self->ipv6s != NULL) { + struct in6_ifreq ifr6; + memset(&ifr6, 0, sizeof(struct in6_ifreq)); + + // Get interface index + if (ioctl(self->kernel_socket, SIOGIFINDEX, &ifr) < 0) { + fprintf(stdout, "--- Unable to get interface index for"); + fprintf(stdout, " (%s).\n", self->name); + fprintf(stdout, " Something really bad happened :/\n"); + return EXIT_FAILURE; + } + ifr6.ifr6_ifindex = ifr.ifr_ifindex; + ifr6.ifr6_prefixlen = 64; + + int i = 0; + for (i = 0; i < 2; i++) { + // Parse IPv6 address into IPv6 address structure + if (!inet_pton(AF_INET6, self->ipv6s[i], &ifr6.ifr6_addr)) { + fprintf(stdout, "--- Invalid cached IPv6 address"); + fprintf(stdout, " (%s) for %s.\n", self->ipv6s[i], self->name); + fprintf(stdout, " Something really bad happened :/\n"); + return EXIT_FAILURE; + } + + // Set IPv6 address + if (ioctl(self->kernel_socket_ipv6, SIOCSIFADDR, &ifr6) < 0) { + fprintf(stdout, "--- Unable to set IPv6 address"); + fprintf(stdout, " (%s) for %s.\n", self->ipv6s[i], self->name); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + return EXIT_FAILURE; + } + } + } + + // Set MTU + ifr.ifr_mtu = self->mtu; + if (ioctl(self->kernel_socket, SIOCSIFMTU, &ifr) != 0) { + fprintf(stdout, "--- Unable to set MTU"); + fprintf(stdout, " (%d) for %s.\n", self->mtu, self->name); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + return EXIT_FAILURE; + } + + self->pktbuff = apr_pcalloc(self->viface_pool, sizeof(self->mtu)); + + if (self->pktbuff == NULL) { + fprintf(stdout, "--- Memory could not be reallocated for pktbuff"); + fprintf(stdout, " for %s network interface.\n", self->name); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + return EXIT_FAILURE; + } + + // Bring-up interface + ifr.ifr_flags |= IFF_UP; + if (ioctl(self->kernel_socket, SIOCSIFFLAGS, &ifr) != 0) { + fprintf(stdout, "--- Unable to bring-up interface"); + fprintf(stdout, " %s.\n", self->name); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + +int viface_down(struct viface* self) +{ + // Read interface flags + struct ifreq ifr; + if (viface_read_flags(self->kernel_socket, self->name, + &ifr) == EXIT_FAILURE) { + return EXIT_FAILURE; + } + + // Bring-down interface + ifr.ifr_flags &= ~IFF_UP; + if (ioctl(self->kernel_socket, SIOCSIFFLAGS, &ifr) != 0) { + fprintf(stdout, "--- Unable to bring-down interface"); + fprintf(stdout, " %s.\n", self->name); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + return EXIT_FAILURE; + } + return EXIT_SUCCESS; +} + +int viface_receive(struct viface* self, uint8_t** result) +{ + // Read packet into our buffer + int nread = read(self->queues.rx, &(self->pktbuff[0]), self->mtu); + + // Handle errors + if (nread == -1) { + // Nothing was read for this fd (non-blocking). + // This could happen, as http://linux.die.net/man/2/select states: + // + // Under Linux, select() may report a socket file descriptor as + // "ready for reading", while nevertheless a subsequent read + // blocks. This could for example happen when data has arrived + // but upon examination has wrong checksum and is discarded. + // There may be other circumstances in which a file descriptor + // is spuriously reported as ready. Thus it may be safer to + // use O_NONBLOCK on sockets that should not block. + // + // I know this is not a socket, but the "There may be other + // circumstances in which a file descriptor is spuriously reported + // as ready" warns it, and so, it better to do this that to have + // an application that frozes for no apparent reason. + // + if (errno == EAGAIN) { + char *packet = apr_pcalloc(TEMPORAL_POOL, sizeof(char) * (3)); + + if (packet == NULL) { + fprintf(stdout, "--- Memory could not be allocated for the"); + fprintf(stdout, " received packet for %s", self->name); + fprintf(stdout, " network interface.\n"); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + return EXIT_FAILURE; + } + + memcpy(&packet[1], "0", 1); + packet[0] = 1; + packet[1] = '\0'; + *result = (uint8_t*)packet; + return EXIT_SUCCESS; + } + + // Something bad happened + fprintf(stdout, "--- IO error while reading from %s.\n", self->name); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + return EXIT_FAILURE; + } + + // Copy packet from buffer and return + char *packet = apr_pcalloc(TEMPORAL_POOL, sizeof(char) * (nread + 2)); + + if (packet == NULL) { + fprintf(stdout, "--- Memory could not be allocated for the received"); + fprintf(stdout, " packet for %s network interface.\n", self->name); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + return EXIT_FAILURE; + } + + + memcpy(&packet[1], self->pktbuff, nread); + packet[0] = nread; + packet[nread + 1] = '\0'; + *result = (uint8_t*)packet; + return EXIT_SUCCESS; +} + +int viface_send(struct viface* self, uint8_t* packet) +{ + int size = packet[0]; + + // RFC 791, p. 24: "Every internet module must be able to forward a + // datagram of 68 octets without further fragmentation." + if (size < 68) { + fprintf(stdout, "--- Packet too small (%d)", size); + fprintf(stdout, " too small (< 68).\n"); + return EXIT_FAILURE; + } + + if (size > self->mtu) { + fprintf(stdout, "--- Packet too large (%d)", size); + fprintf(stdout, " for current MTU (> %d).\n", self->mtu); + return EXIT_FAILURE; + } + + // Write packet to TX queue + int written = write(self->queues.tx, &packet[1], size); + + if (written != size) { + fprintf(stdout, "--- IO error while writting to %s.\n", self->name); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + return EXIT_FAILURE; + } + return EXIT_SUCCESS; +} + +int viface_list_stats(struct viface* self, char** result[]) +{ + const int NUMBER_STATS = 23; + + DIR* dir; + struct dirent* ent; + int i = 1; + + char** stats_names = + apr_pcalloc(TEMPORAL_POOL, sizeof(char*) * NUMBER_STATS + 1); + apr_hash_t *hash_stats = apr_hash_make(self->viface_pool); + + if ((stats_names == NULL) || + (hash_stats == NULL)) { + fprintf(stdout, "--- Memory could not be allocated for"); + fprintf(stdout, " network interface statistics.\n"); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + return EXIT_FAILURE; + } + + int size_bytes_stats_path = strlen("/sys/class/net/") + + strlen(self->name) + strlen("/statistics/"); + + char stats_path[size_bytes_stats_path + 1]; + memset(&stats_path, 0, size_bytes_stats_path); + + snprintf(stats_path, sizeof(stats_path), "%s%s%s", + "/sys/class/net/", self->name, "/statistics/"); + + // Open directory + if ((dir = opendir(stats_path)) == NULL) { + fprintf(stdout, "--- Unable to open statistics folder for interface"); + fprintf(stdout, " %s:\n", self->name); + fprintf(stdout, " %s.\n", stats_path); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + return EXIT_FAILURE; + } + + char *number_stats = apr_pcalloc(TEMPORAL_POOL, sizeof(int)); + + if (number_stats == NULL) { + fprintf(stdout, "--- Memory could not be allocated"); + fprintf(stdout, " for statistic size number.\n"); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + return EXIT_FAILURE; + } + + sprintf(number_stats,"%d", NUMBER_STATS); + stats_names[0] = number_stats; + + // List files + while ((ent = readdir(dir)) != NULL) { + //char entry = ent->d_name; + char* entry = ent->d_name; + + // Ignore current, parent and hidden files + if (entry[0] != '.') { + char *key = apr_pcalloc(TEMPORAL_POOL, strlen(entry) + 1); + + if (key == NULL) { + fprintf(stdout, "--- Memory could not be allocated"); + fprintf(stdout, " for statistic name %s.\n", entry); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + return EXIT_FAILURE; + } + + apr_cpystrn(key, entry, strlen(entry) + 1); + apr_hash_set(hash_stats, key, APR_HASH_KEY_STRING, key); + stats_names[i] = key; + i++; + } + } + + // Close directory + if (closedir(dir) != 0) { + fprintf(stdout, "--- Unable to close statistics folder for interface"); + fprintf(stdout, " %s:\n", self->name); + fprintf(stdout, " %s.\n", stats_path); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + return EXIT_FAILURE; + } + + *result = stats_names; + + // Update cache + self->stats_keys_cache = hash_stats; + return EXIT_SUCCESS; +} + +int viface_read_stat_file(struct viface* self, char* stat, uint64_t* result) +{ + // If no cache exists, create it. + if (apr_hash_count(self->stats_keys_cache) == 0) { + char** stats_names; + if (viface_list_stats(self, &stats_names) == EXIT_FAILURE) { + return EXIT_FAILURE; + } + } + + // Check if stat is valid + if (apr_hash_get(self->stats_keys_cache, stat, + APR_HASH_KEY_STRING) == NULL) { + fprintf(stdout, "--- Unknown statistic %s", stat); + fprintf(stdout, " for interface %s.\n", self->name); + return EXIT_FAILURE; + } + + // Open file + int size_bytes_stats_path = strlen("/sys/class/net/") + + strlen(self->name) + + strlen("/statistics/") + strlen(stat); + + char stats_path[size_bytes_stats_path + 1]; + memset(&stats_path, 0, size_bytes_stats_path); + + snprintf(stats_path, sizeof(stats_path), "%s%s%s%s", + "/sys/class/net/", self->name, "/statistics/", stat); + + int fd = -1; + int nread = -1; + char buffer[sizeof(uint64_t) + 1]; + + // Opens MTU file + fd = open(stats_path, O_RDONLY | O_NONBLOCK); + + // Check file open + if (fd < 0) { + fprintf(stdout, "--- Unable to open statistics file %s", stats_path); + fprintf(stdout, " for interface %s.\n", self->name); + return EXIT_FAILURE; + } + + // Reads stats value + nread = read(fd, &buffer, sizeof(buffer)); + buffer[nread] = '\0'; + + // Handles errors + if (nread == -1) { + fprintf(stdout, "--- Unable to read statistics file %s", stats_path); + fprintf(stdout, " for interface %s.\n", self->name); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + return EXIT_FAILURE; + } + + if (close(fd) < 0) { + fprintf(stdout, "--- Unable to close statistics file %s", stats_path); + fprintf(stdout, " for interface %s.\n", self->name); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + return EXIT_FAILURE; + } + + // Create entry if this stat wasn't cached + if (apr_hash_get(self->stats_cache, stat, + APR_HASH_KEY_STRING) == NULL) { + char* key = apr_pcalloc(self->viface_pool, strlen(stat) + 1); + + uint64_t* value = apr_pcalloc(self->viface_pool, sizeof(uint64_t)); + + if ((key == NULL) || + (value == NULL)) { + fprintf(stdout, "--- Memory could not be allocated reading"); + fprintf(stdout, " statistics values for %s.\n", self->name); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + return EXIT_FAILURE; + } + apr_cpystrn(key, stat, strlen(stat) + 1); + *value = 0; + + apr_hash_set(self->stats_cache, key, APR_HASH_KEY_STRING, value); + } + + *result = strtoul(buffer, NULL, 10); + return EXIT_SUCCESS; +} + +int viface_read_stat(struct viface* self, char* stat, uint64_t* result) +{ + uint64_t value; + if (viface_read_stat_file(self, stat, &value) == EXIT_FAILURE) { + return EXIT_FAILURE; + } + + uint64_t* cache = + (uint64_t*)apr_hash_get(self->stats_cache, + stat, APR_HASH_KEY_STRING); + + if (cache != NULL) { + // Return value minus the cached value + value -= *cache; + } + + *result = value; + + return EXIT_SUCCESS; +} + +int viface_clear_stat(struct viface* self, char* stat) +{ + uint64_t* value = apr_pcalloc(self->viface_pool, sizeof(uint64_t)); + + if (value == NULL) { + fprintf(stdout, "--- Memory could not be allocated clearing"); + fprintf(stdout, " statistics values for %s.\n", self->name); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + return EXIT_FAILURE; + } + + if (viface_read_stat_file(self, stat, &*value) == EXIT_FAILURE) { + return EXIT_FAILURE; + } + + char* key = apr_pcalloc(self->viface_pool, strlen(stat) + 1); + if (key == NULL) { + fprintf(stdout, "--- Memory could not be allocated clearing"); + fprintf(stdout, " statistics values for %s.\n", self->name); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + return EXIT_FAILURE; + } + apr_cpystrn(key, stat, strlen(stat) + 1); + + // Set current value as cache + apr_hash_set(self->stats_cache, key, APR_HASH_KEY_STRING, value); + + return EXIT_SUCCESS; +} + +int viface_dispatch(struct viface* self, int num_ifaces, struct viface** ifaces, + dispatcher_cb callback, int millis) +{ + int fd = -1; + int fds_read = -1; + int nfds = -1; + struct timeval tv; + struct timeval* tvp = NULL; + + // Check non-is_empty( set + if ((num_ifaces == 0) || + (ifaces == NULL)) { + fprintf(stdout, "--- is_empty( virtual interfaces set.\n"); + return EXIT_FAILURE; + } + + // Setup timeout + if (millis >= 0) { + tvp = &tv; + } + + apr_hash_t* reverse_id = apr_hash_make(TEMPORAL_POOL); + if (reverse_id == NULL) { + fprintf(stdout, "--- Memory could not be allocated for"); + fprintf(stdout, " APR hash table.\n"); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + return EXIT_FAILURE; + } + + // Create and clear set of file descriptors + fd_set rfds; + + int i = 0; + + // Create map of file descriptors and get maximum file descriptor for + // select call + for (i = 0; i < num_ifaces; i++) { + // Store identity + if (viface_get_rx(ifaces[i], &fd) == EXIT_FAILURE) { + return EXIT_FAILURE; + } + char* key = apr_pcalloc(TEMPORAL_POOL, sizeof(int)); + + struct viface* value = apr_pcalloc(TEMPORAL_POOL, + sizeof(struct viface)); + + if ((key == NULL) || + (value == NULL)) { + fprintf(stdout, "--- Memory could not be allocated"); + fprintf(stdout, " for dispatch.\n"); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + return EXIT_FAILURE; + } + *key = fd; + value = ifaces[i]; + apr_hash_set(reverse_id, key, APR_HASH_KEY_STRING, value); + + // Get maximum file descriptor + if (fd > nfds) { + nfds = fd; + } + } + nfds++; + + // Perform select system call + while (true) { + // Re-create set + FD_ZERO(&rfds); + for (i = 0; i < num_ifaces; i++) { + if (viface_get_rx(ifaces[i], &fd) == EXIT_FAILURE) { + return EXIT_FAILURE; + } + FD_SET(fd, &rfds); + } + + // Re-set timeout + if (tvp != NULL) { + tv.tv_sec = millis / 1000; + tv.tv_usec = (millis % 1000) * 1000; + } + + fds_read = select(nfds, &rfds, NULL, NULL, tvp); + + // Check if select error + if (fds_read == -1) { + // A signal was caught. Return. + if (errno == EINTR) { + return EXIT_SUCCESS; + } + + // Something bad happened + fprintf(stdout, "--- Unknown error in select() system call:"); + fprintf(stdout, " %d.\n", fds_read); + fprintf(stdout, " Error: %s", strerror(errno)); + fprintf(stdout, " (%d).\n", errno); + return EXIT_FAILURE; + } + + // Check if timeout + if (tvp != NULL && fds_read == 0) { + return EXIT_SUCCESS; + } + + apr_hash_index_t* index = NULL; + void* pair_hash; + struct viface* pair; + int key = -1; + + for (index = apr_hash_first(self->viface_pool, reverse_id); index; + index = apr_hash_next(index)) { + apr_hash_this(index, NULL, NULL, &pair_hash); + pair = (struct viface*)pair_hash; + if (viface_get_rx(pair, &key) == EXIT_FAILURE) { + return EXIT_FAILURE; + } + + // Check if fd wasn't marked in select as available + if (!FD_ISSET(key, &rfds)) { + continue; + } + + // File descriptor is ready, perform read and dispatch + uint8_t* packet; + if (viface_receive(pair, &packet) == EXIT_FAILURE) { + return EXIT_FAILURE; + } + + if (packet[0] == 0) { + // Even if this is very unlikely, supposedly it can happen. + // See receive() comments about this. + continue; + } + + char* name; + uint id; + + if ((viface_get_name(pair, &name) == EXIT_FAILURE) || + (viface_get_id(pair, &id) == EXIT_FAILURE)) { + return EXIT_FAILURE; + } + + // Dispatch packet + bool result_callback = false; + if (callback(pair, packet, &result_callback) == + EXIT_FAILURE) { + return EXIT_FAILURE; + } + + if (!result_callback) { + return EXIT_SUCCESS; + } + } + } + return EXIT_SUCCESS; +} \ No newline at end of file diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index e69de29..e65e4a8 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -0,0 +1,13 @@ +set(EXEC_NAME "tests") + +# Add source to the executable +add_executable( + ${EXEC_NAME} + create.cpp +) + +# Link the executable to the library +target_link_libraries(${EXEC_NAME} viface) + +# Set dependency with the library target +add_dependencies(${PROJECT_NAME} ${EXEC_NAME}) diff --git a/test/create.cpp b/test/create.cpp new file mode 100644 index 0000000..b2d50d4 --- /dev/null +++ b/test/create.cpp @@ -0,0 +1,158 @@ +/** + * Copyright (C) 2015 Hewlett Packard Enterprise Development LP + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use self 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. + */ + +#define CATCH_CONFIG_MAIN + +#include "catch.hpp" +#include "viface/viface.h" + +// Interface configuration data +static char name[IFNAMSIZ]; +static char ip[INET_ADDRSTRLEN] = "192.168.25.46"; +static char mac[18] = "ec:f1:f8:d5:47:6b"; +static char broadcast[INET_ADDRSTRLEN] = "192.168.25.255"; +static char netmask[INET_ADDRSTRLEN] = "255.255.255.0"; +static uint mtu = 1000; +static int id = 1; + +/* Sets network configuration data + * (name, id, ip, mac, netmask, broadcast, mtu). + */ +int set_interface_configuration(struct viface* self) +{ + // Configures interface + REQUIRE(viface_set_ipv4(self, ip) == EXIT_SUCCESS); + REQUIRE(viface_set_mac(self, mac) == EXIT_SUCCESS); + REQUIRE(viface_set_ipv4_broadcast(self, broadcast) == EXIT_SUCCESS); + REQUIRE(viface_set_ipv4_netmask(self, netmask) == EXIT_SUCCESS); + REQUIRE(viface_set_mtu(self, mtu) == EXIT_SUCCESS); + + return EXIT_SUCCESS; +} + +/* Checks the interface configuration data + * (name, id, ip, mac, netmask, broadcast, mtu). + */ +int check_interface_configuration(struct viface* self, bool new_viface) +{ + uint id_value; + bool is_viface_up; + uint mtu_value; + char* viface_name; + char* ip_value; + char* mac_value; + char* broadcast_value; + char* netmask_value; + + // Gets interface configuration data + REQUIRE(viface_get_name(self, &viface_name) == EXIT_SUCCESS); + REQUIRE(viface_get_id(self, &id_value) == EXIT_SUCCESS); + REQUIRE(viface_is_up(self, &is_viface_up) == EXIT_SUCCESS); + REQUIRE(viface_get_ipv4(self, &ip_value) == EXIT_SUCCESS); + REQUIRE(viface_get_mac(self, &mac_value) == EXIT_SUCCESS); + REQUIRE(viface_get_ipv4_broadcast(self, &broadcast_value) == EXIT_SUCCESS); + REQUIRE(viface_get_ipv4_netmask(self, &netmask_value) == EXIT_SUCCESS); + REQUIRE(viface_get_mtu(self, &mtu_value) == EXIT_SUCCESS); + + if (new_viface) { + // Checks interface name + REQUIRE(strcmp(viface_name, name) == 0); + + // Checks interface ID + REQUIRE(id_value == id); + + // Checks if interface is Up + REQUIRE(is_viface_up == true); + + // Checks interface IP + REQUIRE(strcmp(ip_value, ip) == 0); + + // Checks mac value + REQUIRE(strcmp(mac_value, mac) == 0); + + // Checks broadcast value + REQUIRE(strcmp(broadcast_value, broadcast) == 0); + + // Checks netmask value + REQUIRE(strcmp(netmask_value, netmask) == 0); + + // Checks mtu value + REQUIRE(mtu_value == mtu); + } + return EXIT_SUCCESS; +} + +TEST_CASE("Creates and tests new network interface") +{ + bool is_viface_up; + struct viface* self; + + // Sets new viface name + strcpy(name, "viface0"); + + // Creates global APR pool + REQUIRE(viface_create_global_pool() == EXIT_SUCCESS); + + // Creates interface + REQUIRE(viface_create_viface(name, true, id, &self) == EXIT_SUCCESS); + + // Sets interface configuration data + REQUIRE(set_interface_configuration(self) == EXIT_SUCCESS); + + // Brings-up interface + REQUIRE(viface_up(self) == 0); + + // Checks interface configuration data + REQUIRE(check_interface_configuration(self, true) == EXIT_SUCCESS); + + // Brings-down interface + REQUIRE(viface_down(self) == 0); + + // Checks if interface is still Up + REQUIRE(viface_is_up(self, &is_viface_up) == EXIT_SUCCESS); + REQUIRE(is_viface_up == false); + + // Destroys viface struct + REQUIRE(viface_destroy_viface(&self) == EXIT_SUCCESS); + + // Destroys static global APR pool + REQUIRE(viface_destroy_global_pool() == EXIT_SUCCESS); +} + +TEST_CASE("Hooks and tests existing network interface") +{ + bool is_viface_up; + struct viface* self; + + // Sets existing viface name + strcpy(name, "eth0"); + + // Creates global APR pool + REQUIRE(viface_create_global_pool() == EXIT_SUCCESS); + + // Creates interface + REQUIRE(viface_create_viface(name, true, id, &self) == EXIT_SUCCESS); + + // Checks interface configuration data + REQUIRE(check_interface_configuration(self, false) == EXIT_SUCCESS); + + // Destroys viface struct + REQUIRE(viface_destroy_viface(&self) == EXIT_SUCCESS); + + // Destroys static global APR pool + REQUIRE(viface_destroy_global_pool() == EXIT_SUCCESS); +} \ No newline at end of file diff --git a/tools/uncrustify/uncrustify.sh b/tools/uncrustify/uncrustify.sh index 8fcd407..c40dcda 100755 --- a/tools/uncrustify/uncrustify.sh +++ b/tools/uncrustify/uncrustify.sh @@ -4,8 +4,8 @@ DIR=$(dirname $0) # Uncrustify everything if no parameters are given if [ "$#" -eq 0 ]; then - find "${DIR}/../../include/" -type f -name \*.hpp -exec uncrustify -c "${DIR}/uncrustify.cfg" --no-backup {} + - find "${DIR}/../../src/" "${DIR}/../../examples/" "${DIR}/../../test/" -type f -name \*.cpp -exec uncrustify -c "${DIR}/uncrustify.cfg" --no-backup {} + + find "${DIR}/../../include/" -type f \( -name "*.h" -o -name "*.hpp" \) -exec uncrustify -c "${DIR}/uncrustify.cfg" --no-backup {} + + find "${DIR}/../../src/" "${DIR}/../../examples/" "${DIR}/../../test/" -type f \( -name "*.c" -o -name "*.cpp" \) -exec uncrustify -c "${DIR}/uncrustify.cfg" --no-backup {} + exit 0 fi