├── package ├── postinst ├── postrm ├── packagedesc.txt └── copyright ├── doc ├── doxygen │ ├── pictures │ │ ├── LL_Icon.png │ │ ├── modem-router-mac.dia │ │ ├── modem-router-mac.png │ │ ├── dest-advert-sequence.dia │ │ ├── dest-advert-sequence.png │ │ ├── modem-using-dest-advert.dia │ │ └── modem-using-dest-advert.png │ └── markdown │ │ └── Main.md └── CMakeLists.txt ├── tests ├── bad_paramname_config.xml ├── bad_paramval1_config.xml ├── bad_paramval2_config.xml ├── test_modem_config_8175.xml ├── test_router_config.xml ├── test_modem_config_v6.xml ├── test_router_config_8175.xml ├── test_router_config_v6.xml ├── router1_config.xml ├── router2_config.xml ├── LogFile.h ├── CMakeLists.txt ├── helgrind.supp ├── LogFile.cpp ├── test_modem_config.xml ├── modem1_dest_advert.xml ├── modem2_dest_advert.xml ├── serialize.cpp ├── dest_advert.cpp └── TestClientImpl.h ├── .gitignore ├── astylerc ├── destadvert.proto ├── libdlep.pc.in ├── LatencyRange.h ├── config ├── 4nodes_dest_advert │ ├── router1.xml │ ├── router2.xml │ ├── modem1.xml │ ├── modem2.xml │ └── 4nodes.imn ├── CMakeLists.txt ├── modem_dest_advert.xml ├── modem.xml ├── modem_lo.xml ├── router.xml ├── router_lo.xml └── protocol │ ├── multi-hop-06.xml │ ├── latency-range-03.xml │ ├── example-extension-00.xml │ └── protocol-config.xsd ├── Thread.h ├── MultiHop.h ├── IdTypes.h ├── DlepMac.cpp ├── LICENSE ├── Table.h ├── DlepInit.h ├── RELEASENOTES.md ├── DestAdvertInfo.h ├── DlepCommon.h ├── DlepMac.h ├── DlepLogger.h ├── DestAdvertDataBase.h ├── DlepLogger.cpp ├── DestAdvertMessage.h ├── DlepServiceImpl.h ├── DlepInit.cpp ├── NetUtils.h ├── Table.cpp ├── PeerDiscovery.h ├── DestAdvert.h ├── ProtocolMessage.h ├── README.md ├── Dlep.h ├── PeriodicMcastSendRcv.h ├── ExampleDlepClientImpl.h ├── CMakeLists.txt ├── ProtocolConfigImpl.h ├── Serialize.h ├── InfoBaseMgr.h ├── PeriodicMcastSendRcv.cpp └── DlepClient.h /package/postinst: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | /sbin/ldconfig 4 | -------------------------------------------------------------------------------- /package/postrm: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ "$1" = "remove" ]; then 4 | ldconfig 5 | fi 6 | -------------------------------------------------------------------------------- /doc/doxygen/pictures/LL_Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-ll/LL-DLEP/HEAD/doc/doxygen/pictures/LL_Icon.png -------------------------------------------------------------------------------- /doc/doxygen/pictures/modem-router-mac.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-ll/LL-DLEP/HEAD/doc/doxygen/pictures/modem-router-mac.dia -------------------------------------------------------------------------------- /doc/doxygen/pictures/modem-router-mac.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-ll/LL-DLEP/HEAD/doc/doxygen/pictures/modem-router-mac.png -------------------------------------------------------------------------------- /doc/doxygen/pictures/dest-advert-sequence.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-ll/LL-DLEP/HEAD/doc/doxygen/pictures/dest-advert-sequence.dia -------------------------------------------------------------------------------- /doc/doxygen/pictures/dest-advert-sequence.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-ll/LL-DLEP/HEAD/doc/doxygen/pictures/dest-advert-sequence.png -------------------------------------------------------------------------------- /doc/doxygen/pictures/modem-using-dest-advert.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-ll/LL-DLEP/HEAD/doc/doxygen/pictures/modem-using-dest-advert.dia -------------------------------------------------------------------------------- /doc/doxygen/pictures/modem-using-dest-advert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-ll/LL-DLEP/HEAD/doc/doxygen/pictures/modem-using-dest-advert.png -------------------------------------------------------------------------------- /tests/bad_paramname_config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 0 5 | 6 | 7 | -------------------------------------------------------------------------------- /tests/bad_paramval1_config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | this_is_not_an_int 5 | 6 | 7 | -------------------------------------------------------------------------------- /package/packagedesc.txt: -------------------------------------------------------------------------------- 1 | This is an implementation of the IETF DLEP protocol. See 2 | https://datatracker.ietf.org/doc/draft-ietf-manet-dlep/ for 3 | the current draft of DLEP. 4 | -------------------------------------------------------------------------------- /tests/bad_paramval2_config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | this_is_not_a_multicast_addr 5 | 6 | 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *~ 3 | *.log 4 | build-defs.h 5 | Dlep 6 | Dlep-static 7 | cppcheck*xml 8 | *.pb.cc 9 | *.pb.h 10 | lib*.a 11 | lib*so.* 12 | tests/*.log 13 | tests/lib_tests 14 | tests/deps 15 | deps 16 | build*/* 17 | -------------------------------------------------------------------------------- /tests/test_modem_config_8175.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | test_modem_config.xml 5 | test-protocol-config-8175.xml 6 | 7 | 8 | -------------------------------------------------------------------------------- /tests/test_router_config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | test_modem_config.xml 5 | router 6 | test-router 7 | test-router.log 8 | 9 | 10 | -------------------------------------------------------------------------------- /tests/test_modem_config_v6.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | test_modem_config.xml 5 | test-modem-v6.log 6 | ff02::1:7 7 | 8 | 9 | -------------------------------------------------------------------------------- /tests/test_router_config_8175.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | test_modem_config_8175.xml 5 | router 6 | test-router 7 | test-router.log 8 | 9 | 10 | -------------------------------------------------------------------------------- /tests/test_router_config_v6.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | test_router_config.xml 5 | test-router-v6.log 6 | ff02::1:7 7 | 8 | 9 | -------------------------------------------------------------------------------- /astylerc: -------------------------------------------------------------------------------- 1 | # astyle options 2 | # astyle (Artistic Style) is a code formatter. Run like this: 3 | # astyle --options=astylerc *.cpp *.h 4 | --style=bsd 5 | --indent=spaces 6 | --indent-switches 7 | --max-instatement-indent=70 8 | --max-code-length=80 9 | --pad-header --pad-oper --unpad-paren 10 | --add-brackets --lineend=linux 11 | --align-pointer=middle 12 | -------------------------------------------------------------------------------- /tests/router1_config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | modem1_dest_advert.xml 5 | 0 6 | router 7 | test-router1 8 | test-router1.log 9 | 10 | 11 | -------------------------------------------------------------------------------- /tests/router2_config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | modem2_dest_advert.xml 5 | 0 6 | router 7 | test-router2 8 | test-router2.log 9 | 10 | 11 | -------------------------------------------------------------------------------- /destadvert.proto: -------------------------------------------------------------------------------- 1 | message DestinationAdvertisement { 2 | required uint32 reportinterval = 1; // report interval in seconds 3 | required uint32 sequencenumber = 2; // sequence number 4 | required uint64 uptimeinseconds = 3; // application up time in seconds 5 | required bytes localid = 4; // our local modem/radio id 6 | repeated bytes destinations = 5; // destinations to advertise 7 | } 8 | 9 | -------------------------------------------------------------------------------- /libdlep.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@CMAKE_INSTALL_PREFIX@ 2 | exec_prefix=${prefix} 3 | libdir=${exec_prefix}/lib 4 | includedir=${exec_prefix}/include 5 | sysconfdir=@ETCDIR@/dlep 6 | 7 | Name: @PROJECT_NAME@ 8 | Description: MIT Lincoln Laboratory Dynamic Link Exchange Protocol 9 | Version: @DLEP_VERSION@ 10 | Libs: -L${libdir} -ldlep 11 | Cflags: -I${includedir} \ 12 | -DBOOST_MPL_CFG_NO_PREPROCESSED_HEADERS \ 13 | -DBOOST_MPL_LIMIT_LIST_SIZE=30 \ 14 | -DBOOST_MPL_LIMIT_VECTOR_SIZE=30 \ 15 | -DDLEP_SYSCONFDIR=\"${sysconfdir}\" 16 | -------------------------------------------------------------------------------- /LatencyRange.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Dynamic Link Exchange Protocol (DLEP) 3 | * 4 | * Copyright (C) 2018 Massachusetts Institute of Technology 5 | */ 6 | 7 | /// @file 8 | /// Declarations for the Latency Range extension 9 | 10 | #ifndef LATENCY_RANGE_H 11 | #define LATENCY_RANGE_H 12 | 13 | namespace LLDLEP 14 | { 15 | namespace ProtocolStrings 16 | { 17 | 18 | // data item strings 19 | 20 | const std::string Latency_Range = "Latency_Range"; 21 | 22 | } // namespace ProtocolStrings 23 | } // namespace LLDLEP 24 | 25 | #endif // LATENCY_RANGE_H 26 | -------------------------------------------------------------------------------- /tests/LogFile.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Dynamic Link Exchange Protocol (DLEP) 3 | * 4 | * Copyright (C) 2015, 2016 Massachusetts Institute of Technology 5 | */ 6 | 7 | /// @file 8 | /// Utility for examining DLEP log files. 9 | 10 | #ifndef LOG_FILE_H 11 | #define LOG_FILE_H 12 | 13 | #include 14 | #include 15 | 16 | class LogFile 17 | { 18 | public: 19 | explicit LogFile(std::string & filename); 20 | ~LogFile() {}; 21 | 22 | int find(int start_line, const std::string & search_string); 23 | 24 | private: 25 | std::vector lines; 26 | }; 27 | 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | SET(TEST_SRCS serialize.cpp dataitems.cpp messages.cpp lib_interface.cpp dest_advert.cpp LogFile.cpp TestClientImpl.cpp) 2 | 3 | find_package(Boost REQUIRED COMPONENTS unit_test_framework) 4 | add_definitions(${BOOST_INCREASE_VARIANT_TYPES}) 5 | add_definitions(-DBOOST_TEST_DYN_LINK) 6 | 7 | include_directories(${LIBXML2_INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/..) 8 | 9 | add_executable(lib_tests ${TEST_SRCS}) 10 | target_link_libraries(lib_tests dlepShared ${LIBXML2_LIBRARIES} ${PROTOBUF_LIBRARIES} ${Boost_LIBRARIES}) 11 | 12 | add_test(NAME BoostTests COMMAND lib_tests WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) 13 | -------------------------------------------------------------------------------- /tests/helgrind.supp: -------------------------------------------------------------------------------- 1 | # helgrind (valgrind) suppressions file. 2 | # Using these suppressions, the tests run with no helgrind errors 3 | # with valgrind-3.10.0.SVN on Ubuntun 14.04.2. Run like this: 4 | # valgrind --tool=helgrind --verbose --read-var-info=yes --suppressions=helgrind.supp ./lib_tests --report_level=detailed --log_level=all 5 | 6 | { 7 | std::locale::locale() 8 | Helgrind:Race 9 | fun:_ZNSt6localeC1EPNS_5_ImplE 10 | } 11 | 12 | { 13 | std::locale::locale() 14 | Helgrind:Race 15 | fun:_ZNSt6localeaSERKS_ 16 | } 17 | 18 | { 19 | std::has_facet() 20 | Helgrind:Race 21 | fun:_ZSt9has_facetISt5ctypeIcEEbRKSt6locale 22 | } 23 | -------------------------------------------------------------------------------- /doc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | find_package(Doxygen REQUIRED) 2 | if(NOT ${DOXYGEN_DOT_FOUND}) 3 | message(FATAL_ERROR "The Dot program was not found. Please install Graphviz to provide this executable.") 4 | endif(NOT ${DOXYGEN_DOT_FOUND}) 5 | 6 | configure_file(doxygen.config.in ${CMAKE_CURRENT_BINARY_DIR}/doxygen.config @ONLY) 7 | add_custom_target(doc ALL ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/doxygen.config 8 | DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/doxygen.config 9 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} 10 | COMMENT "Generating documentation with doxygen") 11 | 12 | install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/doxygen/ DESTINATION ${DOCDIR} PATTERN "*.md5" EXCLUDE) 13 | -------------------------------------------------------------------------------- /doc/doxygen/markdown/Main.md: -------------------------------------------------------------------------------- 1 | %Table of Contents {#mainpage} 2 | ================= 3 | 4 | - [User Guide](@ref userguide) 5 | - [Design Notes](@ref designnotes) 6 | 7 | 10 | 11 | \page proto_config_schema Protocol configuration schema 12 | \include protocol-config.xsd 13 | 14 | \page rfc8175 DLEP RFC 8175 protocol configuration 15 | \include dlep-rfc-8175.xml 16 | 17 | \page latency_range_config Latency Range extension protocol configuration 18 | \include latency-range-03.xml 19 | 20 | \page multi_hop_config Multi-Hop extension protocol configuration 21 | \include multi-hop-06.xml 22 | -------------------------------------------------------------------------------- /config/4nodes_dest_advert/router1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | router 5 | 0 6 | 1 7 | 4854 8 | eth0 9 | 224.0.0.117 10 | 60 11 | 60 12 | 2 13 | 4854 14 | emulated-router1 15 | dlep-router1.log 16 | 17 | 18 | -------------------------------------------------------------------------------- /config/4nodes_dest_advert/router2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | router 5 | 0 6 | 1 7 | 4854 8 | eth0 9 | 224.0.0.117 10 | 60 11 | 60 12 | 2 13 | 4854 14 | emulated-router2 15 | dlep-router2.log 16 | 17 | 18 | -------------------------------------------------------------------------------- /config/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # files that can be validated against protocol-config.xsd 2 | file(GLOB DRAFTS_XML RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/protocol/dlep*.xml) 3 | 4 | # gather all xml/xsd files 5 | file(GLOB XML_INSTALL_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/protocol/*.x[ms][ld]) 6 | 7 | foreach ( file ${XML_INSTALL_FILES} ) 8 | add_test(wellformedxml_${file} ${LIBXML2_XMLLINT_EXECUTABLE} --noout ${CMAKE_CURRENT_SOURCE_DIR}/${file}) 9 | endforeach(file) 10 | 11 | foreach ( file ${DRAFTS_XML} ) 12 | add_test(validatedxml_${file} ${LIBXML2_XMLLINT_EXECUTABLE} --noout --xinclude --schema ${CMAKE_CURRENT_SOURCE_DIR}/protocol/protocol-config.xsd ${CMAKE_CURRENT_SOURCE_DIR}/${file}) 13 | endforeach(file) 14 | 15 | install(FILES ${XML_INSTALL_FILES} DESTINATION ${ETCDIR}/dlep) 16 | -------------------------------------------------------------------------------- /Thread.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Dynamic Link Exchange Protocol (DLEP) 3 | * 4 | * Copyright (C) 2015, 2016 Massachusetts Institute of Technology 5 | */ 6 | 7 | /// @file 8 | /// Portability header to make it easy to choose between Boost threads 9 | /// and C++ standard library (std::) threads. 10 | 11 | #ifndef THREAD_H 12 | #define THREAD_H 13 | 14 | #ifdef USE_BOOST_THREADS 15 | #include 16 | 17 | namespace LLDLEP 18 | { 19 | namespace internal 20 | { 21 | 22 | typedef boost::thread Thread; 23 | 24 | } // namespace internal 25 | } // namespace LLDLEP 26 | 27 | #else 28 | 29 | // use std threads 30 | #include 31 | 32 | namespace LLDLEP 33 | { 34 | namespace internal 35 | { 36 | 37 | typedef std::thread Thread; 38 | 39 | } // namespace internal 40 | } // namespace LLDLEP 41 | 42 | #endif 43 | 44 | #endif // THREAD_H 45 | -------------------------------------------------------------------------------- /config/modem_dest_advert.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | modem 5 | 1 6 | 1 7 | lo 8 | 1 9 | eth0 10 | 4854 11 | 224.0.0.117 12 | 60 13 | 4854 14 | 60 15 | 2 16 | emulated-modem 17 | dlep-modem.log 18 | 19 | 20 | -------------------------------------------------------------------------------- /config/4nodes_dest_advert/modem1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | modem 5 | 1 6 | 1 7 | eth1 8 | 1 9 | eth0 10 | 4854 11 | 224.0.0.117 12 | 60 13 | 4854 14 | 60 15 | 2 16 | dest-advert-modem1 17 | dlep-modem1.log 18 | 19 | 20 | -------------------------------------------------------------------------------- /config/4nodes_dest_advert/modem2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | modem 5 | 1 6 | 2 7 | eth0 8 | 1 9 | eth1 10 | 4854 11 | 224.0.0.117 12 | 60 13 | 4854 14 | 60 15 | 2 16 | dest-advert-modem2 17 | dlep-modem2.log 18 | 19 | 20 | -------------------------------------------------------------------------------- /tests/LogFile.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Dynamic Link Exchange Protocol (DLEP) 3 | * 4 | * Copyright (C) 2015, 2016 Massachusetts Institute of Technology 5 | */ 6 | 7 | /// @file 8 | /// Utility for examining DLEP log files. 9 | 10 | 11 | #include "LogFile.h" 12 | #include 13 | #include 14 | 15 | LogFile::LogFile(std::string & filename) 16 | { 17 | std::ifstream file(filename); 18 | std::string oneline; 19 | 20 | // Read in all of the lines of the file 21 | while (std::getline(file, oneline)) 22 | { 23 | lines.push_back(oneline); 24 | } 25 | } 26 | 27 | int 28 | LogFile::find(int start_line, const std::string & search_string) 29 | { 30 | for (unsigned int i = start_line; i < lines.size(); i++) 31 | { 32 | if (lines[i].find(search_string) != std::string::npos) 33 | { 34 | return i; 35 | } 36 | } 37 | return -1; 38 | } 39 | -------------------------------------------------------------------------------- /MultiHop.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Dynamic Link Exchange Protocol (DLEP) 3 | * 4 | * Copyright (C) 2018 Massachusetts Institute of Technology 5 | * Modified by LabN Consulting, L.L.C. 6 | */ 7 | 8 | /// @file 9 | /// Declarations for the Multi Hop extension 10 | 11 | #ifndef MULTI_HOP_H 12 | #define MULTI_HOP_H 13 | 14 | namespace LLDLEP 15 | { 16 | namespace ProtocolStrings 17 | { 18 | 19 | // data item strings 20 | 21 | const std::string Hop_Count = "Hop_Count"; 22 | const std::string Hop_Control = "Hop_Control"; 23 | 24 | // extension name string 25 | // 26 | // string must match the module name defined in the protocol xml file 27 | const std::string Multi_Hop = "Multi-Hop"; 28 | 29 | } // namespace ProtocolStrings 30 | 31 | /// Flag definitions for the Hop_Count 32 | enum HopCountFlags : std::uint8_t 33 | { 34 | none = 0, ///< no flags set 35 | p_bit = (1 << 7) ///< P-bit 36 | }; 37 | } // namespace LLDLEP 38 | #endif // MULTI_HOP_H 39 | -------------------------------------------------------------------------------- /config/modem.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | modem 9 | 1 10 | 11 | 12 | eth0 13 | 14 | 15 | 4854 16 | 17 | 18 | 225.0.0.117 19 | 60 20 | 21 | 22 | 4854 23 | 60 24 | 2 25 | emulated-modem 26 | dlep-modem.log 27 | 28 | 29 | -------------------------------------------------------------------------------- /config/modem_lo.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | modem 9 | 1 10 | 11 | 12 | lo 13 | 14 | 15 | 4854 16 | 17 | 18 | 225.0.0.117 19 | 60 20 | 21 | 22 | 4854 23 | 60 24 | 2 25 | emulated-modem 26 | dlep-modem.log 27 | 28 | 29 | -------------------------------------------------------------------------------- /config/router.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | router 9 | 1 10 | 11 | 12 | 4854 13 | 14 | 15 | eth0 16 | 17 | 18 | 225.0.0.117 19 | 60 20 | 60 21 | 2 22 | 23 | 24 | 4854 25 | emulated-router 26 | dlep-router.log 27 | 28 | 29 | -------------------------------------------------------------------------------- /IdTypes.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Dynamic Link Exchange Protocol (DLEP) 3 | * 4 | * Copyright (C) 2013 Massachusetts Institute of Technology 5 | */ 6 | 7 | /// @file 8 | /// Types for various kinds of DLEP IDs. 9 | /// 10 | /// These are NOT the types that are used on the wire, i.e., in the 11 | /// actual protocol. The wire representation varies according to the 12 | /// DLEP draft and is handled via configuration; see ProtocolConfig. 13 | /// These types are used internally and in the library interface to 14 | /// represent the IDs. They should be large enough to accommodate the 15 | /// largest expected wire representation for their respective ID type. 16 | 17 | #ifndef IDTYPES_H 18 | #define IDTYPES_H 19 | 20 | namespace LLDLEP 21 | { 22 | 23 | typedef std::uint32_t SignalIdType; 24 | typedef std::uint32_t DataItemIdType; 25 | typedef std::uint32_t ExtensionIdType; 26 | typedef std::uint32_t StatusCodeIdType; 27 | 28 | // value to use if an ID is unknown or undefined 29 | constexpr std::uint32_t IdUndefined = ~0U; 30 | 31 | } // namespace LLDLEP 32 | 33 | #endif // IDTYPES_H 34 | -------------------------------------------------------------------------------- /tests/test_modem_config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 3 5 | 100 6 | 0 7 | eth0 8 | 4854 9 | 224.0.0.117 10 | 5 11 | 1 12 | 60 13 | 2 14 | modem 15 | test-modem.log 16 | 1 17 | ../config/protocol/dlep-rfc-8175.xml 18 | ../config/protocol/protocol-config.xsd 19 | test-modem 20 | 3 21 | 4854 22 | 23 | 24 | -------------------------------------------------------------------------------- /config/router_lo.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | router 9 | 1 10 | 11 | 12 | 4854 13 | 14 | 15 | lo 16 | 17 | 18 | 225.0.0.117 19 | 60 20 | 60 21 | 2 22 | 23 | 24 | 127.0.0.1 25 | 4855 26 | emulated-router 27 | dlep-router.log 28 | 29 | 30 | -------------------------------------------------------------------------------- /DlepMac.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Dynamic Link Exchange Protocol (DLEP) 3 | * 4 | * Copyright (C) 2015, 2016, 2018 Massachusetts Institute of Technology 5 | */ 6 | 7 | #include 8 | #include 9 | #include "DlepCommon.h" 10 | 11 | namespace LLDLEP 12 | { 13 | /// Return true iff mac1 < mac2 14 | bool operator<(const DlepMac & mac1, const DlepMac & mac2) 15 | { 16 | return (mac1.mac_addr < mac2.mac_addr); 17 | } 18 | 19 | /// Return true iff mac1 == mac2 20 | bool operator==(const DlepMac & mac1, const DlepMac & mac2) 21 | { 22 | return (mac1.mac_addr == mac2.mac_addr); 23 | } 24 | 25 | std::ostream & operator<<(std::ostream & os, const DlepMac & mac) 26 | { 27 | os << mac.to_string(); 28 | return os; 29 | } 30 | 31 | std::string DlepMac::to_string() const 32 | { 33 | std::ostringstream s; 34 | s << std::hex << std::setfill('0'); 35 | std::string colon = ""; 36 | for (auto mac_byte : mac_addr) 37 | { 38 | s << std::setw(0) << colon 39 | << std::setw(2) << (unsigned int)mac_byte; 40 | colon = ":"; 41 | } 42 | 43 | return s.str(); 44 | } 45 | 46 | } // namespace LLDLEP 47 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2015, 2016, 2017, 2018 Massachusetts Institute of Technology 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /package/copyright: -------------------------------------------------------------------------------- 1 | Copyright (C) 2015, 2016 Massachusetts Institute of Technology 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /Table.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Dynamic Link Exchange Protocol (DLEP) 3 | * 4 | * Copyright (C) 2015, 2016 Massachusetts Institute of Technology 5 | */ 6 | 7 | /// @file 8 | /// Declaration of Table class 9 | 10 | #ifndef TABLE_H 11 | #define TABLE_H 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | /// This class provides a convenient way to print tables of text 18 | /// values. Tables can be sparse; not every row/column needs to have 19 | /// a value. The table's column widths auto-adjust to accommodate the 20 | /// column's widest value. 21 | class Table 22 | { 23 | public: 24 | explicit Table(const std::vector & headings); 25 | 26 | void add_field(const std::string & value); 27 | void add_field(const std::string & field_name, const std::string & value); 28 | void finish_row(bool force_empty_row = false); 29 | unsigned int get_row_index(); 30 | void set_row_index(unsigned int ri); 31 | void set_row_index_end(); 32 | void print(std::ostream & os); 33 | 34 | private: 35 | unsigned int current_row; 36 | unsigned int current_column; 37 | typedef std::vector Row; 38 | std::vector table; 39 | }; 40 | 41 | #endif // TABLE_H 42 | -------------------------------------------------------------------------------- /DlepInit.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Dynamic Link Exchange Protocol (DLEP) 3 | * 4 | * Copyright (C) 2015, 2016 Massachusetts Institute of Technology 5 | */ 6 | 7 | /// @file 8 | /// DLEP Service library entry point declaration 9 | 10 | #ifndef DLEP_INIT_H 11 | #define DLEP_INIT_H 12 | 13 | #include "DlepClient.h" 14 | #include "DlepService.h" 15 | 16 | /// All client-visible identifiers necessary to use the DLEP Service Library 17 | /// are in this namespace. 18 | /// If you find it necessary to use identifiers in the Dlep source that are 19 | /// not in this namespace, you are most likely doing something wrong. 20 | namespace LLDLEP 21 | { 22 | /// Main entry point into the DLEP Service library. 23 | /// 24 | /// DLEP service library users call this function first to start the 25 | /// DLEP service. After performing some initialization, this function 26 | /// returns, but one or more threads remain active in the library to 27 | /// manage the DLEP protocol. 28 | /// 29 | /// @param[in] dlep_client 30 | /// used for the library to communicate to the caller 31 | /// 32 | /// @return 33 | /// - nullptr if the library failed to initialize 34 | /// - otherwise, a pointer to a DlepService object that the caller 35 | /// uses to communicate to the DLEP service library 36 | DlepService * DlepInit(DlepClient & dlep_client); 37 | 38 | } // namespace LLDLEP 39 | 40 | #endif // DLEP_INIT_H 41 | -------------------------------------------------------------------------------- /tests/modem1_dest_advert.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 3 5 | 100 6 | 1 7 | 1 8 | 225.6.7.8 9 | 33445 10 | 0 11 | 0 12 | 1 13 | lo 14 | 4854 15 | 224.0.0.117 16 | 5 17 | 1 18 | 60 19 | 2 20 | modem 21 | test-modem1.log 22 | 1 23 | ../config/protocol/dlep-rfc-8175.xml 24 | ../config/protocol/protocol-config.xsd 25 | test-modem 26 | 3 27 | 4854 28 | 29 | 30 | -------------------------------------------------------------------------------- /tests/modem2_dest_advert.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 3 5 | 100 6 | 1 7 | 1 8 | 225.6.7.8 9 | 33445 10 | 0 11 | 0 12 | 2 13 | lo 14 | 4855 15 | 224.0.0.117 16 | 5 17 | 1 18 | 60 19 | 2 20 | modem 21 | test-modem2.log 22 | 1 23 | ../config/protocol/dlep-rfc-8175.xml 24 | ../config/protocol/protocol-config.xsd 25 | test-modem 26 | 3 27 | 4855 28 | 29 | 30 | -------------------------------------------------------------------------------- /RELEASENOTES.md: -------------------------------------------------------------------------------- 1 | MIT Lincoln Laboratory DLEP (LL-DLEP) Implementation 2 | 3 | Release 2.1 July 23, 2018 4 | ================================== 5 | 6 | Unit tests for low-level serialization are added, and defects exposed 7 | by the new tests are fixed. 8 | 9 | Many warnings from gcc -Wall, cppcheck, clang-tidy are fixed. 10 | 11 | Code for an obsolete credit window extension is removed. 12 | 13 | Release 1.10 14 | ================================== 15 | 16 | Initial public release of the MIT LL implementation of the Dynamic 17 | Link Exchange Protocol (DLEP). 18 | 19 | LL-DLEP features the following: 20 | 21 | - A flexible library-based C++11 implementation of the protocol enabling 22 | clean integration with a wide variety of modem and router devices. 23 | 24 | - An example DLEP client (library user) that provides interactive 25 | access to the protocol via a command-line interface. The example 26 | client can be used as a surrogate for either a router or modem 27 | device. 28 | 29 | - Extensive configurability. The implementation supports multiple 30 | versions (drafts) of the DLEP protocol by using an XML-based 31 | protocol configuration file that captures the main protocol 32 | characteristics that vary across drafts. This simplifies 33 | interoperation with other DLEP implementations and makes updating to 34 | new DLEP drafts easier. A configuration files is provided for draft 35 | 24. The configuration system also enables convenient integration of 36 | DLEP extensions. 37 | 38 | - Support for running DLEP over either IPv4 or IPv6. 39 | 40 | - Partial support for the Credit Windowing extension. 41 | 42 | - A supplemental Destination Advertisement protocol that runs 43 | over-the-air between DLEP modems and enables exchange of additional 44 | information about destinations that is typically needed. 45 | 46 | - Documentation covering the library API, a user guide, and design 47 | considerations. 48 | 49 | - Unit and system test cases. 50 | -------------------------------------------------------------------------------- /DestAdvertInfo.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Dynamic Link Exchange Protocol (DLEP) 3 | * 4 | * Copyright (C) 2015, 2016 Massachusetts Institute of Technology 5 | * 6 | * Contributor: Adjacent Link LLC, Bridgewater, NJ 7 | */ 8 | 9 | /// @file 10 | /// DestAdvertInfo class declaration. 11 | 12 | #ifndef DEST_ADVERT_INFO_H 13 | #define DEST_ADVERT_INFO_H 14 | 15 | #include 16 | #include 17 | #include 18 | #include "DlepCommon.h" 19 | 20 | namespace LLDLEP 21 | { 22 | namespace internal 23 | { 24 | 25 | // holds info going in/out of the advertisement msg 26 | struct DestAdvertInfo 27 | { 28 | std::uint32_t reportInterval; 29 | std::int64_t uptime; 30 | std::uint32_t sequenceNumber; 31 | LLDLEP::DlepMac rfId; 32 | LLDLEP::DlepMacAddrs destinations; 33 | 34 | DestAdvertInfo() : 35 | reportInterval {}, 36 | uptime {}, 37 | sequenceNumber {} 38 | { } 39 | 40 | DestAdvertInfo(std::uint32_t interval, 41 | time_t uptm, 42 | std::uint32_t seq, 43 | const LLDLEP::DlepMac & id, 44 | const LLDLEP::DlepMacAddrs & dests) : 45 | reportInterval {interval}, 46 | uptime {uptm}, 47 | sequenceNumber {seq}, 48 | rfId(id), 49 | destinations(dests) 50 | { } 51 | 52 | std::string to_string() const 53 | { 54 | std::stringstream ss; 55 | 56 | ss << "report interval=" << reportInterval; 57 | ss << " uptime=" << uptime; 58 | ss << " seqnum=" << sequenceNumber; 59 | ss << " rfid=" << rfId.to_string(); 60 | ss << " dests:"; 61 | 62 | for (auto dest : destinations) 63 | { 64 | ss << dest.to_string() << ", "; 65 | } 66 | 67 | return ss.str(); 68 | } 69 | }; 70 | 71 | } // namespace internal 72 | } // namespace LLDLEP 73 | 74 | #endif 75 | 76 | -------------------------------------------------------------------------------- /DlepCommon.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Dynamic Link Exchange Protocol (DLEP) 3 | * 4 | * Copyright (C) 2015, 2016 Massachusetts Institute of Technology 5 | */ 6 | 7 | /// @file 8 | /// Declarations that are common to (i.e., needed by) both the client and 9 | /// the library. 10 | 11 | #ifndef DLEP_COMMON_H 12 | #define DLEP_COMMON_H 13 | 14 | #include "DataItem.h" 15 | #include "IdTypes.h" 16 | 17 | namespace LLDLEP 18 | { 19 | 20 | /// Information about a peer 21 | struct PeerInfo 22 | { 23 | /// Uniquely identifies the peer 24 | std::string peer_id; 25 | 26 | /// value of the %Peer Type data item sent by the peer during DLEP 27 | /// session negotiation 28 | std::string peer_type; 29 | 30 | /// the set of extensions to use with this peer (mutually agreed 31 | /// upon during DLEP session negotiation) 32 | std::vector extensions; 33 | 34 | /// values of the Experiment Name data items sent by the peer during 35 | /// DLEP session negotiation 36 | std::vector experiment_names; 37 | 38 | /// metrics and IP addresses associated with the peer 39 | DataItems data_items; 40 | 41 | /// destinations declared up by the peer 42 | std::vector destinations; 43 | 44 | /// heartbeat interval declared by the peer during DLEP session 45 | /// negotiation. This is the exact value sent by the peer in the 46 | /// Heartbeat Interval data item; no unit conversion has been 47 | /// performed. 48 | uint32_t heartbeat_interval; 49 | }; 50 | 51 | /// Information about a destination 52 | struct DestinationInfo 53 | { 54 | /// MAC address of the destination 55 | DlepMac mac_address; 56 | 57 | /// peer to which this destination belongs 58 | std::string peer_id; 59 | 60 | /// boolean flags for this destination (none defined yet) 61 | std::uint32_t flags; 62 | 63 | /// metrics and IP addresses for this destination 64 | DataItems data_items; 65 | }; 66 | 67 | } // namespace LLDLEP 68 | 69 | #endif // DLEP_COMMON_H 70 | -------------------------------------------------------------------------------- /DlepMac.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Dynamic Link Exchange Protocol (DLEP) 3 | * 4 | * Copyright (C) 2015, 2016 Massachusetts Institute of Technology 5 | */ 6 | 7 | /// @file 8 | /// Declaration of MAC address type. 9 | 10 | #ifndef DLEP_MAC_H 11 | #define DLEP_MAC_H 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | namespace LLDLEP 19 | { 20 | 21 | /// MAC address. It is variable size so that we can support 6 or 8 22 | /// byte addresses as required by the draft, or even 2 byte addresses 23 | /// to hold EMANE NEM IDs. 24 | typedef struct d_mac 25 | { 26 | std::vector mac_addr; 27 | 28 | /// Convert to string representation 29 | std::string to_string() const; 30 | 31 | } DlepMac; 32 | 33 | 34 | /// Compare (<) two DlepMacs. With this, we can use a DlepMac as the 35 | /// key in a std::map. 36 | bool operator<(const DlepMac & mac1, const DlepMac & mac2); 37 | 38 | /// Compare two DlepMacs for equality. 39 | bool operator==(const DlepMac & mac1, const DlepMac & mac2); 40 | 41 | /// Output operator for convenient output to an ostream 42 | std::ostream & operator<<(std::ostream & os, const DlepMac & mac); 43 | 44 | 45 | /// set of DlepMac addrs 46 | using DlepMacAddrs = std::set; 47 | 48 | /// Find the difference between to sets of DlepMac addrs 49 | /// possibly use std::set_difference from \ instead 50 | inline void getDifference(const DlepMacAddrs & A, const DlepMacAddrs & B, 51 | DlepMacAddrs & C) 52 | { 53 | // whats in here 54 | for (const auto a : A) 55 | { 56 | bool found = false; 57 | 58 | // and not in here 59 | for (const auto b : B) 60 | { 61 | if (a == b) 62 | { 63 | found = true; 64 | 65 | break; 66 | } 67 | } 68 | 69 | if (! found) 70 | { 71 | C.insert(a); 72 | } 73 | } 74 | } 75 | 76 | 77 | } // namespace LLDLEP 78 | 79 | #endif // DLEP_MAC_H 80 | -------------------------------------------------------------------------------- /DlepLogger.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Dynamic Link Exchange Protocol (DLEP) 3 | * 4 | * Copyright (C) 2013, 2018, 2019 Massachusetts Institute of Technology 5 | */ 6 | #ifndef _DLEP_LOGGER_ 7 | #define _DLEP_LOGGER_ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | namespace LLDLEP 25 | { 26 | namespace internal 27 | { 28 | 29 | #define MAX_LEVEL 5 30 | #define MIN_LEVEL 1 31 | #define DLEP_LOG_FATAL 5 32 | #define DLEP_LOG_ERROR 4 33 | #define DLEP_LOG_NOTICE 3 34 | #define DLEP_LOG_INFO 2 35 | #define DLEP_LOG_DEBUG 1 36 | 37 | #define DEBUG_FILE __FILE__ 38 | #define DEBUG_FUNCTION __func__ 39 | #define DEBUG_LINE __LINE__ 40 | #define DEBUG_DATE __DATE__ 41 | #define DEBUG_TIME __TIME__ 42 | 43 | class DlepLogger 44 | { 45 | public: 46 | explicit DlepLogger(const std::string & filename, unsigned int level); 47 | ~DlepLogger(); 48 | void log(unsigned int level, std::ostringstream & msg); 49 | void set_log_level(unsigned int level); 50 | void set_log_file(const std::string & filename); 51 | private: 52 | unsigned int log_level; 53 | unsigned int clamp_log_level(unsigned int level); 54 | std::ofstream logfile; 55 | std::string time_string_get(); 56 | std::map level_name = { 57 | { DLEP_LOG_DEBUG, "DEBUG: " }, 58 | { DLEP_LOG_INFO, "INFO: " }, 59 | { DLEP_LOG_NOTICE, "NOTICE:" }, 60 | { DLEP_LOG_ERROR, "ERROR: " }, 61 | { DLEP_LOG_FATAL, "FATAL: " }, 62 | }; 63 | boost::mutex mutex; 64 | }; 65 | 66 | typedef boost::shared_ptr DlepLoggerPtr; 67 | 68 | #define LOG(_level, _msg) { \ 69 | std::ostringstream m; \ 70 | m << DEBUG_FILE << ":" << DEBUG_LINE << ":" << DEBUG_FUNCTION << \ 71 | "(): " << (_msg).str() ; \ 72 | logger->log(_level, m); \ 73 | (_msg).str(""); \ 74 | } 75 | 76 | } // namespace internal 77 | } // namespace LLDLEP 78 | 79 | #endif // _DLEP_LOGGER_ 80 | -------------------------------------------------------------------------------- /DestAdvertDataBase.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Dynamic Link Exchange Protocol (DLEP) 3 | * 4 | * Copyright (C) 2015, 2016, 2018 Massachusetts Institute of Technology 5 | * 6 | * Contributor: Adjacent Link LLC, Bridgewater, NJ 7 | */ 8 | 9 | 10 | #ifndef DEST_ADVERT_DATABASE_H 11 | #define DEST_ADVERT_DATABASE_H 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include "DestAdvertInfo.h" 18 | 19 | namespace LLDLEP 20 | { 21 | namespace internal 22 | { 23 | 24 | struct DestAdvertDBEntry 25 | { 26 | /// time that this entry was created or last updated 27 | time_t timestamp; 28 | 29 | /// state of this entry 30 | enum class EntryState 31 | { 32 | /// client says RF ID for this entry is down 33 | down, 34 | 35 | /// client says RF ID for this entry is up 36 | up 37 | }; 38 | 39 | EntryState estate; 40 | 41 | /// Is this a placeholder entry? When true, it means that the 42 | /// client has declared the entry up, but we do not (yet) have 43 | /// a destination advertisement from this RF ID. 44 | bool placeholder; 45 | 46 | /// information from the DestAdvert message 47 | DestAdvertInfo info; 48 | 49 | /// client-supplied metrics for this RF ID when it 50 | /// was declared up, or when last updated 51 | LLDLEP::DataItems data_items; 52 | 53 | DestAdvertDBEntry() : 54 | timestamp {0}, 55 | estate {EntryState::down}, 56 | placeholder {false} 57 | { } 58 | 59 | DestAdvertDBEntry(time_t ts, 60 | EntryState s, 61 | bool p, 62 | const DestAdvertInfo & e, 63 | const LLDLEP::DataItems & di) : 64 | timestamp {ts}, 65 | estate {s}, 66 | placeholder {p}, 67 | info {e}, 68 | data_items {di} 69 | { } 70 | 71 | 72 | std::string to_string() const 73 | { 74 | std::stringstream ss; 75 | 76 | ss << " age=" << time(nullptr) - timestamp; 77 | ss << " state=" << (int)estate; 78 | ss << " placeholder=" << placeholder << " "; 79 | ss << info.to_string(); 80 | return ss.str(); 81 | } 82 | }; 83 | 84 | /// map from RF ID (DlepMac) to an entry 85 | using DestAdvertDB = std::map; 86 | 87 | } // namespace internal 88 | } // namespace LLDLEP 89 | 90 | #endif 91 | -------------------------------------------------------------------------------- /DlepLogger.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Dynamic Link Exchange Protocol (DLEP) 3 | * 4 | * Copyright (C) 2013, 2018, 2019 Massachusetts Institute of Technology 5 | */ 6 | #include "DlepLogger.h" 7 | #include 8 | #include 9 | 10 | using namespace std; 11 | using namespace LLDLEP::internal; 12 | 13 | DlepLogger::DlepLogger(const std::string & filename, unsigned int level) 14 | { 15 | set_log_level(level); 16 | 17 | logfile.open(filename); 18 | if (logfile.fail()) 19 | { 20 | throw std::invalid_argument("could not open log file " + filename); 21 | } 22 | } 23 | 24 | DlepLogger::~DlepLogger() 25 | { 26 | if (logfile.is_open()) 27 | { 28 | logfile.close(); 29 | } 30 | } 31 | 32 | void 33 | DlepLogger::log(unsigned int level, std::ostringstream & msg) 34 | { 35 | boost::mutex::scoped_lock lock(mutex); 36 | 37 | level = clamp_log_level(level); 38 | if (level >= log_level) 39 | { 40 | logfile << time_string_get() << level_name[level] << msg.str() 41 | << endl; 42 | } 43 | } 44 | 45 | unsigned int 46 | DlepLogger::clamp_log_level(unsigned int level) 47 | { 48 | if (level < DLEP_LOG_DEBUG) 49 | { 50 | return DLEP_LOG_DEBUG; 51 | } 52 | else if (level > DLEP_LOG_FATAL) 53 | { 54 | return DLEP_LOG_FATAL; 55 | } 56 | else 57 | { 58 | return level; 59 | } 60 | } 61 | 62 | void 63 | DlepLogger::set_log_level(unsigned int level) 64 | { 65 | boost::mutex::scoped_lock lock(mutex); 66 | log_level = clamp_log_level(level); 67 | } 68 | 69 | void 70 | DlepLogger::set_log_file(const std::string & filename) 71 | { 72 | boost::mutex::scoped_lock lock(mutex); 73 | if (logfile.is_open()) 74 | { 75 | logfile.close(); 76 | } 77 | 78 | logfile.open(filename); 79 | if (logfile.fail()) 80 | { 81 | throw std::invalid_argument(filename); 82 | } 83 | } 84 | 85 | string 86 | DlepLogger::time_string_get() 87 | { 88 | char buf[128]; 89 | timeval tp; 90 | gettimeofday(&tp, nullptr); 91 | time_t tim = time(nullptr); 92 | tm now; 93 | localtime_r(&tim, &now); 94 | snprintf(buf, sizeof(buf), "%02d:%02d:%02d.%03ld ", 95 | now.tm_hour, 96 | now.tm_min, 97 | now.tm_sec, 98 | tp.tv_usec / 1000L); 99 | return string(buf); 100 | } 101 | -------------------------------------------------------------------------------- /config/protocol/multi-hop-06.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 16 | 17 | 18 | 19 | 22 | Multi-Hop 23 | 6 24 | 25 | 29 | 65524 30 | 31 | 32 | 33 | 34 | Hop_Count 35 | u8_u8 36 | 65415 37 | true 38 | count 39 | 40 | 41 | 42 | Hop_Control 43 | u16 44 | 65416 45 | false 46 | 47 | 48 | 49 | 50 | 51 | Session_Update 52 | 53 | Hop_Control 54 | 0-1 55 | 56 | 57 | 58 | 59 | Destination_Up 60 | 61 | Hop_Count 62 | 0-1 63 | 64 | 65 | 66 | 67 | Destination_Update 68 | 69 | Hop_Count 70 | 0-1 71 | 72 | 73 | 74 | 75 | Destination_Announce_Response 76 | 77 | Hop_Count 78 | 0-1 79 | 80 | 81 | 82 | 83 | Link_Characteristics_Request 84 | 85 | Hop_Control 86 | 0-1 87 | 88 | 89 | 90 | 91 | Link_Characteristics_Response 92 | 93 | Hop_Count 94 | 0-1 95 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /config/protocol/latency-range-03.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 14 | 15 | 16 | 17 | 20 | Latency Range 21 | 3 22 | 23 | 27 | 65521 28 | 29 | 30 | 31 | 32 | Latency_Range 33 | u64_u64 34 | 65411 35 | true 36 | microseconds 37 | 38 | 39 | 40 | 41 | 42 | Session_Initialization_Response 43 | 44 | Latency_Range 45 | 0-1 46 | 47 | 48 | 49 | 50 | Session_Update 51 | 52 | Latency_Range 53 | 0-1 54 | 55 | 56 | 57 | 58 | Destination_Up 59 | 60 | Latency_Range 61 | 0-1 62 | 63 | 64 | 65 | 66 | Destination_Update 67 | 68 | Latency_Range 69 | 0-1 70 | 71 | 72 | 73 | 74 | Destination_Announce_Response 75 | 76 | Latency_Range 77 | 0-1 78 | 79 | 80 | 81 | 82 | Link_Characteristics_Request 83 | 84 | Latency_Range 85 | 0-1 86 | 87 | 88 | 89 | 90 | Link_Characteristics_Response 91 | 92 | Latency_Range 93 | 0-1 94 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /DestAdvertMessage.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Dynamic Link Exchange Protocol (DLEP) 3 | * 4 | * Copyright (C) 2015, 2016 Massachusetts Institute of Technology 5 | * 6 | * Contributor: Adjacent Link LLC, Bridgewater, NJ 7 | */ 8 | 9 | 10 | #ifndef DEST_ADVERT_MESSAGE_H 11 | #define DEST_ADVERT_MESSAGE_H 12 | 13 | #include 14 | #include 15 | #include "DlepCommon.h" 16 | #include "destadvert.pb.h" 17 | #include "DestAdvertInfo.h" 18 | 19 | namespace 20 | { 21 | 22 | void doCopyStrToMac(const std::string & str, LLDLEP::DlepMac & mac) 23 | { 24 | mac.mac_addr.resize(str.size()); 25 | 26 | for (size_t i = 0; i < str.size(); ++i) 27 | { 28 | mac.mac_addr[i] = static_cast(str[i]); 29 | } 30 | } 31 | 32 | void doCopyMacToSTR(const LLDLEP::DlepMac & mac, std::string & str) 33 | { 34 | str.resize(mac.mac_addr.size()); 35 | 36 | for (size_t i = 0; i < mac.mac_addr.size(); ++i) 37 | { 38 | str[i] = static_cast(mac.mac_addr[i]); 39 | } 40 | } 41 | } 42 | 43 | 44 | namespace LLDLEP 45 | { 46 | namespace internal 47 | { 48 | 49 | // build/serialize for sending 50 | inline std::pair build_destination_advert( 51 | const DestAdvertInfo & info) 52 | { 53 | std::string str; 54 | 55 | DestinationAdvertisement da; 56 | 57 | da.set_reportinterval(info.reportInterval); 58 | 59 | da.set_uptimeinseconds(info.uptime); 60 | 61 | da.set_sequencenumber(info.sequenceNumber); 62 | 63 | doCopyMacToSTR(info.rfId, *da.mutable_localid()); 64 | 65 | for (auto dest : info.destinations) 66 | { 67 | std::string s; 68 | 69 | doCopyMacToSTR(dest, s); 70 | 71 | da.add_destinations(s); 72 | } 73 | 74 | const bool rc = da.SerializeToString(&str); 75 | 76 | return std::pair(rc, str); 77 | } 78 | 79 | 80 | // un-build/de-serialize for reading 81 | inline std::pair unbuild_destination_advert( 82 | const uint8_t * buff, size_t len) 83 | { 84 | DestAdvertInfo info; 85 | 86 | DestinationAdvertisement da; 87 | 88 | const bool rc = da.ParseFromArray(buff, len); 89 | 90 | if (rc) 91 | { 92 | info.reportInterval = da.reportinterval(); 93 | 94 | info.uptime = da.uptimeinseconds(); 95 | 96 | info.sequenceNumber = da.sequencenumber(); 97 | 98 | doCopyStrToMac(da.localid(), info.rfId); 99 | 100 | for (int i = 0; i < da.destinations_size(); ++i) 101 | { 102 | DlepMac mac; 103 | 104 | doCopyStrToMac(da.destinations(i), mac); 105 | 106 | info.destinations.insert(mac); 107 | } 108 | } 109 | 110 | return std::pair(rc, info); 111 | } 112 | 113 | } // namespace internal 114 | } // namespace LLDLEP 115 | 116 | #endif 117 | 118 | -------------------------------------------------------------------------------- /DlepServiceImpl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Dynamic Link Exchange Protocol (DLEP) 3 | * 4 | * Copyright (C) 2015, 2016, 2018, 2019 Massachusetts Institute of Technology 5 | */ 6 | 7 | /// @file 8 | /// DLEP service implementation class declaration. 9 | 10 | #ifndef DLEP_SERVICE_IMPL_H 11 | #define DLEP_SERVICE_IMPL_H 12 | 13 | #include "DlepService.h" // for base class 14 | #include "Dlep.h" // for DlepPtr 15 | 16 | namespace LLDLEP 17 | { 18 | namespace internal 19 | { 20 | 21 | /// DLEP service implementation class declaration. 22 | class DlepServiceImpl : public LLDLEP::DlepService 23 | { 24 | public: 25 | DlepServiceImpl(DlepPtr dlep, DlepLoggerPtr logger); 26 | 27 | // exception class thrown by constructor when initialization fails 28 | struct InitializationError : public std::runtime_error 29 | { 30 | explicit InitializationError(const std::string & m) : 31 | std::runtime_error(m) { } 32 | }; 33 | 34 | ReturnStatus destination_up(const LLDLEP::DlepMac & mac_address, 35 | const LLDLEP::DataItems & data_items) override; 36 | 37 | ReturnStatus destination_update(const LLDLEP::DlepMac & mac_address, 38 | const LLDLEP::DataItems & data_items) override; 39 | 40 | ReturnStatus destination_down(const LLDLEP::DlepMac & mac_address, 41 | const LLDLEP::DataItems & data_items) override; 42 | 43 | ReturnStatus peer_update(const LLDLEP::DataItems & data_items) override; 44 | 45 | ReturnStatus peer_remove_data_items(const DataItems & data_items) override; 46 | 47 | ReturnStatus get_peers(std::vector & peers) override; 48 | 49 | ReturnStatus get_peer_info(const std::string & peer_id, 50 | LLDLEP::PeerInfo & peer_info) override; 51 | 52 | ReturnStatus get_destination_info(const std::string & peer_id, 53 | const LLDLEP::DlepMac & mac_address, 54 | LLDLEP::DestinationInfo & dest_info) override; 55 | 56 | LLDLEP::ProtocolConfig * get_protocol_config() override; 57 | 58 | ReturnStatus linkchar_request(const DlepMac & mac_address, 59 | const DataItems & data_items) override; 60 | ReturnStatus linkchar_reply(const std::string & peer_id, 61 | const DlepMac & mac_address, 62 | const DataItems & data_items) override; 63 | 64 | void terminate() override; 65 | 66 | private: 67 | // Pointer to the top-level dlep object so we can get to everything we 68 | // need when called from the client's thread. 69 | DlepPtr dlep; 70 | 71 | DlepLoggerPtr logger; 72 | 73 | // Pointer to the top-level thread that the library creates for its 74 | // internal operations 75 | Thread init_thread; 76 | }; 77 | 78 | } // namespace internal 79 | } // namespace LLDLEP 80 | 81 | #endif // DLEP_SERVICE_IMPL_H 82 | -------------------------------------------------------------------------------- /DlepInit.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Dynamic Link Exchange Protocol (DLEP) 3 | * 4 | * Copyright (C) 2015, 2016 Massachusetts Institute of Technology 5 | */ 6 | 7 | /// @file 8 | /// DLEP Service library entry point 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "Dlep.h" 15 | #include "DlepInit.h" 16 | #include "DlepServiceImpl.h" 17 | #include "DlepClient.h" 18 | 19 | using namespace std; 20 | 21 | namespace LLDLEP 22 | { 23 | 24 | DlepService * 25 | DlepInit(DlepClient & dlep_client) 26 | { 27 | ostringstream msg; 28 | 29 | // Set up the logger that will be used by this instance of 30 | // DlepService. This pointer will be passed to the constructors 31 | // of many of the other classes so that they can all use the same 32 | // logger without needing a global variable. It is important 33 | // that the logger always be named "logger" everywhere because 34 | // that's what the LOG macro expects. 35 | 36 | std::string logfile; 37 | unsigned int log_level; 38 | try 39 | { 40 | dlep_client.get_config_parameter("log-file", &logfile); 41 | dlep_client.get_config_parameter("log-level", &log_level); 42 | } 43 | catch (const LLDLEP::DlepClient::BadParameterName & bpn) 44 | { 45 | // The log file isn't set up, so print the message to stderr. 46 | std::cerr << bpn.what() << std::endl; 47 | return nullptr; 48 | } 49 | 50 | // Try to create the logger using the log file and log level retrieved 51 | // from config parameters above. 52 | 53 | internal::DlepLoggerPtr logger; 54 | try 55 | { 56 | logger = internal::DlepLoggerPtr(new internal::DlepLogger(logfile, log_level)); 57 | } 58 | catch (const std::invalid_argument & iae) 59 | { 60 | // The log file isn't set up, so print the message to stderr. 61 | std::cerr << iae.what() << std::endl; 62 | return nullptr; 63 | } 64 | 65 | // Now that logging is set up, fetch some more parameters we need 66 | // to get started. If they're missing, the error will go to the 67 | // log file. 68 | 69 | std::string local_type; 70 | 71 | try 72 | { 73 | dlep_client.get_config_parameter("local-type", &local_type); 74 | } 75 | catch (const LLDLEP::DlepClient::BadParameterName & bpn) 76 | { 77 | msg << bpn.what(); 78 | LOG(DLEP_LOG_ERROR, msg); 79 | return nullptr; 80 | } 81 | 82 | DlepService * dlep_service = nullptr; 83 | try 84 | { 85 | bool dlep_modem = (local_type == "modem"); 86 | 87 | internal::DlepPtr dlep_ptr(new internal::Dlep(dlep_modem, 88 | dlep_client, logger)); 89 | dlep_service = new internal::DlepServiceImpl(dlep_ptr, logger); 90 | } 91 | catch (const internal::DlepServiceImpl::InitializationError &) 92 | { 93 | return nullptr; 94 | } 95 | 96 | return dlep_service; 97 | } 98 | 99 | } // namespace LLDLEP 100 | -------------------------------------------------------------------------------- /NetUtils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Dynamic Link Exchange Protocol (DLEP) 3 | * 4 | * Copyright (C) 2015, 2016 Massachusetts Institute of Technology 5 | * 6 | * Contributor: Adjacent Link LLC, Bridgewater, NJ 7 | */ 8 | 9 | /// @file 10 | /// Various network utility functions. 11 | 12 | #ifndef DLEP_NET_UTILS_H 13 | #define DLEP_NET_UTILS_H 14 | 15 | #include "DlepCommon.h" 16 | #include "DlepLogger.h" 17 | #include 18 | #include 19 | 20 | namespace LLDLEP 21 | { 22 | namespace internal 23 | { 24 | namespace NetUtils 25 | { 26 | /// Find an IP address on a network interface. 27 | /// 28 | /// @param[in] iface_name 29 | /// interface name on which to find an IP address 30 | /// @param[in] want_ipv4_addr 31 | /// If true, find an IPv4 address, else find an IPv6 address. 32 | /// Only link-local IPv6 addresses will be returned. 33 | /// @param[in] logger 34 | /// for logging with the LOG macro 35 | /// @return an IP address that meets the above criteria. If one 36 | /// couldn't be found, the returned IP address's is_unspecified() 37 | // method will return true. 38 | boost::asio::ip::address 39 | get_ip_addr_from_iface(const std::string & iface_name, 40 | bool want_ipv4_addr, 41 | LLDLEP::internal::DlepLoggerPtr logger); 42 | 43 | /// Find a network interface given an IP address. 44 | /// 45 | /// @param[in] ipaddr 46 | /// IPv4 or IPv6 address to look for 47 | /// @param[in] logger 48 | /// for logging with the LOG macro 49 | /// @return the name of the interface on which \a ipaddr was found, 50 | /// or "" if \a ipaddr was not found on any interface. 51 | std::string get_iface_from_ip_addr(const boost::asio::ip::address & ipaddr, 52 | LLDLEP::internal::DlepLoggerPtr logger); 53 | 54 | /// Set a given scope id of a link-local IPv6 address. 55 | /// 56 | /// @param[in,out] ipaddr 57 | /// The IPv6 link-local address for which to set the 58 | /// scope ID. 59 | /// @param[in] scope_id 60 | /// the scope id to set in \a ipaddr. 61 | /// @return true if successful, in which case \a ipaddr is 62 | /// modified, else false and \a ipaddr is not modified. 63 | bool set_ipv6_scope_id(boost::asio::ip::address & ipaddr, 64 | unsigned long scope_id); 65 | 66 | /// Set the scope id of a link-local IPv6 address from an interface name. 67 | /// 68 | /// @param[in,out] ipaddr 69 | /// The IPv6 link-local address for which to set the 70 | /// scope ID. 71 | /// @param[in] iface_name 72 | /// the network interface name used to set the 73 | /// scope id in \a ipaddr. The interface's index 74 | /// is determined and used as the scope id. 75 | /// @return true if successful, in which caSE \a ipaddr is modified, 76 | /// else false and \a ipaddr is not modified. 77 | bool set_ipv6_scope_id(boost::asio::ip::address & ipaddr, 78 | const std::string & iface_name); 79 | 80 | bool ipv4ToEtherMacAddr(const boost::asio::ip::address & addr, 81 | LLDLEP::DlepMac & mac, 82 | std::string & ifname, 83 | std::ostringstream & errMessage); 84 | } // namespace NetUtils 85 | } // namespace internal 86 | } // namespace LLDLEP 87 | 88 | #endif 89 | -------------------------------------------------------------------------------- /Table.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Dynamic Link Exchange Protocol (DLEP) 3 | * 4 | * Copyright (C) 2015, 2016, 2018 Massachusetts Institute of Technology 5 | */ 6 | 7 | #include 8 | #include "Table.h" 9 | 10 | Table::Table(const std::vector & headings) 11 | { 12 | table.push_back(headings); 13 | current_row = 1; 14 | current_column = 0; 15 | } 16 | 17 | void 18 | Table::add_field(const std::string & value) 19 | { 20 | while (current_row >= table.size()) 21 | { 22 | Row new_row; 23 | new_row.resize(table[0].size()); 24 | table.push_back(new_row); 25 | } 26 | 27 | table[current_row][current_column++] = value; 28 | } 29 | 30 | void 31 | Table::add_field(const std::string & field_name, const std::string & value) 32 | { 33 | const Row & headings = table[0]; 34 | // XXX vector doesn't have find() ??? 35 | for (current_column = 0; current_column < headings.size(); current_column++) 36 | { 37 | if (headings[current_column] == field_name) 38 | { 39 | break; 40 | } 41 | } 42 | add_field(value); 43 | } 44 | 45 | void 46 | Table::finish_row(bool force_empty_row) 47 | { 48 | if ( (current_column > 0) || force_empty_row) 49 | { 50 | current_row++; 51 | current_column = 0; 52 | } 53 | } 54 | 55 | unsigned int 56 | Table::get_row_index() 57 | { 58 | return current_row; 59 | } 60 | 61 | void 62 | Table::set_row_index(unsigned int ri) 63 | { 64 | current_row = ri; 65 | } 66 | 67 | void 68 | Table::set_row_index_end() 69 | { 70 | current_row = table.size(); 71 | } 72 | 73 | void Table::print(std::ostream & os) 74 | { 75 | // The first row has the column headings. There must be one 76 | // for each possible column. 77 | std::vector column_widths(table[0].size(), 0); 78 | 79 | // Should we skip printing this column? Yes (true) if the column 80 | // was completely empty except for the column name in the first 81 | // row. 82 | std::vector skip_column(table[0].size(), true); 83 | 84 | // Figure out how wide columns need to be to print nicely. 85 | 86 | bool heading_row = true; // true only for first row 87 | for (const auto & row : table) 88 | { 89 | for (unsigned int ci = 0; ci < row.size(); ci++) 90 | { 91 | column_widths[ci] = std::max(column_widths[ci], 92 | row[ci].length()); 93 | if ( ! heading_row && (row[ci].length() > 0)) 94 | { 95 | // If column ci on this row is non-blank, don't 96 | // skip printing this column 97 | skip_column[ci] = false; 98 | } 99 | } 100 | 101 | heading_row = false; 102 | } 103 | 104 | // Increase each column width by 1 to leave a space between columns. 105 | 106 | for (unsigned int ci = 0; ci < column_widths.size(); ci++) 107 | { 108 | column_widths[ci]++; 109 | } 110 | 111 | // Print out all of the rows. 112 | 113 | os << std::left; 114 | for (const auto & row : table) 115 | { 116 | for (unsigned int ci = 0; ci < row.size(); ci++) 117 | { 118 | if ( ! skip_column[ci]) 119 | { 120 | os << std::setw(column_widths[ci]) << row[ci]; 121 | } 122 | } 123 | os << std::endl; 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /tests/serialize.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Dynamic Link Exchange Protocol (DLEP) 3 | * 4 | * Copyright (C) 2018 Massachusetts Institute of Technology 5 | */ 6 | 7 | /// @file 8 | /// Boost Unit Tests for Serialize.h 9 | 10 | #include 11 | 12 | #include "Serialize.h" 13 | #include 14 | 15 | using namespace LLDLEP; 16 | 17 | 18 | BOOST_AUTO_TEST_SUITE(Serialize) 19 | 20 | template 21 | void 22 | test_serialize() 23 | { 24 | // values to attempt to serialize/deserialize 25 | std::vector test_vals = 26 | { 0, 27 | std::numeric_limits::max()/2, 28 | std::numeric_limits::max()/2 + 1, 29 | std::numeric_limits::max()/3, 30 | std::numeric_limits::max() 31 | }; 32 | 33 | // try serializing into all possible field sizes 34 | 35 | for (std::size_t field_size = 1; field_size <= 8; field_size++) 36 | { 37 | for (auto val : test_vals ) 38 | { 39 | bool serialize_should_succeed = true; 40 | 41 | // If the field size we're serializing into is smaller than 42 | // the type T, the value may not fit. Compare val with the 43 | // largest value that can be represented in field_size 44 | // bytes to see if it will fit. 45 | 46 | if (field_size < sizeof(T)) 47 | { 48 | std::uint64_t max_val_in_field_size = (1ULL << field_size*8) - 1; 49 | BOOST_TEST_MESSAGE(__FILE__ << ":" << __LINE__ << " " << max_val_in_field_size); 50 | if (val > max_val_in_field_size) 51 | { 52 | serialize_should_succeed = false; 53 | } 54 | } 55 | 56 | std::size_t sz; 57 | std::vector buf; // buffer to serialize into 58 | 59 | // Say what we're about to test 60 | 61 | BOOST_TEST_MESSAGE(__FILE__ << ":" << __LINE__ 62 | << ": serialize value " << std::uint64_t(val) 63 | << " in field size " << field_size 64 | << " should succeed " << serialize_should_succeed); 65 | 66 | // attempt serialization 67 | 68 | try 69 | { 70 | sz = serialize(val, field_size, buf); 71 | BOOST_CHECK(serialize_should_succeed); 72 | BOOST_CHECK_EQUAL(sz, field_size); 73 | } 74 | catch (const std::invalid_argument &) 75 | { 76 | BOOST_CHECK( ! serialize_should_succeed); 77 | 78 | // If it didn't serialize, don't bother trying deserialization 79 | 80 | continue; 81 | } 82 | 83 | // attempt deserialization 84 | 85 | auto it_begin = buf.begin(); 86 | auto it_end = buf.end(); 87 | 88 | T val2 = 0; 89 | sz = deserialize(val2, field_size, it_begin, it_end); 90 | BOOST_CHECK_EQUAL(sz, field_size); 91 | BOOST_CHECK_EQUAL(val, val2); 92 | 93 | } // for each value to serialize/deserialize 94 | } // for each field size 95 | } 96 | 97 | BOOST_AUTO_TEST_CASE(serialize_u8) 98 | { 99 | test_serialize(); 100 | } 101 | 102 | BOOST_AUTO_TEST_CASE(serialize_u16) 103 | { 104 | test_serialize(); 105 | } 106 | 107 | BOOST_AUTO_TEST_CASE(serialize_u32) 108 | { 109 | test_serialize(); 110 | } 111 | 112 | BOOST_AUTO_TEST_CASE(serialize_u64) 113 | { 114 | test_serialize(); 115 | } 116 | 117 | BOOST_AUTO_TEST_SUITE_END() 118 | -------------------------------------------------------------------------------- /config/4nodes_dest_advert/4nodes.imn: -------------------------------------------------------------------------------- 1 | comments { 2 | This scenario is intended to help test/demonstrate the Destination 3 | Advertisement feature of the LL DLEP implementation. It works in 4 | conjunction with the Dlep config files in this directory. See the 5 | Design Notes documentation for more information about this feature. 6 | 7 | To use this scenario, first build and install Dlep. Then load the 8 | scenario into CORE. Open a terminal on each of the four nodes. In 9 | each terminal, issue these commands: 10 | 11 | $ cd /config/4nodes_dest_advert 12 | $ Dlep config-file `hostname`.xml 13 | 14 | Router1 and modem1 should become Dlep peers, likewise router2 and 15 | modem2. After a few seconds, the modems should exchange Destination 16 | Advertisements, though this is only evident by examining the log files 17 | dlep-modemX.log. Subsequently, MAC addresses appearing in "dest up" 18 | commands at the modem CLI will be translated using the information 19 | in the received Destination Advertisements. The net effect is that 20 | the routers will see the MAC addresses of other routers in the DLEP 21 | Destination Up signals instead of the addresses of modems. 22 | } 23 | 24 | node n1 { 25 | type router 26 | model router 27 | network-config { 28 | hostname router1 29 | ! 30 | interface eth0 31 | ip address 10.0.0.1/24 32 | ipv6 address 2001:0::1/64 33 | ! 34 | } 35 | iconcoords {67.0 131.0} 36 | labelcoords {67.0 159.0} 37 | canvas c1 38 | interface-peer {eth0 n2} 39 | services {IPForward} 40 | } 41 | 42 | node n2 { 43 | type router 44 | model router 45 | network-config { 46 | hostname modem1 47 | ! 48 | interface eth1 49 | ip address 10.0.1.1/24 50 | ipv6 address 2001:1::1/64 51 | ! 52 | interface eth0 53 | ip address 10.0.0.2/24 54 | ipv6 address 2001:0::2/64 55 | ! 56 | } 57 | iconcoords {353.0 131.5} 58 | labelcoords {353.0 159.5} 59 | canvas c1 60 | interface-peer {eth0 n1} 61 | interface-peer {eth1 n3} 62 | services {IPForward} 63 | } 64 | 65 | node n3 { 66 | type router 67 | model router 68 | network-config { 69 | hostname modem2 70 | ! 71 | interface eth1 72 | ip address 10.0.2.1/24 73 | ipv6 address 2001:2::1/64 74 | ! 75 | interface eth0 76 | ip address 10.0.1.2/24 77 | ipv6 address 2001:1::2/64 78 | ! 79 | } 80 | iconcoords {627.0 132.0} 81 | labelcoords {627.0 160.0} 82 | canvas c1 83 | interface-peer {eth0 n2} 84 | interface-peer {eth1 n4} 85 | services {IPForward} 86 | } 87 | 88 | node n4 { 89 | type router 90 | model router 91 | network-config { 92 | hostname router2 93 | ! 94 | interface eth0 95 | ip address 10.0.2.2/24 96 | ipv6 address 2001:2::2/64 97 | ! 98 | } 99 | iconcoords {870.3333333333334 133.33333333333337} 100 | labelcoords {870.3333333333334 161.33333333333331} 101 | canvas c1 102 | interface-peer {eth0 n3} 103 | } 104 | 105 | link l1 { 106 | nodes {n1 n2} 107 | bandwidth 0 108 | } 109 | 110 | link l2 { 111 | nodes {n2 n3} 112 | bandwidth 0 113 | } 114 | 115 | link l3 { 116 | nodes {n3 n4} 117 | bandwidth 0 118 | } 119 | 120 | annotation a1 { 121 | iconcoords {473.0 173.0} 122 | type text 123 | label {OTA} 124 | labelcolor black 125 | fontfamily {Arial} 126 | fontsize {12} 127 | canvas c1 128 | } 129 | 130 | annotation a2 { 131 | iconcoords {144.0 173.0} 132 | type text 133 | label {DLEP session} 134 | labelcolor black 135 | fontfamily {Arial} 136 | fontsize {12} 137 | canvas c1 138 | } 139 | 140 | annotation a3 { 141 | iconcoords {703.0 173.0} 142 | type text 143 | label {DLEP session} 144 | labelcolor black 145 | fontfamily {Arial} 146 | fontsize {12} 147 | canvas c1 148 | } 149 | 150 | canvas c1 { 151 | name {Canvas1} 152 | refpt {0 0 47.5791667 -122.132322 2.0} 153 | scale {150.0} 154 | size {1000 300} 155 | } 156 | 157 | option global { 158 | interface_names yes 159 | ip_addresses yes 160 | ipv6_addresses no 161 | node_labels yes 162 | link_labels yes 163 | show_api no 164 | background_images no 165 | annotations yes 166 | grid yes 167 | traffic_start 0 168 | } 169 | 170 | option session { 171 | } 172 | 173 | -------------------------------------------------------------------------------- /PeerDiscovery.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Dynamic Link Exchange Protocol (DLEP) 3 | * 4 | * Copyright (C) 2015, 2016 Massachusetts Institute of Technology 5 | */ 6 | 7 | /// @file 8 | /// PeerDiscovery class declaration. 9 | 10 | #ifndef PEER_DISCOVERY_H 11 | #define PEER_DISCOVERY_H 12 | 13 | #include "PeriodicMcastSendRcv.h" 14 | 15 | namespace LLDLEP 16 | { 17 | namespace internal 18 | { 19 | 20 | /// This class handles most of the PeerDiscovery part of DLEP. 21 | /// It combines both the router and the modem parts. 22 | /// Documentation for override methods is in the base class. 23 | class PeerDiscovery : public PeriodicMcastSendRcv 24 | { 25 | public: 26 | 27 | /// Constructor. 28 | /// @param[in] dlep back-pointer to dlep instance 29 | /// @param[in] io_service for handling network I/O and timers 30 | /// @param[in] interface_name name of the network interface to use 31 | /// @param[in] udp_port UDP port number to put on multicast packets 32 | /// @param[in] multicast_address multicast address to put on packets 33 | /// @param[in] discovery_ttl IP TTL to put on discovery packets 34 | /// @param[in] send_interval number of seconds between sending packets 35 | /// @param[in] sending true iff we are sending packets 36 | /// @param[in] receiving true iff we are receiving packets 37 | PeerDiscovery( 38 | DlepPtr dlep, 39 | boost::asio::io_service & io_service, 40 | std::string interface_name, 41 | uint16_t udp_port, 42 | boost::asio::ip::address & multicast_address, 43 | unsigned int discovery_ttl, 44 | unsigned int send_interval, 45 | bool sending, 46 | bool receiving); 47 | 48 | virtual ~PeerDiscovery(); 49 | 50 | bool start() override; 51 | 52 | private: 53 | 54 | void stop() override; 55 | 56 | /// Initiate boost::asio async receive to get Peer Offer (unicast) packets. 57 | /// Router only. 58 | void start_receive(); 59 | 60 | 61 | /// boost::asio calls this to deliver received unicast packets to us 62 | /// Router only. 63 | /// param[in] bytes_recvd number of bytes in received message. 64 | /// The buffer containing the actual message is specified 65 | /// beforehand in the boost asio call async_receive_from(). 66 | 67 | void handle_receive(const boost::system::error_code & error, 68 | std::size_t bytes_recvd); 69 | 70 | /// Handle a received peer discovery or offer message. 71 | /// Router and modem. 72 | /// @param[in] msg_buffer payload bytes of the packet 73 | /// @param[in] from_endpoint source IP addr/port of this packet 74 | void handle_message(DlepMessageBuffer msg_buffer, 75 | boost::asio::ip::udp::endpoint from_endpoint) override; 76 | 77 | /// Handle a received peer discovery message. 78 | /// Modem only. 79 | /// @param[in] pm the peer discovery message 80 | /// @param[in] from_endpoint source IP addr/port of this packet 81 | void handle_discovery(ProtocolMessage & pm, 82 | boost::asio::ip::udp::endpoint from_endpoint); 83 | 84 | /// Handle a received peer offer message. 85 | /// Router only. 86 | /// @param[in] pm the peer offer message 87 | /// @param[in] from_endpoint source IP addr/port of this packet 88 | void handle_peer_offer(ProtocolMessage & pm, 89 | boost::asio::ip::udp::endpoint from_endpoint); 90 | 91 | /// Router only. 92 | DlepMessageBuffer get_message_to_send() override; 93 | 94 | /// Build and send a peer offer message. 95 | /// Modem only. 96 | /// @param[in] to_endpoint contains the IP address to send the message to 97 | void send_peer_offer(boost::asio::ip::udp::endpoint to_endpoint); 98 | 99 | /// boost::asio calls this when the send is complete. 100 | /// Modem only. 101 | void handle_send_peer_offer(const boost::system::error_code & error); 102 | 103 | /// Socket used to send/receive the unicast Peer Offer signal 104 | /// Router and modem. 105 | boost::asio::ip::udp::socket peer_offer_socket; 106 | 107 | /// Source of a received Peer Offer message 108 | /// Router only. 109 | boost::asio::ip::udp::endpoint modem_endpoint; 110 | 111 | /// IP TTL to put on discovery packets 112 | unsigned int send_ttl; 113 | 114 | /// Buffer to hold received Peer Offer messages 115 | /// Router only. 116 | uint8_t recv_peer_offer_message[ProtocolMessage::MAX_SIGNAL_SIZE]; 117 | }; 118 | 119 | } // namespace internal 120 | } // namespace LLDLEP 121 | 122 | #endif // PEER_DISCOVERY_H 123 | -------------------------------------------------------------------------------- /config/protocol/example-extension-00.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 24 | 25 | 26 | 27 | 31 | Example Extension 32 | 0 33 | 34 | 38 | 65520 39 | 40 | 41 | 42 | 43 | Example_u64_Nonmetric_Data_Item 44 | u64 45 | 65444 46 | false 47 | 48 | 49 | 50 | Example_u32_Metric_Data_Item 51 | u32 52 | 65445 53 | true 54 | 55 | 56 | 57 | Example_u8_Metric_Data_Item_With_Units 58 | u8 59 | 65446 60 | true 61 | octets 62 | 63 | 64 | 69 | 70 | 71 | Example_Signal_No_Data_Items 72 | 65520 73 | false 74 | router 75 | 76 | 77 | 78 | Example_Signal_One_Required_Data_Item 79 | 65521 80 | false 81 | modem 82 | 83 | 84 | Example_u64_Nonmetric_Data_Item 85 | 1 86 | 87 | 88 | 89 | 90 | Example_Signal_Two_Optional_Data_Items 91 | 65522 92 | false 93 | modem 94 | 95 | 96 | Example_u32_Metric_Data_Item 97 | 0-1 98 | 99 | 100 | 105 | 106 | IPv4_Address 107 | 0-1 108 | 109 | 110 | 111 | 120 | 121 | 125 | 126 | Example_Message_Response 127 | 65520 128 | true 129 | both 130 | 131 | 132 | 133 | Example_Message_Optional_Repeatable_Data_Item 134 | 65521 135 | true 136 | both 137 | Example_Message_Response 138 | 139 | 140 | Example_u64_Nonmetric_Data_Item 141 | 0+ 142 | 143 | 144 | 145 | 146 | 147 | 148 | Destination_Update 149 | 150 | Example_u8_Metric_Data_Item_With_Units 151 | 0-1 152 | 153 | 154 | 155 | 156 | 157 | 158 | Example_Status_Code 159 | 240 160 | continue 161 | 162 | 163 | 164 | -------------------------------------------------------------------------------- /DestAdvert.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Dynamic Link Exchange Protocol (DLEP) 3 | * 4 | * Copyright (C) 2015, 2016 Massachusetts Institute of Technology 5 | * 6 | * Contributor: Adjacent Link LLC, Bridgewater, NJ 7 | */ 8 | 9 | /// @file 10 | /// DestAdvert class declaration. 11 | 12 | #ifndef DEST_ADVERT_H 13 | #define DEST_ADVERT_H 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #include "PeriodicMcastSendRcv.h" 20 | #include "DestAdvertDataBase.h" 21 | 22 | namespace LLDLEP 23 | { 24 | namespace internal 25 | { 26 | 27 | class Dlep; 28 | 29 | /// This class handles most of the Destination Advertisement part of DLEP. 30 | class DestAdvert : public PeriodicMcastSendRcv 31 | { 32 | public: 33 | 34 | /// Constructor. 35 | /// @param[in] dlep back-pointer to dlep instance 36 | /// @param[in] io_service for handling network I/O and timers 37 | /// @param[in] interface_name name of the network interface to use 38 | /// @param[in] udp_port UDP port number to put on multicast packets 39 | /// @param[in] multicast_address multicast address to put on packets 40 | /// @param[in] send_interval number of seconds between sending packets 41 | /// @param[in] local_rfid rfid of the local node 42 | /// @param[in] logger logger, for LOG macro 43 | DestAdvert( 44 | DlepPtr dlep, 45 | boost::asio::io_service & io_service, 46 | std::string interface_name, 47 | uint16_t udp_port, 48 | boost::asio::ip::address & multicast_address, 49 | unsigned int send_interval, 50 | const LLDLEP::DlepMac & local_rfid, 51 | DlepLoggerPtr logger); 52 | 53 | virtual ~DestAdvert(); 54 | 55 | /// Add a destination to future destination advertisements 56 | /// sent by this process. 57 | /// 58 | /// @param[in] mac the destination to add 59 | void add_destination(const LLDLEP::DlepMac & mac); 60 | 61 | /// Remove a destination from future destination advertisements 62 | /// sent by this process. 63 | /// 64 | /// @param[in] mac the destination to remove 65 | void del_destination(const LLDLEP::DlepMac & mac); 66 | 67 | /// Remove all destinations from future destination advertisements 68 | /// sent by this process. 69 | void clear_destinations(); 70 | 71 | /// Obtain a lock on the destination advertisement database. 72 | /// Use this when more than one operation will be performed on the 73 | /// database to prevent modifications by other threads. 74 | /// This is not needed if just performing one operation. 75 | boost::recursive_mutex::scoped_lock advert_db_lock(); 76 | 77 | /// Add an entry to the destination advertisement database. 78 | /// @param[in] rfId the RF_ID associated with the entry 79 | /// @param[in] advert_entry the entry to add 80 | void add_advert_entry(const LLDLEP::DlepMac & rfId, 81 | const DestAdvertDBEntry & advert_entry); 82 | 83 | /// Find an entry in the destination advertisement database. 84 | /// @param[in] rfId the RF_ID for which to find the entry 85 | /// @return a pair: 86 | /// first: true iff the entry was found 87 | /// second: reference to the entry, if first is true 88 | std::pair 89 | find_advert_entry(const LLDLEP::DlepMac & rfId); 90 | 91 | /// Update the metrics on an entry in the destination advertisement 92 | /// database. 93 | /// @param[in] rfId the RF_ID whose entry will be updated 94 | /// @param[in] data_items the data items associated with rfId 95 | void update_advert_entry_data_items(const LLDLEP::DlepMac & rfId, 96 | const LLDLEP::DataItems & data_items); 97 | 98 | /// Update the state of an entry in the destination advertisement 99 | /// database. 100 | /// @param[in] rfId the RF_ID whose entry will be updated 101 | /// @param[in] newstate new state for the entry 102 | void update_advert_entry_state(const LLDLEP::DlepMac & rfId, 103 | DestAdvertDBEntry::EntryState newstate); 104 | private: 105 | 106 | // Documentation for override methods is in the base class. 107 | 108 | void handle_message(DlepMessageBuffer msg_buffer, 109 | boost::asio::ip::udp::endpoint from_endpoint) override; 110 | 111 | DlepMessageBuffer get_message_to_send() override; 112 | 113 | /// Start the destination advertisement database purge timer. 114 | void start_purge_advert_timer(); 115 | 116 | /// Service a destination advertisement database purge timeout. 117 | void handle_purge_advert_timeout(const boost::system::error_code & error); 118 | 119 | /// Time when this object was constructed. Used for computing the uptime 120 | /// field of the destination advertisement. 121 | time_t begin_time; 122 | 123 | /// Sequence number for destination advertisements 124 | std::uint32_t seq_num; 125 | 126 | /// Wait time between sending destination advertisements 127 | const std::uint32_t send_interval; 128 | 129 | /// RF_ID of the local OTA interface for destination advertisements 130 | const LLDLEP::DlepMac local_rfid; 131 | 132 | /// any local destinations to put in destination advertisements, 133 | /// including the peer router mac 134 | LLDLEP::DlepMacAddrs destinations; 135 | 136 | /// mutex that should be locked whenever dest_advert_db is accessed 137 | boost::recursive_mutex dest_advert_mutex; 138 | 139 | /// mapping of RF_ID's to advertisement data 140 | DestAdvertDB dest_advert_db; 141 | 142 | /// Timer for purging destination advertisements 143 | boost::asio::deadline_timer purge_advert_timer; 144 | }; 145 | 146 | } // namespace internal 147 | } // namespace LLDLEP 148 | 149 | #endif // DEST_ADVERT_H 150 | -------------------------------------------------------------------------------- /ProtocolMessage.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Dynamic Link Exchange Protocol (DLEP) 3 | * 4 | * Copyright (C) 2015, 2016 Massachusetts Institute of Technology 5 | */ 6 | 7 | #ifndef PROTOCOL_MESSAGE_H 8 | #define PROTOCOL_MESSAGE_H 9 | 10 | #include "DlepClient.h" 11 | #include "ProtocolConfig.h" 12 | #include "DlepLogger.h" 13 | 14 | namespace LLDLEP 15 | { 16 | namespace internal 17 | { 18 | 19 | class ProtocolMessage 20 | { 21 | public: 22 | 23 | ProtocolMessage(LLDLEP::ProtocolConfig * protocfg, 24 | DlepLoggerPtr logger); 25 | 26 | // methods for building the protocol message 27 | 28 | void add_header(const std::string & msg_name); 29 | void add_data_item(const LLDLEP::DataItem & di); 30 | void add_data_items(const LLDLEP::DataItems & data_items); 31 | void add_allowed_data_items(const LLDLEP::DataItems & data_items); 32 | 33 | void add_version(); 34 | void add_heartbeat_interval(LLDLEP::DlepClient & dlep_client); 35 | void add_peer_type(LLDLEP::DlepClient & dlep_client); 36 | void add_experiment_names(); 37 | void add_status(std::string status_name, 38 | const std::string & reason); 39 | void add_extensions(const std::vector & extensions); 40 | void add_mac(const LLDLEP::DlepMac & mac); 41 | void add_common_data_items(LLDLEP::DlepClient & dlep_client); 42 | 43 | // clear all data items from the message, leaving just the header 44 | void clear_data_items(); 45 | std::string rebuild_from_data_items(bool modem_sender, 46 | DataItems & rebuild_data_items); 47 | 48 | // low-level buffer manipulation 49 | 50 | static const unsigned int MAX_SIGNAL_SIZE = (1024 * 64); 51 | 52 | /// return the serialized message bytes 53 | const std::uint8_t * get_buffer() const; 54 | 55 | /// return the number of bytes in the serialized message 56 | /// (the size of the buffer returned by get_buffer() ) 57 | std::size_t get_length() const; 58 | 59 | static bool is_complete_message(const LLDLEP::ProtocolConfig * protocfg, 60 | std::uint8_t * buf, 61 | std::size_t buflen, 62 | std::size_t & msg_size); 63 | // retrieval methods 64 | 65 | std::string parse(const uint8_t * buf, size_t buflen, bool is_signal, 66 | const std::string & log_prefix); 67 | 68 | /// Parse the raw message bytes into a message/signal with data items. 69 | /// 70 | /// @param log_prefix string to put at the beginning of the log message 71 | std::string parse(const std::string & log_prefix); 72 | std::string validate(bool modem_sender) const; 73 | 74 | std::string parse_and_validate(const uint8_t * msgbuf, size_t length, 75 | bool is_signal, bool modem_sender, 76 | const std::string & log_prefix); 77 | std::string parse_and_validate(bool modem_sender, 78 | const std::string & log_prefix); 79 | 80 | LLDLEP::SignalIdType get_signal_id() const; 81 | std::string get_signal_name() const; 82 | bool is_signal() const; 83 | 84 | LLDLEP::DlepMac get_mac() const; 85 | std::string get_peer_type() const; 86 | std::string get_status() const; 87 | std::vector get_experiment_names() const; 88 | unsigned int get_heartbeat_interval() const; 89 | std::vector get_extensions() const; 90 | std::uint16_t get_port() const; 91 | LLDLEP::Div_u8_ipv4_t get_ipv4_address() const; 92 | LLDLEP::Div_u8_ipv6_t get_ipv6_address() const; 93 | LLDLEP::Div_u8_ipv4_u16_t get_ipv4_conn_point() const; 94 | LLDLEP::Div_u8_ipv6_u16_t get_ipv6_conn_point() const; 95 | 96 | LLDLEP::DataItems get_metrics_and_ipaddrs() const; 97 | LLDLEP::DataItems get_data_items_no_mac() const; 98 | LLDLEP::DataItems get_data_items() const; 99 | bool get_data_item_exists(const std::string & data_item_name) const; 100 | 101 | // exception classes 102 | 103 | struct DataItemWrongType : public std::runtime_error 104 | { 105 | explicit DataItemWrongType(const std::string & s) : std::runtime_error(s) {} 106 | }; 107 | 108 | struct DataItemNotPresent : public std::runtime_error 109 | { 110 | explicit DataItemNotPresent(const std::string & s) : std::runtime_error(s) {} 111 | }; 112 | 113 | struct SignalIdNotInitialized : public std::runtime_error 114 | { 115 | explicit SignalIdNotInitialized(const std::string & s) : std::runtime_error(s) {} 116 | }; 117 | 118 | private: 119 | 120 | void update_message_length(); 121 | 122 | template 123 | T get_data_item_value(const std::string & data_item_name) const; 124 | 125 | template 126 | std::vector get_data_item_values(const std::string & data_item_name) const; 127 | 128 | /// Index in msgbuf where the message length is stored. 129 | std::size_t msg_len_index; 130 | 131 | /// length in bytes of the entire message header. Data items start 132 | /// right after this. 133 | std::size_t header_length; 134 | 135 | /// raw message bytes (serialized) 136 | std::vector msgbuf; 137 | 138 | /// message ID for convenient access 139 | LLDLEP::SignalIdType signal_id; 140 | 141 | /// has signal_id been initialized yet? 142 | bool signal_id_initialized; 143 | 144 | /// Is signal_id a "signal" vs. a "message" ? 145 | /// Signals have the signal prefix at the beginning of the packet. 146 | bool is_signal_; 147 | 148 | /// data items in this signal, populated by parse() 149 | LLDLEP::DataItems data_items; 150 | 151 | /// DLEP protocol configuration interface 152 | LLDLEP::ProtocolConfig * protocfg; 153 | 154 | /// logger, for LOG macro 155 | DlepLoggerPtr logger; 156 | }; 157 | 158 | } // namespace internal 159 | } // namespace LLDLEP 160 | 161 | #endif // PROTOCOL_MESSAGE_H 162 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | The MIT Lincoln Laboratory DLEP (LL-DLEP) is an implementation of the 2 | Dynamic Link Exchange Protocol, an IETF standards-track protocol 3 | (https://datatracker.ietf.org/doc/rfc8175/) that specifies a 4 | radio-to-router interface. It is an IP network protocol that runs 5 | between a radio/modem and a router over a direct (single hop) 6 | connection. Its primary purpose is to enable the modem to tell the 7 | router about destinations (other computers/networks) that the modem 8 | can reach, and to provide metrics associated with those 9 | destinations. The router can then make routing decisions based on that 10 | information. 11 | 12 | This README describes how to build and run the Dlep implementation 13 | developed at MIT Lincoln Laboratory. See RELEASENOTES.md for what has 14 | changed in this release. 15 | 16 | This release was was developed and tested on: 17 | - Ubuntu Linux version 14.04 LTS 18 | - Ubuntu Linux version 16.04 LTS 19 | - CentOS 7 20 | - CentOS 6 21 | - Mac OS X (10.12.6) 22 | 23 | ********************************************************** 24 | INSTALL OPEN SOURCE PACKAGES 25 | 26 | Install these packages before building anything. Ubuntu/Debian 27 | package names: 28 | 29 | - libboost-thread-dev (version 48 or higher) 30 | - libboost-system-dev (version should match thread-dev) 31 | - libboost-test-dev (version should match thread-dev) 32 | - libxml2 33 | - libxml2-dev 34 | - libxml2-utils (for xmllint) 35 | - libreadline6-dev 36 | - libprotobuf-dev 37 | - protobuf-compiler 38 | - doxygen 39 | - graphviz 40 | - cmake 41 | 42 | Fedora/Red Hat (EL7) package names (for EL6, see below): 43 | 44 | - boost 45 | - boost-devel 46 | - xml2 47 | - libxml2-devel 48 | - readline-devel 49 | - gcc-c++ 50 | - clang 51 | - python 52 | - protobuf 53 | - protobuf-devel 54 | - doxygen 55 | - graphviz 56 | - cmake 57 | - rpm-build 58 | 59 | 60 | MacPorts port names: 61 | 62 | - protobuf3-cpp 63 | - pkgconfig 64 | - boost 65 | - libxml2 66 | - doxygen 67 | - graphviz 68 | - cmake 69 | 70 | ********************************************************** 71 | 72 | Red Hat/CentOS 6 specific notes: 73 | 74 | The default GCC and Boost on EL6 (GCC 4.4.7 and Boost 1.41) are not new enough to build DLEP. However, EL6 includes a parallel install updated version of Boost (v1.48). The Software Collections project contains a group of packages under the "DevToolSet" umbrella, including newer gcc toolchains. To build DLEP on EL6, use the following steps (tested on CentOS 6.10): 75 | 76 | ``` 77 | # Add the Software Collections repository 78 | sudo yum install centos-release-scl 79 | # Install the standard DLEP dependencies 80 | sudo yum install cmake libxml2-devel readline-devel protobuf-devel doxygen graphviz rpm-build 81 | # Install EL6 Boost 1.48 and Software Collections GCC8 82 | sudo yum install boost148-devel devtoolset-8-toolchain 83 | # From the build directory in dlep source code directory, run the following cmake command 84 | CC=/opt/rh/devtoolset-8/root/usr/bin/gcc CXX=/opt/rh/devtoolset-8/root/usr/bin/g++ cmake -DBOOST_INCLUDEDIR=/usr/include/boost148/ -DBOOST_LIBRARYDIR=/usr/lib64/boost148/ -DWARNINGS_AS_ERRORS=OFF .. 85 | # Build DLEP 86 | make 87 | ``` 88 | 89 | ********************************************************** 90 | BUILD 91 | 92 | We will refer to the directory containing the dlep source as dlep-top. 93 | Do the following (shell commands are prefixed with $): 94 | 95 | $ cd dlep-top/build 96 | $ cmake .. 97 | $ make 98 | $ sudo make install 99 | 100 | Some useful build variations are described below. 101 | 102 | By default, the DLEP build treats all compiler warnings as errors 103 | (-Werror compiler flag). If you are experiencing problems compiling on 104 | your system due to this setting, you can disable it with: 105 | 106 | $ cmake -DWARNINGS_AS_ERRORS=OFF .. 107 | 108 | To build with debugging symbols, replace the cmake line above with: 109 | 110 | $ cmake -DCMAKE_BUILD_TYPE=Debug .. 111 | 112 | To build with the GNU C++ Lbrary debugging (error checking) enabled 113 | (see https://gcc.gnu.org/onlinedocs/libstdc++/manual/debug_mode.html), 114 | replace the cmake line above with: 115 | 116 | $ cmake -DCMAKE_CXX_FLAGS="-D_GLIBCXX_DEBUG" .. 117 | 118 | To build with the clang compiler, replace the cmake line above with: 119 | 120 | $ CC=clang CXX=clang++ cmake .. 121 | 122 | To build a package for the type of system you're building on: 123 | 124 | $ cmake -DPACKAGE=on .. 125 | $ make package 126 | 127 | To see the build output on the terminal as it is produced: 128 | 129 | $ make VERBOSE=1 130 | 131 | ********************************************************** 132 | TEST 133 | 134 | To run the unit tests after building: 135 | 136 | $ cd dlep-top/build 137 | $ make test 138 | 139 | If any tests fail, you can get more information with: 140 | 141 | $ CTEST_OUTPUT_ON_FAILURE=1 make test 142 | 143 | To exercise the example DLEP client, you will need two different 144 | machines on the same network, one to run the DLEP modem and one for 145 | the DLEP router. Rather than using physical machines, we suggest 146 | initially creating Linux containers with CORE (Common Open Research 147 | Emulator, http://www.nrl.navy.mil/itd/ncs/products/core). In CORE, 148 | create a 2-node topology using router nodes, and connect them to an 149 | ethernet switch. Open a terminal window to each node. Then: 150 | 151 | In window 1 (node with IP 10.0.0.1), run the modem side: 152 | 153 | $ cd dlep-top 154 | $ ./Dlep config-file config/modem.xml 155 | 156 | Dlep will drop into a command line interface (CLI). You can type help 157 | to get a summary of available commands. Detailed logging will go to 158 | dlep-modem.log, which comes from the config-file. 159 | 160 | In window 2 (node with IP 10.0.0.2), run the router side: 161 | 162 | $ cd dlep-top 163 | $ ./Dlep config-file config/router.xml 164 | 165 | As with the modem, Dlep will drop into a CLI. Detailed logging 166 | will go to dlep-modem.log. You should see a "Peer up" message in 167 | both windows indicating that the Dlep session initialization 168 | successfully completed. 169 | 170 | ********************************************************** 171 | MORE INFORMATION 172 | 173 | Refer to the User Guide doc/doxygen/markdown/UserGuide.md, or the 174 | doxygen-generated version at 175 | file:///dlep-top/build/doc/doxygen/html/index.html . 176 | The doxygen files are also installed in an OS-dependent location, 177 | e.g., /usr/local/share/dlep/html/index.html. 178 | -------------------------------------------------------------------------------- /Dlep.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Dynamic Link Exchange Protocol (DLEP) 3 | * 4 | * Copyright (C) 2015, 2016 Massachusetts Institute of Technology 5 | */ 6 | 7 | #ifndef DLEP_H 8 | #define DLEP_H 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | namespace LLDLEP 37 | { 38 | 39 | /// Library-internal code that should not be visible to clients 40 | /// goes in this namespace. 41 | namespace internal 42 | { 43 | 44 | class Dlep; 45 | 46 | // DlepPtr is intentionally not a shared_ptr. The Dlep object 47 | // contains pointers to many subcomponents, and many of those 48 | // subcomponents contain pointers back to Dlep, creating the dreaded 49 | // cycle that effectively leads to a memory leak when shared pointers 50 | // are used. Using weak pointers to break the cycles would have 51 | // resulted in many more code changes. A bare pointer works just fine 52 | // in this case. 53 | typedef Dlep * DlepPtr; 54 | 55 | // DlepMessageBuffer holds a serialized message to be sent to or 56 | // received from the network. 57 | typedef boost::shared_ptr> DlepMessageBuffer; 58 | 59 | } // namespace internal 60 | } // namespace LLDLEP 61 | 62 | #include "Peer.h" 63 | #include "InfoBaseMgr.h" 64 | #include "DlepClient.h" 65 | #include "Thread.h" 66 | #include "ProtocolConfig.h" 67 | 68 | namespace LLDLEP 69 | { 70 | namespace internal 71 | { 72 | 73 | class Peer; 74 | class InfoBaseMgr; 75 | class DeviceInterface; 76 | class DestAdvert; 77 | 78 | 79 | enum class PeerState; 80 | 81 | class Dlep : public boost::enable_shared_from_this 82 | { 83 | public: 84 | 85 | Dlep(bool is_modem, LLDLEP::DlepClient & dlep_client, 86 | DlepLoggerPtr logger); 87 | 88 | ~Dlep(); 89 | 90 | void initialize(); 91 | 92 | /// Wait for initialize(), which runs in its own thread, to complete 93 | /// @return true if initialization succeeded; the library thread(s) have 94 | /// started normal operation (peer discovery, etc.) 95 | /// false if it failed; the library thread(s) have exited. 96 | bool wait_for_initialization(); 97 | 98 | void start_async_connect(const boost::asio::ip::address & dest_ip, 99 | uint16_t port); 100 | 101 | // Remove Peer objects that have been terminated 102 | void cleanup_ex_peers(); 103 | 104 | /// Get the current state of a peer. 105 | /// @param peer_id the ID of the peer 106 | /// @return the state of peer_id 107 | PeerState peer_state(std::string peer_id); 108 | 109 | /// Find the peer that advertised a given destination. 110 | /// @param mac_address 111 | /// the destination for which to find the peer 112 | /// @return the requested peer, or nullptr if mac_address did not 113 | /// belong to any peer 114 | boost::shared_ptr find_peer(const LLDLEP::DlepMac & mac_address); 115 | 116 | /// Are we configured as the modem or the router? 117 | /// @return true if running as the modem, else false (router) 118 | bool is_modem() 119 | { 120 | return modem; 121 | } 122 | 123 | boost::asio::io_service io_service_; 124 | 125 | /// Default metrics, and destinations that we own. 126 | /// The modem sends these default metrics sent in a 127 | /// Peer Initialization Ack signal. 128 | /// These destinations are located on the same side 129 | /// as this Dlep process (modem or router); they will 130 | /// be communicated via Dlep to the other side. 131 | boost::shared_ptr local_pdp; 132 | 133 | // Peers: router typically has >1, modem just one 134 | std::map > peers; 135 | 136 | std::string get_peer_id_from_endpoint(boost::asio::ip::tcp::endpoint 137 | from_endpoint); 138 | 139 | boost::shared_ptr info_base_manager; 140 | 141 | LLDLEP::DlepClient & dlep_client; 142 | 143 | std::unique_ptr dest_advert; 144 | bool dest_advert_enabled; 145 | 146 | LLDLEP::ProtocolConfig * protocfg; 147 | 148 | DlepLoggerPtr logger; 149 | boost::recursive_mutex mutex; 150 | 151 | private: 152 | 153 | /// Are we the modem (true) or the router (false)? 154 | bool modem; 155 | 156 | /// indicates that Dlep::initialize has finished 157 | bool initialization_done; 158 | 159 | /// tells whether Dlep::initialize succeeded (true) or failed (false) 160 | bool initialization_success; 161 | 162 | /// Are we using IPv6 (true) or IPv4 (false)? 163 | bool using_ipv6; 164 | 165 | /// Is peer discovery enabled (true) or disabled (false)? The 166 | /// value comes from the discovery-enable config parameter. 167 | bool discovery_enable; 168 | 169 | /// inter-thread synchroniztion objects for initialization_done 170 | boost::condition_variable initialization_condvar; 171 | boost::mutex initialization_mutex; 172 | 173 | /// The library thread calls this to let DlepInit (running in the client thread) 174 | /// know that initialization has completed and it is safe to proceed. 175 | /// @param[in] success 176 | /// tells whether initialize succeeded (true) or failed (false). 177 | /// This value is stored in initialization_success for DlepInit 178 | /// to examine. 179 | void notify_initialization_done(bool success); 180 | 181 | boost::asio::deadline_timer cleanup_ex_peers_timer; 182 | 183 | // for accepting async tcp connections 184 | boost::asio::ip::tcp::acceptor * session_acceptor; 185 | 186 | bool start_dlep(); 187 | 188 | void handle_ex_peers_timeout(const boost::system:: error_code & error); 189 | 190 | void handle_async_make_peer(boost::asio::ip::tcp::socket * peer_socket, 191 | const boost::system::error_code & error); 192 | void start_async_accept(); 193 | }; 194 | 195 | } // namespace internal 196 | } // namespace LLDLEP 197 | 198 | #endif // DLEP_H 199 | -------------------------------------------------------------------------------- /PeriodicMcastSendRcv.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Dynamic Link Exchange Protocol (DLEP) 3 | * 4 | * Copyright (C) 2015, 2016, 2018 Massachusetts Institute of Technology 5 | */ 6 | 7 | /// @file 8 | /// PeriodicMcastSendRcv class declaration. 9 | 10 | #ifndef PERIODIC_MCAST_SEND_RCV_H 11 | #define PERIODIC_MCAST_SEND_RCV_H 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "Dlep.h" 20 | #include "DlepLogger.h" 21 | #include "ProtocolMessage.h" 22 | 23 | namespace LLDLEP 24 | { 25 | namespace internal 26 | { 27 | 28 | /// This class provides a way to send and/or receive periodic multicast 29 | /// packets. 30 | /// To use this class: 31 | /// 1. Create a class that inherits from PeriodicMcastSendRcv. 32 | /// 2. In the constructor of your subclass, call the PeriodicMcastSendRcv 33 | /// constructor with the appropriate configuration. You can choose 34 | /// to send, receive, both, or neither. 35 | /// 3. If you have specified sending, provide an implementation of 36 | /// get_message_to_send(). 37 | /// 4. If you have specified receiving, provide an implementation of 38 | /// handle_message(). 39 | class PeriodicMcastSendRcv 40 | { 41 | public: 42 | 43 | /// Constructor. 44 | /// @param[in] dlep back-pointer to dlep instance 45 | /// @param[in] io_service for handling network I/O and timers 46 | /// @param[in] interface_name name of the network interface to use 47 | /// @param[in] udp_port UDP port number to put on multicast packets 48 | /// @param[in] multicast_addr multicast address to put on packets 49 | /// @param[in] ttl IP TTL to put on multicast packets 50 | /// @param[in] send_interval number of seconds between sending packets 51 | /// @param[in] sending true iff we are sending packets 52 | /// @param[in] receiving true iff we are receiving packets 53 | /// @param[in] logger logger, for LOG macro 54 | PeriodicMcastSendRcv(DlepPtr dlep, 55 | boost::asio::io_service & io_service, 56 | std::string interface_name, 57 | uint16_t udp_port, 58 | boost::asio::ip::address & multicast_addr, 59 | unsigned int ttl, 60 | unsigned int send_interval, 61 | bool sending, 62 | bool receiving, 63 | DlepLoggerPtr logger); 64 | virtual ~PeriodicMcastSendRcv(); 65 | 66 | /// Start send/receive operations. 67 | /// @return true if successful, else false. 68 | virtual bool start(); 69 | 70 | /// Stop all send/receive operations. 71 | /// After this is called, start() cannot be called again. 72 | virtual void stop(); 73 | 74 | protected: 75 | 76 | /// Handle the payload of a received multicast packet. 77 | /// 78 | /// @param[in] msg_buffer payload bytes of the multicast packet 79 | /// @param[in] from_endpoint source IP addr/port of this packet 80 | virtual void handle_message(DlepMessageBuffer msg_buffer, 81 | boost::asio::ip::udp::endpoint from_endpoint) = 0; 82 | 83 | /// Called when it is time to send a multicast packet. 84 | /// 85 | /// @return a DlepMessageBuffer containing the payload bytes of the 86 | /// multicast packet to be sent 87 | virtual DlepMessageBuffer get_message_to_send() = 0; 88 | 89 | /// UDP port number for multicast packets 90 | uint16_t udp_port; 91 | 92 | /// IP address of the local interface being used for sending/receiving 93 | /// multicast packets 94 | boost::asio::ip::address interface_address; 95 | 96 | /// back-pointer to dlep instance 97 | DlepPtr dlep; 98 | 99 | /// logger that gets shared throughout the library 100 | DlepLoggerPtr logger; 101 | 102 | private: 103 | 104 | /// Initialize reception of multicast packets. 105 | bool setup_receive(); 106 | 107 | /// Initiate boost::asio async receive to get multicast packets. 108 | void start_receive(); 109 | 110 | /// boost::asio calls this to deliver received multicast packets to us 111 | /// Calls the subclass's handle_message(). 112 | /// param[in] bytes_recvd number of bytes in received message. 113 | /// The buffer containing the actual message is specified 114 | /// beforehand in the boost asio call async_receive_from(). 115 | void handle_receive(const boost::system::error_code & error, 116 | std::size_t bytes_recvd); 117 | 118 | /// Initialize periodic sending of multicast packets. 119 | /// @return true if successful, else false 120 | bool setup_send(); 121 | 122 | /// Build and send a multicast packet. 123 | /// Calls the subclass's get_message_to_send(). 124 | void start_send(); 125 | 126 | /// boost::asio calls this when the send is complete 127 | /// param[in] error boost error code, 0 if no error 128 | void handle_send(DlepMessageBuffer msg_buffer, const boost::system::error_code & error); 129 | 130 | /// boost::asio calls this when the send_timer expires 131 | /// param[in] error boost error code, 0 if no error 132 | void handle_send_timeout(const boost::system::error_code & error); 133 | 134 | /// Name of network interface to send/receive packets on 135 | std::string interface_name; 136 | 137 | /// multicast address to send to/receive from 138 | boost::asio::ip::address multicast_address; 139 | 140 | /// Are we supposed to receive multicast packets? 141 | bool receiving; 142 | 143 | /// Socket used to receive multicast packets 144 | boost::asio::ip::udp::socket receive_socket; 145 | 146 | /// Remote info of received multicast packets 147 | boost::asio::ip::udp::endpoint remote_endpoint; 148 | 149 | /// Multicast address/port to which packets are sent 150 | boost::asio::ip::udp::endpoint send_endpoint; 151 | 152 | /// Are we supposed to send multicast packets? 153 | bool sending; 154 | 155 | // IP TTL to put on multicast packets 156 | unsigned int send_ttl; 157 | 158 | /// Socket used to send multicast packets 159 | boost::asio::ip::udp::socket send_socket; 160 | 161 | /// Timer for sending periodic multicast packets 162 | boost::asio::deadline_timer send_timer; 163 | 164 | /// Interval (seconds) between sending discovery messages 165 | unsigned int send_interval; 166 | 167 | /// Buffer to hold received messages 168 | uint8_t recv_message[ProtocolMessage::MAX_SIGNAL_SIZE]; 169 | }; 170 | 171 | } // namespace internal 172 | } // namespace LLDLEP 173 | 174 | #endif // PERIODIC_MCAST_SEND_RCV_H 175 | -------------------------------------------------------------------------------- /ExampleDlepClientImpl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Dynamic Link Exchange Protocol (DLEP) 3 | * 4 | * Copyright (C) 2015, 2016, 2018, 2019 Massachusetts Institute of Technology 5 | */ 6 | 7 | /// @file 8 | /// Example DLEP client implementation class declaration. 9 | 10 | #ifndef DLEP_CLIENT_IMPL_H 11 | #define DLEP_CLIENT_IMPL_H 12 | 13 | #include "DlepClient.h" // base class 14 | #include "DlepService.h" 15 | 16 | /// Example instantiation of the DlepClient interface. 17 | class DlepClientImpl : public LLDLEP::DlepClient 18 | { 19 | public: 20 | DlepClientImpl(); 21 | 22 | /// @see DlepClient for documentation of inherited methods 23 | 24 | void get_config_parameter(const std::string & parameter_name, 25 | ConfigValue * value) override; 26 | void get_config_parameter(const std::string & parameter_name, 27 | bool * value) override; 28 | void get_config_parameter(const std::string & parameter_name, 29 | unsigned int * value) override; 30 | void get_config_parameter(const std::string & parameter_name, 31 | std::string * value) override; 32 | void get_config_parameter(const std::string & parameter_name, 33 | boost::asio::ip::address * value) override; 34 | void get_config_parameter(const std::string & parameter_name, 35 | std::vector * value) override; 36 | 37 | void print_data_items(const std::string & msg, 38 | const LLDLEP::DataItems & data_items); 39 | 40 | void print_peer_info(const LLDLEP::PeerInfo & peer_info); 41 | 42 | bool peer_init(const std::string & peer_id, 43 | LLDLEP::DataItems & data_items) override; 44 | 45 | void peer_up(const LLDLEP::PeerInfo & peer_info) override; 46 | 47 | void peer_update(const std::string & peer_id, 48 | const LLDLEP::DataItems & data_items) override; 49 | 50 | void peer_down(const std::string & peer_id) override; 51 | 52 | std::string destination_up(const std::string & peer_id, 53 | const LLDLEP::DlepMac & mac_address, 54 | const LLDLEP::DataItems & data_items) override; 55 | 56 | void destination_update(const std::string & peer_id, 57 | const LLDLEP::DlepMac & mac_address, 58 | const LLDLEP::DataItems & data_items) override; 59 | 60 | void destination_down(const std::string & peer_id, 61 | const LLDLEP::DlepMac & mac_address, 62 | const LLDLEP::DataItems & data_items) override; 63 | 64 | void linkchar_request(const std::string & peer_id, 65 | const LLDLEP::DlepMac & mac_address, 66 | const LLDLEP::DataItems & data_items) override; 67 | 68 | void linkchar_reply(const std::string & peer_id, 69 | const LLDLEP::DlepMac & mac_address, 70 | const LLDLEP::DataItems & data_items) override; 71 | 72 | /// Parse command line arguments. 73 | /// Loads the configuration database with values from the command line 74 | /// and any config files that were specified. 75 | /// @param[in] argc argument count 76 | /// @param[in] argv array of argument strings 77 | /// @return false if any parameter names or values were invalid, 78 | /// else true indicating success. 79 | bool parse_args(int argc, char ** argv); 80 | 81 | /// Fill in default configuration parameter values. 82 | bool load_defaults(); 83 | 84 | /// Parse one configuration parameter and put it into the configuration 85 | /// database. 86 | /// @param[in] param_name string name of the parameter 87 | /// @param[in] param_value string value of the parameter 88 | /// @return true if success, else false. 89 | bool parse_parameter(const char * param_name, const char * param_value); 90 | 91 | /// Print the contents of the configuration database. 92 | void print_config() const; 93 | 94 | /// Print a usage message. 95 | void usage(const char * progname) const; 96 | 97 | void set_dlep_service(LLDLEP::DlepService *); 98 | 99 | /// Define the status code to use in response to a future destination up. 100 | /// @param[in] mac_address destination in the destination up message 101 | /// @param[in] status_code status to send for \p destination 102 | void set_destination_response(const LLDLEP::DlepMac & mac_address, 103 | const std::string & status_code); 104 | 105 | // support for colorized output 106 | 107 | /// text color to use for normal output 108 | std::string info_color; 109 | 110 | /// text color to use for error messages 111 | std::string error_color; 112 | 113 | /// text color to use for information that comes from the service library 114 | /// (when it calls a DlepClient method) 115 | std::string lib_color; 116 | 117 | /// reset to the default color 118 | std::string reset_color; 119 | 120 | private: 121 | /// Load configuration parameters from a file. 122 | /// @param[in] config_filename name of the configuration file to read 123 | /// @return true if success, else false. 124 | bool parse_config_file(const char * config_filename); 125 | 126 | /// Configuration database. 127 | /// Maps parameter names to their values. 128 | std::map config_map; 129 | 130 | /// Metadata information about one configuration parameter. 131 | struct ConfigParameterInfo 132 | { 133 | /// Types that config parameters can have 134 | enum class ParameterType 135 | { 136 | UnsignedInteger, 137 | String, 138 | IPAddress, 139 | Boolean, 140 | ConfigFile, // special case of string 141 | ListOfUnsignedInteger 142 | }; 143 | 144 | ParameterType type; 145 | 146 | /// Value to use for the parameter if none is supplied. 147 | /// If "", there is no default value. 148 | std::string default_value; 149 | 150 | /// Description of the parameter, printed in the usage message. 151 | std::string description; 152 | }; 153 | 154 | /// Map of parameter names to their metadata. 155 | typedef std::map ConfigParameterMapType; 156 | 157 | /// Actual config parameter definitions. 158 | static ConfigParameterMapType param_info; 159 | 160 | /// Mapping from destination to status string. This gives the 161 | /// status to use in response to a Destination Up. The "dest response 162 | /// mac-address status-code-name" CLI command populates this. 163 | std::map destination_responses; 164 | 165 | LLDLEP::DlepService * dlep_service; 166 | }; 167 | 168 | #endif // DLEP_CLIENT_IMPL_H 169 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 2.8) 2 | project (dlep) 3 | 4 | SET(DLEP_VERSION 2.1) # Release version of the software 5 | SET(SOVERSION 2.1) # The library version (e.g. libdlep.so.1.0 would be SOVERSION 1.0) 6 | 7 | SET(DLEPLIB_SRCS DestAdvert.cpp DlepInit.cpp DlepLogger.cpp Dlep.cpp Peer.cpp InfoBaseMgr.cpp PeerDiscovery.cpp DlepServiceImpl.cpp DlepMac.cpp PeriodicMcastSendRcv.cpp NetUtils.cpp ProtocolMessage.cpp DataItem.cpp ProtocolConfigImpl.cpp) 8 | SET(DLEP_PUBLIC_HDRS DlepInit.h DlepClient.h DlepService.h DlepCommon.h DataItem.h ProtocolConfig.h IdTypes.h DlepMac.h Serialize.h LatencyRange.h MultiHop.h) 9 | 10 | # Enable "all" c++ warnings 11 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall") 12 | 13 | # By default, treat all warnings as errors 14 | # Can be disalbed with -DWARNINGS_AS_ERRORS:OFF 15 | set(WARNINGS_AS_ERRORS ON CACHE BOOL "Treat all warnings as errors") 16 | if(WARNINGS_AS_ERRORS) 17 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror") 18 | endif() 19 | 20 | include(CheckCXXCompilerFlag) 21 | CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11) 22 | if(COMPILER_SUPPORTS_CXX11) 23 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 24 | else() 25 | message(FATAL_ERROR "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.") 26 | endif() 27 | SET(BUILD_SHARED_LIBS ON) 28 | SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") 29 | 30 | if(APPLE) 31 | if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) 32 | SET(CMAKE_INSTALL_PREFIX "/opt/local" CACHE PATH "Dlep Install Prefix" FORCE) 33 | endif() 34 | EXEC_PROGRAM(sw_vers ARGS -productVersion OUTPUT_VARIABLE OSX_VERSION) 35 | message(STATUS "Detected version of OS X is ${OSX_VERSION}") 36 | if(OSX_VERSION VERSION_GREATER 10.12) 37 | SET(PROTOBUF_MINVERSION 3.2) 38 | endif() 39 | endif() 40 | 41 | find_package (LibXml2 REQUIRED) 42 | include_directories(${LIBXML2_INCLUDE_DIR}) 43 | 44 | INCLUDE(FindProtobuf) 45 | find_package(Protobuf ${PROTOBUF_MINVERSION} REQUIRED) 46 | include_directories(${PROTOBUF_INCLUDE_DIRS}) 47 | include_directories(${CMAKE_CURRENT_BINARY_DIR}) 48 | PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS destadvert.proto) 49 | 50 | find_package(Boost 1.48 REQUIRED COMPONENTS system thread) 51 | include_directories(${Boost_INCLUDE_DIRS}) 52 | SET(BOOST_INCREASE_VARIANT_TYPES -DBOOST_MPL_CFG_NO_PREPROCESSED_HEADERS -DBOOST_MPL_LIMIT_LIST_SIZE=30 -DBOOST_MPL_LIMIT_VECTOR_SIZE=30) 53 | add_definitions(${BOOST_INCREASE_VARIANT_TYPES}) 54 | 55 | # This approach to only build the sources once for the shared/statis objects from: 56 | # https://stackoverflow.com/a/29824424 57 | add_library(dlepObj OBJECT ${DLEPLIB_SRCS} ${PROTO_SRCS} ${PROTO_HDRS}) 58 | # shared libraries need PIC 59 | set_target_properties(dlepObj PROPERTIES POSITION_INDEPENDENT_CODE 1) 60 | add_library(dlepShared SHARED $) 61 | target_link_libraries(dlepShared ${LIBXML2_LIBRARIES} ${PROTOBUF_LIBRARIES} ${Boost_LIBRARIES}) 62 | set_target_properties(dlepShared PROPERTIES VERSION ${DLEP_VERSION} SOVERSION ${SOVERSION} OUTPUT_NAME dlep MACOSX_RPATH ON) 63 | add_library(dlepStatic STATIC $) 64 | set_target_properties(dlepStatic PROPERTIES OUTPUT_NAME dlep) 65 | 66 | SET(ETCDIR "${CMAKE_INSTALL_PREFIX}/etc") 67 | # Default docs location 68 | SET(DOCDIR "share/dlep") 69 | 70 | ### CMake configuration that needs to be different when building for packages 71 | ### Hide them behind one variable for convenience 72 | ### Generate a package with: cmake .. -DPACKAGE=ON && make package 73 | if(PACKAGE) 74 | # Install to /usr 75 | SET(CMAKE_INSTALL_PREFIX "/usr") 76 | # Take install prefix out of /etc 77 | SET(ETCDIR "/etc") 78 | # Clear RPATH for installed objects 79 | SET(CMAKE_INSTALL_RPATH "") 80 | # Strip libraries and binaries 81 | SET(CMAKE_CXX_FLAGS "-s ${CMAKE_CXX_FLAGS}") 82 | # Perform checks for the 'dpkg' and 'rpm' commands 83 | find_file(DPKG dpkg) 84 | find_file(RPM rpm) 85 | # Set docdir to appropriate /usr/share/doc location 86 | if(DPKG) 87 | SET(DOCDIR "share/doc/${PROJECT_NAME}") 88 | endif() 89 | if(RPM) 90 | SET(DOCDIR "share/doc/${PROJECT_NAME}-${DLEP_VERSION}") 91 | endif() 92 | endif() 93 | 94 | # Generate pkg-config file for programs that want to consume the shared lib 95 | file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/pkgconfig) 96 | configure_file(libdlep.pc.in ${CMAKE_CURRENT_BINARY_DIR}/pkgconfig/libdlep.pc @ONLY) 97 | 98 | configure_file(build-defs.h.in build-defs.h @ONLY) 99 | add_executable(Dlep ExampleMain.cpp ExampleDlepClientImpl.cpp Table.cpp) 100 | target_link_libraries(Dlep dlepShared readline ${LIBXML2_LIBRARIES}) 101 | 102 | install(TARGETS dlepShared DESTINATION lib) 103 | install(TARGETS dlepStatic DESTINATION lib) 104 | install(TARGETS Dlep DESTINATION bin) 105 | install(FILES ${DLEP_PUBLIC_HDRS} DESTINATION include) 106 | install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/pkgconfig DESTINATION share 107 | DIRECTORY_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) 108 | install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/package/copyright DESTINATION ${DOCDIR}) 109 | 110 | ENABLE_TESTING() 111 | add_subdirectory(config) 112 | add_subdirectory(doc) 113 | add_subdirectory(tests) 114 | 115 | # Linux Packaging 116 | SET(CPACK_PACKAGE_CONTACT "David P. Wiggins ") 117 | SET(CPACK_PACKAGE_VERSION ${DLEP_VERSION}) 118 | SET(CPACK_PACKAGE_VENDOR "MIT Lincoln Laboratory") 119 | SET(PACKAGE_HOMEPAGE "https://github.com/mit-ll/LL-DLEP") 120 | SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "MIT Lincoln Laboratory Dynamic Link Exchange Protocol") 121 | FILE(READ "${CMAKE_CURRENT_SOURCE_DIR}/package/packagedesc.txt" PACKAGEDESC) 122 | if(DPKG) 123 | SET(CPACK_GENERATOR "DEB") 124 | SET(CPACK_DEBIAN_PACKAGE_DESCRIPTION "${CPACK_PACKAGE_DESCRIPTION_SUMMARY}\n${PACKAGEDESC}") 125 | SET(CPACK_DEBIAN_PACKAGE_HOMEPAGE "${PACKAGE_HOMEPAGE}") 126 | if(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "x86_64") 127 | SET(DEB_ARCH "amd64") 128 | else() 129 | SET(DEB_ARCH ${CMAKE_SYSTEM_PROCESSOR}) 130 | endif() 131 | SET(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-${CPACK_PACKAGE_VERSION}.${DEB_ARCH}") 132 | SET(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_CURRENT_SOURCE_DIR}/package/postinst;${CMAKE_CURRENT_SOURCE_DIR}/package/postrm") 133 | endif() 134 | if(RPM) 135 | SET(CPACK_GENERATOR "RPM") 136 | SET(CPACK_RPM_PACKAGE_RELEASE 1) 137 | SET(CPACK_RPM_PACKAGE_DESCRIPTION "${PACKAGEDESC}") 138 | SET(CPACK_RPM_PACKAGE_URL "${PACKAGE_HOMEPAGE}") 139 | SET(CPACK_RPM_PACKAGE_LICENSE "MIT") 140 | SET(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-${CPACK_PACKAGE_VERSION}-${CPACK_RPM_PACKAGE_RELEASE}.${CMAKE_SYSTEM_PROCESSOR}") 141 | SET(CPACK_RPM_POST_INSTALL_SCRIPT_FILE "${CMAKE_CURRENT_SOURCE_DIR}/package/postinst") 142 | SET(CPACK_RPM_POST_UNINSTALL_SCRIPT_FILE "${CMAKE_CURRENT_SOURCE_DIR}/package/postinst") # Currently we do the same action for post/postun (run ldconfig) 143 | endif() 144 | include(CPack) 145 | -------------------------------------------------------------------------------- /ProtocolConfigImpl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Dynamic Link Exchange Protocol (DLEP) 3 | * 4 | * Copyright (C) 2015, 2016, 2018 Massachusetts Institute of Technology 5 | */ 6 | 7 | #ifndef PROTOCOL_CONFIG_IMPL_H 8 | #define PROTOCOL_CONFIG_IMPL_H 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include "ProtocolConfig.h" 16 | #include "DlepLogger.h" 17 | 18 | namespace LLDLEP 19 | { 20 | namespace internal 21 | { 22 | 23 | class ProtocolConfigImpl : public LLDLEP::ProtocolConfig 24 | { 25 | public: 26 | ProtocolConfigImpl(const std::string & proto_config_schema, 27 | const std::string & proto_config_file, 28 | DlepLoggerPtr logger); 29 | 30 | std::array get_version() const override; 31 | 32 | std::size_t get_data_item_id_size() const override; 33 | std::size_t get_data_item_length_size() const override; 34 | LLDLEP::DataItemIdType get_data_item_id(const std::string & name, 35 | const LLDLEP::DataItemInfo * parent_di_info = nullptr) const override; 36 | std::string get_data_item_name(LLDLEP::DataItemIdType id, 37 | const LLDLEP::DataItemInfo * parent_di_info = nullptr) const override; 38 | LLDLEP::DataItemValueType 39 | get_data_item_value_type(const std::string & name) const override; 40 | 41 | bool is_metric(LLDLEP::DataItemIdType id, 42 | const LLDLEP::DataItemInfo * parent_di_info = nullptr) const override; 43 | bool is_ipaddr(LLDLEP::DataItemIdType id, 44 | const LLDLEP::DataItemInfo * parent_di_info = nullptr) const override; 45 | std::vector get_data_item_info() const override; 46 | LLDLEP::DataItemInfo get_data_item_info(const std::string & di_name) const override; 47 | std::vector 48 | get_data_item_info(const std::vector & di_names) const override; 49 | LLDLEP::DataItemInfo 50 | get_data_item_info(DataItemIdType id, 51 | const LLDLEP::DataItemInfo * parent_di_info = nullptr) const override; 52 | std::size_t get_signal_id_size() const override; 53 | std::size_t get_signal_length_size() const override; 54 | LLDLEP::SignalIdType get_signal_id(const std::string & name, 55 | bool * is_signal_return = nullptr) const override; 56 | std::string get_signal_name(LLDLEP::SignalIdType id) const override; 57 | std::string get_message_name(LLDLEP::SignalIdType id) const override; 58 | std::string get_message_response_name(const std::string & msg_name) const override; 59 | std::string get_signal_prefix() const override; 60 | std::vector get_signal_info() const override; 61 | ProtocolConfig::SignalInfo 62 | get_signal_info(const std::string & sig_name) const override; 63 | std::vector 64 | get_signal_info(const std::vector & sig_names) const override; 65 | 66 | std::size_t get_status_code_size() const override; 67 | LLDLEP::StatusCodeIdType get_status_code_id(const std::string & name) const override; 68 | std::string get_status_code_name(LLDLEP::StatusCodeIdType id) const override; 69 | std::vector get_status_code_info() const override; 70 | StatusCodeInfo get_status_code_info(const std::string & sc_name) const override; 71 | std::vector 72 | get_status_code_info(const std::vector & sc_names) const override ; 73 | 74 | std::vector get_module_info() const override; 75 | ProtocolConfig::ModuleInfo 76 | get_module_info(const std::string & module_name) const override; 77 | std::vector 78 | get_module_info(const std::vector & module_names) const override; 79 | std::size_t get_extension_id_size() const override; 80 | std::vector get_extension_ids() const override; 81 | std::vector get_experiment_names() const override; 82 | 83 | DlepLoggerPtr get_logger() const; 84 | 85 | private: 86 | std::string load_protocol_config( 87 | const std::string & proto_config_schema, 88 | const std::string & proto_config_file); 89 | 90 | void log_xml_tree(xmlNodePtr start_node, int level); 91 | std::string extract_protocol_config(xmlDocPtr doc); 92 | void extract_version(xmlNodePtr node); 93 | void extract_signal_prefix(xmlNodePtr node); 94 | void extract_field_sizes(xmlNodePtr node); 95 | void extract_module(xmlNodePtr node); 96 | void extract_module_signal(xmlNodePtr node, ModuleInfo & modinfo); 97 | void extract_module_data_item(xmlNodePtr node, ModuleInfo & modinfo); 98 | void extract_module_status_code(xmlNodePtr node, ModuleInfo & modinfo); 99 | SubDataItem extract_module_data_item_ref(const std::string & parent_name, 100 | xmlNodePtr node); 101 | 102 | template 103 | void log_node_path_and_value(xmlNodePtr node, T val); 104 | template T extract_node_value(xmlNodePtr node); 105 | template 106 | void insert_id_name_mapping(MapType & id_name_map, IdType id, 107 | const std::string & name, 108 | const std::string & mapname); 109 | 110 | /// map module name --> module info 111 | std::map module_info_map; 112 | 113 | /// map signal id <--> name 114 | boost::bimap signal_map; 115 | 116 | /// map signal id --> signal info 117 | std::map 118 | signal_info_map; 119 | 120 | /// map message id <--> name 121 | boost::bimap message_map; 122 | 123 | /// map message id --> message info 124 | std::map 125 | message_info_map; 126 | 127 | /// map data item id <--> name 128 | /// This only contains mappings for top-level data items, not sub data items 129 | /// because sub data items can have the same id as a top-level data item. 130 | boost::bimap data_item_map; 131 | 132 | /// map data item name(string) --> data item info 133 | /// This contains mappings for top-level AND sub data items. 134 | /// We require the data item name to be unique across all data items. 135 | std::map data_item_info_map; 136 | 137 | /// map status code id <--> name 138 | boost::bimap status_code_map; 139 | 140 | /// map status code id --> status code info 141 | std::map 142 | status_code_info_map; 143 | 144 | // other miscellaneous configuration information 145 | 146 | std::array version; 147 | std::string signal_prefix; 148 | std::size_t signal_length_size; 149 | std::size_t signal_id_size; 150 | std::size_t data_item_length_size; 151 | std::size_t data_item_id_size; 152 | std::size_t extension_id_size; 153 | std::size_t status_code_size; 154 | 155 | DlepLoggerPtr logger; 156 | }; 157 | 158 | } // namespace internal 159 | } // namespace LLDLEP 160 | 161 | #endif // PROTOCOL_CONFIG_IMPL_H 162 | -------------------------------------------------------------------------------- /Serialize.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Dynamic Link Exchange Protocol (DLEP) 3 | * 4 | * Copyright (C) 2015, 2016, 2018 Massachusetts Institute of Technology 5 | */ 6 | 7 | /// @file 8 | /// Serialize and deserialize integers of varying sizes (1,2,4,8 bytes) 9 | /// into fields of varying sizes (1-8 bytes). 10 | /// Use network byte order (MSB first). 11 | /// Handles serializing a type that is larger than the field size, 12 | /// e.g., a uint32 into a 2-byte field, as long as the value can be 13 | /// represented in a field of that size. 14 | /// 15 | /// These functions are not expected to be used directly by DLEP 16 | /// clients, but since this header is included by other DLEP public 17 | /// header files, it has to be installed. 18 | /// 19 | /// Currently this only works on unsigned integers. To handle signed 20 | /// integers, modifications are required to perform sign extension. 21 | 22 | 23 | #ifndef SERIALIZE_H 24 | #define SERIALIZE_H 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | namespace LLDLEP 31 | { 32 | 33 | //----------------------------------------------------------------------------- 34 | 35 | // Serialize integers of varying sizes 36 | 37 | 38 | /// Serialize a value into a specific size and location in a buffer. 39 | /// 40 | /// @param[in] val 41 | /// the value to serialize 42 | /// @param[in] field_size 43 | /// the number of bytes the serialized form must consume 44 | /// @param[in,out] buf 45 | /// the buffer to store the serialized bytes 46 | /// @param[in] it 47 | /// location in buf at which to store the serialized bytes. 48 | /// If this is buf.end(), append bytes to the end of buf. 49 | template 50 | std::size_t serialize(const T & val, const std::size_t field_size, 51 | std::vector & buf, 52 | std::vector::iterator it) 53 | { 54 | static_assert(std::is_integral::value, "T must be an integer type"); 55 | static_assert(! std::is_signed::value, "T must be an unsigned type"); 56 | 57 | // Verify that val will fit in field_size bytes. 58 | 59 | if (sizeof(T) > field_size) 60 | { 61 | T mask = T(~0) << field_size * 8; 62 | 63 | if (val & mask) 64 | { 65 | throw std::invalid_argument( 66 | std::to_string(val) + " cannot fit in " + 67 | std::to_string(field_size) + " bytes" + " mask " + std::to_string(mask)); 68 | } 69 | } 70 | 71 | bool append_bytes = (it == buf.end()); 72 | 73 | for (std::size_t i = field_size; i > 0; i--) 74 | { 75 | std::uint8_t onebyte = 0; 76 | if (i <= sizeof(T)) 77 | { 78 | onebyte = val >> ((i - 1) * 8) & 0xff; 79 | } 80 | 81 | if (append_bytes) 82 | { 83 | buf.push_back(onebyte); 84 | } 85 | else 86 | { 87 | if (it == buf.end()) 88 | { 89 | throw std::length_error("reached end of output buffer"); 90 | } 91 | *it++ = onebyte; 92 | } 93 | } 94 | 95 | return field_size; 96 | } 97 | 98 | /// Serialize a value into a specific size and append it to a buffer. 99 | /// 100 | /// @param[in] val 101 | /// the value to serialize 102 | /// @param[in] field_size 103 | /// the number of bytes the serialized form must consume 104 | /// @param[in,out] buf 105 | /// the buffer to append the serialized bytes to 106 | template 107 | std::size_t serialize(const T & val, const std::size_t field_size, 108 | std::vector & buf) 109 | { 110 | static_assert(std::is_integral::value, "T must be an integer type"); 111 | static_assert(! std::is_signed::value, "T must be an unsigned type"); 112 | 113 | return serialize(val, field_size, buf, buf.end()); 114 | } 115 | 116 | /// Serialize a value and append it to a buffer. 117 | /// This always adds sizeof(T) bytes to the buffer. 118 | /// 119 | /// @param[in] value 120 | /// the value to serialize 121 | /// @param[in,out] buf 122 | /// the buffer to append the serialized bytes to 123 | template 124 | std::size_t serialize(const T & value, std::vector & buf) 125 | { 126 | static_assert(std::is_integral::value, "T must be an integer type"); 127 | static_assert(! std::is_signed::value, "T must be an unsigned type"); 128 | 129 | for (std::size_t i = sizeof(T); i > 0; i--) 130 | { 131 | buf.push_back((value >> ((i - 1) * 8)) & 0xff); 132 | } 133 | 134 | return sizeof(T); 135 | } 136 | 137 | //----------------------------------------------------------------------------- 138 | 139 | // Deserialize integers of varying sizes 140 | 141 | // specialization (overload, really) of the next function for uint8 142 | template 143 | std::size_t deserialize(std::uint8_t & value, Iterator & it, Iterator it_end) 144 | { 145 | if (it == it_end) 146 | { 147 | throw std::length_error("reached end of input buffer"); 148 | } 149 | value = *it++; 150 | return 1; 151 | } 152 | 153 | 154 | /// Deserialize a value from a specific location in a buffer. 155 | /// 156 | /// @param[out] value 157 | /// upon return, the deserialized value 158 | /// @param[in,out] it 159 | /// location in the buffer at which the serialized bytes begin. 160 | /// Advances to reflect bytes consumed by deserialization. 161 | /// @param[in] it_end 162 | /// end of the buffer. Deserialization must not go beyond this. 163 | template 164 | std::size_t deserialize(T & value, Iterator & it, Iterator it_end) 165 | { 166 | static_assert(std::is_integral::value, "T must be an integer type"); 167 | static_assert(! std::is_signed::value, "T must be an unsigned type"); 168 | 169 | value = 0; 170 | 171 | std::size_t i; 172 | for (i = sizeof(T); 173 | i > 0 && it != it_end; 174 | i--, it++) 175 | { 176 | value <<= 8; 177 | value |= *it; 178 | } 179 | 180 | if (i > 0) 181 | { 182 | throw std::length_error("reached end of input buffer"); 183 | } 184 | 185 | return sizeof(T); 186 | } 187 | 188 | 189 | /// Deserialize a value from a specific size and location in a buffer. 190 | /// 191 | /// @param[out] value 192 | /// upon return, the deserialized value 193 | /// @param[in] field_size 194 | /// the number of bytes the serialized form consumes 195 | /// @param[in,out] it 196 | /// location in the buffer at which the serialized bytes begin. 197 | /// Advances to reflect bytes consumed by deserialization. 198 | /// @param[in] it_end 199 | /// end of the buffer. Deserialization must not go beyond this. 200 | template 201 | std::size_t deserialize(T & value, const std::size_t field_size, 202 | Iterator & it, Iterator it_end) 203 | { 204 | static_assert(std::is_integral::value, "T must be an integer type"); 205 | static_assert(! std::is_signed::value, "T must be an unsigned type"); 206 | 207 | std::uint64_t val64 = 0; 208 | 209 | std::size_t i; 210 | for (i = field_size; 211 | (i > 0) && (it != it_end); 212 | i--, it++) 213 | { 214 | val64 <<= 8; 215 | val64 |= *it; 216 | } 217 | 218 | if (i > 0) 219 | { 220 | throw std::length_error("reached end of input buffer"); 221 | } 222 | 223 | T mask = ~0; 224 | if ((val64 & mask) != val64) 225 | { 226 | throw std::invalid_argument( 227 | std::to_string(val64) + " cannot fit in " + 228 | std::to_string(sizeof(T)) + " bytes"); 229 | } 230 | 231 | value = T(val64); 232 | return field_size; 233 | } 234 | 235 | } // namespace LLDLEP 236 | 237 | #endif // SERIALIZE_H 238 | -------------------------------------------------------------------------------- /tests/dest_advert.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Dynamic Link Exchange Protocol (DLEP) 3 | * 4 | * Copyright (C) 2015, 2016 Massachusetts Institute of Technology 5 | */ 6 | 7 | /// @file 8 | /// Boost Unit Tests for Destination Advertisement. 9 | 10 | #include 11 | 12 | #include "DlepInit.h" 13 | #include "TestClientImpl.h" 14 | #include "LogFile.h" 15 | 16 | using namespace LLDLEP; 17 | 18 | BOOST_AUTO_TEST_SUITE(destination_advertisement) 19 | 20 | // config parameter name 21 | std::string dest_advert_iface = "destination-advert-iface"; 22 | 23 | // Tests using a DLEP client in isolation with destination advertisement enabled 24 | BOOST_AUTO_TEST_CASE(isolated_client) 25 | { 26 | TestClientImpl modem_client; 27 | 28 | BOOST_REQUIRE(modem_client.parse_config_file("modem1_dest_advert.xml")); 29 | modem_client.set_loopback_iface(dest_advert_iface); 30 | 31 | // start up the DLEP service 32 | 33 | DlepService * dlep_service = DlepInit(modem_client); 34 | BOOST_REQUIRE(dlep_service != nullptr); 35 | 36 | BOOST_TEST_PASSPOINT(); 37 | dlep_service->terminate(); 38 | delete dlep_service; 39 | BOOST_TEST_PASSPOINT(); 40 | } 41 | 42 | // Tests using two DLEP clients (both modems) 43 | BOOST_AUTO_TEST_CASE(two_modems) 44 | { 45 | // create and start modem1 46 | 47 | TestClientImpl modem1_client; 48 | 49 | BOOST_REQUIRE(modem1_client.parse_config_file("modem1_dest_advert.xml")); 50 | modem1_client.set_loopback_iface(dest_advert_iface); 51 | 52 | // start modem1 DLEP service 53 | 54 | DlepService * modem1_service = DlepInit(modem1_client); 55 | BOOST_REQUIRE(modem1_service != nullptr); 56 | 57 | // create and start modem2 58 | 59 | TestClientImpl modem2_client; 60 | 61 | BOOST_REQUIRE(modem2_client.parse_config_file("modem2_dest_advert.xml")); 62 | modem2_client.set_loopback_iface(dest_advert_iface); 63 | 64 | // start modem2 DLEP service 65 | 66 | DlepService * modem2_service = DlepInit(modem2_client); 67 | BOOST_REQUIRE(modem2_service != nullptr); 68 | 69 | // Give the protocol some time to work 70 | 71 | sleep(10); 72 | 73 | std::string nda = "new destination advertisement entry"; 74 | 75 | // Load modem1's log file into memory 76 | 77 | std::string modem1_logname; 78 | modem1_client.get_config_parameter("log-file", &modem1_logname); 79 | LogFile modem1_log(modem1_logname); 80 | 81 | // check that the new destination advertisement message (from modem2) 82 | // is present in modem1's log 83 | 84 | BOOST_CHECK(modem1_log.find(0, nda) != -1); 85 | 86 | // Load modem2's log file into memory 87 | 88 | std::string modem2_logname; 89 | modem2_client.get_config_parameter("log-file", &modem2_logname); 90 | LogFile modem2_log(modem2_logname); 91 | 92 | // check that the new destination advertisement message (from modem1) 93 | // is present in modem2's log 94 | 95 | BOOST_CHECK(modem2_log.find(0, nda) != -1); 96 | 97 | // Tear down everything 98 | 99 | BOOST_TEST_PASSPOINT(); 100 | modem1_service->terminate(); 101 | delete modem1_service; 102 | 103 | BOOST_TEST_PASSPOINT(); 104 | 105 | modem2_service->terminate(); 106 | delete modem2_service; 107 | BOOST_TEST_PASSPOINT(); 108 | } 109 | 110 | DlepMac 111 | get_rfid(TestClientImpl & modem_client) 112 | { 113 | std::vector rfid; 114 | modem_client.get_config_parameter("destination-advert-rf-id", &rfid); 115 | DlepMac mac_rfid; 116 | 117 | for (unsigned int x : rfid) 118 | { 119 | mac_rfid.mac_addr.push_back(x); 120 | } 121 | 122 | return mac_rfid; 123 | } 124 | 125 | // Tests using four DLEP clients: router1---modem1-----modem2---router2 126 | BOOST_AUTO_TEST_CASE(two_modems_two_routers) 127 | { 128 | // create and start modem1 129 | TestClientImpl modem1_client; 130 | 131 | BOOST_REQUIRE(modem1_client.parse_config_file("modem1_dest_advert.xml")); 132 | modem1_client.set_loopback_iface(dest_advert_iface); 133 | 134 | // start modem1 DLEP service 135 | DlepService * modem1_service = DlepInit(modem1_client); 136 | BOOST_REQUIRE(modem1_service != nullptr); 137 | 138 | // create and start modem2 139 | TestClientImpl modem2_client; 140 | 141 | BOOST_REQUIRE(modem2_client.parse_config_file("modem2_dest_advert.xml")); 142 | modem2_client.set_loopback_iface(dest_advert_iface); 143 | 144 | // start modem2 DLEP service 145 | DlepService * modem2_service = DlepInit(modem2_client); 146 | BOOST_REQUIRE(modem2_service != nullptr); 147 | 148 | // create and start router1 149 | TestClientImpl router1_client; 150 | BOOST_REQUIRE(router1_client.parse_config_file("router1_config.xml")); 151 | router1_client.set_loopback_iface(dest_advert_iface); 152 | 153 | modem1_client.peer_up_waiter.prepare_to_wait(); 154 | router1_client.peer_up_waiter.prepare_to_wait(); 155 | 156 | DlepService * router1_service = DlepInit(router1_client); 157 | BOOST_REQUIRE(router1_service != nullptr); 158 | 159 | // check that modem1 and router1 peer up 160 | BOOST_CHECK(modem1_client.peer_up_waiter.wait_for_client_call()); 161 | BOOST_CHECK(router1_client.peer_up_waiter.wait_for_client_call()); 162 | 163 | // create and start router2 164 | TestClientImpl router2_client; 165 | BOOST_REQUIRE(router2_client.parse_config_file("router2_config.xml")); 166 | router2_client.set_loopback_iface(dest_advert_iface); 167 | 168 | modem2_client.peer_up_waiter.prepare_to_wait(); 169 | router2_client.peer_up_waiter.prepare_to_wait(); 170 | 171 | DlepService * router2_service = DlepInit(router2_client); 172 | BOOST_REQUIRE(router2_service != nullptr); 173 | 174 | // check that modem2 and router2 peer up 175 | BOOST_CHECK(modem2_client.peer_up_waiter.wait_for_client_call()); 176 | BOOST_CHECK(router2_client.peer_up_waiter.wait_for_client_call()); 177 | 178 | // get the rf ids of the modems 179 | DlepMac modem1_rfid = get_rfid(modem1_client); 180 | DlepMac modem2_rfid = get_rfid(modem2_client); 181 | 182 | DataItems data_items; 183 | DlepService::ReturnStatus r; 184 | 185 | // modem1 declares modem2's rfid to be up 186 | router1_client.destination_up_waiter.prepare_to_wait(); 187 | r = modem1_service->destination_up(modem2_rfid, data_items); 188 | BOOST_REQUIRE(r == DlepService::ReturnStatus::ok); 189 | 190 | // check that router1 sees the destination up 191 | BOOST_REQUIRE(router1_client.destination_up_waiter.wait_for_client_call()); 192 | 193 | // The MAC address should NOT be modem2's rf id because destination 194 | // advertisement should have translated it to the router's MAC address 195 | // (we should enhance this check to figure out the router's MAC address 196 | // look for for that instead) 197 | BOOST_CHECK(! router1_client.destination_up_waiter.check_result(modem2_rfid)); 198 | 199 | // now do the same checks on the other side (modem2/router2) 200 | 201 | // modem2 declares modem1's rfid to be up 202 | router2_client.destination_up_waiter.prepare_to_wait(); 203 | r = modem2_service->destination_up(modem1_rfid, data_items); 204 | BOOST_REQUIRE(r == DlepService::ReturnStatus::ok); 205 | 206 | // check that router1 sees the destination up 207 | BOOST_REQUIRE(router2_client.destination_up_waiter.wait_for_client_call()); 208 | 209 | // The MAC address should NOT be modem2's rf id because destination 210 | // advertisement should have translated it to the router's MAC address 211 | // (we should enhance this check to figure out the router's MAC address 212 | // look for for that instead) 213 | BOOST_CHECK(! router2_client.destination_up_waiter.check_result(modem1_rfid)); 214 | 215 | // Tear down everything 216 | BOOST_TEST_PASSPOINT(); 217 | 218 | modem1_service->terminate(); 219 | delete modem1_service; 220 | 221 | BOOST_TEST_PASSPOINT(); 222 | 223 | modem2_service->terminate(); 224 | delete modem2_service; 225 | 226 | BOOST_TEST_PASSPOINT(); 227 | 228 | router1_service->terminate(); 229 | delete router1_service; 230 | 231 | BOOST_TEST_PASSPOINT(); 232 | 233 | router2_service->terminate(); 234 | delete router2_service; 235 | } 236 | 237 | 238 | BOOST_AUTO_TEST_SUITE_END() 239 | -------------------------------------------------------------------------------- /InfoBaseMgr.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Dynamic Link Exchange Protocol (DLEP) 3 | * 4 | * Copyright (C) 2013, 2015, 2016, 2019 Massachusetts Institute of Technology 5 | */ 6 | #ifndef _INFO_BASE_MGR_ 7 | #define _INFO_BASE_MGR_ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "Dlep.h" 27 | #include "DlepLogger.h" 28 | #include "DataItem.h" 29 | 30 | namespace LLDLEP 31 | { 32 | namespace internal 33 | { 34 | 35 | class Dlep; 36 | class Peer; 37 | 38 | // Map data item ID to its value 39 | typedef std::map DataItemMap; 40 | 41 | /// Information about a destination 42 | class DestinationData 43 | { 44 | public: 45 | /// Constructor. 46 | /// @param[in] mac MAC address of new destination 47 | /// @param[in] initial_data_items data items associated with mac 48 | /// @param[in] dlep back-pointer to dlep instance 49 | DestinationData(const LLDLEP::DlepMac & mac, 50 | const LLDLEP::DataItems & initial_data_items, 51 | DlepPtr dlep); 52 | ~DestinationData(); 53 | 54 | /// Record updated data items for this destination. 55 | /// @param[in] updates new data items to record 56 | /// @param[in] tell_peers should we send peers a DestinationUpdate signal 57 | /// with these updates? 58 | /// @return the number of updates recorded 59 | unsigned int update(const LLDLEP::DataItems & updates, bool tell_peers); 60 | 61 | /// Get a list of all of this destination's current data items. 62 | /// @param[out] data_items_out vector to store the data items in 63 | void get_all_data_items(LLDLEP::DataItems & data_items_out) const; 64 | 65 | /// Get a list of all of this destination's data items containing 66 | /// IP addresses. 67 | LLDLEP::DataItems get_ip_data_items() const; 68 | 69 | /// Log information about this destination. 70 | /// @param[in] prefix string to put at the beginning of the log message 71 | /// @param[in] log_level log level to use for LOG 72 | void log(const std::string & prefix, int log_level) const; 73 | 74 | void needs_response(const std::string & response_name); 75 | std::string needs_response() const; 76 | 77 | /// Search for an IP address on this destination. 78 | /// @param[in] ip_data_item 79 | /// data item containing an IP address to search for in this 80 | /// destination's IP addresses 81 | /// @return "" if not found, else a non-empty string identifying this 82 | /// destination. 83 | std::string find_ip_data_item(const DataItem & ip_data_item) const; 84 | 85 | private: 86 | /// MAC address of this destination 87 | LLDLEP::DlepMac mac_address; 88 | 89 | /// Metric data items associated with this destination. Only one 90 | /// data item per metric type is allowed, so this is a map. 91 | DataItemMap metric_data_items; 92 | 93 | /// IP address data items associated with this destination. 94 | /// There can be multiple IP addresses of each type, so this 95 | /// is a vector. 96 | DataItems ip_data_items; 97 | 98 | /// Is the peer expecting a Destination Announce Response or Destination 99 | /// Up Response for this destination? 100 | std::string needs_response_; 101 | 102 | /// back-pointer to dlep instance 103 | DlepPtr dlep; 104 | 105 | /// logger, for LOG macro 106 | DlepLoggerPtr logger; 107 | }; 108 | 109 | typedef boost::shared_ptr DestinationDataPtr; 110 | 111 | class PeerData 112 | { 113 | public: 114 | /// Constructor. 115 | /// @param[in] id peer id 116 | /// @param[in] initial_data_items data items associated with this peer 117 | /// @param[in] dlep back-pointer to dlep instance 118 | PeerData(const std::string & id, const LLDLEP::DataItems & initial_data_items, 119 | DlepPtr dlep); 120 | ~PeerData(); 121 | 122 | bool addDestination(const LLDLEP::DlepMac & mac, 123 | const LLDLEP::DataItems & initial_data_items, 124 | bool tell_peers); 125 | void sendAllDestinations(boost::shared_ptr peer); 126 | bool updateDestination(const LLDLEP::DlepMac & mac, 127 | const LLDLEP::DataItems & updates, 128 | bool tell_peers); 129 | bool removeDestination(const LLDLEP::DlepMac & mac, bool tell_peers, 130 | const LLDLEP::DataItems & data_items = LLDLEP::DataItems()); 131 | bool getDestinationData(const LLDLEP::DlepMac & mac, DestinationDataPtr * ddpp); 132 | void logDestinations(bool include_metrics); 133 | void getDestinations(std::vector & destinations); 134 | 135 | bool validDestination(const LLDLEP::DlepMac & mac); 136 | 137 | std::string update_data_items(const LLDLEP::DataItems & updates, 138 | bool tell_peers); 139 | void remove_data_items(const DataItems & data_items); 140 | LLDLEP::DataItems get_data_items(); 141 | 142 | /// Get a list of all of this peer's data items containing 143 | /// IP addresses. 144 | LLDLEP::DataItems get_ip_data_items() const; 145 | 146 | void log_data_items(); 147 | void needs_response(const LLDLEP::DlepMac & mac, const std::string & response_name); 148 | std::string needs_response(const LLDLEP::DlepMac & mac); 149 | 150 | /// Search for an IP address on this peer. 151 | /// @param[in] ip_data_item 152 | /// data item containing an IP address to search for in this 153 | /// peer's IP addresses 154 | /// @return "" if not found, else a non-empty string identifying where the 155 | /// IP address was found: this peer, or one of its destinations. 156 | std::string find_ip_data_item(const DataItem & ip_data_item) const; 157 | 158 | private: 159 | 160 | DataItems update_data_items_helper(const DataItems & data_items, 161 | DlepPtr dlep); 162 | 163 | /// peer_id is a combination of the TCP remote IP and port of the session 164 | std::string peer_id; 165 | 166 | /// Map destination mac to Destination Data 167 | std::map destination_data; 168 | 169 | /// The combination of the metric_data_items, ip_data_items, and 170 | /// other_data_items fields below constitute the set of session 171 | /// initialization data items referred to in the DlepService API. 172 | 173 | /// Metric data items that this peer supports, and their default 174 | /// values. Only one data item per metric type is allowed, so 175 | /// this is a map. 176 | DataItemMap metric_data_items; 177 | 178 | /// IP address data items associated with this peer. There can be 179 | /// multiple IP addresses of each type, so this is a vector. 180 | DataItems ip_data_items; 181 | 182 | // Other data items associated with this peer. 183 | DataItems other_data_items; 184 | 185 | /// back-pointer to dlep instance 186 | DlepPtr dlep; 187 | 188 | /// logger, for LOG macro 189 | DlepLoggerPtr logger; 190 | }; 191 | 192 | typedef boost::shared_ptr PeerDataPtr; 193 | 194 | 195 | class InfoBaseMgr 196 | { 197 | public: 198 | explicit InfoBaseMgr(DlepPtr dlep); 199 | ~InfoBaseMgr(); 200 | 201 | PeerDataPtr addPeer(const std::string & peer_id, 202 | const LLDLEP::DataItems & initial_values); 203 | bool removePeer(const std::string & peer_id); 204 | bool getPeerData(const std::string & peer_id, PeerDataPtr * pdpp); 205 | void logInfoBase(bool include_metrics); 206 | 207 | bool validPeer(const std::string & peer_id); 208 | bool validDestination(const std::string & peer_id, const LLDLEP::DlepMac & mac); 209 | 210 | private: 211 | 212 | // Peers, by peer ID 213 | std::map peer_data; 214 | 215 | DlepPtr dlep; 216 | DlepLoggerPtr logger; 217 | }; 218 | 219 | typedef boost::shared_ptr InfoBaseMgrPtr; 220 | 221 | } // namespace internal 222 | } // namespace LLDLEP 223 | 224 | #endif // _INFO_BASE_MGR_ 225 | -------------------------------------------------------------------------------- /tests/TestClientImpl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Dynamic Link Exchange Protocol (DLEP) 3 | * 4 | * Copyright (C) 2015, 2016, 2018 Massachusetts Institute of Technology 5 | */ 6 | 7 | /// @file 8 | /// Test DLEP client implementation class declaration. 9 | 10 | #ifndef TEST_CLIENT_IMPL_H 11 | #define TEST_CLIENT_IMPL_H 12 | 13 | #include "DlepClient.h" // base class 14 | #include "Thread.h" 15 | #include 16 | #include 17 | #include // for xmlDocPtr, xmlNodePtr 18 | 19 | /// Test instantiation of the DlepClient interface. 20 | class TestClientImpl : public LLDLEP::DlepClient 21 | { 22 | public: 23 | TestClientImpl(); 24 | 25 | /// @see DlepClient for documentation of inherited methods 26 | 27 | void get_config_parameter(const std::string & parameter_name, 28 | ConfigValue * value) override; 29 | void get_config_parameter(const std::string & parameter_name, 30 | bool * value) override; 31 | void get_config_parameter(const std::string & parameter_name, 32 | unsigned int * value) override; 33 | void get_config_parameter(const std::string & parameter_name, 34 | std::string * value) override; 35 | void get_config_parameter(const std::string & parameter_name, 36 | boost::asio::ip::address * value) override; 37 | void get_config_parameter(const std::string & parameter_name, 38 | std::vector * value) override; 39 | 40 | bool peer_init(const std::string & peer_id, 41 | LLDLEP::DataItems & data_items) override; 42 | bool modify_peer_init_peer_type = false; 43 | 44 | void peer_up(const LLDLEP::PeerInfo & peer_info) override; 45 | 46 | void peer_update(const std::string & peer_id, 47 | const LLDLEP::DataItems & data_items) override; 48 | 49 | void peer_down(const std::string & peer_id) override; 50 | 51 | std::string destination_up(const std::string & peer_id, 52 | const LLDLEP::DlepMac & mac_address, 53 | const LLDLEP::DataItems & data_items) override; 54 | 55 | void destination_update(const std::string & peer_id, 56 | const LLDLEP::DlepMac & mac_address, 57 | const LLDLEP::DataItems & data_items) override; 58 | 59 | void destination_down(const std::string & peer_id, 60 | const LLDLEP::DlepMac & mac_address, 61 | const LLDLEP::DataItems & data_items) override; 62 | 63 | void linkchar_request(const std::string & peer_id, 64 | const LLDLEP::DlepMac & mac_address, 65 | const LLDLEP::DataItems & data_items) override; 66 | 67 | void linkchar_reply(const std::string & peer_id, 68 | const LLDLEP::DlepMac & mac_address, 69 | const LLDLEP::DataItems & data_items) override; 70 | 71 | /// Parse one configuration parameter and put it into the configuration 72 | /// database. 73 | /// @param[in] param_name string name of the parameter 74 | /// @param[in] param_value string value of the parameter 75 | /// @return true if success, else false. 76 | bool parse_parameter(const char * param_name, const char * param_value); 77 | 78 | /// Print the contents of the configuration database. 79 | void print_config() const; 80 | 81 | /// Load configuration parameters from a file. 82 | /// @param[in] config_filename name of the configuration file to read 83 | /// @return true if success, else false. 84 | bool parse_config_file(const char * config_filename); 85 | 86 | /// Set the session-port configuration parameter. 87 | void set_session_port(uint16_t session_port); 88 | 89 | /// Set the discovery-iface configuration parameter to a suitable 90 | /// value. 91 | /// @param[in] want_ipv4_addr 92 | /// If true, find an interface with an IPv4 address, else 93 | /// find one with an IPv6 address. In the IPv6 case, only 94 | /// interfaces with link-local IPv6 addresses will be used. 95 | /// This usually (always?) excludes the loopback interface. 96 | void set_discovery_iface(bool want_ipv4_addr); 97 | 98 | /// Set a configuration parameter to the name of the loopback interface. 99 | /// @param[in] param_name 100 | /// The parameter name to set. 101 | void set_loopback_iface(std::string & param_name); 102 | 103 | struct DestinationDownInfo 104 | { 105 | LLDLEP::DlepMac mac; 106 | LLDLEP::DataItems data_items; 107 | bool operator==(const DestinationDownInfo & other) const 108 | { 109 | return (mac == other.mac) && (data_items == other.data_items); 110 | } 111 | }; 112 | 113 | /// This class eases the job of waiting for a call by the Dlep library 114 | /// from a different thread to a DlepClient method. 115 | template 116 | class ClientCallWaiter 117 | { 118 | public: 119 | ClientCallWaiter() : ready(false) {} 120 | 121 | // A test case should call this before there is any chance that the 122 | // DlepClient method has been called. 123 | void prepare_to_wait() 124 | { 125 | boost::lock_guard lock(mtx); 126 | ready = false; 127 | } 128 | 129 | /// Wait for a service call from a different thread. 130 | /// @return true if the expected call happened within a reasonable 131 | /// time, else false. 132 | bool wait_for_client_call() 133 | { 134 | boost::system_time timeout = 135 | boost::get_system_time() + boost::posix_time::minutes(1); 136 | boost::unique_lock lock(mtx); 137 | 138 | // Sometimes a condition variable wakes up even though its 139 | // condition hasn't actually happened. Search the web for 140 | // "condition variable spurious wakeup". To deal with 141 | // that possibility, we have to wrap the wait in a loop 142 | // that checks to see if the condition *really* occurred. 143 | while (! ready) 144 | { 145 | // We have to work with older versions of Boost (1.48) that don't 146 | // have wait_for(), so use timed_wait(). 147 | bool ok = cv.timed_wait(lock, timeout); 148 | if (! ok) 149 | { 150 | // timed out 151 | return false; 152 | } 153 | } 154 | return true; 155 | } 156 | 157 | /// Tell the thread that should be waiting in wait_for_client_call() 158 | /// that the expected call has occured. notify() is called from the 159 | /// library's thread. 160 | /// @param[in] x information that was provided to the DlepClient 161 | /// method that will be recorded for possible later use 162 | /// by check_result() 163 | void notify(const T & x) 164 | { 165 | boost::lock_guard lock(mtx); 166 | ready = true; 167 | result = x; 168 | cv.notify_one(); 169 | } 170 | 171 | /// Return the information recorded in notify(). 172 | T get_result() { return result; } 173 | 174 | /// Compare the information recorded in notify() with the expected result. 175 | /// @return true if they are equal, else false 176 | bool check_result(const T & expected_result) 177 | { 178 | return (result == expected_result); 179 | } 180 | 181 | private: 182 | /// inter-thread synchronization objects 183 | boost::condition_variable cv; 184 | boost::mutex mtx; 185 | bool ready; 186 | 187 | /// Information that was passed to the DlepClient method and 188 | /// recorded by notify() for later inspection. 189 | T result; 190 | }; // class ClientCallWaiter 191 | 192 | // Waiters for various DlepClient methods 193 | 194 | ClientCallWaiter peer_init_waiter; 195 | ClientCallWaiter peer_up_waiter; 196 | ClientCallWaiter peer_down_waiter; 197 | ClientCallWaiter peer_update_waiter; 198 | ClientCallWaiter destination_up_waiter; 199 | ClientCallWaiter destination_update_waiter; 200 | ClientCallWaiter destination_down_waiter; 201 | 202 | private: 203 | /// Configuration database. 204 | /// Maps parameter names to their values. 205 | std::map config_map; 206 | 207 | /// Metadata information about one configuration parameter. 208 | struct ConfigParameterInfo 209 | { 210 | /// Types that config parameters can have 211 | enum class ParameterType 212 | { 213 | UnsignedInteger, 214 | String, 215 | IPAddress, 216 | Boolean, 217 | ConfigFile, // special case of string 218 | ListOfUnsignedInteger 219 | }; 220 | 221 | ParameterType type; 222 | }; 223 | 224 | /// Map of parameter names to their metadata. 225 | typedef std::map ConfigParameterMapType; 226 | 227 | /// Actual config parameter definitions. 228 | static ConfigParameterMapType param_info; 229 | }; 230 | 231 | #endif // DLEP_CLIENT_IMPL_H 232 | -------------------------------------------------------------------------------- /config/protocol/protocol-config.xsd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 11 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 32 | 33 | 35 | 37 | 39 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 103 | 104 | 105 | 106 | 107 | 108 | 110 | 111 | 112 | 114 | 115 | 116 | 117 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 143 | 145 | 147 | 149 | 150 | 151 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 212 | 214 | 216 | 218 | 220 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 230 | 231 | 233 | 234 | 236 | 237 | 238 | 239 | 240 | 241 | -------------------------------------------------------------------------------- /PeriodicMcastSendRcv.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Dynamic Link Exchange Protocol (DLEP) 3 | * 4 | * Copyright (C) 2015, 2016, 2018 Massachusetts Institute of Technology 5 | */ 6 | 7 | /// @file 8 | /// The PeriodicMcastSendRcv class implements a mechanism to 9 | /// send and/or receive periodic multicast packets on an interface. 10 | /// Classes can inherit from this class and provide their own methods 11 | /// for constructing and interpreting the multicast packets. 12 | 13 | #include "PeriodicMcastSendRcv.h" 14 | #include "NetUtils.h" 15 | 16 | using namespace LLDLEP; 17 | using namespace LLDLEP::internal; 18 | 19 | PeriodicMcastSendRcv::PeriodicMcastSendRcv( 20 | DlepPtr dlep, 21 | boost::asio::io_service & io_service, 22 | std::string interface_name, 23 | uint16_t udp_port, 24 | boost::asio::ip::address & multicast_addr, 25 | unsigned int ttl, 26 | unsigned int send_interval, 27 | bool sending, 28 | bool receiving, 29 | DlepLoggerPtr logger) : 30 | udp_port(udp_port), 31 | dlep(dlep), 32 | logger(logger), 33 | interface_name(interface_name), 34 | multicast_address(multicast_addr), 35 | receiving(receiving), 36 | receive_socket(io_service), 37 | sending(sending), 38 | send_ttl(ttl), 39 | send_socket(io_service), 40 | send_timer(io_service), 41 | send_interval(send_interval), 42 | recv_message{0} 43 | { 44 | // If we have a link-local IPv6 multicast address, we have to set 45 | // its scope id to the interface index to which it is scoped. 46 | // Without doing this, bind() will give an EINVAL error. 47 | 48 | if (multicast_address.is_v6()) 49 | { 50 | std::ostringstream msg; 51 | if (! NetUtils::set_ipv6_scope_id(multicast_address, interface_name)) 52 | { 53 | msg << "failed to set scope id for multicast address=" 54 | << multicast_address; 55 | LOG(DLEP_LOG_ERROR, msg); 56 | } 57 | else 58 | { 59 | msg << "scoped multicast address=" << multicast_address; 60 | LOG(DLEP_LOG_DEBUG, msg); 61 | } 62 | } 63 | } 64 | 65 | PeriodicMcastSendRcv::~PeriodicMcastSendRcv() 66 | { 67 | stop(); 68 | } 69 | 70 | bool 71 | PeriodicMcastSendRcv::start() 72 | { 73 | std::ostringstream msg; 74 | 75 | if (!sending && !receiving) 76 | { 77 | // This could happen if peer discovery is disabled. 78 | msg << "Neither sending nor receiving is enabled"; 79 | LOG(DLEP_LOG_INFO, msg); 80 | return true; 81 | } 82 | 83 | // Convert the interface_name parameter to an IP address 84 | // on that interface. 85 | 86 | interface_address = 87 | NetUtils::get_ip_addr_from_iface(interface_name, 88 | multicast_address.is_v4(), 89 | logger); 90 | if (interface_address.is_unspecified()) 91 | { 92 | msg << "Could not determine IP address from interface " << interface_name; 93 | LOG(DLEP_LOG_ERROR, msg); 94 | return false; 95 | } 96 | 97 | msg << "interface=" << interface_name << " address=" << interface_address; 98 | LOG(DLEP_LOG_INFO, msg); 99 | 100 | if (receiving) 101 | { 102 | if (! setup_receive()) 103 | { 104 | msg << "Problem setting up reception of multicast packets"; 105 | LOG(DLEP_LOG_ERROR, msg); 106 | return false; 107 | } 108 | start_receive(); 109 | } 110 | 111 | if (sending) 112 | { 113 | if (! setup_send()) 114 | { 115 | msg << "Problem setting up sending of multicast packets"; 116 | LOG(DLEP_LOG_ERROR, msg); 117 | return false; 118 | } 119 | start_send(); 120 | } 121 | 122 | return true; 123 | } 124 | 125 | void 126 | PeriodicMcastSendRcv::stop() 127 | { 128 | std::ostringstream msg("stopping"); 129 | LOG(DLEP_LOG_INFO, msg); 130 | 131 | boost::system::error_code ec; 132 | 133 | std::size_t n = send_timer.cancel(ec); 134 | if (ec) 135 | { 136 | msg << "timer cancel error: " << ec; 137 | LOG(DLEP_LOG_ERROR, msg); 138 | } 139 | else 140 | { 141 | msg << n << " timer async operations were cancelled"; 142 | LOG(DLEP_LOG_INFO, msg); 143 | } 144 | 145 | receive_socket.close(ec); 146 | if (ec) 147 | { 148 | msg << "receive socket close error: " << ec; 149 | LOG(DLEP_LOG_ERROR, msg); 150 | } 151 | 152 | send_socket.close(ec); 153 | if (ec) 154 | { 155 | msg << "send socket close error: " << ec; 156 | LOG(DLEP_LOG_ERROR, msg); 157 | } 158 | } 159 | 160 | //***************************************************************************** 161 | 162 | // methods related to sending multicast packets 163 | 164 | bool 165 | PeriodicMcastSendRcv::setup_send() 166 | { 167 | std::ostringstream msg; 168 | 169 | send_endpoint.address(multicast_address); 170 | send_endpoint.port(udp_port); 171 | 172 | msg << "send endpoint=" << send_endpoint; 173 | LOG(DLEP_LOG_INFO, msg); 174 | 175 | try 176 | { 177 | send_socket.open(send_endpoint.protocol()); 178 | 179 | msg << "Done assigning multicast address and port"; 180 | LOG(DLEP_LOG_DEBUG, msg); 181 | 182 | send_socket.set_option(boost::asio::ip::udp::socket::reuse_address(true)); 183 | send_socket.set_option(boost::asio::ip::multicast::enable_loopback(true)); 184 | if (send_ttl != 0) 185 | { 186 | send_socket.set_option(boost::asio::ip::multicast::hops(send_ttl)); 187 | } 188 | 189 | // Explicitly bind to (any IP addr, any port) for clarity. 190 | boost::asio::ip::udp::endpoint bind_endpoint; 191 | 192 | if (multicast_address.is_v6()) 193 | { 194 | bind_endpoint.address(boost::asio::ip::address_v6::any()); 195 | } 196 | else 197 | { 198 | bind_endpoint.address(boost::asio::ip::address_v4::any()); 199 | } 200 | 201 | // let the kernel pick a port 202 | bind_endpoint.port(0); 203 | 204 | send_socket.bind(bind_endpoint); 205 | 206 | msg << "Done setting socket enable loopback and socket reuse option, bind to " 207 | << bind_endpoint << " local endpoint " << send_socket.local_endpoint(); 208 | LOG(DLEP_LOG_DEBUG, msg); 209 | 210 | msg << "Setting outbound interface to: " << interface_address.to_string(); 211 | LOG(DLEP_LOG_DEBUG, msg); 212 | if (interface_address.is_v6()) 213 | { 214 | // XXX-BNC: need to figure out how to bind to IPv6 outgoing interface; 215 | // This gives a "no matching function call" error. 216 | // send_socket.set_option( 217 | // boost::asio::ip::multicast::outbound_interface(interface_address.to_v6())); 218 | } 219 | else 220 | { 221 | send_socket.set_option( 222 | boost::asio::ip::multicast::outbound_interface(interface_address.to_v4())); 223 | } 224 | } 225 | catch (std::exception & e) 226 | { 227 | msg << "Unable to bind and set options on interface"; 228 | LOG(DLEP_LOG_ERROR, msg); 229 | return false; 230 | } 231 | 232 | return true; 233 | } 234 | 235 | void 236 | PeriodicMcastSendRcv::handle_send(DlepMessageBuffer msg_buffer, 237 | const boost::system::error_code & error) 238 | { 239 | if (error) 240 | { 241 | std::ostringstream msg; 242 | msg << "error=" << error; 243 | LOG(DLEP_LOG_ERROR, msg); 244 | } 245 | else 246 | { 247 | send_timer.expires_from_now( 248 | boost::posix_time::seconds(send_interval)); 249 | send_timer.async_wait( 250 | boost::bind(&PeriodicMcastSendRcv::handle_send_timeout, 251 | this, 252 | boost::asio::placeholders::error)); 253 | } 254 | // XXX verify that this frees the vector in msg_buffer? 255 | } 256 | 257 | void 258 | PeriodicMcastSendRcv::handle_send_timeout(const boost::system::error_code & 259 | error) 260 | { 261 | if (error) 262 | { 263 | std::ostringstream msg; 264 | msg << "error=" << error; 265 | LOG(DLEP_LOG_ERROR, msg); 266 | } 267 | else 268 | { 269 | start_send(); 270 | } 271 | } 272 | 273 | void 274 | PeriodicMcastSendRcv::start_send() 275 | { 276 | std::ostringstream msg; 277 | 278 | DlepMessageBuffer msg_buffer = get_message_to_send(); 279 | 280 | msg << "sending packet with size=" << msg_buffer->size() << " to " << send_endpoint; 281 | LOG(DLEP_LOG_DEBUG, msg); 282 | 283 | // By binding the msg_buffer to the asio async completion function 284 | // below, we ensure that the buffer remains allocated until it is 285 | // transmitted, and freed when the completion function returns. 286 | // XXX verify this! 287 | send_socket.async_send_to( 288 | boost::asio::buffer(*msg_buffer), send_endpoint, 289 | boost::bind(&PeriodicMcastSendRcv::handle_send, this, msg_buffer, 290 | boost::asio::placeholders::error)); 291 | } 292 | 293 | //***************************************************************************** 294 | 295 | // methods related to receiving multicast packets 296 | 297 | bool 298 | PeriodicMcastSendRcv::setup_receive() 299 | { 300 | std::ostringstream msg; 301 | unsigned long if_index = if_nametoindex(interface_name.c_str()); 302 | 303 | // set up the receive endpoint 304 | 305 | boost::asio::ip::udp::endpoint receive_endpoint; 306 | receive_endpoint.port(udp_port); 307 | receive_endpoint.address(multicast_address); 308 | 309 | msg << "receive endpoint=" << receive_endpoint; 310 | LOG(DLEP_LOG_INFO, msg); 311 | 312 | try 313 | { 314 | receive_socket.open(receive_endpoint.protocol()); 315 | 316 | // set socket options for multicast: 317 | receive_socket.set_option(boost::asio::ip::udp::socket::reuse_address(true)); 318 | receive_socket.set_option(boost::asio::ip::multicast::enable_loopback(true)); 319 | 320 | receive_socket.bind(receive_endpoint); 321 | 322 | // join multicast group 323 | msg << "Joining Multicast Group: " << multicast_address 324 | << ":" << udp_port; 325 | LOG(DLEP_LOG_INFO, msg); 326 | 327 | if (multicast_address.is_v4()) 328 | { 329 | receive_socket.set_option( 330 | boost::asio::ip::multicast::join_group( 331 | multicast_address.to_v4(), 332 | interface_address.to_v4())); 333 | } 334 | else 335 | { 336 | receive_socket.set_option( 337 | boost::asio::ip::multicast::join_group( 338 | multicast_address.to_v6(), 339 | if_index)); 340 | } 341 | } 342 | catch (std::exception & e) 343 | { 344 | msg << "Unable to bind and set options on receive socket: " << e.what(); 345 | LOG(DLEP_LOG_ERROR, msg); 346 | return false; 347 | } 348 | 349 | msg << "Finished Setting Socket Options - Initiating receive"; 350 | LOG(DLEP_LOG_INFO, msg); 351 | return true; 352 | } 353 | 354 | void 355 | PeriodicMcastSendRcv::start_receive() 356 | { 357 | receive_socket.async_receive_from( 358 | boost::asio::buffer(recv_message), remote_endpoint, 359 | boost::bind(&PeriodicMcastSendRcv::handle_receive, this, 360 | boost::asio::placeholders::error, 361 | boost::asio::placeholders::bytes_transferred)); 362 | } 363 | 364 | void 365 | PeriodicMcastSendRcv::handle_receive(const boost::system::error_code & error, 366 | std::size_t bytes_recvd) 367 | { 368 | std::ostringstream msg; 369 | 370 | if (error) 371 | { 372 | msg << "Got a discovery socket receive error of " << error; 373 | LOG(DLEP_LOG_ERROR, msg); 374 | if (error == boost::asio::error::operation_aborted) 375 | { 376 | // The operation was cancelled, which means we're 377 | // shutting down. We don't want to restart the 378 | // read at the end of this function, so return here. 379 | return; 380 | } 381 | } 382 | else 383 | { 384 | // check for self msg since loopback may be enabled 385 | if (sending and 386 | (remote_endpoint.address() == interface_address) and 387 | (remote_endpoint.port() == send_socket.local_endpoint().port())) 388 | { 389 | msg << "Received Message from self " << remote_endpoint 390 | << " size=" << bytes_recvd << " drop"; 391 | LOG(DLEP_LOG_INFO, msg); 392 | } 393 | else 394 | { 395 | msg << "Received Message from " << remote_endpoint 396 | << " size=" << bytes_recvd; 397 | LOG(DLEP_LOG_INFO, msg); 398 | 399 | // Copy the received message to a DlepMessageBuffer 400 | 401 | DlepMessageBuffer msg_buffer {new std::vector(bytes_recvd)}; 402 | memcpy(msg_buffer->data(), recv_message, bytes_recvd); 403 | 404 | handle_message(msg_buffer, remote_endpoint); 405 | } 406 | } 407 | 408 | start_receive(); 409 | } 410 | 411 | -------------------------------------------------------------------------------- /DlepClient.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Dynamic Link Exchange Protocol (DLEP) 3 | * 4 | * Copyright (C) 2015, 2016, 2019 Massachusetts Institute of Technology 5 | */ 6 | 7 | /// @file 8 | /// This is the abstract interface that the DLEP client (library user) 9 | /// must present to the DLEP service (library). 10 | /// I.e., the DLEP client implements this interface and the 11 | /// DLEP service calls it. 12 | /// Clients should include this file indirectly by including DlepInit.h. 13 | 14 | #ifndef DLEP_CLIENT_H 15 | #define DLEP_CLIENT_H 16 | 17 | #include 18 | #include // for ip::address 19 | #include 20 | #include "DlepCommon.h" 21 | 22 | namespace LLDLEP 23 | { 24 | 25 | /// This is the abstract interface that the DLEP client (library user) 26 | /// must present to the DLEP service (library). 27 | /// 28 | /// At library initialization time (DlepInit), the client passes a 29 | /// pointer to an object that implements the DlepClient interface. 30 | /// The DLEP library calls these methods to get information from the 31 | /// client or notify the client of events related to the DLEP 32 | /// protocol. The DLEP client subclasses from this class and 33 | /// implements all of the required methods. The DLEP library calls 34 | /// these methods from its own internal threads, distinct from the 35 | /// client's threads. The client must be prepared for this, possibly 36 | /// implementing mutex mechanisms as appropriate. 37 | class DlepClient 38 | { 39 | public: 40 | 41 | /// Possible types for configuration parameter values. 42 | typedef boost::variant < bool, 43 | unsigned int, 44 | std::string, 45 | boost::asio::ip::address, 46 | std::vector 47 | > ConfigValue; 48 | 49 | // There is an overloaded get_config_parameter method for each parameter 50 | // type that can be returned. I could probably do this more elegantly 51 | // with templates. 52 | 53 | /// Get a configuration parameter of any type defined in ConfigValue. 54 | /// @param[in] parameter_name 55 | /// the name of the parameter to retrieve 56 | /// @param[out] value 57 | /// place to store the parameter's value 58 | /// @throw BadParameterName if parameter_name does not exist 59 | virtual void get_config_parameter(const std::string & parameter_name, 60 | ConfigValue * value) = 0; 61 | 62 | /// Get a boolean configuration parameter. 63 | /// @param[in] parameter_name 64 | /// the name of the parameter to retrieve 65 | /// @param[out] value 66 | /// place to store the parameter's value 67 | /// @throw BadParameterName if parameter_name does not exist 68 | virtual void get_config_parameter(const std::string & parameter_name, 69 | bool * value) = 0; 70 | 71 | /// Get an unsigned int configuration parameter. 72 | /// @param[in] parameter_name 73 | /// the name of the parameter to retrieve 74 | /// @param[out] value 75 | /// place to store the parameter's value 76 | /// @throw BadParameterName if parameter_name does not exist 77 | virtual void get_config_parameter(const std::string & parameter_name, 78 | unsigned int * value) = 0; 79 | 80 | /// Get a string configuration parameter. 81 | /// @param[in] parameter_name 82 | /// the name of the parameter to retrieve 83 | /// @param[out] value 84 | /// place to store the parameter's value 85 | /// @throw BadParameterName if parameter_name does not exist 86 | virtual void get_config_parameter(const std::string & parameter_name, 87 | std::string * value) = 0; 88 | 89 | /// Get an IP address (v4 or v6) configuration parameter. 90 | /// @param[in] parameter_name 91 | /// the name of the parameter to retrieve 92 | /// @param[out] value 93 | /// place to store the parameter's value 94 | /// @throw BadParameterName if parameter_name does not exist 95 | virtual void get_config_parameter(const std::string & parameter_name, 96 | boost::asio::ip::address * value) = 0; 97 | 98 | /// Get a vector configuration parameter. 99 | /// @param[in] parameter_name 100 | /// the name of the parameter to retrieve 101 | /// @param[out] value 102 | /// place to store the parameter's value 103 | /// @throw BadParameterName if parameter_name does not exist 104 | virtual void get_config_parameter(const std::string & parameter_name, 105 | std::vector * value) = 0; 106 | 107 | /// Exception class for get_config_parameter methods. 108 | class BadParameterName : public std::runtime_error 109 | { 110 | public: 111 | /// Name of the parameter that did not exist. 112 | std::string parameter_name; 113 | explicit BadParameterName(const std::string & pn) : 114 | runtime_error("Missing value for parameter " + pn), 115 | parameter_name(pn) {} 116 | }; 117 | 118 | /// Give the client a chance to modify the data items sent during 119 | /// session establishment. 120 | /// 121 | /// @param[in] peer_id 122 | /// uniquely identifies the peer 123 | /// @param[in] data_items 124 | /// Proposed data items that will be sent to the peer. 125 | /// If Dlep is configured as a router, these data 126 | /// items are sent in a Session Initialization message. 127 | /// If Dlep is configured as a modem, these data 128 | /// items are sent in a Session Initialization Response 129 | /// message. The client can add, change, or remove any 130 | /// data items from the list. 131 | /// @return 132 | /// true if the data_items were modified, else false 133 | virtual bool peer_init(const std::string & peer_id, 134 | DataItems & data_items) {return false;} 135 | 136 | /// Notify the client that a new peer session is up. 137 | /// @param[in] peer_info 138 | /// contains detailed information about the peer 139 | virtual void peer_up(const LLDLEP::PeerInfo & peer_info) = 0; 140 | 141 | /// Notify the client that a peer has been updated. 142 | /// @param[in] peer_id 143 | /// uniquely identifies the peer 144 | /// @param[in] data_items 145 | /// Data items that have changed for this peer 146 | virtual void peer_update(const std::string & peer_id, 147 | const DataItems & data_items) = 0; 148 | 149 | /// Notify the client that the peer session is down. 150 | /// @param[in] peer_id 151 | /// uniquely identifies the peer 152 | virtual void peer_down(const std::string & peer_id) = 0; 153 | 154 | /// Notify the client that a new destination from the peer is up. 155 | /// @param[in] peer_id 156 | /// the peer reporting on the destination 157 | /// @param[in] mac_address 158 | /// the destination that is up. If this represents a 159 | /// multicast address, the modem should begin sending 160 | /// traffic for this address to the router. 161 | /// @param[in] data_items 162 | /// data_items associated with the destination 163 | /// 164 | /// @return 165 | /// A ProtocolString from ProtocolConfig.h specifying the status to 166 | /// put in the Destination Up Response message. Plausible values: 167 | /// - "" (empty string) to omit sending status (interpreted as Success) 168 | /// - ProtocolStrings::Success if all is well 169 | /// - ProtocolStrings::Not_Interested to tell the peer to refrain 170 | /// from sending further messages about this \p mac_address 171 | virtual std::string destination_up(const std::string & peer_id, 172 | const DlepMac & mac_address, 173 | const DataItems & data_items) = 0; 174 | 175 | /// Notify the client that an existing destination's 176 | /// attributes have changed. 177 | /// 178 | /// @param[in] peer_id 179 | /// the peer reporting on the destination 180 | /// @param[in] mac_address 181 | /// the destination that is being updated 182 | /// @param[in] data_items 183 | /// data_items associated with the destination 184 | virtual void destination_update(const std::string & peer_id, 185 | const DlepMac & mac_address, 186 | const DataItems & data_items) = 0; 187 | 188 | /// Notify the client that an existing destination from the peer is down. 189 | /// @param[in] peer_id 190 | /// the peer reporting on the destination 191 | /// @param[in] mac_address 192 | /// the destination that is down. If this represents a 193 | /// multicast address, the modem should cease sending 194 | /// traffic for this address to the router. 195 | /// @param[in] data_items 196 | /// data_items associated with the destination 197 | virtual void destination_down(const std::string & peer_id, 198 | const DlepMac & mac_address, 199 | const DataItems & data_items) = 0; 200 | 201 | /// Request that the client establish specific link characteristics 202 | /// for a destination. 203 | /// 204 | /// This is called when a Link Characteristics Request signal is 205 | /// received with a non-empty list of metrics. If a Link 206 | /// Characteristics Request signal is received that contains an 207 | /// empty list of metrics, it is interpreted as a request for all 208 | /// of the current metrics for \p mac_address. In this case, the 209 | /// response is sent automatically by DlepService without calling 210 | /// this method. 211 | /// 212 | /// See DlepClient::linkchar_reply() for the complete sequence of events 213 | /// in a link characteristics request/response transacation. 214 | /// 215 | /// @param[in] peer_id 216 | /// the peer making the request 217 | /// @param[in] mac_address 218 | /// the destination for which link characteristics are requested. 219 | /// This must be a destination originating from the client 220 | /// side, not from the peer. 221 | /// @param[in] data_items 222 | /// Contains any subset of the metrics defined by the 223 | /// Link Characteristics Request signal of DLEP draft 224 | /// or any configured extensions. The client should 225 | /// reconfigure the link to \p mac_address to have 226 | /// these requested metric values. When the new metric 227 | /// values have taken effect, the client inform the 228 | /// peer by calling DlepService::linkchar_reply(). 229 | /// 230 | virtual void linkchar_request(const std::string & peer_id, 231 | const DlepMac & mac_address, 232 | const DataItems & data_items) = 0; 233 | 234 | /// Notify the client that a Link Characteristics Response signal was 235 | /// received. 236 | /// 237 | /// This is the final API call in the Link Characteristics 238 | /// transaction. The complete sequence looks like this: 239 | /// 240 | /// - Client calls DlepService::linkchar_request() to send the 241 | /// request to the peer 242 | /// - Link Characteristics Request goes over the wire and into the 243 | /// peer's DlepService 244 | /// - Peer is notified by a call to DlepClient::linkchar_request() 245 | /// - Peer processes the linkchar request to assign the new metrics 246 | /// - Peer calls DlepService::linkchar_reply() to send the response 247 | /// to the client 248 | /// - Link Characteristics Response goes over the wire and into the 249 | /// client's DlepService 250 | /// - Client is notified by a call to DlepClient::linkchar_reply() 251 | /// (this method) 252 | /// 253 | /// @param[in] peer_id 254 | /// the peer sending the response 255 | /// @param[in] mac_address 256 | /// the destination to which the link characteristics in 257 | /// \p data_items apply. 258 | /// This must be a destination originating from the peer. 259 | /// @param[in] data_items 260 | /// Contains either: 261 | /// - a full set of metrics for \p mac_address, if the original 262 | /// linkchar request contained no data items, or 263 | /// - the same subset of metrics that appeared in the Link 264 | /// Characteristics Request signal to which this is a response. 265 | /// The metric values are updated to reflect the state after 266 | /// the peer processed the Link Characteristics Request. 267 | /// If the peer was unable to establish one or more of the 268 | /// requested metrics, the list will include a Status data 269 | /// item with the status code Request Denied. 270 | virtual void linkchar_reply(const std::string & peer_id, 271 | const DlepMac & mac_address, 272 | const DataItems & data_items) = 0; 273 | 274 | protected: 275 | DlepClient() {}; 276 | virtual ~DlepClient() {}; 277 | }; 278 | 279 | } // namespace LLDLEP 280 | 281 | #endif // DLEP_CLIENT_H 282 | --------------------------------------------------------------------------------