diff --git a/.appveyor.yml b/.appveyor.yml index d3cfb07..7be5f9a 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -4,5 +4,6 @@ environment: - CMAKE_GENERATOR: "Visual Studio 15 2017 Win64" - CMAKE_GENERATOR: "Visual Studio 15 2017" build_script: - - cmd: git submodule update --init --recursive - - cmd: .\.ci\common\script\appveyor.bat + - cmd: cmake -G "%CMAKE_GENERATOR%" . + - cmd: cmake --build . -- /nologo /property:Configuration=Release + - cmd: ctest --output-on-failure -C Release -a diff --git a/.ci/common b/.ci/common deleted file mode 160000 index 46845c7..0000000 --- a/.ci/common +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 46845c708c5ba015eb17ff2c5d24ac8f960887ac diff --git a/.gitignore b/.gitignore index a24f0d4..796b96d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,44 +1 @@ -/.ninja_deps -/.ninja_log -/.vs -/ALL_BUILD.vcxproj -/ALL_BUILD.vcxproj.filters -/argh.h -/build.ninja -/catch.hpp -/cmake_install.cmake -/CMakeCache.txt -/CMakeFiles/ -/CTestTestfile.cmake -/html -/INSTALL.vcxproj -/INSTALL.vcxproj.filters -/install_manifest.txt -/json.hpp -/latex -/libndt.a -/libndt.dylib -/libndt.sln -/libndt-client -/libndt-client.dir/ -/libndt-client.vcxproj -/libndt-client.vcxproj.filters -/Makefile -/MK_DIST/ -/Release/ -/rules.ninja -/RUN_TESTS.vcxproj -/RUN_TESTS.vcxproj.filters -/Testing/ -/tests-curl -/tests-curl.dir/ -/tests-curl.vcxproj -/tests-curl.vcxproj.filters -/tests-libndt -/tests-libndt.dir/ -/tests-libndt.vcxproj -/tests-libndt.vcxproj.filters -/windows-curl-7.61.0-1.tar.gz -/x64/ -/ZERO_CHECK.vcxproj -/ZERO_CHECK.vcxproj.filters +/build diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 5ef9023..0000000 --- a/.gitmodules +++ /dev/null @@ -1,6 +0,0 @@ -[submodule ".ci/common"] - path = .ci/common - url = https://github.com/measurement-kit/ci-common -[submodule "cmake/Modules"] - path = cmake/Modules - url = https://github.com/measurement-kit/cmake-modules diff --git a/.travis.yml b/.travis.yml index 35c49ee..dac4367 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,4 +10,4 @@ matrix: - env: BUILD_TYPE="ubsan" - env: BUILD_TYPE="vanilla" script: - - ./.ci/common/script/travis $BUILD_TYPE + - ./docker.sh $BUILD_TYPE diff --git a/CMakeLists.txt b/CMakeLists.txt index 9187e14..2a13e1c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,46 +1,52 @@ -cmake_minimum_required(VERSION 3.1.0) -project(libndt LANGUAGES C CXX) +# Autogenerated by `mkbuild`; DO NOT EDIT! -list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/Modules") -include(MkUtils) +cmake_minimum_required(VERSION 3.12.0) +project("libndt") -# Settings +include(CheckIncludeFileCXX) +include(CheckLibraryExists) +include(CheckCXXCompilerFlag) -set(LIBNDT_OPENSSL "${LIBNDT_OPENSSL}" CACHE PATH - "Path where OpenSSL is installed") -if(NOT ("${LIBNDT_OPENSSL}" STREQUAL "")) - list(APPEND CMAKE_REQUIRED_INCLUDES "${LIBNDT_OPENSSL}/include") - list(APPEND CMAKE_LIBRARY_PATH "${LIBNDT_OPENSSL}/lib") -endif() +set(THREADS_PREFER_PTHREAD_FLAG ON) +find_package(Threads REQUIRED) -# Download dependencies -# --------------------- +set(CMAKE_POSITION_INDEPENDENT_CODE ON) +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) +set(CMAKE_C_STANDARD 11) +set(CMAKE_C_STANDARD_REQUIRED ON) +set(CMAKE_C_EXTENSIONS OFF) -MkDownloadAdishavitArgh() -MkDownloadNlohmannJson() -MkDownloadCatchorgCatch2() +list(APPEND CMAKE_REQUIRED_LIBRARIES Threads::Threads) -set(LIBNDT_ENABLE_CURL "TRUE" CACHE BOOL "Whether to enable cURL") -if("${MSVC}" AND "${LIBNDT_ENABLE_CURL}") - MkDownloadMeasurementKitPrebuiltWindowsCurl() - list(APPEND CMAKE_INCLUDE_PATH "${MK_WINDOWS_CURL_INCLUDE_PATH}") - list(APPEND CMAKE_LIBRARY_PATH "${MK_WINDOWS_CURL_LIBRARY_PATH}") - add_definitions(${MK_WINDOWS_CURL_DEFINITIONS}) - list(APPEND LIBNDT_LIBS ${MK_WINDOWS_CURL_EXTRA_LINK_LIBS}) +if(("${WIN32}")) + list(APPEND CMAKE_REQUIRED_LIBRARIES ws2_32 crypt32) endif() -# Checks -# ------ +enable_testing() + +if(("${WIN32}")) + if(("${CMAKE_SIZEOF_VOID_P}" EQUAL 4)) + SET(MK_WIN32_ARCH "x86") + elseif(("${CMAKE_SIZEOF_VOID_P}" EQUAL 8)) + SET(MK_WIN32_ARCH "x64") + else() + message(FATAL_ERROR "Neither 32 not 64 bit") + endif() +endif() +if((${APPLE})) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I/usr/local/include") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L/usr/local/lib") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -L/usr/local/lib") +endif() include(CheckFunctionExists) -include(CheckIncludeFiles) include(CheckSymbolExists) - check_function_exists(strtonum LIBNDT_HAVE_STRTONUM) if(${LIBNDT_HAVE_STRTONUM}) add_definitions(-DLIBNDT_HAVE_STRTONUM) endif() - check_symbol_exists(SO_NOSIGPIPE sys/socket.h LIBNDT_HAVE_SO_NOSIGPIPE) if(${LIBNDT_HAVE_SO_NOSIGPIPE}) add_definitions(-DLIBNDT_HAVE_SO_NOSIGPIPE) @@ -50,81 +56,325 @@ if(${LIBNDT_HAVE_MSG_NOSIGNAL}) add_definitions(-DLIBNDT_HAVE_MSG_NOSIGNAL) endif() -check_include_files(openssl/ssl.h LIBNDT_HAVE_OPENSSL_SSL_H) -find_library(CRYPTO_LIBRARY crypto) -find_library(SSL_LIBRARY ssl) -if (NOT ("${LIBNDT_HAVE_OPENSSL_SSL_H}" STREQUAL "") AND NOT - ("${CRYPTO_LIBRARY}" STREQUAL "CRYPTO_LIBRARY-NOTFOUND") AND NOT - ("${SSL_LIBRARY}" STREQUAL "SSL_LIBRARY-NOTFOUND")) - message(STATUS "crypto library: ${CRYPTO_LIBRARY}") - list(APPEND LIBNDT_LIBS "${CRYPTO_LIBRARY}") - message(STATUS "ssl library: ${SSL_LIBRARY}") - list(APPEND LIBNDT_LIBS "${SSL_LIBRARY}") - add_definitions(-DLIBNDT_HAVE_OPENSSL) -else() - message(WARNING "OpenSSL not found; will disable TLS support") +# +# argh.h +# + +message(STATUS "mkdirAll: ${CMAKE_BINARY_DIR}/.mkbuild/include") +execute_process(COMMAND + ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/.mkbuild/include" + RESULT_VARIABLE FAILURE_1799) +if("${FAILURE_1799}") + message(FATAL_ERROR "${FAILURE_1799}") +endif() +message(STATUS "download: https://raw.githubusercontent.com/adishavit/argh/v1.3.1/argh.h") +file(DOWNLOAD https://raw.githubusercontent.com/adishavit/argh/v1.3.1/argh.h + "${CMAKE_BINARY_DIR}/.mkbuild/include/argh.h" + EXPECTED_HASH SHA256=ddb7dfc18dcf90149735b76fb2cff101067453a1df1943a6911233cb7085980c + TLS_VERIFY ON) +LIST(APPEND CMAKE_REQUIRED_INCLUDES "${CMAKE_BINARY_DIR}/.mkbuild/include") +CHECK_INCLUDE_FILE_CXX("argh.h" MK_HAVE_HEADER_2299) +if(NOT ("${MK_HAVE_HEADER_2299}")) + message(FATAL_ERROR "cannot find: argh.h") +endif() + +# +# catch.hpp +# + +message(STATUS "mkdirAll: ${CMAKE_BINARY_DIR}/.mkbuild/include") +execute_process(COMMAND + ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/.mkbuild/include" + RESULT_VARIABLE FAILURE_2623) +if("${FAILURE_2623}") + message(FATAL_ERROR "${FAILURE_2623}") +endif() +message(STATUS "download: https://github.com/catchorg/Catch2/releases/download/v2.8.0/catch.hpp") +file(DOWNLOAD https://github.com/catchorg/Catch2/releases/download/v2.8.0/catch.hpp + "${CMAKE_BINARY_DIR}/.mkbuild/include/catch.hpp" + EXPECTED_HASH SHA256=2791047e459b981a1035f4ee16a2ad031f5bfb4ba66487ad4d3fc816c8946f61 + TLS_VERIFY ON) +LIST(APPEND CMAKE_REQUIRED_INCLUDES "${CMAKE_BINARY_DIR}/.mkbuild/include") +CHECK_INCLUDE_FILE_CXX("catch.hpp" MK_HAVE_HEADER_3140) +if(NOT ("${MK_HAVE_HEADER_3140}")) + message(FATAL_ERROR "cannot find: catch.hpp") endif() -if(${LIBNDT_ENABLE_CURL}) - find_package(CURL) - if(${CURL_FOUND}) - add_definitions(-DLIBNDT_HAVE_CURL) +if(("${WIN32}")) + + # + # windows-curl-7.61.1-1.tar.gz + # + + message(STATUS "mkdirAll: ${CMAKE_BINARY_DIR}/.mkbuild/download") + execute_process(COMMAND + ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/.mkbuild/download" + RESULT_VARIABLE FAILURE_3521) + if("${FAILURE_3521}") + message(FATAL_ERROR "${FAILURE_3521}") + endif() + message(STATUS "download: https://github.com/measurement-kit/prebuilt/releases/download//testing/windows-curl-7.61.1-1.tar.gz") + file(DOWNLOAD https://github.com/measurement-kit/prebuilt/releases/download//testing/windows-curl-7.61.1-1.tar.gz + "${CMAKE_BINARY_DIR}/.mkbuild/download/windows-curl-7.61.1-1.tar.gz" + EXPECTED_HASH SHA256=424d2f18f0f74dd6a0128f0f4e59860b7d2f00c80bbf24b2702e9cac661357cf + TLS_VERIFY ON) + message(STATUS "Extract: ${CMAKE_BINARY_DIR}/.mkbuild/download/windows-curl-7.61.1-1.tar.gz") + execute_process(COMMAND + ${CMAKE_COMMAND} -E tar xf "${CMAKE_BINARY_DIR}/.mkbuild/download/windows-curl-7.61.1-1.tar.gz" + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/.mkbuild/download" + RESULT_VARIABLE FAILURE_4344) + if("${FAILURE_4344}") + message(FATAL_ERROR "${FAILURE_4344}") + endif() + LIST(APPEND CMAKE_REQUIRED_INCLUDES "${CMAKE_BINARY_DIR}/.mkbuild/download/MK_DIST/windows/curl/7.61.1-1/${MK_WIN32_ARCH}/include") + CHECK_INCLUDE_FILE_CXX("curl/curl.h" MK_HAVE_HEADER_4589) + if(NOT ("${MK_HAVE_HEADER_4589}")) + message(FATAL_ERROR "cannot find: curl/curl.h") + endif() + CHECK_LIBRARY_EXISTS("${CMAKE_BINARY_DIR}/.mkbuild/download/MK_DIST/windows/curl/7.61.1-1/${MK_WIN32_ARCH}/lib/libcurl.lib" "curl_easy_init" "" MK_HAVE_LIB_4748) + if(NOT ("${MK_HAVE_LIB_4748}")) + message(FATAL_ERROR "cannot find: ${CMAKE_BINARY_DIR}/.mkbuild/download/MK_DIST/windows/curl/7.61.1-1/${MK_WIN32_ARCH}/lib/libcurl.lib") + endif() + LIST(APPEND CMAKE_REQUIRED_LIBRARIES "${CMAKE_BINARY_DIR}/.mkbuild/download/MK_DIST/windows/curl/7.61.1-1/${MK_WIN32_ARCH}/lib/libcurl.lib") + LIST(APPEND CMAKE_REQUIRED_DEFINITIONS -DCURL_STATICLIB) +else() + CHECK_INCLUDE_FILE_CXX("curl/curl.h" MK_HAVE_HEADER_5306) + if(NOT ("${MK_HAVE_HEADER_5306}")) + message(FATAL_ERROR "cannot find: curl/curl.h") endif() + CHECK_LIBRARY_EXISTS("curl" "curl_easy_init" "" MK_HAVE_LIB_5465) + if(NOT ("${MK_HAVE_LIB_5465}")) + message(FATAL_ERROR "cannot find: curl") + endif() + LIST(APPEND CMAKE_REQUIRED_LIBRARIES "curl") endif() -# Compiler flags +# +# generic-assets-20190520205742.tar.gz +# -MkSetCompilerFlags() +message(STATUS "mkdirAll: ${CMAKE_BINARY_DIR}/.mkbuild/download") +execute_process(COMMAND + ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/.mkbuild/download" + RESULT_VARIABLE FAILURE_5889) +if("${FAILURE_5889}") + message(FATAL_ERROR "${FAILURE_5889}") +endif() +message(STATUS "download: https://github.com/measurement-kit/generic-assets/releases/download/20190520205742/generic-assets-20190520205742.tar.gz") +file(DOWNLOAD https://github.com/measurement-kit/generic-assets/releases/download/20190520205742/generic-assets-20190520205742.tar.gz + "${CMAKE_BINARY_DIR}/.mkbuild/download/generic-assets-20190520205742.tar.gz" + EXPECTED_HASH SHA256=70d590c20b2ed31fd43cc63709b267672fecfeac7e908d11e845664ddd43b04f + TLS_VERIFY ON) +message(STATUS "Extract: ${CMAKE_BINARY_DIR}/.mkbuild/download/generic-assets-20190520205742.tar.gz") +execute_process(COMMAND + ${CMAKE_COMMAND} -E tar xf "${CMAKE_BINARY_DIR}/.mkbuild/download/generic-assets-20190520205742.tar.gz" + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/.mkbuild/download" + RESULT_VARIABLE FAILURE_6750) +if("${FAILURE_6750}") + message(FATAL_ERROR "${FAILURE_6750}") +endif() -# Library and binary -# ------------------ +# +# json.hpp +# -set(LIBNDT_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} - ${CURL_INCLUDE_DIRS} ${CMAKE_REQUIRED_INCLUDES}) +message(STATUS "mkdirAll: ${CMAKE_BINARY_DIR}/.mkbuild/include") +execute_process(COMMAND + ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/.mkbuild/include" + RESULT_VARIABLE FAILURE_7035) +if("${FAILURE_7035}") + message(FATAL_ERROR "${FAILURE_7035}") +endif() +message(STATUS "download: https://raw.githubusercontent.com/nlohmann/json/v3.6.1/single_include/nlohmann/json.hpp") +file(DOWNLOAD https://raw.githubusercontent.com/nlohmann/json/v3.6.1/single_include/nlohmann/json.hpp + "${CMAKE_BINARY_DIR}/.mkbuild/include/json.hpp" + EXPECTED_HASH SHA256=d2eeb25d2e95bffeb08ebb7704cdffd2e8fca7113eba9a0b38d60a5c391ea09a + TLS_VERIFY ON) +LIST(APPEND CMAKE_REQUIRED_INCLUDES "${CMAKE_BINARY_DIR}/.mkbuild/include") +CHECK_INCLUDE_FILE_CXX("json.hpp" MK_HAVE_HEADER_7587) +if(NOT ("${MK_HAVE_HEADER_7587}")) + message(FATAL_ERROR "cannot find: json.hpp") +endif() -add_executable(libndt-client libndt-client.cpp) -target_include_directories(libndt-client PUBLIC ${LIBNDT_INCLUDES}) -list (APPEND LIBNDT_LIBS ${CURL_LIBRARIES}) -install(FILES libndt.hpp DESTINATION include/measurement-kit/libndt) -install(TARGETS libndt-client DESTINATION bin) -if("${WIN32}" OR "${MINGW}") - list(APPEND LIBNDT_LIBS "ws2_32") - if ("${MINGW}") - list(APPEND LIBNDT_LIBS -static-libgcc -static-libstdc++) +if(("${APPLE}")) + if(EXISTS "/usr/local/opt/openssl@1.1") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I/usr/local/opt/openssl@1.1/include") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I/usr/local/opt/openssl@1.1/include") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L/usr/local/opt/openssl@1.1/lib") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -L/usr/local/opt/openssl@1.1/lib") endif() endif() -list(APPEND LIBNDT_LIBS Threads::Threads) -target_link_libraries(libndt-client "${LIBNDT_LIBS}") +CHECK_INCLUDE_FILE_CXX("openssl/rsa.h" MK_HAVE_HEADER_8172) +if(NOT ("${MK_HAVE_HEADER_8172}")) + message(FATAL_ERROR "cannot find: openssl/rsa.h") +endif() +CHECK_LIBRARY_EXISTS("crypto" "RSA_new" "" MK_HAVE_LIB_8327) +if(NOT ("${MK_HAVE_LIB_8327}")) + message(FATAL_ERROR "cannot find: crypto") +endif() +LIST(APPEND CMAKE_REQUIRED_LIBRARIES "crypto") +CHECK_INCLUDE_FILE_CXX("openssl/ssl.h" MK_HAVE_HEADER_8520) +if(NOT ("${MK_HAVE_HEADER_8520}")) + message(FATAL_ERROR "cannot find: openssl/ssl.h") +endif() +CHECK_LIBRARY_EXISTS("ssl" "SSL_read" "" MK_HAVE_LIB_8675) +if(NOT ("${MK_HAVE_LIB_8675}")) + message(FATAL_ERROR "cannot find: ssl") +endif() +LIST(APPEND CMAKE_REQUIRED_LIBRARIES "ssl") -# Testing -# ------- +# +# Set restrictive compiler flags +# -set(BUILD_TESTING "ON" CACHE BOOL "Whether to build tests") -if(${BUILD_TESTING}) - enable_testing() - if(${CURL_FOUND}) - add_executable(tests-curl curlx_test.cpp) - target_link_libraries(tests-curl "${LIBNDT_LIBS}") - target_include_directories(tests-curl PUBLIC ${LIBNDT_INCLUDES}) - add_test(NAME curl_unit_tests COMMAND tests-curl) - endif() - add_executable(tests-libndt libndt_test.cpp strtonum_test.cpp) - target_link_libraries(tests-libndt "${LIBNDT_LIBS}") - target_include_directories(tests-libndt PUBLIC ${LIBNDT_INCLUDES}) - add_test(NAME other_unit_tests COMMAND tests-libndt) - if(${CURL_FOUND}) # Some tests require cURL for mlab-ns - add_test(NAME simple_test COMMAND libndt-client --verbose - --download --upload) - add_test(NAME json_test COMMAND libndt-client --verbose --json - --download --upload) - add_test(NAME websocket_test COMMAND libndt-client --verbose --websocket - --download --upload) - if(${UNIX}) # On UNIX We auto-discover the CA bundle path - add_test(NAME tls_test COMMAND libndt-client --verbose --download - --upload --tls --json) - # This is how NDT should run - add_test(NAME modern_test COMMAND libndt-client --verbose --download - --upload --tls --json --websocket) +macro(MKSetRestrictiveCompilerFlags) + if(("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") OR + ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")) + set(MK_COMMON_FLAGS "${MK_COMMON_FLAGS} -Werror") + # https://www.owasp.org/index.php/C-Based_Toolchain_Hardening_Cheat_Sheet + set(MK_COMMON_FLAGS "${MK_COMMON_FLAGS} -Wall") + set(MK_COMMON_FLAGS "${MK_COMMON_FLAGS} -Wextra") + set(MK_COMMON_FLAGS "${MK_COMMON_FLAGS} -Wconversion") + set(MK_COMMON_FLAGS "${MK_COMMON_FLAGS} -Wcast-align") + set(MK_COMMON_FLAGS "${MK_COMMON_FLAGS} -Wformat=2") + set(MK_COMMON_FLAGS "${MK_COMMON_FLAGS} -Wformat-security") + set(MK_COMMON_FLAGS "${MK_COMMON_FLAGS} -fno-common") + # Some options are only supported by GCC when we're compiling C code: + if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") + set(MK_COMMON_FLAGS "${MK_COMMON_FLAGS} -Wmissing-prototypes") + set(MK_COMMON_FLAGS "${MK_COMMON_FLAGS} -Wstrict-prototypes") + else() + set(MK_C_FLAGS "${MK_C_FLAGS} -Wmissing-prototypes") + set(MK_C_FLAGS "${MK_C_FLAGS} -Wstrict-prototypes") + endif() + set(MK_COMMON_FLAGS "${MK_COMMON_FLAGS} -Wmissing-declarations") + set(MK_COMMON_FLAGS "${MK_COMMON_FLAGS} -Wstrict-overflow") + if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") + set(MK_COMMON_FLAGS "${MK_COMMON_FLAGS} -Wtrampolines") endif() + set(MK_CXX_FLAGS "${MK_CXX_FLAGS} -Woverloaded-virtual") + set(MK_CXX_FLAGS "${MK_CXX_FLAGS} -Wreorder") + set(MK_CXX_FLAGS "${MK_CXX_FLAGS} -Wsign-promo") + set(MK_CXX_FLAGS "${MK_CXX_FLAGS} -Wnon-virtual-dtor") + set(MK_COMMON_FLAGS "${MK_COMMON_FLAGS} -fstack-protector-all") + if(NOT "${APPLE}" AND NOT "${MINGW}") + set(MK_LD_FLAGS "${MK_LD_FLAGS} -Wl,-z,noexecstack") + set(MK_LD_FLAGS "${MK_LD_FLAGS} -Wl,-z,now") + set(MK_LD_FLAGS "${MK_LD_FLAGS} -Wl,-z,relro") + set(MK_LD_FLAGS "${MK_LD_FLAGS} -Wl,-z,nodlopen") + set(MK_LD_FLAGS "${MK_LD_FLAGS} -Wl,-z,nodump") + elseif(("${MINGW}")) + set(MK_LD_FLAGS "${MK_LD_FLAGS} -static") + endif() + add_definitions(-D_FORTIFY_SOURCES=2) + elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + # TODO(bassosimone): add support for /Wall and /analyze + set(MK_COMMON_FLAGS "${MK_COMMON_FLAGS} /WX /W4 /EHs") + set(MK_LD_FLAGS "${MK_LD_FLAGS} /WX") + else() + message(FATAL_ERROR "Compiler not supported: ${CMAKE_CXX_COMPILER_ID}") endif() -endif() + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${MK_COMMON_FLAGS} ${MK_C_FLAGS}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${MK_COMMON_FLAGS} ${MK_CXX_FLAGS}") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${MK_LD_FLAGS}") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${MK_LD_FLAGS}") + if("${WIN32}") + add_definitions(-D_WIN32_WINNT=0x0600) # for NI_NUMERICSERV and WSAPoll + endif() +endmacro() + +MKSetRestrictiveCompilerFlags() + +# +# Prepare for compiling targets +# + +add_definitions(${CMAKE_REQUIRED_DEFINITIONS}) +include_directories(${CMAKE_REQUIRED_INCLUDES}) + +# +# libndt-client +# + +add_executable( + libndt-client + libndt-client.cpp +) +target_link_libraries( + libndt-client + ${CMAKE_REQUIRED_LIBRARIES} +) + +# +# tests-curl +# + +add_executable( + tests-curl + curlx_test.cpp +) +target_link_libraries( + tests-curl + ${CMAKE_REQUIRED_LIBRARIES} +) + +# +# tests-libndt +# + +add_executable( + tests-libndt + libndt_test.cpp strtonum_test.cpp +) +target_link_libraries( + tests-libndt + ${CMAKE_REQUIRED_LIBRARIES} +) + +# +# test: curl_unit_tests +# + +add_test( + NAME curl_unit_tests COMMAND tests-curl +) + +# +# test: ndt3_test +# + +add_test( + NAME ndt3_test COMMAND libndt-client -verbose -download -upload ndt-iupui-mlab3-lga0t.measurement-lab.org +) + +# +# test: ndt4_test +# + +add_test( + NAME ndt4_test COMMAND libndt-client -verbose -json -websocket -download -upload ndt-iupui-mlab3-lga0t.measurement-lab.org +) + +# +# test: ndt5_test +# + +add_test( + NAME ndt5_test COMMAND libndt-client -verbose -download -upload -tls -json -websocket ndt-iupui-mlab3-lga0t.measurement-lab.org +) + +# +# test: ndt7_test +# + +add_test( + NAME ndt7_test COMMAND libndt-client -verbose -download -upload -ndt7 ndt-iupui-mlab3-lga0t.measurement-lab.org +) + +# +# test: other_unit_tests +# + +add_test( + NAME other_unit_tests COMMAND tests-libndt +) diff --git a/MKBuild.yaml b/MKBuild.yaml new file mode 100644 index 0000000..fd9baf7 --- /dev/null +++ b/MKBuild.yaml @@ -0,0 +1,51 @@ +name: libndt + +docker: bassosimone/mk-debian +docker_tc_disabled: false + +function_checks: +- name: strtonum + define: LIBNDT_HAVE_STRTONUM + +symbol_checks: +- name: SO_NOSIGPIPE + header: sys/socket.h + define: LIBNDT_HAVE_SO_NOSIGPIPE +- name: MSG_NOSIGNAL + header: sys/socket.h + define: LIBNDT_HAVE_MSG_NOSIGNAL + +dependencies: +- github.com/adishavit/argh +- github.com/catchorg/catch2 +- github.com/curl/curl +- github.com/measurement-kit/generic-assets +- github.com/nlohmann/json +- github.com/openssl/openssl + +targets: + executables: + libndt-client: + compile: [libndt-client.cpp] + tests-curl: + compile: [curlx_test.cpp] + tests-libndt: + compile: [libndt_test.cpp strtonum_test.cpp] + +tests: + curl_unit_tests: + command: tests-curl + other_unit_tests: + command: tests-libndt + ndt3_test: + command: libndt-client -verbose -download -upload + ndt-iupui-mlab3-lga0t.measurement-lab.org + ndt4_test: + command: libndt-client -verbose -json -websocket -download -upload + ndt-iupui-mlab3-lga0t.measurement-lab.org + ndt5_test: + command: libndt-client -verbose -download -upload -tls -json -websocket + ndt-iupui-mlab3-lga0t.measurement-lab.org + ndt7_test: + command: libndt-client -verbose -download -upload -ndt7 + ndt-iupui-mlab3-lga0t.measurement-lab.org diff --git a/README.md b/README.md index d948595..3233b7f 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,10 @@ https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json.hpp) before proceeding. The minimum supported version is v3.0.0. Put `json.hpp` in the current working directory. +Libndt depends on OpenSSL (for TLS support and in the future for +WebSocket support) and cURL (to autodiscover servers). CMake will +fail if such dependencies are not installed. + Then, download [libndt.hpp]( https://github.com/measurement-kit/libndt/blob/master/libndt.hpp) and put it in the current working directory. @@ -37,18 +41,6 @@ int main() { Compile with `g++ -std=c++11 -Wall -Wextra -I. -o main main.cpp`. -Libndt optionally depends on OpenSSL (for TLS support and in the future for -WebSocket support) and cURL (to autodiscover servers). You can use the following -preprocessor macros to tell libndt that such dependencies are available: - -- `LIBNDT_HAVE_OPENSSL`: just define this macro to use OpenSSL (it does not - matter whether the macro is defined to a true or false value); - -- `LIBNDT_HAVE_CURL`: just define to use cURL (likewise). - -If these dependencies are not installed in canonical locations, make sure you -add the pass the compiler the proper flags. - See [codedocs.xyz/measurement-kit/libndt]( https://codedocs.xyz/measurement-kit/libndt/) for API documentation; [libndt.hpp](libndt.hpp) for the full API. diff --git a/cmake/Modules b/cmake/Modules deleted file mode 160000 index 3c70b2f..0000000 --- a/cmake/Modules +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 3c70b2f60d313ee5a58a97d8c4e94c6e38f64360 diff --git a/docker.sh b/docker.sh new file mode 100755 index 0000000..9e2c06e --- /dev/null +++ b/docker.sh @@ -0,0 +1,95 @@ +#!/bin/sh -e +# Autogenerated by 'mkbuild'; DO NOT EDIT! + +USAGE="Usage: $0 asan|clang|coverage|ubsan|vanilla" + +if [ $# -eq 1 ]; then + INTERNAL=0 + BUILD_TYPE="$1" +elif [ $# -eq 2 -a "$1" = "-internal" ]; then + INTERNAL=1 + BUILD_TYPE="$2" +else + echo "$USAGE" 1>&2 + exit 1 +fi + +if [ "$CODECOV_TOKEN" = "" ]; then + echo "WARNING: CODECOV_TOKEN is not set" 1>&2 +fi +if [ "$TRAVIS_BRANCH" = "" ]; then + echo "WARNING: TRAVIS_BRANCH is not set" 1>&2 +fi + +set -x + +if [ $INTERNAL -eq 0 ]; then + exec docker run --cap-add=NET_ADMIN \ + --cap-add=SYS_PTRACE \ + -e CODECOV_TOKEN=$CODECOV_TOKEN \ + -e TRAVIS_BRANCH=$TRAVIS_BRANCH \ + -v "$(pwd):/mk" \ + --workdir /mk \ + -t bassosimone/mk-debian \ + ./docker.sh -internal "$1" +fi + +env | grep -v TOKEN | sort + +# Select the proper build flags depending on the build type +if [ "$BUILD_TYPE" = "asan" ]; then + export CFLAGS="-fsanitize=address -O1 -fno-omit-frame-pointer" + export CXXFLAGS="-fsanitize=address -O1 -fno-omit-frame-pointer" + export LDFLAGS="-fsanitize=address -fno-omit-frame-pointer" + export CMAKE_BUILD_TYPE="Debug" + +elif [ "$BUILD_TYPE" = "clang" ]; then + export CMAKE_BUILD_TYPE="Release" + export CXXFLAGS="-stdlib=libc++" + export CC=clang + export CXX=clang++ + +elif [ "$BUILD_TYPE" = "coverage" ]; then + export CFLAGS="-O0 -g -fprofile-arcs -ftest-coverage" + export CMAKE_BUILD_TYPE="Debug" + export CXXFLAGS="-O0 -g -fprofile-arcs -ftest-coverage" + export LDFLAGS="-lgcov" + +elif [ "$BUILD_TYPE" = "ubsan" ]; then + export CFLAGS="-fsanitize=undefined -fno-sanitize-recover" + export CXXFLAGS="-fsanitize=undefined -fno-sanitize-recover" + export LDFLAGS="-fsanitize=undefined" + export CMAKE_BUILD_TYPE="Debug" + +elif [ "$BUILD_TYPE" = "vanilla" ]; then + export CMAKE_BUILD_TYPE="Release" + +else + echo "$0: BUILD_TYPE not in: asan, clang, coverage, ubsan, vanilla" 1>&2 + exit 1 +fi + +# Configure and make equivalent +mkdir -p build/$BUILD_TYPE +cd build/$BUILD_TYPE +cmake -GNinja -DCMAKE_BUILD_TYPE=$CMAKE_BUILD_TYPE ../../ +cmake --build . -- -v + +# Make sure we don't consume too much resources by bumping latency. Not all +# repositories need this feature. For them the code is commented out. +tc qdisc add dev eth0 root netem delay 200ms 10ms + +# Make check equivalent +ctest --output-on-failure -a -j1 + +# Stop adding latency. Commented out if we don't need it. +tc qdisc del dev eth0 root + +# Measure and possibly report the test coverage +if [ "$BUILD_TYPE" = "coverage" ]; then + lcov --directory . --capture -o lcov.info + if [ "$CODECOV_TOKEN" != "" ]; then + curl -fsSL -o codecov.sh https://codecov.io/bash + bash codecov.sh -X gcov -Z -f lcov.info + fi +fi diff --git a/libndt.hpp b/libndt.hpp index baa203a..63f1743 100644 --- a/libndt.hpp +++ b/libndt.hpp @@ -91,16 +91,12 @@ #include #include -#ifdef LIBNDT_HAVE_OPENSSL // Define this macro to enable OpenSSL support #include #include #include #include -#endif -#ifdef LIBNDT_HAVE_CURL // Likewise but to enable cURL support #include -#endif namespace measurement_kit { namespace libndt { @@ -511,7 +507,6 @@ class Client { // // Note that we cannot have ndt7 without OpenSSL. -#ifdef LIBNDT_HAVE_OPENSSL // ndt7_download performs a ndt7 download. Returns true if the download // succeeds and false in case of failure. bool ndt7_download() noexcept; @@ -521,7 +516,6 @@ class Client { // ndt7_connect connects to @p url_path. bool ndt7_connect(std::string url_path) noexcept; -#endif // LIBNDT_HAVE_OPENSSL // NDT protocol API // ```````````````` @@ -703,7 +697,6 @@ class Client { // ``````````````````` // // This section contains functionality used by cURL. -#ifdef LIBNDT_HAVE_CURL class CurlDeleter { public: void operator()(CURL *handle) noexcept; @@ -738,7 +731,6 @@ class Client { virtual CURLcode curlx_getinfo_response_code( UniqueCurl &handle, long *response_code) noexcept; -#endif // LIBNDT_HAVE_CURL virtual bool query_mlabns_curl(const std::string &url, long timeout, std::string *body) noexcept; @@ -832,9 +824,7 @@ class Client { Socket sock_ = (Socket)-1; std::vector granted_suite_; Settings settings_; -#ifdef LIBNDT_HAVE_OPENSSL std::map fd_to_ssl_; -#endif #ifdef _WIN32 Winsock winsock_; #endif @@ -964,7 +954,6 @@ constexpr size_t msg_kickoff_size = sizeof(msg_kickoff) - 1; // Private utils // ````````````` -#ifdef LIBNDT_HAVE_OPENSSL // Format OpenSSL error as a C++ string. static std::string ssl_format_error() noexcept { std::stringstream ss; @@ -977,7 +966,6 @@ static std::string ssl_format_error() noexcept { } return ss.str(); } -#endif // LIBNDT_HAVE_OPENSSL // Map an error code to the corresponding string value. static std::string libndt_perror(Err err) noexcept { @@ -1021,12 +1009,10 @@ static std::string libndt_perror(Err err) noexcept { } #undef LIBNDT_PERROR // Tidy // -#ifdef LIBNDT_HAVE_OPENSSL if (err == Err::ssl_generic) { rv += ": "; rv += ssl_format_error(); } -#endif // LIBNDT_HAVE_OPENSSL // return rv; } @@ -1235,7 +1221,6 @@ bool Client::run() noexcept { // TODO(bassosimone): we will eventually want to refactor the code to // make ndt7 the default and ndt5 the optional case. if ((settings_.protocol_flags & protocol_flag_ndt7) != 0) { -#ifdef LIBNDT_HAVE_OPENSSL LIBNDT_EMIT_INFO("using the ndt7 protocol"); if ((settings_.nettest_flags & nettest_flag_download) != 0) { // TODO(bassosimone): for now we do not try with more than one host @@ -1256,10 +1241,6 @@ bool Client::run() noexcept { // TODO(bassosimone): here we may want to warn if the user selects // subtests that we actually do not implement. return true; -#else - LIBNDT_EMIT_WARNING("ndt7: OpenSSL support not compiled in"); - return false; -#endif } if (!connect()) { LIBNDT_EMIT_WARNING("cannot connect to remote host; trying another one"); @@ -1902,7 +1883,6 @@ bool Client::run_upload() noexcept { // ndt7 protocol API // ````````````````` -#ifdef LIBNDT_HAVE_OPENSSL bool Client::ndt7_download() noexcept { if (!ndt7_connect("/ndt/v7/download")) { @@ -2013,8 +1993,6 @@ bool Client::ndt7_connect(std::string url_path) noexcept { return true; } -#endif // LIBNDT_HAVE_OPENSSL - // NDT protocol API // ```````````````` @@ -2841,8 +2819,6 @@ Err Client::ws_recvmsg( // #define OS_EINVAL EINVAL #endif -#ifdef LIBNDT_HAVE_OPENSSL - // - - - BEGIN BIO IMPLEMENTATION - - - { // // This BIO implementation is based on the implementation of rabbitmq-c @@ -3041,8 +3017,6 @@ static Err ssl_retry_unary_op(std::string opname, Client *client, SSL *ssl, return err; } -#endif // LIBNDT_HAVE_OPENSSL - Err Client::netx_maybews_dial(const std::string &hostname, const std::string &port, uint64_t ws_flags, std::string ws_protocol, std::string url_path, @@ -3085,7 +3059,6 @@ Err Client::netx_maybessl_dial(const std::string &hostname, LIBNDT_EMIT_DEBUG("netx_maybessl_dial: TLS not enabled"); return Err::none; } -#ifdef LIBNDT_HAVE_OPENSSL LIBNDT_EMIT_DEBUG("netx_maybetls_dial: about to start TLS handshake"); if (settings_.ca_bundle_path.empty() && settings_.tls_verify_peer) { #ifndef _WIN32 @@ -3192,10 +3165,6 @@ Err Client::netx_maybessl_dial(const std::string &hostname, } LIBNDT_EMIT_DEBUG("SSL handshake complete"); return Err::none; -#else - LIBNDT_EMIT_WARNING("SSL support not compiled in"); - return Err::function_not_supported; -#endif } Err Client::netx_maybesocks5h_dial(const std::string &hostname, @@ -3615,7 +3584,6 @@ Err Client::netx_recv_nonblocking(Socket fd, void *base, Size count, return Err::invalid_argument; } sys_set_last_error(0); -#ifdef LIBNDT_HAVE_OPENSSL if ((settings_.protocol_flags & protocol_flag_tls) != 0) { if (count > INT_MAX) { return Err::invalid_argument; @@ -3633,7 +3601,6 @@ Err Client::netx_recv_nonblocking(Socket fd, void *base, Size count, *actual = (Size)ret; return Err::none; } -#endif auto rv = sys_recv(fd, base, count); if (rv < 0) { assert(rv == -1); @@ -3698,7 +3665,6 @@ Err Client::netx_send_nonblocking(Socket fd, const void *base, Size count, return Err::invalid_argument; } sys_set_last_error(0); -#ifdef LIBNDT_HAVE_OPENSSL if ((settings_.protocol_flags & protocol_flag_tls) != 0) { if (count > INT_MAX) { return Err::invalid_argument; @@ -3716,7 +3682,6 @@ Err Client::netx_send_nonblocking(Socket fd, const void *base, Size count, *actual = (Size)ret; return Err::none; } -#endif auto rv = sys_send(fd, base, count); if (rv < 0) { assert(rv == -1); @@ -3909,7 +3874,6 @@ Err Client::netx_poll( } Err Client::netx_shutdown_both(Socket fd) noexcept { -#ifdef LIBNDT_HAVE_OPENSSL if ((settings_.protocol_flags & protocol_flag_tls) != 0) { if (fd_to_ssl_.count(fd) != 1) { return Err::invalid_argument; @@ -3925,7 +3889,6 @@ Err Client::netx_shutdown_both(Socket fd) noexcept { return err; } } -#endif if (sys_shutdown(fd, LIBNDT_OS_SHUT_RDWR) != 0) { return netx_map_errno(sys_get_last_error()); } @@ -3933,7 +3896,6 @@ Err Client::netx_shutdown_both(Socket fd) noexcept { } Err Client::netx_closesocket(Socket fd) noexcept { -#if LIBNDT_HAVE_OPENSSL if ((settings_.protocol_flags & protocol_flag_tls) != 0) { if (fd_to_ssl_.count(fd) != 1) { return Err::invalid_argument; @@ -3941,7 +3903,6 @@ Err Client::netx_closesocket(Socket fd) noexcept { ::SSL_free(fd_to_ssl_.at(fd)); fd_to_ssl_.erase(fd); } -#endif if (sys_closesocket(fd) != 0) { return netx_map_errno(sys_get_last_error()); } @@ -3950,7 +3911,6 @@ Err Client::netx_closesocket(Socket fd) noexcept { // Dependencies (cURL) // ``````````````````` -#ifdef LIBNDT_HAVE_CURL } // namespace libndt } // namespace measurement_kit extern "C" { @@ -4107,17 +4067,9 @@ CURLcode Client::curlx_getinfo_response_code( handle.get(), CURLINFO_RESPONSE_CODE, response_code); } -#endif // LIBNDT_HAVE_CURL - bool Client::query_mlabns_curl(const std::string &url, long timeout, std::string *body) noexcept { -#ifdef LIBNDT_HAVE_CURL return curlx_get_maybe_socks5(settings_.socks5h_port, url, timeout, body); -#else - (void)url, (void)timeout, (void)body; - LIBNDT_EMIT_WARNING("cURL not compiled in; don't know how to get server"); - return false; -#endif } // Other helpers