├── .gitignore ├── .travis.yml ├── AUTHORS ├── CMakeLists.txt ├── Doxyfile.in ├── LICENSE ├── README.md ├── build.sh ├── cmake ├── Coveralls.cmake ├── CoverallsClear.cmake ├── CoverallsGenerateGcov.cmake ├── GetGitRevisionDescription.cmake ├── GetGitRevisionDescription.cmake.in ├── LCov.cmake └── Uncrustify.cmake ├── config.h.cmake ├── coverage.sh ├── icelib.pc.in ├── include ├── CMakeLists.txt ├── icelib.h ├── icelib_config.h ├── icelib_debugwebserver.h └── icelibtypes.h ├── src ├── CMakeLists.txt ├── fifo.c ├── icelib.c ├── icelib_debugwebserver.c ├── icelib_intern.h ├── icelibtypes.c └── timer.c ├── test ├── CMakeLists.txt ├── ctest.h ├── icelib_ce_test.c ├── icelib_nomination_medialines_test.c ├── icelib_nomination_test.c ├── icelib_running_test.c ├── icelib_test.c ├── icelibtypes_test.c ├── test_utils.c └── test_utils.h └── uncrustify.cfg /.gitignore: -------------------------------------------------------------------------------- 1 | CMakeCache.txt 2 | CMakeFiles 3 | Makefile 4 | cmake_install.cmake 5 | install_manifest.txt 6 | 7 | 8 | # Object files 9 | *.o 10 | *.ko 11 | *.obj 12 | *.elf 13 | 14 | # Precompiled Headers 15 | *.gch 16 | *.pch 17 | 18 | # Libraries 19 | *.lib 20 | *.a 21 | *.la 22 | *.lo 23 | 24 | # Shared objects (inc. Windows DLLs) 25 | *.dll 26 | *.so 27 | *.so.* 28 | *.dylib 29 | 30 | # Executables 31 | *.exe 32 | *.out 33 | *.app 34 | *.i*86 35 | *.x86_64 36 | *.hex 37 | 38 | #Automake with driends 39 | *.m4 40 | build-aux/* 41 | *.guess 42 | config.h 43 | config.h.in 44 | *.log 45 | *.status 46 | configure 47 | libtool 48 | Makefile 49 | stamp-h1 50 | autom4te.cache/* 51 | .libs 52 | 53 | #coverage report files 54 | *.gcno 55 | 56 | #tmp files 57 | *~ 58 | *# 59 | .#* 60 | 61 | *.Plo 62 | *.Po 63 | *.lai 64 | *.sub 65 | *.trs 66 | .deps/ 67 | .dirstamp 68 | 69 | 70 | cscope.files 71 | build 72 | *.make 73 | *.pc 74 | .DS_Store 75 | 76 | .idea 77 | 78 | 79 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | compiler: 3 | 4 | - gcc 5 | env: 6 | - COVERAGE=true 7 | - COVERAGE=false; 8 | matrix: 9 | exclude: 10 | - compiler: clang 11 | env: COVERAGE=true 12 | - compiler: gcc 13 | env: COVERAGE=false 14 | addons: 15 | apt: 16 | sources: 17 | - george-edison55-precise-backports 18 | - ubuntu-toolchain-r-test 19 | packages: 20 | - cmake 21 | - cmake-data 22 | - libbsd-dev 23 | - gcc-5 24 | before_install: 25 | - export PATH=$HOME/.local/bin:$PATH 26 | - pip install cpp-coveralls --user `whoami` 27 | script: 28 | - sudo unlink /usr/bin/gcc && sudo ln -s /usr/bin/gcc-5 /usr/bin/gcc 29 | - ./build.sh all test 30 | after_success: 31 | - if [[ $COVERAGE == 'true' ]]; then ./coverage.sh; cd build && make package_source; fi 32 | notifications: 33 | slack: 34 | secure: KDvBQ+lCNDwnXFKWngmNpBu7SqiE+wFUZTFXM0j5xH6CpoJgyc9bruBjS+IQEgwjuW+IHKPcdMpkuh4wDW3W5byCLummgo39gIsQUGQItelAv9PpSiM1oB2NPPZAA9ZYn2QWvP+oSIszscvb36g2im0AlCpbc7YAcH/snr3+iIVIPHBbrrl1ktNHuNHZP5D92vpJhAQCic7SEhQqILH2neehW1WmC8MMExlmmQwzy8rUJ/J75ipy10wYxmqHnNR8GMiiBEJXKt48BxRq//xwu+GAri6atF3OGzGmZgLD2aavSPiREWi01BM1Mt6SDqMpZaKSDt+ju7IH8h52LTEiOiN1MoPA7T3sarTQBtZW9TGCXiEoxfcA6XXOSZi2WQ8WfemMr3kSrC7LR2OLfQQrDHUXozhXS1gJPRaer75tKMaNNBDkH4AG6efs9NMd37G/jKg/RZvUwA5jXlMKmCz9fKBVxBjF33wmcLrskLqJuHz5a6dqh1yDzetGsPj8vJ/eaLKXGnk37RYBCcHgsKcajiuiYpmKc07AwMF+00TJBZr15K175HE4bzhUKu1BwehCNeLEGTxVZ3hgqMBkbSRDSYGjqrjRFOLvHiR1Y9OHlDFsktlQrNg3VfvF4tQlZcCnogy64837il06bAwBp+pPBOJ+oDQKeYhk6UUklue9yq0= 35 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | # ICElib Authors 2 | # List alphabetically by surname 3 | 4 | Trond Andersen 5 | Pål-Erik Martinsen 6 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # 3 | # top level build file for the icelib library 4 | 5 | ## prepare CMAKE 6 | cmake_minimum_required ( VERSION 3.2.0 ) 7 | set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH}) 8 | include ( Uncrustify ) 9 | include ( GetGitRevisionDescription ) 10 | git_describe(VERSION --tags --dirty=-d) 11 | 12 | string(REGEX REPLACE "^v([0-9]+)\\..*" "\\1" ICELIB_VERSION_MAJOR "${VERSION}") 13 | string(REGEX REPLACE "^v[0-9]+\\.([0-9]+).*" "\\1" ICELIB_VERSION_MINOR "${VERSION}") 14 | string(REGEX REPLACE "^v[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" ICELIB_VERSION_PATCH "${VERSION}") 15 | string(REGEX REPLACE "^v[0-9]+\\.[0-9]+\\.[0-9]+(.*)" "\\1" ICELIB_VERSION_SHA1 "${VERSION}") 16 | mark_as_advanced(ICELIB_VERSION_MAJOR ICELIB_VERSION_MINOR SOCADDRUTIL_VERSION_PATCH) 17 | 18 | 19 | set ( ICELIB_VERSION "${ICELIB_VERSION_MAJOR}.${ICELIB_VERSION_MINOR}.${ICELIB_VERSION_PATCH}" ) 20 | 21 | project ( "icelib" VERSION "${icelib_VERSION}") 22 | 23 | find_package(Doxygen) 24 | 25 | ## setup options 26 | option ( verbose "Produce verbose makefile output" OFF ) 27 | option ( optimize "Set high optimization level" OFF ) 28 | option ( fatal_warnings "Treat build warnings as errors" ON ) 29 | option ( coveralls "Generate coveralls data" ON ) 30 | option ( coveralls_send "Send data to coveralls site" OFF ) 31 | option ( build_docs "Create docs using Doxygen" ${DOXYGEN_FOUND} ) 32 | option ( uncrustify "Uncrustify the source code" ${UNCRUSTIFY_FOUND} ) 33 | 34 | set ( dist_dir ${CMAKE_BINARY_DIR}/dist ) 35 | set ( prefix ${CMAKE_INSTALL_PREFIX} ) 36 | set ( exec_prefix ${CMAKE_INSTALL_PREFIX}/bin ) 37 | set ( libdir ${CMAKE_INSTALL_PREFIX}/lib ) 38 | set ( includedir ${CMAKE_INSTALL_PREFIX}/include ) 39 | configure_file(${CMAKE_CURRENT_SOURCE_DIR}/icelib.pc.in 40 | ${CMAKE_CURRENT_BINARY_DIR}/icelib.pc @ONLY) 41 | install (FILES ${CMAKE_CURRENT_BINARY_DIR}/icelib.pc DESTINATION lib/pkgconfig ) 42 | 43 | set ( package_prefix "${CMAKE_PACKAGE_NAME}-${CMAKE_SYSTEM_NAME}" ) 44 | 45 | set ( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${dist_dir}/bin ) 46 | set ( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${dist_dir}/lib ) 47 | set ( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${dist_dir}/lib ) 48 | set ( CMAKE_BUILD_TYPE Debug ) 49 | 50 | ## check and generate configuration 51 | 52 | include ( CheckIncludeFiles ) 53 | include ( CheckLibraryExists ) 54 | include ( CheckFunctionExists ) 55 | include ( CheckTypeSize ) 56 | 57 | check_include_files ( stdint.h HAVE_STDINT_H ) 58 | check_include_files ( stdlib.h HAVE_STDLIB_H ) 59 | check_include_files ( stdbool.h HAVE_STDBOOL_H ) 60 | #check_function_exists ( arc4random HAVE_ARC4RANDOM ) 61 | #check_library_exists ( pthread pthread_create "" HAVE_LIBPTHREAD ) 62 | #check_library_exists ( m tan "" HAVE_LIBM ) 63 | 64 | 65 | configure_file ( ${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h ) 66 | 67 | ## setup global compiler options 68 | include_directories ( ${CMAKE_CURRENT_BINARY_DIR} ) 69 | if ( CMAKE_C_COMPILER_ID STREQUAL "GNU" OR 70 | CMAKE_C_COMPILER_ID MATCHES "Clang" ) 71 | message ( STATUS "adding GCC/Clang options ") 72 | add_definitions ( -std=gnu11 -Wall -Wextra -pedantic ) 73 | ## disable VLA "is a GNU extension" warning 74 | ##add_definitions ( -Wno-gnu-zero-variadic-macro-arguments ) 75 | if ( fatal_warnings ) 76 | add_definitions ( -Werror ) 77 | endif () 78 | if ( optimize ) 79 | add_definitions ( -O2 ) 80 | endif () 81 | elseif ( MSVC ) 82 | add_definitions ( /W3 ) 83 | if ( fatal_warnings ) 84 | add_definitions ( /WX ) 85 | endif () 86 | else () 87 | message ( FATAL_ERROR "unhandled compiler id: ${CMAKE_C_COMPILER_ID}" ) 88 | endif () 89 | if ( verbose ) 90 | set ( CMAKE_VERBOSE_MAKEFILE ON ) 91 | endif () 92 | 93 | 94 | 95 | install (FILES AUTHORS LICENSE README.md DESTINATION .) 96 | 97 | ## setup packaging 98 | set ( CPACK_GENERATOR "TGZ" ) 99 | set ( CPACK_PACKAGE_VERSION "${PROJECT_VERSION}" ) 100 | set ( CPACK_SOURCE_GENERATOR "TGZ" ) 101 | set ( CPACK_SOURCE_IGNORE_FILES "/\\\\.git/" ) 102 | file(STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/.gitignore igs) 103 | foreach (ig IN ITEMS ${igs}) 104 | # remove comments 105 | string ( REGEX REPLACE "^\\s*#.*" "" ig "${ig}") 106 | # remove any other whitespace 107 | string ( STRIP "${ig}" ig) 108 | # anything left? 109 | if (ig) 110 | # dots are literal 111 | string ( REPLACE "." "\\\\." ig "${ig}" ) 112 | # stars are on thars 113 | string ( REPLACE "*" ".*" ig "${ig}" ) 114 | list ( APPEND CPACK_SOURCE_IGNORE_FILES "/${ig}/" ) 115 | endif() 116 | endforeach() 117 | 118 | #message ( "CPACK_SOURCE_IGNORE_FILES: " ${CPACK_SOURCE_IGNORE_FILES} ) 119 | set ( CPACK_PACKAGE_DESCRIPTION_FILE ${CMAKE_CURRENT_SOURCE_DIR}/README.md ) 120 | set ( CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE" ) 121 | 122 | include ( CPack ) 123 | include ( CTest ) 124 | include ( LCov ) 125 | 126 | UncrustifyTop(${uncrustify}) 127 | 128 | if (build_docs) 129 | if(NOT DOXYGEN_FOUND) 130 | message(FATAL_ERROR "Doxygen is needed to build the documentation.") 131 | endif() 132 | 133 | set(doxyfile_in ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in) 134 | set(doxyfile ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile) 135 | 136 | configure_file(${doxyfile_in} ${doxyfile} @ONLY) 137 | 138 | add_custom_target(doc 139 | COMMAND ${DOXYGEN_EXECUTABLE} ${doxyfile} 140 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} 141 | COMMENT "Generating API documentation wit1h Doxygen" 142 | VERBATIM) 143 | 144 | install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html DESTINATION share/doc) 145 | endif() 146 | 147 | 148 | Include(ExternalProject) 149 | 150 | # setup sockaddr dependency 151 | ExternalProject_Add( 152 | project_sockaddrutil 153 | GIT_REPOSITORY https://github.com/NATTools/sockaddrutil.git 154 | CMAKE_ARGS -Doptimize=OFF -Dbuild_docs=OFF -DCMAKE_INSTALL_PREFIX:PATH= 155 | INSTALL_DIR "${dist_dir}" 156 | UPDATE_DISCONNECTED 1 157 | ) 158 | 159 | ExternalProject_Get_Property(project_sockaddrutil install_dir) 160 | include_directories ( "${install_dir}/include" ) 161 | add_library(sockaddrutil STATIC IMPORTED) 162 | set_property(TARGET sockaddrutil PROPERTY IMPORTED_LOCATION "${install_dir}/lib/${CMAKE_SHARED_MODULE_PREFIX}sockaddrutil${CMAKE_SHARED_LIBRARY_SUFFIX}") 163 | add_dependencies(sockaddrutil project_sockaddrutil) 164 | 165 | # setup stunlib dependency 166 | ExternalProject_Add( 167 | project_stunlib 168 | GIT_REPOSITORY https://github.com/NATTools/stunlib.git 169 | CMAKE_ARGS -Doptimize=OFF -Dbuild_docs=OFF -DCMAKE_INSTALL_PREFIX:PATH= 170 | INSTALL_DIR "${dist_dir}" 171 | UPDATE_DISCONNECTED 1 172 | ) 173 | 174 | ExternalProject_Get_Property(project_stunlib install_dir) 175 | include_directories ( "${install_dir}/include" ) 176 | add_library(stunlib STATIC IMPORTED) 177 | set_property(TARGET stunlib PROPERTY IMPORTED_LOCATION "${install_dir}/lib/${CMAKE_SHARED_MODULE_PREFIX}stunlib${CMAKE_SHARED_LIBRARY_SUFFIX}") 178 | add_dependencies(stunlib project_stunlib) 179 | 180 | ## include the parts 181 | add_subdirectory ( include ) 182 | add_subdirectory ( src ) 183 | add_subdirectory ( test ) 184 | -------------------------------------------------------------------------------- /Doxyfile.in: -------------------------------------------------------------------------------- 1 | PROJECT_NAME = "@CMAKE_PROJECT_NAME@" 2 | PROJECT_NUMBER = @SOCKADDRUTIL_VERSION_MAJOR@.@SOCKADDRUTIL_VERSION_MINOR@.@SOCKADDRUTIL_VERSION_PATCH@ 3 | STRIP_FROM_PATH = @PROJECT_SOURCE_DIR@ \ 4 | @PROJECT_BINARY_DIR@ 5 | INPUT = @PROJECT_SOURCE_DIR@/README.md \ 6 | @PROJECT_SOURCE_DIR@/include 7 | FILE_PATTERNS = *.h 8 | RECURSIVE = YES 9 | USE_MDFILE_AS_MAINPAGE = @PROJECT_SOURCE_DIR@/README.md 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, NATTools 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 18 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/NATTools/icelib.svg?branch=master)](https://travis-ci.org/NATTools/icelib) 2 | [![Coverage Status](https://coveralls.io/repos/github/NATTools/icelib/badge.svg?branch=master)](https://coveralls.io/github/NATTools/icelib?branch=master) 3 | 4 | Coverity Scan Build Status 6 | 7 | [![GitHub version](https://badge.fury.io/gh/NATTools%2Ficelib.svg)](https://github.com/NATTools/icelib/releases) 8 | 9 | # icelib 10 | An ICE implementation. 11 | 12 | ## Compiling 13 | 14 | `build.sh` does the following 15 | 16 | mkdir build (hold all of the build files in a separate directory) 17 | cd build; cmake (create the makefiles) 18 | make (To build the code) 19 | 20 | You will end up with a library you can link 21 | against in build/dist/lib. 22 | 23 | 24 | ## Development 25 | 26 | You need to have [cmake](http://www.cmake.org/) to build. 27 | Note that version 3.2 or newer is needed. (Some linux distributions are a bit slow to update, so manuall install may be needed.) 28 | 29 | ### Unit Tests 30 | 31 | Build and run the checks with 32 | 33 | make -C build test 34 | 35 | If tests fail it can help to run the binaries in `build/dist/test` to see where 36 | they fail. 37 | 38 | Travis will compile and run the tests. 39 | 40 | ### Coverage 41 | 42 | Coveralls use the coverage.sh script to generate coverage reports. 43 | 44 | To manually generate lcov reports you can run the ./coveragereport.sh script. 45 | A nice html page can be found in lcov/index.html 46 | 47 | It can be a bit tricky to get your favorite platform to support gcov and 48 | friends, but do not give up! (I had problems on os-x, but unfortunately I do not 49 | remember how it was fixed) 50 | 51 | ### Coding Standard 52 | 53 | Using uncrustify to clean up code. There is a uncrustify.cfg file that describes 54 | the format. Run uncrustify before posting pull requests. 55 | 56 | [Semantic versioning](http://semver.org/) is used. 57 | 58 | 59 | ## Contributing 60 | 61 | Fork and send pull requests. Please add your name to the AUTHORS list in your 62 | first patch. 63 | 64 | # License 65 | 66 | BSD 2-clause: 67 | 68 | Copyright (c) 2015, ICElib AUTHORS 69 | All rights reserved. 70 | 71 | Redistribution and use in source and binary forms, with or without modification, 72 | are permitted provided that the following conditions are met: 73 | 74 | 1. Redistributions of source code must retain the above copyright notice, this 75 | list of conditions and the following disclaimer. 76 | 77 | 2. Redistributions in binary form must reproduce the above copyright notice, 78 | this list of conditions and the following disclaimer in the documentation 79 | and/or other materials provided with the distribution. 80 | 81 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 82 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 83 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 84 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 85 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 86 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 87 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 88 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 89 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 90 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 91 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | if [ ! -d "build" ]; then 2 | mkdir build 3 | fi 4 | cd build && cmake .. && make CTEST_OUTPUT_ON_FAILURE=TRUE $* 5 | -------------------------------------------------------------------------------- /cmake/Coveralls.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Permission is hereby granted, free of charge, to any person obtaining a copy 3 | # of this software and associated documentation files (the "Software"), to deal 4 | # in the Software without restriction, including without limitation the rights 5 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 6 | # copies of the Software, and to permit persons to whom the Software is 7 | # furnished to do so, subject to the following conditions: 8 | # 9 | # The above copyright notice and this permission notice shall be included in all 10 | # copies or substantial portions of the Software. 11 | # 12 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 15 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 18 | # SOFTWARE. 19 | # 20 | # Copyright (C) 2014 Joakim Söderberg 21 | # 22 | 23 | 24 | # 25 | # Param _COVERAGE_SRCS A list of source files that coverage should be collected for. 26 | # Param _COVERALLS_UPLOAD Upload the result to coveralls? 27 | # 28 | function(coveralls_setup _COVERAGE_SRCS _COVERALLS_UPLOAD) 29 | 30 | if (ARGC GREATER 2) 31 | set(_CMAKE_SCRIPT_PATH ${ARGN}) 32 | message("Coveralls: Using alternate CMake script dir: ${_CMAKE_SCRIPT_PATH}") 33 | else() 34 | set(_CMAKE_SCRIPT_PATH ${PROJECT_SOURCE_DIR}/cmake) 35 | endif() 36 | 37 | if (NOT EXISTS "${_CMAKE_SCRIPT_PATH}/CoverallsClear.cmake") 38 | message(FATAL_ERROR "Coveralls: Missing ${_CMAKE_SCRIPT_PATH}/CoverallsClear.cmake") 39 | endif() 40 | 41 | if (NOT EXISTS "${_CMAKE_SCRIPT_PATH}/CoverallsGenerateGcov.cmake") 42 | message(FATAL_ERROR "Coveralls: Missing ${_CMAKE_SCRIPT_PATH}/CoverallsGenerateGcov.cmake") 43 | endif() 44 | 45 | # When passing a CMake list to an external process, the list 46 | # will be converted from the format "1;2;3" to "1 2 3". 47 | # This means the script we're calling won't see it as a list 48 | # of sources, but rather just one long path. We remedy this 49 | # by replacing ";" with "*" and then reversing that in the script 50 | # that we're calling. 51 | # http://cmake.3232098.n2.nabble.com/Passing-a-CMake-list-quot-as-is-quot-to-a-custom-target-td6505681.html 52 | set(COVERAGE_SRCS_TMP ${_COVERAGE_SRCS}) 53 | set(COVERAGE_SRCS "") 54 | foreach (COVERAGE_SRC ${COVERAGE_SRCS_TMP}) 55 | set(COVERAGE_SRCS "${COVERAGE_SRCS}*${COVERAGE_SRC}") 56 | endforeach() 57 | 58 | #message("Coverage sources: ${COVERAGE_SRCS}") 59 | set(COVERALLS_FILE ${PROJECT_BINARY_DIR}/coveralls.json) 60 | 61 | add_custom_target(coveralls_generate 62 | 63 | # Zero the coverage counters. 64 | COMMAND ${CMAKE_COMMAND} 65 | -P "${_CMAKE_SCRIPT_PATH}/CoverallsClear.cmake" 66 | 67 | # Run regress tests. 68 | COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure 69 | 70 | # Generate Gcov and translate it into coveralls JSON. 71 | # We do this by executing an external CMake script. 72 | # (We don't want this to run at CMake generation time, but after compilation and everything has run). 73 | COMMAND ${CMAKE_COMMAND} 74 | -DCOVERAGE_SRCS="${COVERAGE_SRCS}" # TODO: This is passed like: "a b c", not "a;b;c" 75 | -DCOVERALLS_OUTPUT_FILE="${COVERALLS_FILE}" 76 | -DCOV_PATH="${PROJECT_BINARY_DIR}" 77 | -DPROJECT_ROOT="${PROJECT_SOURCE_DIR}" 78 | -P "${_CMAKE_SCRIPT_PATH}/CoverallsGenerateGcov.cmake" 79 | 80 | WORKING_DIRECTORY ${PROJECT_BINARY_DIR} 81 | COMMENT "Generating coveralls output..." 82 | ) 83 | 84 | if (_COVERALLS_UPLOAD) 85 | message("COVERALLS UPLOAD: ON") 86 | 87 | find_program(CURL_EXECUTABLE curl) 88 | 89 | if (NOT CURL_EXECUTABLE) 90 | message(FATAL_ERROR "Coveralls: curl not found! Aborting") 91 | endif() 92 | 93 | add_custom_target(coveralls_upload 94 | # Upload the JSON to coveralls. 95 | COMMAND ${CURL_EXECUTABLE} 96 | -S -F json_file=@${COVERALLS_FILE} 97 | https://coveralls.io/api/v1/jobs 98 | 99 | DEPENDS coveralls_generate 100 | 101 | WORKING_DIRECTORY ${PROJECT_BINARY_DIR} 102 | COMMENT "Uploading coveralls output...") 103 | 104 | add_custom_target(coveralls DEPENDS coveralls_upload) 105 | else() 106 | message("COVERALLS UPLOAD: OFF") 107 | add_custom_target(coveralls DEPENDS coveralls_generate) 108 | endif() 109 | 110 | endfunction() 111 | 112 | macro(coveralls_turn_on_coverage) 113 | if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug") 114 | message(FATAL_ERROR "Coveralls: Code coverage results with an optimised (non-Debug) build may be misleading! Add -DCMAKE_BUILD_TYPE=Debug") 115 | endif() 116 | 117 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage") 118 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage") 119 | endmacro() 120 | -------------------------------------------------------------------------------- /cmake/CoverallsClear.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Permission is hereby granted, free of charge, to any person obtaining a copy 3 | # of this software and associated documentation files (the "Software"), to deal 4 | # in the Software without restriction, including without limitation the rights 5 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 6 | # copies of the Software, and to permit persons to whom the Software is 7 | # furnished to do so, subject to the following conditions: 8 | # 9 | # The above copyright notice and this permission notice shall be included in all 10 | # copies or substantial portions of the Software. 11 | # 12 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 15 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 18 | # SOFTWARE. 19 | # 20 | # Copyright (C) 2014 Joakim Söderberg 21 | # 22 | 23 | file(REMOVE_RECURSE ${PROJECT_BINARY_DIR}/*.gcda) 24 | 25 | -------------------------------------------------------------------------------- /cmake/CoverallsGenerateGcov.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Permission is hereby granted, free of charge, to any person obtaining a copy 3 | # of this software and associated documentation files (the "Software"), to deal 4 | # in the Software without restriction, including without limitation the rights 5 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 6 | # copies of the Software, and to permit persons to whom the Software is 7 | # furnished to do so, subject to the following conditions: 8 | # 9 | # The above copyright notice and this permission notice shall be included in all 10 | # copies or substantial portions of the Software. 11 | # 12 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 15 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 18 | # SOFTWARE. 19 | # 20 | # Copyright (C) 2014 Joakim Söderberg 21 | # 22 | # This is intended to be run by a custom target in a CMake project like this. 23 | # 0. Compile program with coverage support. 24 | # 1. Clear coverage data. (Recursively delete *.gcda in build dir) 25 | # 2. Run the unit tests. 26 | # 3. Run this script specifying which source files the coverage should be performed on. 27 | # 28 | # This script will then use gcov to generate .gcov files in the directory specified 29 | # via the COV_PATH var. This should probably be the same as your cmake build dir. 30 | # 31 | # It then parses the .gcov files to convert them into the Coveralls JSON format: 32 | # https://coveralls.io/docs/api 33 | # 34 | # Example for running as standalone CMake script from the command line: 35 | # (Note it is important the -P is at the end...) 36 | # $ cmake -DCOV_PATH=$(pwd) 37 | # -DCOVERAGE_SRCS="catcierge_rfid.c;catcierge_timer.c" 38 | # -P ../cmake/CoverallsGcovUpload.cmake 39 | # 40 | CMAKE_MINIMUM_REQUIRED(VERSION 2.8) 41 | 42 | 43 | # 44 | # Make sure we have the needed arguments. 45 | # 46 | if (NOT COVERALLS_OUTPUT_FILE) 47 | message(FATAL_ERROR "Coveralls: No coveralls output file specified. Please set COVERALLS_OUTPUT_FILE") 48 | endif() 49 | 50 | if (NOT COV_PATH) 51 | message(FATAL_ERROR "Coveralls: Missing coverage directory path where gcov files will be generated. Please set COV_PATH") 52 | endif() 53 | 54 | if (NOT COVERAGE_SRCS) 55 | message(FATAL_ERROR "Coveralls: Missing the list of source files that we should get the coverage data for COVERAGE_SRCS") 56 | endif() 57 | 58 | if (NOT PROJECT_ROOT) 59 | message(FATAL_ERROR "Coveralls: Missing PROJECT_ROOT.") 60 | endif() 61 | 62 | # Since it's not possible to pass a CMake list properly in the 63 | # "1;2;3" format to an external process, we have replaced the 64 | # ";" with "*", so reverse that here so we get it back into the 65 | # CMake list format. 66 | string(REGEX REPLACE "\\*" ";" COVERAGE_SRCS ${COVERAGE_SRCS}) 67 | 68 | find_program(GCOV_EXECUTABLE gcov) 69 | 70 | if (NOT GCOV_EXECUTABLE) 71 | message(FATAL_ERROR "gcov not found! Aborting...") 72 | endif() 73 | 74 | find_package(Git) 75 | 76 | # TODO: Add these git things to the coveralls json. 77 | if (GIT_FOUND) 78 | # Branch. 79 | execute_process( 80 | COMMAND ${GIT_EXECUTABLE} rev-parse --abbrev-ref HEAD 81 | WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} 82 | OUTPUT_VARIABLE GIT_BRANCH 83 | OUTPUT_STRIP_TRAILING_WHITESPACE 84 | ) 85 | 86 | macro (git_log_format FORMAT_CHARS VAR_NAME) 87 | execute_process( 88 | COMMAND ${GIT_EXECUTABLE} log -1 --pretty=format:%${FORMAT_CHARS} 89 | WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} 90 | OUTPUT_VARIABLE ${VAR_NAME} 91 | OUTPUT_STRIP_TRAILING_WHITESPACE 92 | ) 93 | endmacro() 94 | 95 | git_log_format(an GIT_AUTHOR_EMAIL) 96 | git_log_format(ae GIT_AUTHOR_EMAIL) 97 | git_log_format(cn GIT_COMMITTER_NAME) 98 | git_log_format(ce GIT_COMMITTER_EMAIL) 99 | git_log_format(B GIT_COMMIT_MESSAGE) 100 | 101 | message("Git exe: ${GIT_EXECUTABLE}") 102 | message("Git branch: ${GIT_BRANCH}") 103 | message("Git author: ${GIT_AUTHOR_NAME}") 104 | message("Git e-mail: ${GIT_AUTHOR_EMAIL}") 105 | message("Git commiter name: ${GIT_COMMITTER_NAME}") 106 | message("Git commiter e-mail: ${GIT_COMMITTER_EMAIL}") 107 | message("Git commit message: ${GIT_COMMIT_MESSAGE}") 108 | 109 | endif() 110 | 111 | ############################# Macros ######################################### 112 | 113 | # 114 | # This macro converts from the full path format gcov outputs: 115 | # 116 | # /path/to/project/root/build/#path#to#project#root#subdir#the_file.c.gcov 117 | # 118 | # to the original source file path the .gcov is for: 119 | # 120 | # /path/to/project/root/subdir/the_file.c 121 | # 122 | macro(get_source_path_from_gcov_filename _SRC_FILENAME _GCOV_FILENAME) 123 | 124 | # /path/to/project/root/build/#path#to#project#root#subdir#the_file.c.gcov 125 | # -> 126 | # #path#to#project#root#subdir#the_file.c.gcov 127 | get_filename_component(_GCOV_FILENAME_WEXT ${_GCOV_FILENAME} NAME) 128 | 129 | # #path#to#project#root#subdir#the_file.c.gcov -> /path/to/project/root/subdir/the_file.c 130 | string(REGEX REPLACE "\\.gcov$" "" SRC_FILENAME_TMP ${_GCOV_FILENAME_WEXT}) 131 | string(REGEX REPLACE "\#" "/" SRC_FILENAME_TMP ${SRC_FILENAME_TMP}) 132 | set(${_SRC_FILENAME} "${SRC_FILENAME_TMP}") 133 | endmacro() 134 | 135 | ############################################################################## 136 | 137 | # Get the coverage data. 138 | file(GLOB_RECURSE GCDA_FILES "${COV_PATH}/*.gcda") 139 | message("GCDA files:") 140 | 141 | # Get a list of all the object directories needed by gcov 142 | # (The directories the .gcda files and .o files are found in) 143 | # and run gcov on those. 144 | foreach(GCDA ${GCDA_FILES}) 145 | message("Process: ${GCDA}") 146 | message("------------------------------------------------------------------------------") 147 | get_filename_component(GCDA_DIR ${GCDA} PATH) 148 | 149 | # 150 | # The -p below refers to "Preserve path components", 151 | # This means that the generated gcov filename of a source file will 152 | # keep the original files entire filepath, but / is replaced with #. 153 | # Example: 154 | # 155 | # /path/to/project/root/build/CMakeFiles/the_file.dir/subdir/the_file.c.gcda 156 | # ------------------------------------------------------------------------------ 157 | # File '/path/to/project/root/subdir/the_file.c' 158 | # Lines executed:68.34% of 199 159 | # /path/to/project/root/subdir/the_file.c:creating '#path#to#project#root#subdir#the_file.c.gcov' 160 | # 161 | # If -p is not specified then the file is named only "the_file.c.gcov" 162 | # 163 | execute_process( 164 | COMMAND ${GCOV_EXECUTABLE} -p -o ${GCDA_DIR} ${GCDA} 165 | WORKING_DIRECTORY ${COV_PATH} 166 | ) 167 | endforeach() 168 | 169 | # TODO: Make these be absolute path 170 | file(GLOB ALL_GCOV_FILES ${COV_PATH}/*.gcov) 171 | 172 | # Get only the filenames to use for filtering. 173 | #set(COVERAGE_SRCS_NAMES "") 174 | #foreach (COVSRC ${COVERAGE_SRCS}) 175 | # get_filename_component(COVSRC_NAME ${COVSRC} NAME) 176 | # message("${COVSRC} -> ${COVSRC_NAME}") 177 | # list(APPEND COVERAGE_SRCS_NAMES "${COVSRC_NAME}") 178 | #endforeach() 179 | 180 | # 181 | # Filter out all but the gcov files we want. 182 | # 183 | # We do this by comparing the list of COVERAGE_SRCS filepaths that the 184 | # user wants the coverage data for with the paths of the generated .gcov files, 185 | # so that we only keep the relevant gcov files. 186 | # 187 | # Example: 188 | # COVERAGE_SRCS = 189 | # /path/to/project/root/subdir/the_file.c 190 | # 191 | # ALL_GCOV_FILES = 192 | # /path/to/project/root/build/#path#to#project#root#subdir#the_file.c.gcov 193 | # /path/to/project/root/build/#path#to#project#root#subdir#other_file.c.gcov 194 | # 195 | # Result should be: 196 | # GCOV_FILES = 197 | # /path/to/project/root/build/#path#to#project#root#subdir#the_file.c.gcov 198 | # 199 | set(GCOV_FILES "") 200 | #message("Look in coverage sources: ${COVERAGE_SRCS}") 201 | message("\nFilter out unwanted GCOV files:") 202 | message("===============================") 203 | 204 | set(COVERAGE_SRCS_REMAINING ${COVERAGE_SRCS}) 205 | 206 | foreach (GCOV_FILE ${ALL_GCOV_FILES}) 207 | 208 | # 209 | # /path/to/project/root/build/#path#to#project#root#subdir#the_file.c.gcov 210 | # -> 211 | # /path/to/project/root/subdir/the_file.c 212 | get_source_path_from_gcov_filename(GCOV_SRC_PATH ${GCOV_FILE}) 213 | 214 | # Is this in the list of source files? 215 | # TODO: We want to match against relative path filenames from the source file root... 216 | list(FIND COVERAGE_SRCS ${GCOV_SRC_PATH} WAS_FOUND) 217 | 218 | if (NOT WAS_FOUND EQUAL -1) 219 | message("YES: ${GCOV_FILE}") 220 | list(APPEND GCOV_FILES ${GCOV_FILE}) 221 | 222 | # We remove it from the list, so we don't bother searching for it again. 223 | # Also files left in COVERAGE_SRCS_REMAINING after this loop ends should 224 | # have coverage data generated from them (no lines are covered). 225 | list(REMOVE_ITEM COVERAGE_SRCS_REMAINING ${GCOV_SRC_PATH}) 226 | else() 227 | message("NO: ${GCOV_FILE}") 228 | endif() 229 | endforeach() 230 | 231 | # TODO: Enable setting these 232 | set(JSON_SERVICE_NAME "travis-ci") 233 | set(JSON_SERVICE_JOB_ID $ENV{TRAVIS_JOB_ID}) 234 | 235 | set(JSON_TEMPLATE 236 | "{ 237 | \"service_name\": \"\@JSON_SERVICE_NAME\@\", 238 | \"service_job_id\": \"\@JSON_SERVICE_JOB_ID\@\", 239 | \"source_files\": \@JSON_GCOV_FILES\@ 240 | }" 241 | ) 242 | 243 | set(SRC_FILE_TEMPLATE 244 | "{ 245 | \"name\": \"\@GCOV_SRC_REL_PATH\@\", 246 | \"source_digest\": \"\@GCOV_CONTENTS_MD5\@\", 247 | \"coverage\": \@GCOV_FILE_COVERAGE\@ 248 | }" 249 | ) 250 | 251 | message("\nGenerate JSON for files:") 252 | message("=========================") 253 | 254 | set(JSON_GCOV_FILES "[") 255 | 256 | # Read the GCOV files line by line and get the coverage data. 257 | foreach (GCOV_FILE ${GCOV_FILES}) 258 | 259 | get_source_path_from_gcov_filename(GCOV_SRC_PATH ${GCOV_FILE}) 260 | file(RELATIVE_PATH GCOV_SRC_REL_PATH "${PROJECT_ROOT}" "${GCOV_SRC_PATH}") 261 | 262 | # The new coveralls API doesn't need the entire source (Yay!) 263 | # However, still keeping that part for now. Will cleanup in the future. 264 | file(MD5 "${GCOV_SRC_PATH}" GCOV_CONTENTS_MD5) 265 | message("MD5: ${GCOV_SRC_PATH} = ${GCOV_CONTENTS_MD5}") 266 | 267 | # Loads the gcov file as a list of lines. 268 | # (We first open the file and replace all occurences of [] with _ 269 | # because CMake will fail to parse a line containing unmatched brackets... 270 | # also the \ to escaped \n in macros screws up things.) 271 | # https://public.kitware.com/Bug/view.php?id=15369 272 | file(READ ${GCOV_FILE} GCOV_CONTENTS) 273 | string(REPLACE "[" "_" GCOV_CONTENTS "${GCOV_CONTENTS}") 274 | string(REPLACE "]" "_" GCOV_CONTENTS "${GCOV_CONTENTS}") 275 | string(REPLACE "\\" "_" GCOV_CONTENTS "${GCOV_CONTENTS}") 276 | file(WRITE ${GCOV_FILE}_tmp "${GCOV_CONTENTS}") 277 | 278 | file(STRINGS ${GCOV_FILE}_tmp GCOV_LINES) 279 | list(LENGTH GCOV_LINES LINE_COUNT) 280 | 281 | # Instead of trying to parse the source from the 282 | # gcov file, simply read the file contents from the source file. 283 | # (Parsing it from the gcov is hard because C-code uses ; in many places 284 | # which also happens to be the same as the CMake list delimeter). 285 | file(READ ${GCOV_SRC_PATH} GCOV_FILE_SOURCE) 286 | 287 | string(REPLACE "\\" "\\\\" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}") 288 | string(REGEX REPLACE "\"" "\\\\\"" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}") 289 | string(REPLACE "\t" "\\\\t" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}") 290 | string(REPLACE "\r" "\\\\r" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}") 291 | string(REPLACE "\n" "\\\\n" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}") 292 | # According to http://json.org/ these should be escaped as well. 293 | # Don't know how to do that in CMake however... 294 | #string(REPLACE "\b" "\\\\b" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}") 295 | #string(REPLACE "\f" "\\\\f" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}") 296 | #string(REGEX REPLACE "\u([a-fA-F0-9]{4})" "\\\\u\\1" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}") 297 | 298 | # We want a json array of coverage data as a single string 299 | # start building them from the contents of the .gcov 300 | set(GCOV_FILE_COVERAGE "[") 301 | 302 | set(GCOV_LINE_COUNT 1) # Line number for the .gcov. 303 | set(DO_SKIP 0) 304 | foreach (GCOV_LINE ${GCOV_LINES}) 305 | #message("${GCOV_LINE}") 306 | # Example of what we're parsing: 307 | # Hitcount |Line | Source 308 | # " 8: 26: if (!allowed || (strlen(allowed) == 0))" 309 | string(REGEX REPLACE 310 | "^([^:]*):([^:]*):(.*)$" 311 | "\\1;\\2;\\3" 312 | RES 313 | "${GCOV_LINE}") 314 | 315 | # Check if we should exclude lines using the Lcov syntax. 316 | string(REGEX MATCH "LCOV_EXCL_START" START_SKIP "${GCOV_LINE}") 317 | string(REGEX MATCH "LCOV_EXCL_END" END_SKIP "${GCOV_LINE}") 318 | string(REGEX MATCH "LCOV_EXCL_LINE" LINE_SKIP "${GCOV_LINE}") 319 | 320 | set(RESET_SKIP 0) 321 | if (LINE_SKIP AND NOT DO_SKIP) 322 | set(DO_SKIP 1) 323 | set(RESET_SKIP 1) 324 | endif() 325 | 326 | if (START_SKIP) 327 | set(DO_SKIP 1) 328 | message("${GCOV_LINE_COUNT}: Start skip") 329 | endif() 330 | 331 | if (END_SKIP) 332 | set(DO_SKIP 0) 333 | endif() 334 | 335 | list(LENGTH RES RES_COUNT) 336 | 337 | if (RES_COUNT GREATER 2) 338 | list(GET RES 0 HITCOUNT) 339 | list(GET RES 1 LINE) 340 | list(GET RES 2 SOURCE) 341 | 342 | string(STRIP ${HITCOUNT} HITCOUNT) 343 | string(STRIP ${LINE} LINE) 344 | 345 | # Lines with 0 line numbers are metadata and can be ignored. 346 | if (NOT ${LINE} EQUAL 0) 347 | 348 | if (DO_SKIP) 349 | set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}null, ") 350 | else() 351 | # Translate the hitcount into valid JSON values. 352 | if (${HITCOUNT} STREQUAL "#####") 353 | set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}0, ") 354 | elseif (${HITCOUNT} STREQUAL "-") 355 | set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}null, ") 356 | else() 357 | set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}${HITCOUNT}, ") 358 | endif() 359 | endif() 360 | endif() 361 | else() 362 | message(WARNING "Failed to properly parse line (RES_COUNT = ${RES_COUNT}) ${GCOV_FILE}:${GCOV_LINE_COUNT}\n-->${GCOV_LINE}") 363 | endif() 364 | 365 | if (RESET_SKIP) 366 | set(DO_SKIP 0) 367 | endif() 368 | math(EXPR GCOV_LINE_COUNT "${GCOV_LINE_COUNT}+1") 369 | endforeach() 370 | 371 | message("${GCOV_LINE_COUNT} of ${LINE_COUNT} lines read!") 372 | 373 | # Advanced way of removing the trailing comma in the JSON array. 374 | # "[1, 2, 3, " -> "[1, 2, 3" 375 | string(REGEX REPLACE ",[ ]*$" "" GCOV_FILE_COVERAGE ${GCOV_FILE_COVERAGE}) 376 | 377 | # Append the trailing ] to complete the JSON array. 378 | set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}]") 379 | 380 | # Generate the final JSON for this file. 381 | message("Generate JSON for file: ${GCOV_SRC_REL_PATH}...") 382 | string(CONFIGURE ${SRC_FILE_TEMPLATE} FILE_JSON) 383 | 384 | set(JSON_GCOV_FILES "${JSON_GCOV_FILES}${FILE_JSON}, ") 385 | endforeach() 386 | 387 | # Loop through all files we couldn't find any coverage for 388 | # as well, and generate JSON for those as well with 0% coverage. 389 | foreach(NOT_COVERED_SRC ${COVERAGE_SRCS_REMAINING}) 390 | 391 | # Loads the source file as a list of lines. 392 | file(STRINGS ${NOT_COVERED_SRC} SRC_LINES) 393 | 394 | set(GCOV_FILE_COVERAGE "[") 395 | set(GCOV_FILE_SOURCE "") 396 | 397 | foreach (SOURCE ${SRC_LINES}) 398 | set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}0, ") 399 | 400 | string(REPLACE "\\" "\\\\" SOURCE "${SOURCE}") 401 | string(REGEX REPLACE "\"" "\\\\\"" SOURCE "${SOURCE}") 402 | string(REPLACE "\t" "\\\\t" SOURCE "${SOURCE}") 403 | string(REPLACE "\r" "\\\\r" SOURCE "${SOURCE}") 404 | set(GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}${SOURCE}\\n") 405 | endforeach() 406 | 407 | # Remove trailing comma, and complete JSON array with ] 408 | string(REGEX REPLACE ",[ ]*$" "" GCOV_FILE_COVERAGE ${GCOV_FILE_COVERAGE}) 409 | set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}]") 410 | 411 | # Generate the final JSON for this file. 412 | message("Generate JSON for non-gcov file: ${NOT_COVERED_SRC}...") 413 | string(CONFIGURE ${SRC_FILE_TEMPLATE} FILE_JSON) 414 | set(JSON_GCOV_FILES "${JSON_GCOV_FILES}${FILE_JSON}, ") 415 | endforeach() 416 | 417 | # Get rid of trailing comma. 418 | string(REGEX REPLACE ",[ ]*$" "" JSON_GCOV_FILES ${JSON_GCOV_FILES}) 419 | set(JSON_GCOV_FILES "${JSON_GCOV_FILES}]") 420 | 421 | # Generate the final complete JSON! 422 | message("Generate final JSON...") 423 | string(CONFIGURE ${JSON_TEMPLATE} JSON) 424 | 425 | file(WRITE "${COVERALLS_OUTPUT_FILE}" "${JSON}") 426 | message("###########################################################################") 427 | message("Generated coveralls JSON containing coverage data:") 428 | message("${COVERALLS_OUTPUT_FILE}") 429 | message("###########################################################################") 430 | -------------------------------------------------------------------------------- /cmake/GetGitRevisionDescription.cmake: -------------------------------------------------------------------------------- 1 | # - Returns a version string from Git 2 | # 3 | # These functions force a re-configure on each git commit so that you can 4 | # trust the values of the variables in your build system. 5 | # 6 | # get_git_head_revision( [ ...]) 7 | # 8 | # Returns the refspec and sha hash of the current head revision 9 | # 10 | # git_describe( [ ...]) 11 | # 12 | # Returns the results of git describe on the source tree, and adjusting 13 | # the output so that it tests false if an error occurs. 14 | # 15 | # git_get_exact_tag( [ ...]) 16 | # 17 | # Returns the results of git describe --exact-match on the source tree, 18 | # and adjusting the output so that it tests false if there was no exact 19 | # matching tag. 20 | # 21 | # Requires CMake 2.6 or newer (uses the 'function' command) 22 | # 23 | # Original Author: 24 | # 2009-2010 Ryan Pavlik 25 | # http://academic.cleardefinition.com 26 | # Iowa State University HCI Graduate Program/VRAC 27 | # 28 | # Copyright Iowa State University 2009-2010. 29 | # Distributed under the Boost Software License, Version 1.0. 30 | # (See accompanying file LICENSE_1_0.txt or copy at 31 | # http://www.boost.org/LICENSE_1_0.txt) 32 | 33 | if(__get_git_revision_description) 34 | return() 35 | endif() 36 | set(__get_git_revision_description YES) 37 | 38 | # We must run the following at "include" time, not at function call time, 39 | # to find the path to this module rather than the path to a calling list file 40 | get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH) 41 | 42 | function(get_git_head_revision _refspecvar _hashvar) 43 | set(GIT_PARENT_DIR "${CMAKE_CURRENT_SOURCE_DIR}") 44 | set(GIT_DIR "${GIT_PARENT_DIR}/.git") 45 | while(NOT EXISTS "${GIT_DIR}") # .git dir not found, search parent directories 46 | set(GIT_PREVIOUS_PARENT "${GIT_PARENT_DIR}") 47 | get_filename_component(GIT_PARENT_DIR ${GIT_PARENT_DIR} PATH) 48 | if(GIT_PARENT_DIR STREQUAL GIT_PREVIOUS_PARENT) 49 | # We have reached the root directory, we are not in git 50 | set(${_refspecvar} "GITDIR-NOTFOUND" PARENT_SCOPE) 51 | set(${_hashvar} "GITDIR-NOTFOUND" PARENT_SCOPE) 52 | return() 53 | endif() 54 | set(GIT_DIR "${GIT_PARENT_DIR}/.git") 55 | endwhile() 56 | # check if this is a submodule 57 | if(NOT IS_DIRECTORY ${GIT_DIR}) 58 | file(READ ${GIT_DIR} submodule) 59 | string(REGEX REPLACE "gitdir: (.*)\n$" "\\1" GIT_DIR_RELATIVE ${submodule}) 60 | get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH) 61 | get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE} ABSOLUTE) 62 | endif() 63 | set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data") 64 | if(NOT EXISTS "${GIT_DATA}") 65 | file(MAKE_DIRECTORY "${GIT_DATA}") 66 | endif() 67 | 68 | if(NOT EXISTS "${GIT_DIR}/HEAD") 69 | return() 70 | endif() 71 | set(HEAD_FILE "${GIT_DATA}/HEAD") 72 | configure_file("${GIT_DIR}/HEAD" "${HEAD_FILE}" COPYONLY) 73 | 74 | configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in" 75 | "${GIT_DATA}/grabRef.cmake" 76 | @ONLY) 77 | include("${GIT_DATA}/grabRef.cmake") 78 | 79 | set(${_refspecvar} "${HEAD_REF}" PARENT_SCOPE) 80 | set(${_hashvar} "${HEAD_HASH}" PARENT_SCOPE) 81 | endfunction() 82 | 83 | function(git_describe _var) 84 | if(NOT GIT_FOUND) 85 | find_package(Git QUIET) 86 | endif() 87 | get_git_head_revision(refspec hash) 88 | if(NOT GIT_FOUND) 89 | set(${_var} "GIT-NOTFOUND" PARENT_SCOPE) 90 | return() 91 | endif() 92 | if(NOT hash) 93 | set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE) 94 | return() 95 | endif() 96 | 97 | # TODO sanitize 98 | #if((${ARGN}" MATCHES "&&") OR 99 | # (ARGN MATCHES "||") OR 100 | # (ARGN MATCHES "\\;")) 101 | # message("Please report the following error to the project!") 102 | # message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}") 103 | #endif() 104 | 105 | #message(STATUS "Arguments to execute_process: ${ARGN}") 106 | 107 | execute_process(COMMAND 108 | "${GIT_EXECUTABLE}" 109 | describe 110 | # ${hash} 111 | ${ARGN} 112 | WORKING_DIRECTORY 113 | "${CMAKE_CURRENT_SOURCE_DIR}" 114 | RESULT_VARIABLE 115 | res 116 | OUTPUT_VARIABLE 117 | out 118 | ERROR_QUIET 119 | OUTPUT_STRIP_TRAILING_WHITESPACE) 120 | if(NOT res EQUAL 0) 121 | set(out "${out}-${res}-NOTFOUND") 122 | endif() 123 | 124 | set(${_var} "${out}" PARENT_SCOPE) 125 | endfunction() 126 | 127 | function(git_get_exact_tag _var) 128 | git_describe(out --exact-match ${ARGN}) 129 | set(${_var} "${out}" PARENT_SCOPE) 130 | endfunction() 131 | -------------------------------------------------------------------------------- /cmake/GetGitRevisionDescription.cmake.in: -------------------------------------------------------------------------------- 1 | # 2 | # Internal file for GetGitRevisionDescription.cmake 3 | # 4 | # Requires CMake 2.6 or newer (uses the 'function' command) 5 | # 6 | # Original Author: 7 | # 2009-2010 Ryan Pavlik 8 | # http://academic.cleardefinition.com 9 | # Iowa State University HCI Graduate Program/VRAC 10 | # 11 | # Copyright Iowa State University 2009-2010. 12 | # Distributed under the Boost Software License, Version 1.0. 13 | # (See accompanying file LICENSE_1_0.txt or copy at 14 | # http://www.boost.org/LICENSE_1_0.txt) 15 | 16 | set(HEAD_HASH) 17 | 18 | file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024) 19 | 20 | string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS) 21 | if(HEAD_CONTENTS MATCHES "ref") 22 | # named branch 23 | string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}") 24 | if(EXISTS "@GIT_DIR@/${HEAD_REF}") 25 | configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY) 26 | else() 27 | configure_file("@GIT_DIR@/packed-refs" "@GIT_DATA@/packed-refs" COPYONLY) 28 | file(READ "@GIT_DATA@/packed-refs" PACKED_REFS) 29 | if(${PACKED_REFS} MATCHES "([0-9a-z]*) ${HEAD_REF}") 30 | set(HEAD_HASH "${CMAKE_MATCH_1}") 31 | endif() 32 | endif() 33 | else() 34 | # detached HEAD 35 | configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY) 36 | endif() 37 | 38 | if(NOT HEAD_HASH) 39 | file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024) 40 | string(STRIP "${HEAD_HASH}" HEAD_HASH) 41 | endif() 42 | -------------------------------------------------------------------------------- /cmake/LCov.cmake: -------------------------------------------------------------------------------- 1 | # TODO: parameterize for reuse 2 | add_custom_target(coverage_report 3 | COMMAND lcov --directory src/CMakeFiles/icelib.dir --capture --output-file icelib.info 4 | COMMAND genhtml --output-directory lcov icelib.info 5 | COMMAND echo "Coverage report in: file://${CMAKE_BINARY_DIR}/lcov/index.html" 6 | ) 7 | -------------------------------------------------------------------------------- /cmake/Uncrustify.cmake: -------------------------------------------------------------------------------- 1 | find_program(UNCRUSTIFY_EXE uncrustify) 2 | if (DEFINED UNCRUSTIFY_EXE) 3 | set (UNCRUSTIFY_FOUND ON) 4 | set (uncrustify_cfg "${PROJECT_SOURCE_DIR}/uncrustify.cfg") 5 | else() 6 | set (UNCRUSTIFY_FOUND OFF) 7 | endif() 8 | 9 | function(UncrustifyTop enabled) 10 | if (NOT enabled) 11 | return() 12 | endif() 13 | 14 | if (NOT UNCRUSTIFY_FOUND) 15 | message(FATAL_ERROR "Uncrustify is needed to pretty up the source.") 16 | endif() 17 | 18 | add_custom_target(uncrustify 19 | COMMENT "Prettying source code with uncrustify") 20 | endfunction() 21 | 22 | function(UncrustifyDir file_list_var) 23 | get_filename_component(THIS_DIR "${CMAKE_CURRENT_SOURCE_DIR}" NAME) 24 | set(THIS_TS "${CMAKE_CURRENT_SOURCE_DIR}/.uncrustify_time") 25 | 26 | add_custom_command( 27 | OUTPUT "${THIS_TS}" 28 | COMMAND "${UNCRUSTIFY_EXE}" --replace --no-backup -c "${uncrustify_cfg}" ${${file_list_var}} 29 | COMMAND touch "${THIS_TS}" 30 | DEPENDS ${${file_list_var}} "${uncrustify_cfg}" 31 | WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" 32 | COMMENT "Uncrustifying ${THIS_DIR}") 33 | add_custom_target( 34 | "uncrustify-${THIS_DIR}" 35 | DEPENDS "${THIS_TS}") 36 | add_dependencies(uncrustify "uncrustify-${THIS_DIR}") 37 | endfunction() 38 | -------------------------------------------------------------------------------- /config.h.cmake: -------------------------------------------------------------------------------- 1 | /* config.h.in. Generated from configure.ac by autoheader. */ 2 | 3 | /* Define to 1 if you have the `arc4random' function. */ 4 | #cmakedefine HAVE_ARC4RANDOM 5 | 6 | /* Define to 1 if you have the header file. */ 7 | #cmakedefine HAVE_DLFCN_H 8 | 9 | /* Define to 1 if you have the header file. */ 10 | #cmakedefine HAVE_INTTYPES_H 11 | 12 | /* Define to 1 if you have the `m' library (-lm). */ 13 | #cmakedefine HAVE_LIBM 14 | 15 | /* Define to 1 if you have the `pthread' library (-lpthread). */ 16 | #cmakedefine HAVE_LIBPTHREAD 17 | 18 | /* Define to 1 if you have the header file. */ 19 | #cmakedefine HAVE_MEMORY_H 20 | 21 | /* Define to 1 if you have the `memset' function. */ 22 | #cmakedefine HAVE_MEMSET 23 | 24 | /* Define to 1 if you have the header file. */ 25 | #cmakedefine HAVE_NETINET_IN_H 26 | 27 | /* Define to 1 if stdbool.h conforms to C99. */ 28 | #cmakedefine HAVE_STDBOOL_H 29 | 30 | /* Define to 1 if you have the header file. */ 31 | #cmakedefine HAVE_STDDEF_H 32 | 33 | /* Define to 1 if you have the header file. */ 34 | #cmakedefine HAVE_STDINT_H 35 | 36 | /* Define to 1 if you have the header file. */ 37 | #cmakedefine HAVE_STDLIB_H 38 | 39 | /* Define to 1 if you have the header file. */ 40 | #cmakedefine HAVE_STRINGS_H 41 | 42 | /* Define to 1 if you have the header file. */ 43 | #cmakedefine HAVE_STRING_H 44 | 45 | /* Define to 1 if you have the header file. */ 46 | #cmakedefine HAVE_SYS_STAT_H 47 | 48 | /* Define to 1 if you have the header file. */ 49 | #cmakedefine HAVE_SYS_TYPES_H 50 | 51 | /* Define to 1 if you have the header file. */ 52 | #cmakedefine HAVE_UNISTD_H 53 | 54 | /* Define to 1 if the system has the type `_Bool'. */ 55 | #cmakedefine HAVE__BOOL 56 | 57 | /* Define to 1 if you have the file `/dev/urandom'. */ 58 | #cmakedefine HAVE__DEV_URANDOM 59 | 60 | /* Define to the sub-directory where libtool stores uninstalled libraries. */ 61 | #cmakedefine LT_OBJDIR 62 | 63 | /* Name of package */ 64 | #cmakedefine PACKAGE 65 | 66 | /* Define to the address where bug reports for this package should be sent. */ 67 | #cmakedefine PACKAGE_BUGREPORT 68 | 69 | /* Define to the full name of this package. */ 70 | #cmakedefine PACKAGE_NAME 71 | 72 | /* Define to the full name and version of this package. */ 73 | #cmakedefine PACKAGE_STRING 74 | 75 | /* Define to the one symbol short name of this package. */ 76 | #cmakedefine PACKAGE_TARNAME 77 | 78 | /* Define to the home page for this package. */ 79 | #cmakedefine PACKAGE_URL 80 | 81 | /* Define to the version of this package. */ 82 | #cmakedefine PACKAGE_VERSION 83 | 84 | /* Define to 1 if you have the ANSI C header files. */ 85 | #cmakedefine STDC_HEADERS 86 | 87 | /* Version number of package */ 88 | #cmakedefine VERSION 89 | 90 | /* Define for Solaris 2.5.1 so the uint32_t typedef from , 91 | , or is not used. If the typedef were allowed, the 92 | #define below would cause a syntax error. */ 93 | #cmakedefine _UINT32_T 94 | 95 | /* Define for Solaris 2.5.1 so the uint64_t typedef from , 96 | , or is not used. If the typedef were allowed, the 97 | #define below would cause a syntax error. */ 98 | #cmakedefine _UINT64_T 99 | 100 | /* Define for Solaris 2.5.1 so the uint8_t typedef from , 101 | , or is not used. If the typedef were allowed, the 102 | #define below would cause a syntax error. */ 103 | #cmakedefine _UINT8_T 104 | 105 | /* Define to the type of a signed integer type of width exactly 32 bits if 106 | such a type exists and the standard includes do not define it. */ 107 | #cmakedefine int32_t 108 | 109 | /* Define to `unsigned int' if does not define. */ 110 | #cmakedefine size_t 111 | 112 | /* Define to the type of an unsigned integer type of width exactly 16 bits if 113 | such a type exists and the standard includes do not define it. */ 114 | #cmakedefine uint16_t 115 | 116 | /* Define to the type of an unsigned integer type of width exactly 32 bits if 117 | such a type exists and the standard includes do not define it. */ 118 | #cmakedefine uint32_t 119 | 120 | /* Define to the type of an unsigned integer type of width exactly 64 bits if 121 | such a type exists and the standard includes do not define it. */ 122 | #cmakedefine uint64_t 123 | 124 | /* Define to the type of an unsigned integer type of width exactly 8 bits if 125 | such a type exists and the standard includes do not define it. */ 126 | #cmakedefine uint8_t 127 | -------------------------------------------------------------------------------- /coverage.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ ! -d "build" ]; then 4 | mkdir build 5 | fi 6 | cd build && cmake .. -DCMAKE_BUILD_TYPE=Debug -Dcoveralls=ON -Dcoveralls_send=ON && make all coveralls 7 | 8 | #coveralls --include src -x '.c' --gcov-options '\-lp' -b src 9 | -------------------------------------------------------------------------------- /icelib.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@prefix@ 2 | exec_prefix=@exec_prefix@ 3 | libdir=@libdir@ 4 | includedir=@includedir@ 5 | 6 | Name: icelib 7 | Description: ICE Implementation 8 | URL: https://github.com/NPPT/icelib 9 | Version: @ICELIB_VERSION@ 10 | Libs: -L${libdir} -licelib 11 | Cflags: -I${includedir} 12 | -------------------------------------------------------------------------------- /include/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | install ( DIRECTORY ../include DESTINATION . 2 | PATTERN CMakeLists.txt EXCLUDE ) 3 | -------------------------------------------------------------------------------- /include/icelib.h: -------------------------------------------------------------------------------- 1 | /* 2 | * See License file 3 | */ 4 | 5 | 6 | 7 | #ifndef ICELIB_H 8 | #define ICELIB_H 9 | 10 | #include "sockaddr_util.h" 11 | #include "icelibtypes.h" 12 | 13 | #include 14 | 15 | #ifdef __cplusplus 16 | extern "C" { 17 | #endif 18 | 19 | #ifdef __GNUC__ 20 | #define FORMAT_CHECK(ff,ee) __attribute__( ( format(printf, ff, ee) ) ) 21 | #else 22 | #define FORMAT_CHECK(ff,ee) 23 | #endif 24 | 25 | 26 | 27 | 28 | /* ----------------------------------------------------------------------------- 29 | * */ 30 | /* */ 31 | /* ===== Callback functions */ 32 | /* */ 33 | 34 | /* */ 35 | /* ----- Callback for sending a Binding Request message (STUN client role) */ 36 | /* */ 37 | typedef ICELIB_Result (* ICELIB_outgoingBindingRequest)(void* 38 | pUserData, 39 | int 40 | proto, 41 | int socket, 42 | const struct sockaddr* 43 | destination, 44 | const struct sockaddr* 45 | source, 46 | uint32_t 47 | userValue1, 48 | uint32_t 49 | userValue2, 50 | uint32_t 51 | componentId, 52 | bool 53 | useRelay, 54 | const char* 55 | pUfragPair, 56 | const char* 57 | pPasswd, 58 | uint32_t 59 | peerPriority, 60 | bool 61 | useCandidate, 62 | bool 63 | iceControlling, 64 | bool 65 | iceControlled, 66 | uint64_t 67 | tieBreaker, 68 | StunMsgId 69 | transactionId); 70 | 71 | /* */ 72 | /* ----- Callback sending a Binding Response message (STUN server role) */ 73 | /* */ 74 | typedef ICELIB_Result (* ICELIB_outgoingBindingResponse)(void* 75 | pUserData, 76 | uint32_t 77 | userValue1, 78 | uint32_t 79 | userValue2, 80 | uint32_t 81 | componentId, 82 | int 83 | sockfd, 84 | int 85 | proto, 86 | const struct sockaddr* 87 | source, 88 | const struct sockaddr* 89 | destination, 90 | const struct sockaddr* 91 | MappedAddress, 92 | uint16_t 93 | errorResponse, 94 | StunMsgId 95 | transactionId, 96 | bool 97 | useRelay, 98 | const char* 99 | pPasswd); 100 | 101 | 102 | /* */ 103 | /* ----- Callback to signal ICE completion */ 104 | /* */ 105 | typedef ICELIB_Result (* ICELIB_connectivityChecksComplete)(void* pUserData, 106 | uint32_t userValue1, 107 | bool 108 | isControlling, 109 | bool iceFailed); 110 | 111 | /* */ 112 | /* ----- Callback to signal that a canidate pair has been nominated */ 113 | /* */ 114 | typedef ICELIB_Result (* ICELIB_nominated)(void* pUserData, 115 | uint32_t userValue1, 116 | uint32_t userValue2, 117 | uint32_t componentId, 118 | uint64_t priority, 119 | int32_t proto, 120 | const struct sockaddr* local, 121 | const struct sockaddr* remote); 122 | 123 | /* */ 124 | /* ----- Callback used to generate keepalives */ 125 | /* */ 126 | typedef ICELIB_Result (* ICELIB_sendKeepAlive)(void* pUserData, 127 | uint32_t userValue1, 128 | uint32_t userValue2, 129 | uint32_t mediaIdx); 130 | 131 | /* */ 132 | /* ----- Callback for cancelling a Binding Request message (STUN client role) */ 133 | /* */ 134 | typedef ICELIB_Result (* ICELIB_outgoingCancelRequest)(void* pUserData, 135 | uint32_t userValue1, 136 | StunMsgId transactionId); 137 | 138 | /* */ 139 | /* ----- Callback for updating password in the media stream (Used to validate 140 | * STUN packets) */ 141 | /* */ 142 | typedef ICELIB_Result (* ICELIB_passwordUpdate)(void* pUserData, 143 | uint32_t userValue1, 144 | uint32_t userValue2, 145 | char* password); 146 | 147 | /* */ 148 | /* ----- Callback for logging */ 149 | /* */ 150 | typedef void (* ICELIB_logCallback)(void* pUserData, 151 | ICELIB_logLevel logLevel, 152 | const char* str); 153 | 154 | 155 | 156 | /* */ 157 | /* ----- ICE callback function pointers and data */ 158 | /* */ 159 | struct tag_ICELIB_INSTANCE; 160 | typedef struct tag_ICELIB_INSTANCE ICELIB_INSTANCE_; 161 | 162 | typedef struct { 163 | ICELIB_connectivityChecksComplete pICELIB_connectivityChecksComplete; 164 | void* pConnectivityChecksCompleteUserData; 165 | ICELIB_INSTANCE_* pInstance; 166 | } ICELIB_CALLBACK_COMPLETE; 167 | 168 | typedef struct { 169 | ICELIB_nominated pICELIB_nominated; 170 | void* pNominatedUserData; 171 | ICELIB_INSTANCE_* pInstance; 172 | } ICELIB_CALLBACK_NOMINATED; 173 | 174 | typedef struct { 175 | ICELIB_outgoingBindingRequest pICELIB_sendBindingRequest; 176 | void* pBindingRequestUserData; 177 | ICELIB_INSTANCE_* pInstance; 178 | } ICELIB_CALLBACK_REQUEST; 179 | 180 | 181 | typedef struct { 182 | ICELIB_outgoingBindingResponse pICELIB_sendBindingResponse; 183 | void* pBindingResponseUserData; 184 | ICELIB_INSTANCE_* pInstance; 185 | } ICELIB_CALLBACK_RESPONSE; 186 | 187 | 188 | typedef struct { 189 | ICELIB_outgoingCancelRequest pICELIB_sendCancelRequest; 190 | void* pCancelRequestUserData; 191 | ICELIB_INSTANCE_* pInstance; 192 | } ICELIB_CALLBACK_CANCEL_REQUEST; 193 | 194 | typedef struct { 195 | ICELIB_sendKeepAlive pICELIB_sendKeepAlive; 196 | void* pUserDataKeepAlive; 197 | ICELIB_INSTANCE_* pInstance; 198 | } ICELIB_CALLBACK_KEEPALIVE; 199 | 200 | 201 | typedef struct { 202 | ICELIB_passwordUpdate pICELIB_passwordUpdate; 203 | void* pUserDataPasswordUpdate; 204 | ICELIB_INSTANCE_* pInstance; 205 | } ICELIB_CALLBACK_PASSWORD_UPDATE; 206 | 207 | typedef struct { 208 | ICELIB_logCallback pICELIB_logCallback; 209 | void* pLogUserData; 210 | ICELIB_INSTANCE_* pInstance; 211 | } ICELIB_CALLBACK_LOG; 212 | 213 | 214 | typedef struct { 215 | ICELIB_CALLBACK_REQUEST callbackRequest; 216 | ICELIB_CALLBACK_RESPONSE callbackResponse; 217 | ICELIB_CALLBACK_KEEPALIVE callbackKeepAlive; 218 | ICELIB_CALLBACK_COMPLETE callbackComplete; 219 | ICELIB_CALLBACK_NOMINATED callbackNominated; 220 | ICELIB_CALLBACK_CANCEL_REQUEST callbackCancelRequest; 221 | ICELIB_CALLBACK_PASSWORD_UPDATE callbackPasswordUpdate; 222 | ICELIB_CALLBACK_LOG callbackLog; 223 | } ICELIB_CALLBACKS; 224 | 225 | 226 | 227 | 228 | /* */ 229 | /* ----- ICE configuration data */ 230 | /* */ 231 | typedef struct { 232 | unsigned int tickIntervalMS; 233 | unsigned int keepAliveIntervalS; 234 | unsigned int maxCheckListPairs; 235 | bool aggressiveNomination; 236 | bool iceLite; 237 | bool dropRflx; 238 | ICELIB_logLevel logLevel; 239 | } ICELIB_CONFIGURATION; 240 | 241 | 242 | /* */ 243 | /* ----- ICE instance data */ 244 | /* */ 245 | typedef struct tag_ICELIB_INSTANCE { 246 | ICELIB_STATE iceState; 247 | ICELIB_CONFIGURATION iceConfiguration; 248 | ICELIB_CALLBACKS callbacks; 249 | ICE_MEDIA localIceMedia; 250 | ICE_MEDIA remoteIceMedia; 251 | bool roleHasSwapped; 252 | bool iceControlling; 253 | bool iceControlled; 254 | bool iceSupportVerified; 255 | uint64_t tieBreaker; 256 | ICELIB_STREAM_CONTROLLER streamControllers[ ICE_MAX_MEDIALINES]; 257 | unsigned int numberOfMediaStreams; 258 | unsigned int roundRobinStreamControllerIndex; 259 | uint32_t tickCount; 260 | uint32_t keepAliveTickCount; 261 | } ICELIB_INSTANCE; 262 | 263 | 264 | 265 | void 266 | ICELIB_logString(const ICELIB_CALLBACK_LOG* pCallbackLog, 267 | ICELIB_logLevel logLevel, 268 | const char* str); 269 | 270 | void 271 | FORMAT_CHECK(3, 272 | 4) ICELIB_logVaString(const ICELIB_CALLBACK_LOG * pCallbackLog, 273 | ICELIB_logLevel logLevel, 274 | const char* fmt, 275 | ...); 276 | /* ----------------------------------------------------------------------------- 277 | * */ 278 | /* */ 279 | /* ----- TEST API Functions */ 280 | /* */ 281 | void 282 | ICELIB_timerConstructor(ICELIB_TIMER* timer, 283 | unsigned int tickIntervalMS); 284 | void 285 | ICELIB_timerStart(ICELIB_TIMER* timer, 286 | unsigned int timeoutMS); 287 | void 288 | ICELIB_timerStop(ICELIB_TIMER* timer); 289 | void 290 | ICELIB_timerTick(ICELIB_TIMER* timer); 291 | bool 292 | ICELIB_timerIsRunning(const ICELIB_TIMER* timer); 293 | bool 294 | ICELIB_timerIsTimedOut(const ICELIB_TIMER* timer); 295 | 296 | 297 | /* ----------------------------------------------------------------------------- 298 | * */ 299 | /* */ 300 | /* ----- API Functions */ 301 | /* */ 302 | 303 | 304 | void 305 | ICELIB_Constructor(ICELIB_INSTANCE* pInstance, 306 | const ICELIB_CONFIGURATION* pConfiguration); 307 | void 308 | ICELIB_Destructor (ICELIB_INSTANCE* pInstance); 309 | 310 | bool 311 | ICELIB_Start(ICELIB_INSTANCE* pInstance, 312 | bool controlling); 313 | void 314 | ICELIB_Stop(ICELIB_INSTANCE* pInstance); 315 | 316 | void 317 | ICELIB_ReStart(ICELIB_INSTANCE* pInstance); 318 | 319 | void 320 | ICELIB_Tick(ICELIB_INSTANCE* pInstance); 321 | 322 | void 323 | ICELIB_setCallbackConnecitivityChecksComplete( 324 | ICELIB_INSTANCE* pInstance, 325 | ICELIB_connectivityChecksComplete pICELIB_connectivityChecksComplete, 326 | void* userData); 327 | 328 | void 329 | ICELIB_setCallbackNominated(ICELIB_INSTANCE* pInstance, 330 | ICELIB_nominated pICELIB_nominated, 331 | void* userData); 332 | void 333 | ICELIB_setCallbackOutgoingBindingRequest( 334 | ICELIB_INSTANCE* pInstance, 335 | ICELIB_outgoingBindingRequest pICELIB_sendBindingRequest, 336 | void* pBindingRequestUserData); 337 | 338 | void 339 | ICELIB_setCallbackOutgoingBindingResponse( 340 | ICELIB_INSTANCE* pInstance, 341 | ICELIB_outgoingBindingResponse pICELIB_sendBindingResponse, 342 | void* pBindingResponseUserData); 343 | 344 | void 345 | ICELIB_setCallbackOutgoingCancelRequest(ICELIB_INSTANCE* pInstance, 346 | ICELIB_outgoingCancelRequest pICELIB_sendBindingCancelRequest, 347 | void* pCancelRequestUserData); 348 | 349 | 350 | void 351 | ICELIB_setCallbackKeepAlive(ICELIB_INSTANCE* pInstance, 352 | ICELIB_sendKeepAlive pICELIB_sendKeepAlive, 353 | void* pUserDataKeepAlive); 354 | 355 | void 356 | ICELIB_setCallbackPasswordUpdate(ICELIB_INSTANCE* pInstance, 357 | ICELIB_passwordUpdate pICELIB_passwordUpdate, 358 | void* pUserDataPasswordUpdate); 359 | 360 | void 361 | ICELIB_setCallbackLog(ICELIB_INSTANCE* pInstance, 362 | ICELIB_logCallback pICELIB_logCallback, 363 | void* pLogUserData, 364 | ICELIB_logLevel logLevel); 365 | 366 | void 367 | ICELIB_incomingBindingResponse(ICELIB_INSTANCE* pInstance, 368 | uint16_t errorResponse, 369 | StunMsgId transactionId, 370 | const struct sockaddr* source, /* 371 | * From 372 | * response 373 | **/ 374 | const struct sockaddr* destination, /* 375 | * From 376 | * response 377 | **/ 378 | const struct sockaddr* mappedAddress); 379 | 380 | void 381 | ICELIB_incomingTimeout(ICELIB_INSTANCE* pInstance, 382 | StunMsgId Transactionid); 383 | 384 | void 385 | ICELIB_incomingBindingRequest(ICELIB_INSTANCE* pInstance, 386 | uint32_t userValue1, 387 | uint32_t userValue2, 388 | const char* pUfragPair, 389 | uint32_t peerPriority, 390 | bool useCandidate, 391 | bool iceControlling, 392 | bool iceControlled, 393 | uint64_t tieBreaker, 394 | StunMsgId transactionId, 395 | int sockfd, 396 | int proto, 397 | const struct sockaddr* source, 398 | const struct sockaddr* destination, 399 | bool fromRelay, 400 | const struct sockaddr* peerAddr, 401 | uint16_t componentId); 402 | 403 | ICE_TURN_STATE 404 | ICELIB_getTurnState(const ICELIB_INSTANCE* pInstance, 405 | uint32_t mediaIdx); 406 | 407 | void 408 | ICELIB_setTurnState(ICELIB_INSTANCE* pInstance, 409 | uint32_t mediaIdx, 410 | ICE_TURN_STATE turnState); 411 | 412 | int32_t 413 | ICELIB_getNumberOfLocalICEMediaLines(const ICELIB_INSTANCE* pInstance); 414 | int32_t 415 | ICELIB_getNumberOfRemoteICEMediaLines(const ICELIB_INSTANCE* pInstance); 416 | 417 | int32_t 418 | ICELIB_getNumberOfLocalCandidates(const ICELIB_INSTANCE* pInstance, 419 | uint32_t idx); 420 | int32_t 421 | ICELIB_getNumberOfRemoteCandidates(const ICELIB_INSTANCE* pInstance, 422 | uint32_t idx); 423 | 424 | const char* 425 | ICELIB_getLocalPassword(const ICELIB_INSTANCE* pInstance, 426 | uint32_t idx); 427 | 428 | uint32_t 429 | ICELIB_getLocalComponentId(const ICELIB_INSTANCE* pInstance, 430 | uint32_t mediaIdx, 431 | uint32_t candIdx); 432 | 433 | uint32_t 434 | ICELIB_getRemoteComponentId(const ICELIB_INSTANCE* pInstance, 435 | uint32_t mediaIdx, 436 | uint32_t candIdx); 437 | 438 | struct sockaddr const* 439 | ICELIB_getLocalConnectionAddr(const ICELIB_INSTANCE* pInstance, 440 | uint32_t mediaIdx, 441 | uint32_t candIdx); 442 | 443 | struct sockaddr const* 444 | ICELIB_getRemoteConnectionAddr(const ICELIB_INSTANCE* pInstance, 445 | uint32_t mediaIdx, 446 | uint32_t candIdx); 447 | 448 | ICE_CANDIDATE_TYPE 449 | ICELIB_getLocalCandidateType(const ICELIB_INSTANCE* pInstance, 450 | uint32_t mediaIdx, 451 | uint32_t candIdx); 452 | 453 | ICE_CANDIDATE_TYPE 454 | ICELIB_getRemoteCandidateType(const ICELIB_INSTANCE* pInstance, 455 | uint32_t mediaIdx, 456 | uint32_t candIdx); 457 | 458 | ICE_TRANSPORT 459 | ICELIB_getRemoteTransport(const ICELIB_INSTANCE* instance, 460 | uint32_t mediaIdx, 461 | uint32_t candIdx); 462 | 463 | ICE_MEDIA const* 464 | ICELIB_getLocalIceMedia(const ICELIB_INSTANCE* pInstance); 465 | 466 | void 467 | ICELIB_disableMediaStream(ICELIB_INSTANCE* pInstance); 468 | int32_t 469 | ICELIB_addRemoteMediaStream(ICELIB_INSTANCE* pInstance, 470 | const char* ufrag, 471 | const char* pwd, 472 | const struct sockaddr* defaultAddr); 473 | 474 | int32_t 475 | ICELIB_setRemoteMediaStream(ICELIB_INSTANCE* pInstance, 476 | uint32_t mediaIdx, 477 | const char* ufrag, 478 | const char* pwd, 479 | const struct sockaddr* defaultAddr); 480 | 481 | int32_t 482 | ICELIB_addRemoteCandidate(ICELIB_INSTANCE* pInstance, 483 | uint32_t mediaIdx, 484 | const char* foundation, 485 | uint32_t foundationLen, 486 | uint32_t componentId, 487 | uint32_t priority, 488 | const char* connectionAddr, 489 | uint16_t port, 490 | ICE_TRANSPORT transport, 491 | ICE_CANDIDATE_TYPE candType); 492 | 493 | int32_t 494 | ICELIB_updateLocalMediaStreamDefaultCandidate(ICELIB_INSTANCE* pInstance, 495 | uint32_t mediaIdx, 496 | ICE_CANDIDATE_TYPE defaultCandType); 497 | 498 | int32_t 499 | ICELIB_addLocalMediaStream(ICELIB_INSTANCE* pInstance, 500 | uint32_t userValue1, 501 | uint32_t userValue2, 502 | ICE_CANDIDATE_TYPE defaultCandType); 503 | 504 | int32_t 505 | ICELIB_setLocalMediaStream(ICELIB_INSTANCE* pInstance, 506 | uint32_t mediaIdx, 507 | uint32_t userValue1, 508 | uint32_t userValue2, 509 | ICE_CANDIDATE_TYPE defaultCandType); 510 | 511 | int32_t 512 | ICELIB_addLocalCandidate(ICELIB_INSTANCE* pInstance, 513 | uint32_t mediaIdx, 514 | uint32_t componentId, 515 | int socket, 516 | const struct sockaddr* connectionAddr, 517 | const struct sockaddr* relAddr, 518 | ICE_TRANSPORT transport, 519 | ICE_CANDIDATE_TYPE candType, 520 | uint16_t local_pref); 521 | 522 | 523 | bool 524 | ICELIB_isControlling(const ICELIB_INSTANCE* pInstance); 525 | 526 | 527 | void 528 | ICELIB_checkListDumpAllLog(const ICELIB_CALLBACK_LOG* pCallbackLog, 529 | ICELIB_logLevel logLevel, 530 | const ICELIB_INSTANCE* pInstance); 531 | 532 | 533 | bool 534 | ICELIB_isRestart(ICELIB_INSTANCE* pInstance, 535 | unsigned int mediaIdx, 536 | const char* ufrag, 537 | const char* passwd); 538 | 539 | 540 | struct sockaddr const* 541 | ICELIB_getLocalRelayAddr(const ICELIB_INSTANCE* pInstance, 542 | uint32_t mediaIdx); 543 | ICE_CANDIDATE const* 544 | ICELIB_getLocalRelayCandidate(const ICELIB_INSTANCE* pInstance, 545 | uint32_t mediaIdx, 546 | uint32_t componentId); 547 | 548 | struct sockaddr const* 549 | ICELIB_getLocalRelayAddrFromHostAddr(const ICELIB_INSTANCE* pInstance, 550 | const struct sockaddr* hostAddr); 551 | 552 | ICE_CANDIDATE const* 553 | ICELIB_getActiveCandidate(const ICELIB_INSTANCE* pInstance, 554 | int mediaLineId, 555 | uint32_t componentId); 556 | 557 | ICE_REMOTE_CANDIDATES const* 558 | ICELIB_getActiveRemoteCandidates(const ICELIB_INSTANCE* pInstance, 559 | int mediaLineId); 560 | 561 | char* 562 | ICELIB_getCheckListRemoteUsernamePair(char* dst, 563 | int maxlength, 564 | const ICELIB_CHECKLIST* pCheckList, 565 | bool outgoing); 566 | 567 | 568 | 569 | bool 570 | ICELIB_isRunning(const ICELIB_INSTANCE* pInstance); 571 | bool 572 | ICELIB_isIceComplete(const ICELIB_INSTANCE* pInstance); 573 | bool 574 | ICELIB_Mangled (const ICELIB_INSTANCE* pInstance); 575 | bool 576 | ICELIB_UnsupportedByRemote (const ICELIB_INSTANCE* pInstance); 577 | 578 | const ICE_MEDIA_STREAM* 579 | ICELIB_getLocalMediaStream(const ICELIB_INSTANCE* pInstance, 580 | uint32_t mediaIdx); 581 | 582 | void 583 | ICELIB_dropRflx(ICELIB_INSTANCE* pInstance); 584 | 585 | #ifdef __cplusplus 586 | } 587 | #endif 588 | 589 | #endif 590 | -------------------------------------------------------------------------------- /include/icelib_config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * See License file 3 | */ 4 | 5 | #ifndef ICELIB_ICELIB_CONFIG_H 6 | #define ICELIB_ICELIB_CONFIG_H 7 | 8 | #define ICELIB_RANDOM_SEGMENT_LENGTH (32 / 6) 9 | 10 | #define ICE_MAX_DEBUG_STRING 200 11 | 12 | #define ICELIB_UFRAG_LENGTH (4 + 1) /* includes zero ('\0') 13 | * termination */ 14 | #define ICELIB_PASSWD_LENGTH (22 + 1) /* includes zero ('\0') 15 | * termination */ 16 | #define ICELIB_FOUNDATION_LENGTH (16 + 1) /* includes zero ('\0') 17 | * termination */ 18 | 19 | #define ICE_MAX_UFRAG_PAIR_LENGTH ( (ICE_MAX_UFRAG_LENGTH * 2) + 1 ) 20 | #define ICE_MAX_FOUNDATION_PAIR_LENGTH ( (ICE_MAX_FOUNDATION_LENGTH * 2) ) 21 | 22 | #define ICELIB_MAX_PAIRS 40 23 | #define ICELIB_MAX_FIFO_ELEMENTS 40 24 | #define ICELIB_MAX_COMPONENTS 5 25 | 26 | #define ICELIB_LOCAL_TYPEPREF 126 27 | #define ICELIB_PEERREF_TYPEREF 110 28 | #define ICELIB_REFLEX_TYPEREF 100 29 | #define ICELIB_RELAY_TYPEREF 0 30 | 31 | #define ICELIB_RTP_COMPONENT_ID 1 32 | #define ICELIB_RTCP_COMPONENT_ID 2 33 | 34 | #define ICELIB_RTP_COMPONENT_INDEX 0 35 | #define ICELIB_RTCP_COMPONENT_INDEX 1 36 | 37 | #define ICELIB_FAIL_AFTER_MS 5000 /*5 sec*/ 38 | 39 | #define ICE_MAX_UFRAG_LENGTH (256 + 1) /* zero terminated */ 40 | #define ICE_MAX_PASSWD_LENGTH (256 + 1) /* zero terminated */ 41 | #define ICE_MAX_CANDIDATES 32 42 | #define ICE_MAX_FOUNDATION_LENGTH (32 + 1) /* zero terminated */ 43 | #define ICE_MAX_MEDIALINES 20 44 | #define ICE_MAX_COMPONENTS 2 45 | 46 | #endif //ICELIB_ICELIB_CONFIG_H 47 | -------------------------------------------------------------------------------- /include/icelib_debugwebserver.h: -------------------------------------------------------------------------------- 1 | /* 2 | * See License file 3 | */ 4 | 5 | #ifndef ICELIB_DEBUGWEBSERVER_H 6 | #define ICELIB_DEBUGWEBSERVER_H 7 | 8 | void 9 | ICELIB_FormatIcePage(char* resp, 10 | char* resp_head); 11 | void 12 | ICELIB_FormatValidCheckListsBodyTable(ICELIB_INSTANCE* icelib, 13 | char* s, 14 | char* content); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /include/icelibtypes.h: -------------------------------------------------------------------------------- 1 | /* 2 | * See License file 3 | */ 4 | 5 | #ifndef ICELIBTYPES_H 6 | #define ICELIBTYPES_H 7 | 8 | #include "stunlib.h" 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | struct console_output; 15 | 16 | #ifdef __cplusplus 17 | extern "C" { 18 | #else 19 | #include 20 | #endif 21 | 22 | #ifdef ICELIB_CUSTOM_CONFIG 23 | #include ICELIB_CUSTOM_CONFIG 24 | #else 25 | #include "icelib_config.h" 26 | #endif 27 | 28 | /* ----------------------------------------------------------------------------- 29 | * */ 30 | /* */ 31 | /* ----- List of effective components in a check list */ 32 | /* */ 33 | typedef struct { 34 | unsigned int numberOfComponents; 35 | uint32_t componentIds[ ICELIB_MAX_COMPONENTS]; 36 | } ICELIB_COMPONENTLIST; 37 | 38 | 39 | /* */ 40 | /* ----- Timer */ 41 | /* */ 42 | typedef enum { 43 | ICELIB_timerStopped, 44 | ICELIB_timerRunning, 45 | ICELIB_timerTimeout 46 | } ICELIB_timerState; 47 | 48 | 49 | typedef struct { 50 | ICELIB_timerState timerState; 51 | unsigned int timeoutValueMS; 52 | unsigned int countUpMS; 53 | unsigned int tickIntervalMS; 54 | } ICELIB_TIMER; 55 | 56 | /* */ 57 | /* ----- Fifo (Triggered Checks) */ 58 | /* */ 59 | typedef uint32_t ICELIB_FIFO_ELEMENT; 60 | #define ICELIB_FIFO_IS_EMPTY 0 61 | #define ICELIB_FIFO_ELEMENT_REMOVED 0xFFFFFFFF 62 | 63 | typedef struct { 64 | ICELIB_FIFO_ELEMENT elements[ ICELIB_MAX_FIFO_ELEMENTS]; 65 | unsigned int inIndex; 66 | unsigned int outIndex; 67 | bool isFull; 68 | } ICELIB_TRIGGERED_FIFO; 69 | 70 | 71 | typedef struct { 72 | ICELIB_TRIGGERED_FIFO* fifo; 73 | unsigned int index; 74 | bool atEnd; 75 | } ICELIB_TRIGGERED_FIFO_ITERATOR; 76 | 77 | typedef enum { 78 | ICELIB_logDebug = -1, 79 | ICELIB_logInfo = 0, 80 | ICELIB_logWarning = 1, 81 | ICELIB_logError = 2, 82 | ICELIB_logDisable = 3 83 | } ICELIB_logLevel; 84 | 85 | 86 | typedef enum { 87 | ICELIB_Result_None, 88 | ICELIB_Result_Error, 89 | ICELIB_Result_CandidatesReady, 90 | ICELIB_Result_Finished, 91 | ICELIB_Result_OK 92 | } ICELIB_Result; 93 | 94 | 95 | typedef struct { 96 | uint64_t ms64; 97 | uint64_t ls64; 98 | } ICELIB_uint128_t; 99 | 100 | /* */ 101 | /* ----- ICE candidate pair states */ 102 | /* */ 103 | typedef enum { 104 | ICELIB_PAIR_IDLE, 105 | ICELIB_PAIR_PAIRED, 106 | ICELIB_PAIR_REMOVED, 107 | ICELIB_PAIR_FROZEN, 108 | ICELIB_PAIR_WAITING, 109 | ICELIB_PAIR_INPROGRESS, 110 | ICELIB_PAIR_SUCCEEDED, 111 | ICELIB_PAIR_FAILED 112 | } ICELIB_PAIR_STATE; 113 | 114 | 115 | /* */ 116 | /* ----- ICE check list states */ 117 | /* */ 118 | typedef enum { 119 | ICELIB_CHECKLIST_IDLE, 120 | ICELIB_CHECKLIST_RUNNING, 121 | ICELIB_CHECKLIST_COMPLETED, 122 | ICELIB_CHECKLIST_FAILED 123 | } ICELIB_CHECKLIST_STATE; 124 | 125 | 126 | /* */ 127 | /* ----- ICE states */ 128 | /* */ 129 | typedef enum { 130 | ICELIB_IDLE, 131 | ICELIB_RUNNING, 132 | ICELIB_COMPLETED, 133 | ICELIB_MANGLED, 134 | ICELIB_FAILED 135 | } ICELIB_STATE; 136 | 137 | 138 | 139 | typedef enum { 140 | ICE_CAND_TYPE_NONE, 141 | ICE_CAND_TYPE_HOST, 142 | ICE_CAND_TYPE_SRFLX, 143 | ICE_CAND_TYPE_RELAY, 144 | ICE_CAND_TYPE_PRFLX 145 | } ICE_CANDIDATE_TYPE; 146 | 147 | typedef enum { 148 | ICE_TURN_IDLE, 149 | ICE_TURN_ALLOCATING, 150 | ICE_TURN_ALLOCATED, 151 | ICE_TURN_SETTING_ACTIVE, 152 | ICE_TURN_ACTIVE 153 | }ICE_TURN_STATE; 154 | 155 | typedef enum { 156 | ICE_TRANS_NONE, 157 | ICE_TRANS_UDP, 158 | ICE_TRANS_TCPACT, 159 | ICE_TRANS_TCPPASS 160 | } ICE_TRANSPORT; 161 | 162 | /*! 163 | * ICE single candidate 164 | * 165 | * From draft-ietf-mmusic-ice-18: 166 | * 167 | * foundation = 1*32 ice-char 168 | * componentid = 1*5 digit (0..65535) 169 | * priority = 1*10 digit (0..2147483647) 170 | * connectionAddr = address including port 171 | * relAddr = host addres when sending relayed candidates (Optional, 172 | * used for debugging) 173 | */ 174 | typedef struct { 175 | char foundation[ ICE_MAX_FOUNDATION_LENGTH]; 176 | uint32_t componentid; 177 | uint32_t priority; 178 | int socket; 179 | struct sockaddr_storage connectionAddr; 180 | ICE_TRANSPORT transport; 181 | ICE_CANDIDATE_TYPE type; 182 | struct sockaddr_storage relAddr; 183 | uint32_t userValue1; 184 | uint32_t userValue2; 185 | } ICE_CANDIDATE; 186 | 187 | typedef struct { 188 | uint32_t componentId; 189 | struct sockaddr_storage connectionAddr; 190 | ICE_TRANSPORT transport; 191 | ICE_CANDIDATE_TYPE type; 192 | } ICE_REMOTE_CANDIDATE; 193 | 194 | typedef struct { 195 | ICE_REMOTE_CANDIDATE remoteCandidate[ICE_MAX_COMPONENTS]; 196 | uint32_t numberOfComponents; 197 | } ICE_REMOTE_CANDIDATES; 198 | 199 | /*! 200 | * ICE candidates for a single media stream 201 | */ 202 | typedef struct { 203 | char ufrag [ ICE_MAX_UFRAG_LENGTH]; 204 | char passwd [ ICE_MAX_PASSWD_LENGTH]; 205 | ICE_CANDIDATE candidate[ ICE_MAX_CANDIDATES]; 206 | uint32_t numberOfCandidates; 207 | ICE_TURN_STATE turnState; 208 | uint32_t userValue1; 209 | uint32_t userValue2; 210 | struct sockaddr_storage defaultAddr; 211 | ICE_CANDIDATE_TYPE defaultCandType; 212 | } ICE_MEDIA_STREAM; 213 | 214 | 215 | /*! 216 | * ICE candidates for all media streams 217 | */ 218 | typedef struct { 219 | bool controlling; 220 | ICE_MEDIA_STREAM mediaStream[ ICE_MAX_MEDIALINES ]; 221 | uint32_t numberOfICEMediaLines; 222 | } ICE_MEDIA; 223 | 224 | /* one for the original request and one triggered check */ 225 | #define ICELIB_MAX_NO_OF_TRANSID 2 226 | 227 | /* */ 228 | /* ----- ICE check list and valid list pair */ 229 | /* */ 230 | typedef struct { 231 | ICELIB_PAIR_STATE pairState; 232 | uint32_t pairId; 233 | uint32_t refersToPairId; 234 | bool defaultPair; 235 | bool useCandidate; 236 | bool triggeredUseCandidate; 237 | bool nominatedPair; 238 | bool sentUseCandidateAlready; 239 | uint64_t pairPriority; 240 | const ICE_CANDIDATE* pLocalCandidate; 241 | const ICE_CANDIDATE* pRemoteCandidate; 242 | StunMsgId transactionIdTable[ICELIB_MAX_NO_OF_TRANSID]; 243 | unsigned int numberOfTransactionIds; 244 | } ICELIB_LIST_PAIR; 245 | 246 | /* */ 247 | /* ----- Valid List */ 248 | /* */ 249 | #define ICELIB_MAX_VALID_ELEMENTS ICELIB_MAX_PAIRS 250 | typedef ICELIB_LIST_PAIR ICELIB_VALIDLIST_ELEMENT; 251 | 252 | 253 | typedef struct { 254 | ICELIB_VALIDLIST_ELEMENT elements[ ICELIB_MAX_VALID_ELEMENTS]; 255 | unsigned int numberOfElements; 256 | } ICELIB_LIST_VL; 257 | 258 | typedef struct { 259 | ICELIB_LIST_VL pairs; 260 | uint32_t nextPairId; 261 | uint32_t readyToNominateWeighting; 262 | uint32_t nominatedPathScore; 263 | } ICELIB_VALIDLIST; 264 | 265 | 266 | typedef struct { 267 | ICELIB_VALIDLIST* pValidList; 268 | unsigned int index; 269 | } ICELIB_VALIDLIST_ITERATOR; 270 | 271 | 272 | /* */ 273 | /* ----- ICE check list */ 274 | /* */ 275 | typedef struct { 276 | unsigned int id; 277 | const char* ufragLocal; 278 | const char* ufragRemote; 279 | const char* passwdLocal; 280 | const char* passwdRemote; 281 | ICELIB_CHECKLIST_STATE checkListState; 282 | bool timerRunning; 283 | bool stopChecks; /* Almost complete, don't fire of any 284 | * new checks. */ 285 | unsigned int numberOfPairs; 286 | ICELIB_LIST_PAIR checkListPairs[ ICELIB_MAX_PAIRS]; 287 | ICELIB_COMPONENTLIST componentList; 288 | uint32_t nextPairId; 289 | } ICELIB_CHECKLIST; 290 | 291 | /* */ 292 | /* ----- One controller per media stream */ 293 | /* */ 294 | typedef struct { 295 | ICELIB_CHECKLIST checkList; 296 | ICELIB_VALIDLIST validList; 297 | ICELIB_TRIGGERED_FIFO triggeredChecksFifo; 298 | ICE_MEDIA_STREAM discoveredLocalCandidates; 299 | ICE_MEDIA_STREAM discoveredRemoteCandidates; 300 | ICE_REMOTE_CANDIDATES remoteCandidates; /*When ICE is complete, the 301 | * remote 302 | * candidates will be stored 303 | * here */ 304 | } ICELIB_STREAM_CONTROLLER; 305 | 306 | void 307 | ICELIBTYPES_ICE_CANDIDATE_reset(ICE_CANDIDATE* candidate); 308 | 309 | void 310 | ICELIBTYPES_ICE_MEDIA_STREAM_reset(ICE_MEDIA_STREAM* iceMediaStream); 311 | bool 312 | ICELIBTYPES_ICE_MEDIA_STREAM_isEmpty(const ICE_MEDIA_STREAM* iceMediaStream); 313 | 314 | void 315 | ICELIBTYPES_ICE_MEDIA_reset(ICE_MEDIA* iceMedia); 316 | bool 317 | ICELIBTYPES_ICE_MEDIA_isEmpty(const ICE_MEDIA* iceMedia); 318 | 319 | char const* 320 | ICELIBTYPES_ICE_CANDIDATE_TYPE_toString(const ICE_CANDIDATE_TYPE candidateType); 321 | char const* 322 | ICELIBTYPES_ICE_CANDIDATE_Component_toString (uint32_t componentid); 323 | 324 | char const* 325 | ICELIBTYPES_ICE_TRANSPORT_toString(ICE_TRANSPORT t); 326 | 327 | char const* 328 | ICELIBTYPES_ICE_TRANSPORT_PROTO_toString(const ICE_TRANSPORT t); 329 | 330 | int 331 | ICE_TRANSPORT_proto(ICE_TRANSPORT transport); 332 | 333 | #ifdef __cplusplus 334 | } 335 | #endif 336 | 337 | #endif 338 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # 3 | # compiling/installing sources for icelib 4 | 5 | set ( icelib_srcs 6 | fifo.c 7 | icelib.c 8 | timer.c 9 | icelibtypes.c 10 | ) 11 | 12 | set (ADDITIONAL_LIBS "") 13 | 14 | add_library ( icelib SHARED ${icelib_srcs} ) 15 | target_include_directories ( icelib PUBLIC ../include ) 16 | target_include_directories ( icelib PRIVATE ../src ) 17 | 18 | 19 | install ( TARGETS icelib 20 | LIBRARY DESTINATION lib 21 | ARCHIVE DESTINATION lib 22 | RUNTIME DESTINATION bin) 23 | 24 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/cmake) 25 | 26 | find_package( ZLIB REQUIRED ) 27 | if ( ZLIB_FOUND ) 28 | include_directories( ${ZLIB_INCLUDE_DIRS} ) 29 | list(APPEND ADDITIONAL_LIBS ${ZLIB_LIBRARIES}) 30 | endif( ZLIB_FOUND ) 31 | 32 | 33 | find_package( OpenSSL ) 34 | if( OPENSSL_FOUND ) 35 | include_directories( ${OPENSSL_INCLUDE_DIR} ) 36 | list(APPEND ADDITIONAL_LIBS ${OPENSSL_LIBRARIES}) 37 | endif( OPENSSL_FOUND ) 38 | 39 | 40 | target_link_libraries ( icelib PUBLIC sockaddrutil stunlib 41 | ${ADDITIONAL_LIBS}) 42 | 43 | if (coveralls) 44 | include(Coveralls) 45 | coveralls_turn_on_coverage() 46 | 47 | set(COVERAGE_SRCS "") 48 | foreach (S ${icelib_srcs}) 49 | get_filename_component(S_ABS ${S} ABSOLUTE) 50 | list (APPEND COVERAGE_SRCS ${S_ABS}) 51 | endforeach() 52 | 53 | # Create the coveralls target. 54 | coveralls_setup( 55 | "${COVERAGE_SRCS}" 56 | ${coveralls_send} # If we should upload. 57 | ) 58 | 59 | #add_dependencies(coveralls, all) 60 | endif() 61 | -------------------------------------------------------------------------------- /src/fifo.c: -------------------------------------------------------------------------------- 1 | /* 2 | * See License file 3 | */ 4 | 5 | 6 | #include 7 | #include "icelib.h" 8 | #include "icelib_intern.h" 9 | 10 | 11 | #define fifoIncrementToNext(index) (index = (index + 1) % \ 12 | ICELIB_MAX_FIFO_ELEMENTS) 13 | 14 | 15 | void 16 | ICELIB_fifoClear(ICELIB_TRIGGERED_FIFO* fifo) 17 | { 18 | memset( fifo, 0, sizeof(*fifo) ); 19 | } 20 | 21 | 22 | unsigned int 23 | ICELIB_fifoCount(const ICELIB_TRIGGERED_FIFO* fifo) 24 | { 25 | if (fifo->isFull) 26 | { 27 | return ICELIB_MAX_FIFO_ELEMENTS; 28 | } 29 | 30 | if (fifo->inIndex >= fifo->outIndex) 31 | { 32 | return fifo->inIndex - fifo->outIndex; 33 | } 34 | else 35 | { 36 | return ICELIB_MAX_FIFO_ELEMENTS - (fifo->outIndex - fifo->inIndex); 37 | } 38 | } 39 | 40 | 41 | bool 42 | ICELIB_fifoIsEmpty(const ICELIB_TRIGGERED_FIFO* fifo) 43 | { 44 | return (fifo->inIndex == fifo->outIndex) && !fifo->isFull; 45 | } 46 | 47 | 48 | bool 49 | ICELIB_fifoIsFull(const ICELIB_TRIGGERED_FIFO* fifo) 50 | { 51 | return fifo->isFull; 52 | } 53 | 54 | 55 | /* */ 56 | /* ----- Return: true - no more room, fifo is full!! */ 57 | /* false - element was inserted into fifo */ 58 | /* */ 59 | bool 60 | ICELIB_fifoPut(ICELIB_TRIGGERED_FIFO* fifo, 61 | ICELIB_FIFO_ELEMENT element) 62 | { 63 | if ( ICELIB_fifoIsFull(fifo) ) 64 | { 65 | return true; 66 | } 67 | 68 | fifo->elements[ fifo->inIndex] = element; 69 | fifoIncrementToNext(fifo->inIndex); 70 | if (fifo->inIndex == fifo->outIndex) 71 | { 72 | fifo->isFull = true; 73 | } 74 | 75 | return false; 76 | } 77 | 78 | 79 | /* */ 80 | /* ----- Return: element - fifo was not empty */ 81 | /* ICELIB_FIFO_IS_EMPTY - fifo is empty!! */ 82 | /* */ 83 | ICELIB_FIFO_ELEMENT 84 | ICELIB_fifoGet(ICELIB_TRIGGERED_FIFO* fifo) 85 | { 86 | unsigned int outPreIndex; 87 | 88 | if ( ICELIB_fifoIsEmpty(fifo) ) 89 | { 90 | return ICELIB_FIFO_IS_EMPTY; 91 | } 92 | 93 | fifo->isFull = false; 94 | outPreIndex = fifo->outIndex; 95 | fifoIncrementToNext(fifo->outIndex); 96 | 97 | return fifo->elements[ outPreIndex]; 98 | } 99 | 100 | 101 | void 102 | ICELIB_fifoIteratorConstructor(ICELIB_TRIGGERED_FIFO_ITERATOR* iterator, 103 | ICELIB_TRIGGERED_FIFO* fifo) 104 | { 105 | iterator->fifo = fifo; 106 | iterator->index = fifo->outIndex; 107 | iterator->atEnd = false; 108 | } 109 | 110 | 111 | ICELIB_FIFO_ELEMENT* 112 | pICELIB_fifoIteratorNext(ICELIB_TRIGGERED_FIFO_ITERATOR* iterator) 113 | { 114 | ICELIB_FIFO_ELEMENT* element = NULL; 115 | 116 | if ( ICELIB_fifoIsEmpty(iterator->fifo) ) 117 | { 118 | return NULL; 119 | } 120 | 121 | if (iterator->atEnd) 122 | { 123 | return NULL; 124 | } 125 | 126 | if ( ICELIB_fifoIsFull(iterator->fifo) ) 127 | { 128 | element = &iterator->fifo->elements[ iterator->index]; 129 | fifoIncrementToNext(iterator->index); 130 | if (iterator->index == iterator->fifo->inIndex) 131 | { 132 | iterator->atEnd = true; 133 | } 134 | } 135 | else 136 | { 137 | if (iterator->index == iterator->fifo->inIndex) 138 | { 139 | iterator->atEnd = true; 140 | return NULL; 141 | } 142 | 143 | element = &iterator->fifo->elements[ iterator->index]; 144 | fifoIncrementToNext(iterator->index); 145 | } 146 | 147 | return element; 148 | } 149 | 150 | 151 | void 152 | ICELIB_triggeredFifoClear(ICELIB_TRIGGERED_FIFO* fifo) 153 | { 154 | ICELIB_fifoClear(fifo); 155 | } 156 | 157 | 158 | unsigned int 159 | ICELIB_triggeredFifoCount(const ICELIB_TRIGGERED_FIFO* fifo) 160 | { 161 | return ICELIB_fifoCount(fifo); 162 | } 163 | 164 | 165 | bool 166 | ICELIB_triggeredFifoIsEmpty(const ICELIB_TRIGGERED_FIFO* fifo) 167 | { 168 | return ICELIB_fifoIsEmpty(fifo); 169 | } 170 | 171 | 172 | bool 173 | ICELIB_triggeredFifoIsFull(const ICELIB_TRIGGERED_FIFO* fifo) 174 | { 175 | return ICELIB_fifoIsFull(fifo); 176 | } 177 | 178 | 179 | /* */ 180 | /* ----- Return: true - no more room, fifo is full!! */ 181 | /* false - element was inserted into fifo */ 182 | /* */ 183 | bool 184 | ICELIB_triggeredFifoPut(ICELIB_TRIGGERED_FIFO* fifo, 185 | ICELIB_LIST_PAIR* pair) 186 | { 187 | return ICELIB_fifoPut(fifo, pair->pairId); 188 | } 189 | 190 | 191 | bool 192 | ICELIB_isTriggeredFifoPairPresent(ICELIB_TRIGGERED_FIFO* fifo, 193 | ICELIB_LIST_PAIR* pair, 194 | ICELIB_CALLBACK_LOG* callbackLog) 195 | { 196 | uint32_t* pairId; 197 | ICELIB_TRIGGERED_FIFO_ITERATOR tfIterator; 198 | 199 | ICELIB_fifoIteratorConstructor(&tfIterator, fifo); 200 | 201 | while ( ( pairId = pICELIB_fifoIteratorNext(&tfIterator) ) != NULL ) 202 | { 203 | if (*pairId == pair->pairId) 204 | { 205 | ICELIB_log(callbackLog, ICELIB_logDebug, "pair already present in FIFO"); 206 | return true; 207 | } 208 | } 209 | return false; 210 | } 211 | 212 | 213 | /* */ 214 | /* ----- Return: true - no more room, fifo is full!! */ 215 | /* false - element was inserted into fifo */ 216 | /* */ 217 | bool 218 | ICELIB_triggeredFifoPutIfNotPresent(ICELIB_TRIGGERED_FIFO* fifo, 219 | ICELIB_LIST_PAIR* pair, 220 | ICELIB_CALLBACK_LOG* callbackLog) 221 | { 222 | if ( !ICELIB_isTriggeredFifoPairPresent(fifo, pair, callbackLog) ) 223 | { 224 | return ICELIB_fifoPut(fifo, pair->pairId); 225 | } 226 | return false; 227 | } 228 | 229 | 230 | /* */ 231 | /* ----- Get a pair from the triggered checks queue */ 232 | /* */ 233 | /* Get a pointer to the pair. */ 234 | /* Since the fifo holds pairId's, the address of the pair is found by */ 235 | /* looking up the pair in the check list by its pairId. */ 236 | /* */ 237 | /* Return: pointer to pair - fifo was not empty */ 238 | /* NULL - fifo is empty!! */ 239 | /* */ 240 | ICELIB_LIST_PAIR* 241 | pICELIB_triggeredFifoGet(ICELIB_CHECKLIST* checkList, 242 | ICELIB_CALLBACK_LOG* callbackLog, 243 | ICELIB_TRIGGERED_FIFO* fifo) 244 | { 245 | uint32_t pairId; 246 | ICELIB_LIST_PAIR* pair; 247 | 248 | do 249 | { 250 | if ( ICELIB_fifoIsEmpty(fifo) ) 251 | { 252 | ICELIB_log(callbackLog, ICELIB_logDebug, 253 | "Triggered Check FIFO is empty!"); 254 | return NULL; 255 | } 256 | pairId = ICELIB_fifoGet(fifo); 257 | } while (pairId == ICELIB_FIFO_ELEMENT_REMOVED); 258 | 259 | pair = ICELIB_getPairById(checkList, pairId); 260 | 261 | if (pair == NULL) 262 | { 263 | ICELIB_log1(callbackLog, 264 | ICELIB_logDebug, 265 | "Could not find pair by Id: %u", 266 | pairId); 267 | } 268 | 269 | return pair; 270 | } 271 | 272 | 273 | void 274 | ICELIB_triggeredFifoRemove(ICELIB_TRIGGERED_FIFO* fifo, 275 | ICELIB_LIST_PAIR* pair) 276 | { 277 | uint32_t* pairId; 278 | ICELIB_TRIGGERED_FIFO_ITERATOR tfIterator; 279 | 280 | ICELIB_fifoIteratorConstructor(&tfIterator, fifo); 281 | 282 | while ( ( pairId = pICELIB_fifoIteratorNext(&tfIterator) ) != NULL ) 283 | { 284 | if (*pairId == pair->pairId) 285 | { 286 | *pairId = ICELIB_FIFO_ELEMENT_REMOVED; 287 | } 288 | } 289 | } 290 | 291 | 292 | void 293 | ICELIB_triggeredfifoIteratorConstructor( 294 | ICELIB_TRIGGERED_FIFO_ITERATOR* iterator, 295 | ICELIB_TRIGGERED_FIFO* fifo) 296 | { 297 | ICELIB_fifoIteratorConstructor(iterator, fifo); 298 | } 299 | 300 | 301 | ICELIB_LIST_PAIR* 302 | pICELIB_triggeredfifoIteratorNext(ICELIB_CHECKLIST* checkList, 303 | ICELIB_CALLBACK_LOG* callbackLog, 304 | ICELIB_TRIGGERED_FIFO_ITERATOR* iterator) 305 | { 306 | uint32_t* pairId; 307 | ICELIB_LIST_PAIR* pair = NULL; 308 | 309 | pairId = pICELIB_fifoIteratorNext(iterator); 310 | 311 | if (pairId != NULL) 312 | { 313 | 314 | pair = ICELIB_getPairById(checkList, *pairId); 315 | 316 | if (pair == NULL) 317 | { 318 | ICELIB_log1(callbackLog, 319 | ICELIB_logDebug, 320 | "Could not find pair by Id: %u", 321 | *pairId); 322 | } 323 | } 324 | 325 | return pair; 326 | } 327 | -------------------------------------------------------------------------------- /src/icelib_debugwebserver.c: -------------------------------------------------------------------------------- 1 | /* 2 | * See License file 3 | */ 4 | 5 | #include "icelib.h" 6 | #include "icelib_intern.h" 7 | #include "icelib_debugwebserver.h" 8 | 9 | #include "netaddr.h" 10 | 11 | #include 12 | 13 | static void 14 | ICELIB_FormatHeaderOk(char* resp_head, 15 | char* resp, 16 | const char* content) 17 | { 18 | sprintf( resp_head, "HTTP/1.0 200 OK\r\n"); 19 | sprintf( &resp_head[strlen(resp_head)], "Content-type: %s\r\n", content); 20 | sprintf( &resp_head[strlen(resp_head)], "Content-length: %d\r\n", 21 | strlen(resp) ); 22 | sprintf(&resp_head[strlen(resp_head)], "\r\n"); 23 | } 24 | 25 | static void 26 | ICELIB_RowStart(char* s, 27 | const char* bgColour, 28 | bool isExcel) 29 | { 30 | if (!isExcel) 31 | { 32 | sprintf(&s[strlen(s)], "", bgColour); 33 | } 34 | } 35 | 36 | static void 37 | ICELIB_RowEnd(char* s, 38 | bool isExcel) 39 | { 40 | if (!isExcel) 41 | { 42 | sprintf(&s[strlen(s)], ""); 43 | } 44 | } 45 | 46 | static void 47 | ICELIB_FormatUint32_1(char* s, 48 | uint32_t val, 49 | bool isExcel, 50 | bool isTable, 51 | bool singleRow) 52 | { 53 | if (isExcel) 54 | { 55 | sprintf(&s[strlen(s)], "\t %d\n", val); /* simple tab field separator 56 | * */ 57 | } 58 | else if (isTable) 59 | { 60 | if (singleRow) 61 | { 62 | sprintf(&s[strlen(s)], "%d\n", val); /* single 63 | * row */ 64 | } 65 | else 66 | { 67 | sprintf(&s[strlen(s)], "%d\n", val); /* 68 | * continuation 69 | * */ 70 | } 71 | } 72 | else 73 | { 74 | sprintf(&s[strlen(s)], "%d
\n", val); 75 | } 76 | } 77 | 78 | 79 | static void 80 | ICELIB_FormatStr(char* s, 81 | const char* val, 82 | bool isExcel, 83 | bool isTable, 84 | bool singleRow) 85 | { 86 | if (isExcel) 87 | { 88 | sprintf(&s[strlen(s)], "\t %s\n", val); /* simple tab field separator 89 | * */ 90 | } 91 | else if (isTable) 92 | { 93 | if (singleRow) 94 | { 95 | sprintf(&s[strlen(s)], "%s\n", val); /* row */ 96 | } 97 | else 98 | { 99 | sprintf(&s[strlen(s)], "%s\n", val); /* row */ 100 | } 101 | } 102 | else 103 | { 104 | sprintf(&s[strlen(s)], "%s
\n", val); 105 | } 106 | } 107 | 108 | 109 | 110 | 111 | static const char* 112 | ICELIB_IceComponentIdToStr(uint32_t componentId) 113 | { 114 | switch (componentId) 115 | { 116 | case 1: return "RTP"; 117 | case 2: return "RTCP"; 118 | default: return "???"; 119 | } 120 | } 121 | 122 | 123 | 124 | void 125 | ICELIB_FormatValidCheckListsBodyTable(ICELIB_INSTANCE* icelib, 126 | char* s, 127 | char* content) 128 | { 129 | int32_t j = 0; 130 | uint32_t i; 131 | sprintf(&s[strlen(s)], "

Session %i

\n", j); 132 | 133 | sprintf(&s[strlen(s)], "\n"); 134 | 135 | /* for all media streams */ 136 | for (i = 0; i < icelib->numberOfMediaStreams; ++i) 137 | { 138 | ICELIB_VALIDLIST* pValidList; 139 | ICELIB_VALIDLIST_ITERATOR vlIterator; 140 | ICELIB_VALIDLIST_ELEMENT* pValidPair; 141 | int j; 142 | 143 | pValidList = &icelib->streamControllers[i].validList; 144 | ICELIB_validListIteratorConstructor(&vlIterator, pValidList); 145 | 146 | /* for all valid pairs */ 147 | for (j = 0; 148 | ( ( pValidPair = pICELIB_validListIteratorNext(&vlIterator) ) != 149 | NULL ); 150 | j++) 151 | { 152 | char addr[MAX_NET_ADDR_STRING_SIZE]; 153 | 154 | if ( (i == 0) && (j == 0) ) 155 | { 156 | /* table header row */ 157 | ICELIB_RowStart(&s[strlen(s)], "wheat", false); 158 | sprintf(&s[strlen(s)], "\n"); 159 | sprintf(&s[strlen(s)], "\n"); 160 | sprintf(&s[strlen(s)], "\n"); 161 | sprintf(&s[strlen(s)], "\n"); 162 | sprintf(&s[strlen(s)], "\n"); 163 | sprintf(&s[strlen(s)], "\n"); 164 | sprintf(&s[strlen(s)], "\n"); 165 | sprintf(&s[strlen(s)], "\n"); 166 | sprintf(&s[strlen(s)], "\n"); 167 | sprintf(&s[strlen(s)], "\n"); 168 | ICELIB_RowEnd(&s[strlen(s)], false); 169 | } 170 | 171 | ICELIB_RowStart(&s[strlen( 172 | s)], pValidPair->nominatedPair ? "chartreuse" : "white", 173 | false); 174 | ICELIB_FormatUint32_1(&s[strlen( 175 | s)], i, false, true, false); 176 | ICELIB_FormatUint32_1(&s[strlen( 177 | s)], pValidPair->pairId, false, true, false); 178 | ICELIB_FormatStr(&s[strlen(s)], 179 | ICELIB_toString_CheckListPairState( 180 | pValidPair->pairState), false, true, false); 181 | ICELIB_FormatUint32_1(&s[strlen( 182 | s)], pValidPair->nominatedPair ? 1 : 0, false, true, 183 | false); 184 | 185 | /* local cand */ 186 | ICELIB_FormatStr(&s[strlen(s)], 187 | ICELIB_IceComponentIdToStr(pValidPair->pLocalCandidate-> 188 | componentid), false, true, 189 | false); 190 | ICELIB_FormatStr(&s[strlen(s)], 191 | ICELIBTYPES_ICE_CANDIDATE_TYPE_toString(pValidPair-> 192 | pLocalCandidate-> 193 | type), false, true, 194 | false); 195 | netaddr_toString(&pValidPair->pLocalCandidate->connectionAddr, 196 | addr, 197 | sizeof(addr), 198 | true); 199 | ICELIB_FormatStr(&s[strlen(s)], addr, false, true, false); 200 | 201 | /* remote cand */ 202 | ICELIB_FormatStr(&s[strlen(s)], 203 | ICELIB_IceComponentIdToStr(pValidPair->pRemoteCandidate-> 204 | componentid), false, true, 205 | false); 206 | ICELIB_FormatStr(&s[strlen(s)], 207 | ICELIBTYPES_ICE_CANDIDATE_TYPE_toString(pValidPair-> 208 | pRemoteCandidate 209 | ->type), false, true, 210 | false); 211 | netaddr_toString(&pValidPair->pRemoteCandidate->connectionAddr, 212 | addr, 213 | sizeof(addr), 214 | true); 215 | ICELIB_FormatStr(&s[strlen(s)], addr, false, true, false); 216 | 217 | ICELIB_RowEnd(&s[strlen(s)], false); 218 | 219 | } /* for all valid pairs */ 220 | 221 | } /* for all media streams */ 222 | 223 | sprintf(&s[strlen(s)], "
MediaStreamPairIdStateNominatedL-CompL-TypeL-AddrR-CompR-TypeR-Addr
\n"); 224 | } 225 | 226 | void 227 | ICELIB_FormatIcePage(char* resp, 228 | char* resp_head) 229 | { 230 | /* body */ 231 | sprintf(resp, "

TANDBERG ICE DEBUGGER

\n"); 232 | sprintf(&resp[strlen(resp)], "

ICE

\n"); 233 | 234 | sprintf(&resp[strlen( 235 | resp)], 236 | "
DumpAllCheckLists\n"); 237 | sprintf(&resp[strlen( 238 | resp)], 239 | "
DumpValidCheckLists\n"); 240 | 241 | /* Create response header */ 242 | ICELIB_FormatHeaderOk(resp_head, resp, "text/html"); 243 | } 244 | -------------------------------------------------------------------------------- /src/icelib_intern.h: -------------------------------------------------------------------------------- 1 | /* 2 | * See License file 3 | */ 4 | 5 | 6 | #ifndef ICELIB_INTERN_H 7 | #define ICELIB_INTERN_H 8 | 9 | #include "icelib.h" 10 | #include "icelibtypes.h" 11 | 12 | 13 | #ifdef __cplusplus 14 | extern "C" { 15 | #endif 16 | 17 | 18 | #define ICELIB_log1(pCallbacks, level, message, arg1) ICELIB_log_(pCallbacks, \ 19 | level, \ 20 | __func__, \ 21 | __FILE__, \ 22 | __LINE__, \ 23 | message, \ 24 | arg1) 25 | 26 | #define ICELIB_log(pCallbacks, level, message) ICELIB_log_(pCallbacks, \ 27 | level, \ 28 | __func__, \ 29 | __FILE__, \ 30 | __LINE__, \ 31 | message) 32 | 33 | 34 | char* 35 | ICELIB_strncpy(char* dst, 36 | const char* src, 37 | int maxlength); 38 | char* 39 | ICELIB_strncat(char* dst, 40 | const char* src, 41 | int maxlength); 42 | 43 | uint64_t 44 | ICELIB_random64(void); 45 | ICELIB_uint128_t 46 | ICELIB_random128(void); 47 | 48 | int 49 | ICELIB_compareTransactionId(const StunMsgId* pid1, 50 | const StunMsgId* pid2); 51 | 52 | bool 53 | ICELIB_veryfyICESupportOnStream(const ICELIB_INSTANCE* pInstance, 54 | const ICE_MEDIA_STREAM* stream); 55 | 56 | bool 57 | ICELIB_verifyICESupport(const ICELIB_INSTANCE* pInstance, 58 | const ICE_MEDIA* iceRemoteMedia); 59 | 60 | const char* 61 | pICELIB_splitUfragPair(const char* pUfragPair, 62 | size_t* pColonIndex); 63 | 64 | bool 65 | ICELIB_compareUfragPair(const char* pUfragPair, 66 | const char* pUfragLeft, 67 | const char* pUfragRight); 68 | 69 | void 70 | ICELIB_logStringBasic(const ICELIB_CALLBACK_LOG* pCallbackLog, 71 | ICELIB_logLevel logLevel, 72 | const char* str); 73 | 74 | void 75 | ICELIB_log_(const ICELIB_CALLBACK_LOG* pCallbackLog, 76 | ICELIB_logLevel logLevel, 77 | const char* function, 78 | const char* file, 79 | unsigned int line, 80 | const char* fmt, 81 | ...); 82 | 83 | void 84 | ICELIB_startAllStoppingTimers(ICELIB_INSTANCE* pInstance); 85 | void 86 | ICELIB_tickAllStoppingTimers(ICELIB_INSTANCE* pInstance); 87 | 88 | void 89 | ICELIB_longToIcechar(long data, 90 | char* b64, 91 | int maxLength); 92 | void 93 | ICELIB_createRandomString(char* dst, 94 | int maxlength); 95 | 96 | uint32_t 97 | ICELIB_calculatePriority(ICE_CANDIDATE_TYPE type, 98 | ICE_TRANSPORT transport, 99 | uint16_t compid, 100 | uint16_t local_pref); 101 | 102 | bool 103 | ICELIB_isEmptyCandidate(const ICE_CANDIDATE* pCandidate); 104 | bool 105 | ICELIB_isNonValidCandidate(const ICE_CANDIDATE* pCandidate); 106 | bool 107 | ICELIB_isEmptyOrNonValidCandidate(const ICE_CANDIDATE* pCandidate); 108 | 109 | void 110 | ICELIB_clearRedundantCandidates(ICE_CANDIDATE candidates[]); 111 | void 112 | ICELIB_compactTable(ICE_CANDIDATE candidates[]); 113 | int 114 | ICELIB_countCandidates(ICE_CANDIDATE candidates[]); 115 | 116 | int 117 | ICELIB_eliminateRedundantCandidates(ICE_CANDIDATE candidates[]); 118 | 119 | void 120 | ICELIB_EliminateRedundantCandidates(ICELIB_INSTANCE* pInstance); 121 | 122 | void 123 | ICELIB_fillLocalCandidate(ICE_CANDIDATE* cand, 124 | uint32_t componentId, 125 | int socket, 126 | const struct sockaddr* connectionAddr, 127 | const struct sockaddr* relAddr, 128 | ICE_TRANSPORT transport, 129 | ICE_CANDIDATE_TYPE candType, 130 | uint16_t local_pref); 131 | 132 | void 133 | ICELIB_fillRemoteCandidate(ICE_CANDIDATE* cand, 134 | uint32_t componentId, 135 | const char* foundation, 136 | uint32_t foundationLen, 137 | uint32_t priority, 138 | struct sockaddr* connectionAddr, 139 | ICE_TRANSPORT transport, 140 | ICE_CANDIDATE_TYPE candType); 141 | 142 | int 143 | ICELIB_candidateSort(const void* x, 144 | const void* y); 145 | 146 | const char* 147 | ICELIB_toString_CheckListState(ICELIB_CHECKLIST_STATE state); 148 | const char* 149 | ICELIB_toString_CheckListPairState(ICELIB_PAIR_STATE state); 150 | 151 | void 152 | ICELIB_resetCheckList(ICELIB_CHECKLIST* pCheckList, 153 | unsigned int checkListId); 154 | void 155 | ICELIB_resetPair(ICELIB_LIST_PAIR* pPair); 156 | void 157 | ICELIB_resetCandidate(ICE_CANDIDATE* pCandidate); 158 | 159 | int 160 | ICELIB_comparePairsCL(const void* cp1, 161 | const void* cp2); 162 | void 163 | ICELIB_computePairPriority(ICELIB_LIST_PAIR* pCheckListPair, 164 | bool iceControlling); 165 | 166 | bool 167 | ICELIB_isComponentIdPresent(const ICELIB_COMPONENTLIST* pComponentList, 168 | uint32_t componentId); 169 | 170 | bool 171 | ICELIB_addComponentId(ICELIB_COMPONENTLIST* pComponentList, 172 | uint32_t componentId); 173 | 174 | bool 175 | ICELIB_addComponentIdIfUnique(ICELIB_COMPONENTLIST* pComponentList, 176 | uint32_t componentId); 177 | 178 | bool 179 | ICELIB_collectEffectiveCompontIds(ICELIB_CHECKLIST* pCheckList); 180 | 181 | void 182 | ICELIB_prunePairsReplaceWithBase(ICELIB_CHECKLIST* pCheckList, 183 | const ICE_CANDIDATE* pBbaseServerReflexiveRtp, 184 | const ICE_CANDIDATE* pBaseServerReflexiveRtcp); 185 | 186 | bool 187 | ICELIB_prunePairsIsEqual(const ICELIB_LIST_PAIR* pPair1, 188 | const ICELIB_LIST_PAIR* pPair2); 189 | 190 | bool 191 | ICELIB_prunePairsIsClear(const ICELIB_LIST_PAIR* pPair); 192 | void 193 | ICELIB_prunePairsClear(ICELIB_LIST_PAIR* pPair); 194 | void 195 | ICELIB_prunePairsClearDuplicates(ICELIB_CHECKLIST* pCheckList); 196 | void 197 | ICELIB_prunePairsCompact(ICELIB_CHECKLIST* pCheckList); 198 | unsigned int 199 | ICELIB_prunePairsCountPairs(ICELIB_LIST_PAIR pairs[]); 200 | 201 | void 202 | ICELIB_computeStatesSetState(ICELIB_CHECKLIST* pCheckList, 203 | ICELIB_PAIR_STATE state, 204 | ICELIB_CALLBACK_LOG* pCallbackLog); 205 | 206 | void 207 | ICELIB_makeAllCheckLists(ICELIB_INSTANCE* pInstance); 208 | 209 | bool 210 | ICELIB_isPairAddressMatchInChecklist(ICELIB_CHECKLIST* pCheckList, 211 | ICELIB_LIST_PAIR* pair); 212 | 213 | ICELIB_LIST_PAIR* 214 | ICELIB_getPairById(ICELIB_CHECKLIST* pCheckList, 215 | uint32_t pairId); 216 | 217 | bool 218 | ICELIB_isTriggeredFifoPairPresent(ICELIB_TRIGGERED_FIFO* pFifo, 219 | ICELIB_LIST_PAIR* pPair, 220 | ICELIB_CALLBACK_LOG* pCallbackLog); 221 | 222 | bool 223 | ICELIB_triggeredFifoPutIfNotPresent(ICELIB_TRIGGERED_FIFO* pFifo, 224 | ICELIB_LIST_PAIR* pPair, 225 | ICELIB_CALLBACK_LOG* pCallbackLog); 226 | 227 | void 228 | ICELIB_triggeredFifoRemove(ICELIB_TRIGGERED_FIFO* pFifo, 229 | ICELIB_LIST_PAIR* pPair); 230 | 231 | void 232 | ICELIB_triggeredfifoIteratorConstructor( 233 | ICELIB_TRIGGERED_FIFO_ITERATOR* pIterator, 234 | ICELIB_TRIGGERED_FIFO* pFifo); 235 | 236 | ICELIB_LIST_PAIR* 237 | pICELIB_triggeredfifoIteratorNext(ICELIB_CHECKLIST* pCheckList, 238 | ICELIB_CALLBACK_LOG* pCallbackLog, 239 | ICELIB_TRIGGERED_FIFO_ITERATOR* pIterator); 240 | 241 | void 242 | ICELIB_resetStreamController(ICELIB_STREAM_CONTROLLER* pStreamController, 243 | unsigned int tickIntervalMS); 244 | 245 | ICELIB_LIST_PAIR* 246 | pICELIB_findPairToScedule(ICELIB_STREAM_CONTROLLER* pController, 247 | ICELIB_CALLBACK_LOG* pCallbackLog); 248 | 249 | bool 250 | ICELIB_insertTransactionId(ICELIB_LIST_PAIR* pair, 251 | StunMsgId id); 252 | 253 | void 254 | ICELIB_scheduleCheck(ICELIB_INSTANCE* pInstance, 255 | ICELIB_CHECKLIST* pCheckList, 256 | ICELIB_LIST_PAIR* pPair); 257 | 258 | void 259 | ICELIB_tickStreamController(ICELIB_INSTANCE* pInstance); 260 | 261 | void 262 | ICELIB_unfreezeAllFrozenCheckLists(ICELIB_STREAM_CONTROLLER streamControllers[], 263 | unsigned int numberOfMediaStreams, 264 | ICELIB_CALLBACK_LOG* pCallbackLog); 265 | 266 | void 267 | ICELIB_recomputeAllPairPriorities(ICELIB_STREAM_CONTROLLER streamControllers[], 268 | unsigned int numberOfMediaStreams, 269 | bool iceControlling); 270 | 271 | unsigned int 272 | ICELIB_findStreamByAddress(ICELIB_STREAM_CONTROLLER streamControllers[], 273 | unsigned int numberOfMediaStreams, 274 | int proto, 275 | const struct sockaddr* pHostAddr); 276 | 277 | int 278 | ICELIB_listCompareVL(const void* cp1, 279 | const void* cp2); 280 | void 281 | ICELIB_listSortVL(ICELIB_LIST_VL* pList); 282 | void 283 | ICELIB_listConstructorVL(ICELIB_LIST_VL* pList); 284 | unsigned int 285 | ICELIB_listCountVL(const ICELIB_LIST_VL* pList); 286 | 287 | ICELIB_VALIDLIST_ELEMENT* 288 | pICELIB_listGetElementVL(ICELIB_LIST_VL* pList, 289 | unsigned int index); 290 | bool 291 | ICELIB_listAddBackVL(ICELIB_LIST_VL* pList, 292 | ICELIB_VALIDLIST_ELEMENT* pPair); 293 | 294 | bool 295 | ICELIB_listInsertVL(ICELIB_LIST_VL* pList, 296 | ICELIB_VALIDLIST_ELEMENT* pPair); 297 | 298 | void 299 | ICELIB_validListConstructor(ICELIB_VALIDLIST* pValidList); 300 | 301 | ICELIB_VALIDLIST_ELEMENT* 302 | pICELIB_validListGetElement(ICELIB_VALIDLIST* pValidList, 303 | unsigned int index); 304 | 305 | uint32_t 306 | ICELIB_validListLastPairId(const ICELIB_VALIDLIST* pValidList); 307 | 308 | void 309 | ICELIB_validListIteratorConstructor(ICELIB_VALIDLIST_ITERATOR* pIterator, 310 | ICELIB_VALIDLIST* pValidList); 311 | 312 | ICELIB_VALIDLIST_ELEMENT* 313 | pICELIB_validListIteratorNext(ICELIB_VALIDLIST_ITERATOR* pIterator); 314 | ICELIB_VALIDLIST_ELEMENT* 315 | pICELIB_validListFindPairById(ICELIB_VALIDLIST* pValidList, 316 | uint32_t pairId); 317 | 318 | void 319 | ICELIB_storeRemoteCandidates(ICELIB_INSTANCE* pInstance); 320 | 321 | bool 322 | ICELIB_validListNominatePair(ICELIB_VALIDLIST* pValidList, 323 | ICELIB_LIST_PAIR* pPair, 324 | const struct sockaddr* pMappedAddress); 325 | 326 | bool 327 | ICELIB_validListAddBack(ICELIB_VALIDLIST* pValidList, 328 | ICELIB_VALIDLIST_ELEMENT* pPair); 329 | 330 | bool 331 | ICELIB_validListInsert(ICELIB_VALIDLIST* pValidList, 332 | ICELIB_VALIDLIST_ELEMENT* pPair); 333 | 334 | unsigned int 335 | ICELIB_countNominatedPairsInValidList(ICELIB_VALIDLIST* pValidList); 336 | 337 | ICELIB_VALIDLIST_ELEMENT* 338 | ICELIB_findElementInValidListByid(ICELIB_VALIDLIST* pValidList, 339 | uint32_t id); 340 | 341 | bool 342 | ICELIB_isPairForEachComponentInValidList(ICELIB_VALIDLIST* pValidList, 343 | const ICELIB_COMPONENTLIST* pComponentList); 344 | 345 | void 346 | ICELIB_unfreezePairsByMatchingFoundation(ICELIB_VALIDLIST* pValidList, 347 | ICELIB_CHECKLIST* pCheckList, 348 | ICELIB_CALLBACK_LOG* pCallbackLog); 349 | 350 | bool 351 | ICELIB_atLeastOneFoundationMatch(ICELIB_VALIDLIST* pValidList, 352 | ICELIB_CHECKLIST* pCheckList); 353 | 354 | void 355 | ICELIB_resetCallbacks(ICELIB_CALLBACKS* pCallbacks); 356 | 357 | void 358 | ICELIB_callbackConstructor(ICELIB_CALLBACKS* pCallbacks, 359 | ICELIB_INSTANCE* pInstance); 360 | 361 | bool 362 | ICELIB_checkSourceAndDestinationAddr(const ICELIB_LIST_PAIR* pPair, 363 | const struct sockaddr* source, 364 | const struct sockaddr* destination); 365 | 366 | ICE_CANDIDATE* 367 | ICELIB_addDiscoveredCandidate(ICE_MEDIA_STREAM* pMediaStream, 368 | const ICE_CANDIDATE* pPeerCandidate); 369 | 370 | void 371 | ICELIB_makePeerLocalReflexiveCandidate(ICE_CANDIDATE* pPeerCandidate, 372 | ICELIB_CALLBACK_LOG* pCallbackLog, 373 | const struct sockaddr* pMappedAddress, 374 | ICE_TRANSPORT transport, 375 | int socketfd, 376 | uint16_t componentId); 377 | 378 | void 379 | ICELIB_makePeerRemoteReflexiveCandidate(ICE_CANDIDATE* pPeerCandidate, 380 | ICELIB_CALLBACK_LOG* pCallbackLog, 381 | const struct sockaddr* sourceAddr, 382 | ICE_TRANSPORT transport, 383 | uint32_t peerPriority, 384 | uint16_t componentId); 385 | 386 | ICELIB_LIST_PAIR* 387 | pICELIB_findPairInCheckList(ICELIB_CHECKLIST* pCheckList, 388 | const ICELIB_LIST_PAIR* pPair); 389 | 390 | bool 391 | ICELIB_isAllPairsFailedOrSucceded(const ICELIB_CHECKLIST* pCheckList); 392 | 393 | void 394 | ICELIB_updateCheckListState(ICELIB_CHECKLIST* pCheckList, 395 | ICELIB_VALIDLIST* pValidList, 396 | ICELIB_STREAM_CONTROLLER streamControllers[], 397 | unsigned int numberOfMediaStreams, 398 | ICELIB_CALLBACK_LOG* pCallbackLog); 399 | 400 | void 401 | ICELIB_processSuccessResponse(ICELIB_INSTANCE* pInstance, 402 | const ICE_MEDIA_STREAM* pLocalMediaStream, 403 | ICE_MEDIA_STREAM* pDiscoveredLocalCandidates, 404 | ICELIB_CHECKLIST* pCurrentCheckList, 405 | ICELIB_VALIDLIST* pValidList, 406 | ICELIB_LIST_PAIR* pPair, 407 | const struct sockaddr* pMappedAddress, 408 | bool iceControlling); 409 | 410 | void 411 | ICELIB_sendBindingResponse(ICELIB_INSTANCE* pInstance, 412 | int sockfd, 413 | int proto, 414 | const struct sockaddr* source, 415 | const struct sockaddr* destination, 416 | const struct sockaddr* MappedAddress, 417 | uint32_t userValue1, 418 | uint32_t userValue2, 419 | uint16_t componentId, 420 | uint16_t errorResponse, 421 | StunMsgId transactionId, 422 | bool useRelay, 423 | const char* pPasswd); 424 | 425 | void 426 | ICELIB_processSuccessRequest(ICELIB_INSTANCE* pInstance, 427 | StunMsgId transactionId, 428 | int sockfd, 429 | int proto, 430 | const struct sockaddr* source, 431 | const struct sockaddr* destination, 432 | const struct sockaddr* relayBaseAddr, 433 | uint32_t userValue1, 434 | uint32_t userValue2, 435 | uint32_t peerPriority, 436 | const ICE_MEDIA_STREAM* pLocalMediaStream, 437 | const ICE_MEDIA_STREAM* pRemoteMediaStream, 438 | ICE_MEDIA_STREAM* pDiscoveredRemoteCandidates, 439 | ICE_MEDIA_STREAM* pDiscoveredLocalCandidates, 440 | ICELIB_CHECKLIST* pCurrentCheckList, 441 | ICELIB_VALIDLIST* pCurrentValidList, 442 | ICELIB_TRIGGERED_FIFO* pTriggeredFifo, 443 | bool iceControlling, 444 | bool useCandidate, 445 | bool fromRelay, 446 | uint16_t componentId); 447 | 448 | void 449 | ICELIB_processIncommingLite(ICELIB_INSTANCE* pInstance, 450 | uint32_t userValue1, 451 | uint32_t userValue2, 452 | const char* pUfragPair, 453 | uint32_t peerPriority, 454 | bool useCandidate, 455 | bool iceControlling, 456 | bool iceControlled, 457 | uint64_t tieBreaker, 458 | StunMsgId transactionId, 459 | const struct sockaddr* source, 460 | const struct sockaddr* destination, 461 | uint16_t componentId); 462 | 463 | void 464 | ICELIB_processIncommingFull(ICELIB_INSTANCE* pInstance, 465 | uint32_t userValue1, 466 | uint32_t userValue2, 467 | const char* pUfragPair, 468 | uint32_t peerPriority, 469 | bool useCandidate, 470 | bool iceControlling, 471 | bool iceControlled, 472 | uint64_t tieBreaker, 473 | StunMsgId transactionId, 474 | int sockfd, 475 | int proto, 476 | const struct sockaddr* source, 477 | const struct sockaddr* destination, 478 | bool fromRelay, 479 | const struct sockaddr* relayBaseAddr, 480 | uint16_t componentId); 481 | 482 | bool 483 | ICELIB_isNominatingCriteriaMet(ICELIB_VALIDLIST* pValidList, 484 | ICELIB_CHECKLIST* pChecklist); 485 | 486 | bool 487 | ICELIB_isNominatingCriteriaMetForAllMediaStreams(ICELIB_INSTANCE* pInstance); 488 | 489 | void 490 | ICELIB_stopChecks(ICELIB_INSTANCE* pInstance, 491 | ICELIB_CHECKLIST* pCheckList, 492 | ICELIB_TRIGGERED_FIFO* pTriggeredChecksFifo); 493 | 494 | ICELIB_LIST_PAIR* 495 | pICELIB_pickValidPairForNominationNormalMode(ICELIB_VALIDLIST* pValidList, 496 | uint32_t componentId); 497 | 498 | ICELIB_LIST_PAIR* 499 | pICELIB_pickValidPairForNomination(ICELIB_VALIDLIST* pValidList, 500 | uint32_t componentId); 501 | 502 | 503 | void 504 | ICELIB_enqueueValidPair(ICELIB_TRIGGERED_FIFO* pTriggeredChecksFifo, 505 | ICELIB_CHECKLIST* pCheckList, 506 | ICELIB_CALLBACK_LOG* pCallbackLog, 507 | ICELIB_LIST_PAIR* pValidPair); 508 | 509 | void 510 | ICELIB_nominateAggressive(ICELIB_INSTANCE* pInstance); 511 | void 512 | ICELIB_nominateRegularIfComplete(ICELIB_INSTANCE* pInstance); 513 | 514 | void 515 | ICELIB_removePairFromCheckList(ICELIB_CHECKLIST* pCheckList, 516 | ICELIB_LIST_PAIR* pPair, 517 | ICELIB_CALLBACK_LOG* pCallbackLog); 518 | 519 | void 520 | ICELIB_removeWaitingAndFrozenByComponentFromCheckList( 521 | ICELIB_CHECKLIST* pCheckList, 522 | uint32_t componentId, 523 | ICELIB_CALLBACK_LOG* pCallbackLog); 524 | 525 | void 526 | ICELIB_removeWaitingAndFrozenByComponentFromTriggeredChecksFifo( 527 | ICELIB_CHECKLIST* pCheckList, 528 | ICELIB_TRIGGERED_FIFO* pTriggeredChecksFifo, 529 | ICELIB_CALLBACK_LOG* pCallbackLog, 530 | uint32_t componentId); 531 | 532 | void 533 | ICELIB_removeWaitingAndFrozen(ICELIB_CHECKLIST* pCheckList, 534 | ICELIB_VALIDLIST* pValidList, 535 | ICELIB_TRIGGERED_FIFO* pTriggeredChecksFifo, 536 | ICELIB_CALLBACK_LOG* pCallbackLog); 537 | 538 | void 539 | ICELIB_ceaseRetransmissions(ICELIB_CHECKLIST* pCheckList, 540 | ICELIB_VALIDLIST* pValidList, 541 | ICELIB_TRIGGERED_FIFO* pTriggeredChecksFifo); 542 | 543 | void 544 | ICELIB_updateCheckListStateConcluding(ICELIB_INSTANCE* pInstance, 545 | ICELIB_CHECKLIST* pCheckList, 546 | ICELIB_VALIDLIST* pValidList, 547 | ICELIB_TRIGGERED_FIFO* pTriggeredChecksFifo, 548 | ICELIB_CALLBACK_LOG* pCallbackLog); 549 | 550 | void 551 | ICE_concludeFullIfComplete(ICELIB_INSTANCE* pInstance); 552 | void 553 | ICE_concludingLite(ICELIB_INSTANCE* pInstance); 554 | void 555 | ICELIB_concludeICEProcessingIfComplete(ICELIB_INSTANCE* pInstance); 556 | 557 | void 558 | ICELIB_resetIceInstance(ICELIB_INSTANCE* pInstance); 559 | void 560 | ICELIB_resetAllStreamControllers(ICELIB_INSTANCE* pInstance); 561 | 562 | uint32_t 563 | ICELIB_getWeightTimeMultiplier(ICELIB_INSTANCE* pInstance); 564 | 565 | 566 | void 567 | ICELIB_PasswordUpdate(ICELIB_INSTANCE* pInstance); 568 | 569 | unsigned int 570 | ICELIB_numberOfMediaStreams(ICELIB_INSTANCE* pInstance); 571 | 572 | void 573 | ICELIB_doKeepAlive(ICELIB_INSTANCE* pInstance); 574 | 575 | void 576 | ICELIB_generateTransactionId(StunMsgId* transactionId); 577 | 578 | char* 579 | ICELIB_makeUsernamePair(char* dst, 580 | int maxlength, 581 | const char* ufrag1, 582 | const char* ufrag2); 583 | 584 | uint64_t 585 | ICELIB_makeTieBreaker(void); 586 | 587 | void 588 | ICELIB_createUfrag (char* dst, 589 | int maxLength); 590 | void 591 | ICELIB_createPasswd(char* dst, 592 | int maxLength); 593 | 594 | void 595 | ICELIB_createFoundation(char* dst, 596 | ICE_CANDIDATE_TYPE type, 597 | ICE_TRANSPORT transport, 598 | int socketfd, 599 | size_t maxlength); 600 | 601 | void 602 | ICELIB_removChecksFromCheckList(ICELIB_CHECKLIST* pCheckList); 603 | 604 | void 605 | ICELIB_resetCheckList(ICELIB_CHECKLIST* pCheckList, 606 | unsigned int checkListId); 607 | 608 | void 609 | ICELIB_resetCandidate(ICE_CANDIDATE* pCandidate); 610 | 611 | void 612 | ICELIB_saveUfragPasswd(ICELIB_CHECKLIST* pCheckList, 613 | const ICE_MEDIA_STREAM* pLocalMediaStream, 614 | const ICE_MEDIA_STREAM* pRemoteMediaStream); 615 | 616 | void 617 | ICELIB_formPairs(ICELIB_CHECKLIST* pCheckList, 618 | ICELIB_CALLBACK_LOG* pCallbackLog, 619 | const ICE_MEDIA_STREAM* pLocalMediaStream, 620 | const ICE_MEDIA_STREAM* pRemoteMediaStream, 621 | unsigned int maxPairs); 622 | 623 | uint64_t 624 | ICELIB_pairPriority(uint32_t G, 625 | uint32_t D); 626 | 627 | void 628 | ICELIB_computeListPairPriority(ICELIB_CHECKLIST* pCheckList, 629 | bool iceControlling); 630 | 631 | void 632 | ICELIB_sortPairsCL(ICELIB_CHECKLIST* pCheckList); 633 | 634 | bool 635 | ICELIB_findReflexiveBaseAddresses( 636 | const ICE_CANDIDATE** ppBaseServerReflexiveRtp, 637 | const ICE_CANDIDATE** ppBaseServerReflexiveRtcp, 638 | const ICE_MEDIA_STREAM* pLocalMediaStream); 639 | 640 | void 641 | ICELIB_prunePairs(ICELIB_CHECKLIST* pCheckList, 642 | const ICE_CANDIDATE* pBbaseServerReflexiveRtp, 643 | const ICE_CANDIDATE* pBaseServerReflexiveRtcp); 644 | 645 | void 646 | ICELIB_computeStatesSetWaitingFrozen(ICELIB_CHECKLIST* pCheckList, 647 | ICELIB_CALLBACK_LOG* pCallbackLog); 648 | 649 | bool 650 | ICELIB_makeCheckList(ICELIB_CHECKLIST* pCheckList, 651 | ICELIB_CALLBACK_LOG* pCallbackLog, 652 | const ICE_MEDIA_STREAM* pLocalMediaStream, 653 | const ICE_MEDIA_STREAM* pRemoteMediaStream, 654 | bool iceControlling, 655 | unsigned int maxPairs, 656 | unsigned int checkListId); 657 | 658 | bool 659 | ICELIB_insertIntoCheckList(ICELIB_CHECKLIST* pCheckList, 660 | ICELIB_LIST_PAIR* pPair); 661 | 662 | ICELIB_LIST_PAIR* 663 | pICELIB_findPairByState(ICELIB_CHECKLIST* pCheckList, 664 | ICELIB_PAIR_STATE pairState); 665 | 666 | ICELIB_LIST_PAIR* 667 | pICELIB_chooseOrdinaryPair(ICELIB_CHECKLIST* pCheckList); 668 | 669 | bool 670 | ICELIB_isActiveCheckList(const ICELIB_CHECKLIST* pCheckList); 671 | bool 672 | ICELIB_isFrozenCheckList(const ICELIB_CHECKLIST* pCheckList); 673 | 674 | void 675 | ICELIB_unfreezeFrozenCheckList(ICELIB_CHECKLIST* pCheckList, 676 | ICELIB_CALLBACK_LOG* pCallbackLog); 677 | void 678 | ICELIB_unfreezePairsByFoundation(ICELIB_CHECKLIST* pCheckList, 679 | const char pairFoundationToMatch[], 680 | ICELIB_CALLBACK_LOG* pCallbackLog); 681 | 682 | void 683 | ICELIB_fifoClear(ICELIB_TRIGGERED_FIFO* pFifo); 684 | unsigned int 685 | ICELIB_fifoCount(const ICELIB_TRIGGERED_FIFO* pFifo); 686 | bool 687 | ICELIB_fifoIsEmpty(const ICELIB_TRIGGERED_FIFO* pFifo); 688 | bool 689 | ICELIB_fifoIsFull(const ICELIB_TRIGGERED_FIFO* pFifo); 690 | bool 691 | ICELIB_fifoPut(ICELIB_TRIGGERED_FIFO* pFifo, 692 | ICELIB_FIFO_ELEMENT element); 693 | ICELIB_FIFO_ELEMENT 694 | ICELIB_fifoGet(ICELIB_TRIGGERED_FIFO* pFifo); 695 | 696 | void 697 | ICELIB_fifoIteratorConstructor(ICELIB_TRIGGERED_FIFO_ITERATOR* pIterator, 698 | ICELIB_TRIGGERED_FIFO* pFifo); 699 | ICELIB_FIFO_ELEMENT* 700 | pICELIB_fifoIteratorNext(ICELIB_TRIGGERED_FIFO_ITERATOR* pIterator); 701 | 702 | void 703 | ICELIB_triggeredFifoClear(ICELIB_TRIGGERED_FIFO* pFifo); 704 | unsigned int 705 | ICELIB_triggeredFifoCount(const ICELIB_TRIGGERED_FIFO* pFifo); 706 | bool 707 | ICELIB_triggeredFifoIsEmpty(const ICELIB_TRIGGERED_FIFO* pFifo); 708 | bool 709 | ICELIB_triggeredFifoIsFull(const ICELIB_TRIGGERED_FIFO* pFifo); 710 | bool 711 | ICELIB_triggeredFifoPut(ICELIB_TRIGGERED_FIFO* pFifo, 712 | ICELIB_LIST_PAIR* pPair); 713 | ICELIB_LIST_PAIR* 714 | pICELIB_triggeredFifoGet(ICELIB_CHECKLIST* pCheckList, 715 | ICELIB_CALLBACK_LOG* pCallbackLog, 716 | ICELIB_TRIGGERED_FIFO* pFifo); 717 | 718 | 719 | bool 720 | ICELIB_scheduleSingle(ICELIB_INSTANCE* pInstance, 721 | ICELIB_STREAM_CONTROLLER* pController, 722 | ICELIB_CALLBACK_LOG* pCallbackLog); 723 | 724 | 725 | char* 726 | ICELIB_getCheckListLocalUsernamePair(char* dst, 727 | int maxlength, 728 | const ICELIB_CHECKLIST* pCheckList); 729 | 730 | char* 731 | ICELIB_getCheckListRemoteUsernamePair(char* dst, 732 | int maxlength, 733 | const ICELIB_CHECKLIST* pCheckList, 734 | bool outgoing); 735 | 736 | const char* 737 | ICELIB_getCheckListRemotePasswd(const ICELIB_CHECKLIST* pCheckList); 738 | const char* 739 | ICELIB_getCheckListLocalPasswd(const ICELIB_CHECKLIST* pCheckList); 740 | 741 | bool 742 | ICELIB_isPairAddressMatch(const ICELIB_LIST_PAIR* pPair1, 743 | const ICELIB_LIST_PAIR* pPair2); 744 | 745 | ICELIB_LIST_PAIR* 746 | pICELIB_correlateToRequest(unsigned int* pStreamIndex, 747 | ICELIB_INSTANCE* pInstance, 748 | const StunMsgId* pTransactionId); 749 | 750 | unsigned int 751 | ICELIB_validListCount(const ICELIB_VALIDLIST* pValidList); 752 | 753 | void 754 | ICELIB_updatingStates(ICELIB_INSTANCE* pInstance); 755 | 756 | uint32_t 757 | ICELIB_getCandidateTypeWeight(ICE_CANDIDATE_TYPE type); 758 | 759 | uint32_t 760 | ICELIB_calculateReadyWeight(ICE_CANDIDATE_TYPE localType, 761 | ICE_CANDIDATE_TYPE remoteType, 762 | uint32_t timeMultiplier); 763 | 764 | const ICE_CANDIDATE* 765 | pICELIB_findCandidate(const ICE_MEDIA_STREAM* pMediaStream, 766 | int proto, 767 | const struct sockaddr* address, 768 | unsigned componentId); 769 | 770 | void 771 | ICELIB_validListIteratorConstructor(ICELIB_VALIDLIST_ITERATOR* pIterator, 772 | ICELIB_VALIDLIST* pValidList); 773 | ICELIB_VALIDLIST_ELEMENT* 774 | pICELIB_validListIteratorNext(ICELIB_VALIDLIST_ITERATOR* pIterator); 775 | const char* 776 | ICELIB_toString_CheckListPairState(ICELIB_PAIR_STATE state); 777 | 778 | 779 | char* 780 | ICELIB_getPairFoundation(char* dst, 781 | int maxlength, 782 | const ICELIB_LIST_PAIR* pPair); 783 | 784 | 785 | void 786 | ICELIB_netAddrDumpLog(const ICELIB_CALLBACK_LOG* pCallbackLog, 787 | ICELIB_logLevel logLevel, 788 | const struct sockaddr* netAddr); 789 | void 790 | ICELIB_transactionIdDumpLog(const ICELIB_CALLBACK_LOG* pCallbackLog, 791 | ICELIB_logLevel logLevel, 792 | StunMsgId tId); 793 | void 794 | ICELIB_candidateDumpLog(const ICELIB_CALLBACK_LOG* pCallbackLog, 795 | ICELIB_logLevel logLevel, 796 | const ICE_CANDIDATE* candidate); 797 | void 798 | ICELIB_componentIdsDumpLog(const ICELIB_CALLBACK_LOG* pCallbackLog, 799 | ICELIB_logLevel logLevel, 800 | const ICELIB_COMPONENTLIST* pComponentList); 801 | void 802 | ICELIB_pairDumpLog(const ICELIB_CALLBACK_LOG* pCallbackLog, 803 | ICELIB_logLevel logLevel, 804 | const ICELIB_LIST_PAIR* pPair); 805 | void 806 | ICELIB_checkListDumpLog(const ICELIB_CALLBACK_LOG* pCallbackLog, 807 | ICELIB_logLevel logLevel, 808 | const ICELIB_CHECKLIST* pCheckList); 809 | void 810 | ICELIB_checkListDumpLogLog(const ICELIB_CALLBACK_LOG* pCallbackLog, 811 | ICELIB_logLevel logLevel, 812 | const ICELIB_CHECKLIST* pCheckList); 813 | void 814 | ICELIB_validListDumpLog(const ICELIB_CALLBACK_LOG* pCallbackLog, 815 | ICELIB_logLevel logLevel, 816 | ICELIB_VALIDLIST* pValidList); 817 | 818 | void 819 | ICELIB_netAddrDump(const struct sockaddr* netAddr); 820 | void 821 | ICELIB_transactionIdDump(StunMsgId tId); 822 | void 823 | ICELIB_candidateDump(const ICE_CANDIDATE* candidate); 824 | void 825 | ICELIB_componentIdsDump(const ICELIB_COMPONENTLIST* pComponentList); 826 | void 827 | ICELIB_checkListDumpPair(const ICELIB_LIST_PAIR* pPair); 828 | void 829 | ICELIB_checkListDump(const ICELIB_CHECKLIST* pCheckList); 830 | void 831 | ICELIB_checkListDumpAll(const ICELIB_INSTANCE* pInstance); 832 | void 833 | ICELIB_validListDump(ICELIB_VALIDLIST* pValidList); 834 | 835 | #ifdef __cplusplus 836 | } 837 | #endif 838 | 839 | 840 | #endif /* ICELIB_INTERN_H */ 841 | -------------------------------------------------------------------------------- /src/icelibtypes.c: -------------------------------------------------------------------------------- 1 | /* 2 | * See License file 3 | */ 4 | 5 | #include "sockaddr_util.h" 6 | #include "icelibtypes.h" 7 | #include 8 | #include 9 | 10 | char const* 11 | ICELIBTYPES_ICE_CANDIDATE_TYPE_toString(const ICE_CANDIDATE_TYPE candidateType) 12 | { 13 | switch (candidateType) 14 | { 15 | case ICE_CAND_TYPE_NONE: 16 | return "none"; 17 | case ICE_CAND_TYPE_HOST: 18 | return "host"; 19 | case ICE_CAND_TYPE_SRFLX: 20 | return "srflx"; 21 | case ICE_CAND_TYPE_RELAY: 22 | return "relay"; 23 | case ICE_CAND_TYPE_PRFLX: 24 | return "prflx"; 25 | } 26 | return "unknown"; 27 | } 28 | 29 | char const* 30 | ICELIBTYPES_ICE_TRANSPORT_PROTO_toString(const ICE_TRANSPORT t) 31 | { 32 | switch (t) 33 | { 34 | case ICE_TRANS_NONE: 35 | return "NONE"; 36 | case ICE_TRANS_UDP: 37 | return "UDP"; 38 | case ICE_TRANS_TCPACT: 39 | case ICE_TRANS_TCPPASS: 40 | return "TCP"; 41 | } 42 | return "UNKNOWN"; 43 | } 44 | 45 | char const* 46 | ICELIBTYPES_ICE_TRANSPORT_toString(ICE_TRANSPORT t) 47 | { 48 | switch (t) 49 | { 50 | case ICE_TRANS_NONE: return "none"; 51 | case ICE_TRANS_UDP: return "udp"; 52 | case ICE_TRANS_TCPACT: return "tcpact"; 53 | case ICE_TRANS_TCPPASS: return "tcppass"; 54 | } 55 | return "UNKNOWN"; 56 | } 57 | 58 | char const* 59 | ICELIBTYPES_ICE_CANDIDATE_Component_toString (uint32_t componentid) 60 | { 61 | if (componentid == ICELIB_RTP_COMPONENT_ID) 62 | { 63 | return "RTP"; 64 | } 65 | else if (componentid == ICELIB_RTCP_COMPONENT_ID) 66 | { 67 | return "RTCP"; 68 | } 69 | 70 | return "UNKNOWN Component"; 71 | 72 | } 73 | 74 | void 75 | ICELIBTYPES_ICE_CANDIDATE_reset(ICE_CANDIDATE* candidate) 76 | { 77 | memset( candidate, 0, sizeof(*candidate) ); 78 | } 79 | 80 | bool 81 | ICELIBTYPES_ICE_MEDIA_STREAM_isEmpty(const ICE_MEDIA_STREAM* iceMediaStream) 82 | { 83 | if (iceMediaStream->numberOfCandidates > 0) 84 | { 85 | return false; 86 | } 87 | return true; 88 | } 89 | 90 | bool 91 | ICELIBTYPES_ICE_MEDIA_isEmpty(const ICE_MEDIA* iceMedia) 92 | { 93 | if (iceMedia->numberOfICEMediaLines > 0) 94 | { 95 | return false; 96 | } 97 | return true; 98 | } 99 | 100 | void 101 | ICELIBTYPES_ICE_MEDIA_STREAM_reset(ICE_MEDIA_STREAM* iceMediaStream) 102 | { 103 | memset( iceMediaStream, 0, sizeof(*iceMediaStream) ); 104 | } 105 | 106 | void 107 | ICELIBTYPES_ICE_MEDIA_reset(ICE_MEDIA* iceMedia) 108 | { 109 | memset( iceMedia, 0, sizeof(*iceMedia) ); 110 | } 111 | 112 | int 113 | ICE_TRANSPORT_proto(ICE_TRANSPORT transport) 114 | { 115 | switch (transport) 116 | { 117 | case ICE_TRANS_NONE: 118 | return -1; 119 | case ICE_TRANS_UDP: 120 | return IPPROTO_UDP; 121 | 122 | case ICE_TRANS_TCPACT: 123 | case ICE_TRANS_TCPPASS: 124 | return IPPROTO_TCP; 125 | } 126 | 127 | abort(); 128 | } 129 | -------------------------------------------------------------------------------- /src/timer.c: -------------------------------------------------------------------------------- 1 | /* 2 | * See License file 3 | */ 4 | 5 | 6 | #include 7 | #include "icelib.h" 8 | #include "icelib_intern.h" 9 | 10 | 11 | void 12 | ICELIB_timerConstructor(ICELIB_TIMER* timer, 13 | unsigned int tickIntervalMS) 14 | { 15 | memset( timer, 0, sizeof(*timer) ); 16 | timer->tickIntervalMS = tickIntervalMS; 17 | timer->countUpMS = 0; 18 | timer->timerState = ICELIB_timerStopped; 19 | } 20 | 21 | 22 | void 23 | ICELIB_timerStart(ICELIB_TIMER* timer, 24 | unsigned int timeoutMS) 25 | { 26 | timer->timeoutValueMS = timeoutMS; 27 | timer->countUpMS = 0; 28 | timer->timerState = ICELIB_timerRunning; 29 | } 30 | 31 | 32 | void 33 | ICELIB_timerStop(ICELIB_TIMER* timer) 34 | { 35 | timer->timerState = ICELIB_timerStopped; 36 | } 37 | 38 | 39 | void 40 | ICELIB_timerTick(ICELIB_TIMER* timer) 41 | { 42 | if (timer->timerState == ICELIB_timerRunning) 43 | { 44 | 45 | timer->countUpMS += timer->tickIntervalMS; 46 | 47 | if (timer->countUpMS >= timer->timeoutValueMS) 48 | { 49 | timer->timerState = ICELIB_timerTimeout; 50 | } 51 | } 52 | } 53 | 54 | 55 | bool 56 | ICELIB_timerIsRunning(const ICELIB_TIMER* timer) 57 | { 58 | return timer->timerState == ICELIB_timerRunning; 59 | } 60 | 61 | 62 | bool 63 | ICELIB_timerIsTimedOut(const ICELIB_TIMER* timer) 64 | { 65 | return timer->timerState == ICELIB_timerTimeout; 66 | } 67 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # 3 | # Compiling/running tests 4 | set ( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${dist_dir}/test ) 5 | 6 | function (sa_test name) 7 | add_executable ( ${name}_test ${name}_test.c test_utils.c) 8 | target_link_libraries ( ${name}_test PRIVATE icelib stunlib sockaddrutil ) 9 | target_include_directories ( ${name}_test PRIVATE ../include ) 10 | add_test ( NAME ${name} COMMAND ${name}_test ) 11 | endfunction() 12 | 13 | sa_test ( icelib ) 14 | sa_test ( icelibtypes ) 15 | sa_test ( icelib_running ) 16 | sa_test ( icelib_ce ) 17 | sa_test ( icelib_nomination ) 18 | sa_test ( icelib_nomination_medialines ) 19 | 20 | include ( CTest ) 21 | -------------------------------------------------------------------------------- /test/ctest.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2011,2012 Bas van den Berg 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef CTEST_H 17 | #define CTEST_H 18 | 19 | #ifndef UNUSED_PARAM 20 | /** 21 | * \def UNUSED_PARAM(p); 22 | * 23 | * A macro for quelling compiler warnings about unused variables. 24 | */ 25 | # define UNUSED_PARAM(p) ( (void)&(p) ) 26 | #endif /* UNUSED_PARM */ 27 | 28 | typedef void (* SetupFunc)(void*); 29 | typedef void (* TearDownFunc)(void*); 30 | 31 | struct ctest { 32 | const char* ssname; /* suite name */ 33 | const char* ttname; /* test name */ 34 | void (* run)(); 35 | int skip; 36 | 37 | void* data; 38 | SetupFunc setup; 39 | TearDownFunc teardown; 40 | 41 | unsigned int magic; 42 | }; 43 | 44 | #define __FNAME(sname, tname) __ctest_ ## sname ## _ ## tname ## _run 45 | #define __TNAME(sname, tname) __ctest_ ## sname ## _ ## tname 46 | 47 | #define __CTEST_MAGIC (0xdeadbeef) 48 | #ifdef __APPLE__ 49 | #define __Test_Section __attribute__ ( ( unused,section("__DATA, .ctest") ) ) 50 | #else 51 | #define __Test_Section __attribute__ ( ( unused,section(".ctest") ) ) 52 | #endif 53 | 54 | #define __CTEST_STRUCT(sname, tname, _skip, __data, __setup, __teardown) \ 55 | struct ctest __TNAME(sname, tname) __Test_Section = { \ 56 | .ssname =#sname, \ 57 | .ttname =#tname, \ 58 | .run = __FNAME(sname, tname), \ 59 | .skip = _skip, \ 60 | .data = __data, \ 61 | .setup = (SetupFunc)__setup, \ 62 | .teardown = (TearDownFunc)__teardown, \ 63 | .magic = __CTEST_MAGIC }; 64 | 65 | #define CTEST_DATA(sname) struct sname ## _data 66 | 67 | #define CTEST_SETUP(sname) \ 68 | void __attribute__ ( (weak) ) sname ## _setup(struct sname ## _data* data) 69 | 70 | #define CTEST_TEARDOWN(sname) \ 71 | void __attribute__ ( (weak) ) sname ## _teardown(struct sname ## _data* data) 72 | 73 | #define __CTEST_INTERNAL(sname, tname, _skip) \ 74 | void __FNAME(sname, tname)(); \ 75 | __CTEST_STRUCT(sname, tname, _skip, NULL, NULL, NULL) \ 76 | void __FNAME(sname, tname)() 77 | 78 | #ifdef __APPLE__ 79 | #define SETUP_FNAME(sname) NULL 80 | #define TEARDOWN_FNAME(sname) NULL 81 | #else 82 | #define SETUP_FNAME(sname) sname ## _setup 83 | #define TEARDOWN_FNAME(sname) sname ## _teardown 84 | #endif 85 | 86 | #define __CTEST2_INTERNAL(sname, tname, _skip) \ 87 | static struct sname ## _data __ctest_ ## sname ## _data; \ 88 | CTEST_SETUP(sname); \ 89 | CTEST_TEARDOWN(sname); \ 90 | void __FNAME(sname, tname)(struct sname ## _data* data); \ 91 | __CTEST_STRUCT( sname, tname, _skip, &__ctest_ ## sname ## _data, \ 92 | SETUP_FNAME(sname), TEARDOWN_FNAME(sname) ) \ 93 | void __FNAME(sname, tname)(struct sname ## _data* data) 94 | 95 | 96 | void 97 | CTEST_LOG(char* fmt, 98 | ...); 99 | void 100 | CTEST_ERR(char* fmt, 101 | ...); /* doesn't return */ 102 | 103 | #define CTEST(sname, tname) __CTEST_INTERNAL(sname, tname, 0) 104 | #define CTEST_SKIP(sname, tname) __CTEST_INTERNAL(sname, tname, 1) 105 | 106 | #define CTEST2(sname, tname) __CTEST2_INTERNAL(sname, tname, 0) 107 | #define CTEST2_SKIP(sname, tname) __CTEST2_INTERNAL(sname, tname, 1) 108 | 109 | 110 | void 111 | assert_str(const char* exp, 112 | const char* real, 113 | const char* caller, 114 | int line); 115 | #define ASSERT_STR(exp, real) assert_str(exp, real, __FILE__, __LINE__) 116 | 117 | void 118 | assert_data(const unsigned char* exp, 119 | int expsize, 120 | const unsigned char* real, 121 | int realsize, 122 | const char* caller, 123 | int line); 124 | #define ASSERT_DATA(exp, expsize, real, realsize) \ 125 | assert_data(exp, expsize, real, realsize, __FILE__, __LINE__) 126 | 127 | void 128 | assert_equal(long exp, 129 | long real, 130 | const char* caller, 131 | int line); 132 | #define ASSERT_EQUAL(exp, real) assert_equal(exp, real, __FILE__, __LINE__) 133 | 134 | void 135 | assert_not_equal(long exp, 136 | long real, 137 | const char* caller, 138 | int line); 139 | #define ASSERT_NOT_EQUAL(exp, real) assert_not_equal(exp, \ 140 | real, \ 141 | __FILE__, \ 142 | __LINE__) 143 | 144 | void 145 | assert_null(void* real, 146 | const char* caller, 147 | int line); 148 | #define ASSERT_NULL(real) assert_null( (void*)real, __FILE__, __LINE__ ) 149 | 150 | void 151 | assert_not_null(const void* real, 152 | const char* caller, 153 | int line); 154 | #define ASSERT_NOT_NULL(real) assert_not_null(real, __FILE__, __LINE__) 155 | 156 | void 157 | assert_true(int real, 158 | const char* caller, 159 | int line); 160 | #define ASSERT_TRUE(real) assert_true(real, __FILE__, __LINE__) 161 | 162 | void 163 | assert_false(int real, 164 | const char* caller, 165 | int line); 166 | #define ASSERT_FALSE(real) assert_false(real, __FILE__, __LINE__) 167 | 168 | void 169 | assert_fail(const char* caller, 170 | int line); 171 | #define ASSERT_FAIL() assert_fail(__FILE__, __LINE__) 172 | 173 | #ifdef CTEST_MAIN 174 | 175 | #include 176 | #include 177 | #include 178 | #include 179 | #include 180 | #include 181 | #include 182 | #include 183 | #include 184 | 185 | #ifdef __APPLE__ 186 | #include 187 | #endif 188 | 189 | /* #define COLOR_OK */ 190 | 191 | static size_t ctest_errorsize; 192 | static char* ctest_errormsg; 193 | #define MSG_SIZE 4096 194 | static char ctest_errorbuffer[MSG_SIZE]; 195 | static jmp_buf ctest_err; 196 | static int color_output = 1; 197 | static const char* suite_name; 198 | 199 | typedef int (* filter_func)(struct ctest*); 200 | 201 | #define ANSI_BLACK "\033[0;30m" 202 | #define ANSI_RED "\033[0;31m" 203 | #define ANSI_GREEN "\033[0;32m" 204 | #define ANSI_YELLOW "\033[0;33m" 205 | #define ANSI_BLUE "\033[0;34m" 206 | #define ANSI_MAGENTA "\033[0;35m" 207 | #define ANSI_CYAN "\033[0;36m" 208 | #define ANSI_GREY "\033[0;37m" 209 | #define ANSI_DARKGREY "\033[01;30m" 210 | #define ANSI_BRED "\033[01;31m" 211 | #define ANSI_BGREEN "\033[01;32m" 212 | #define ANSI_BYELLOW "\033[01;33m" 213 | #define ANSI_BBLUE "\033[01;34m" 214 | #define ANSI_BMAGENTA "\033[01;35m" 215 | #define ANSI_BCYAN "\033[01;36m" 216 | #define ANSI_WHITE "\033[01;37m" 217 | #define ANSI_NORMAL "\033[0m" 218 | 219 | static CTEST(suite, test) { 220 | } 221 | 222 | static void 223 | msg_start(const char* color, 224 | const char* title) 225 | { 226 | int size; 227 | if (color_output) 228 | { 229 | size = snprintf(ctest_errormsg, ctest_errorsize, "%s", color); 230 | ctest_errorsize -= size; 231 | ctest_errormsg += size; 232 | } 233 | size = snprintf(ctest_errormsg, ctest_errorsize, " %s: ", title); 234 | ctest_errorsize -= size; 235 | ctest_errormsg += size; 236 | } 237 | 238 | static void 239 | msg_end() 240 | { 241 | int size; 242 | if (color_output) 243 | { 244 | size = snprintf(ctest_errormsg, ctest_errorsize, ANSI_NORMAL); 245 | ctest_errorsize -= size; 246 | ctest_errormsg += size; 247 | } 248 | size = snprintf(ctest_errormsg, ctest_errorsize, "\n"); 249 | ctest_errorsize -= size; 250 | ctest_errormsg += size; 251 | } 252 | 253 | void 254 | CTEST_LOG(char* fmt, 255 | ...) 256 | { 257 | va_list argp; 258 | msg_start(ANSI_BLUE, "LOG"); 259 | 260 | va_start(argp, fmt); 261 | int size = vsnprintf(ctest_errormsg, ctest_errorsize, fmt, argp); 262 | ctest_errorsize -= size; 263 | ctest_errormsg += size; 264 | va_end(argp); 265 | 266 | msg_end(); 267 | } 268 | 269 | void 270 | CTEST_ERR(char* fmt, 271 | ...) 272 | { 273 | va_list argp; 274 | msg_start(ANSI_YELLOW, "ERR"); 275 | 276 | va_start(argp, fmt); 277 | int size = vsnprintf(ctest_errormsg, ctest_errorsize, fmt, argp); 278 | ctest_errorsize -= size; 279 | ctest_errormsg += size; 280 | va_end(argp); 281 | 282 | msg_end(); 283 | longjmp(ctest_err, 1); 284 | } 285 | 286 | void 287 | assert_str(const char* exp, 288 | const char* real, 289 | const char* caller, 290 | int line) 291 | { 292 | if ( ( (exp == NULL) && (real != NULL) ) || 293 | ( (exp != NULL) && (real == NULL) ) || 294 | ( exp && real && (strcmp(exp, real) != 0) ) ) 295 | { 296 | CTEST_ERR("%s:%d expected '%s', got '%s'", caller, line, exp, real); 297 | } 298 | } 299 | 300 | void 301 | assert_data(const unsigned char* exp, 302 | int expsize, 303 | const unsigned char* real, 304 | int realsize, 305 | const char* caller, 306 | int line) 307 | { 308 | int i; 309 | if (expsize != realsize) 310 | { 311 | CTEST_ERR("%s:%d expected %d bytes, got %d", 312 | caller, 313 | line, 314 | expsize, 315 | realsize); 316 | } 317 | for (i = 0; i < expsize; i++) 318 | { 319 | if (exp[i] != real[i]) 320 | { 321 | CTEST_ERR("%s:%d expected 0x%02x at offset %d got 0x%02x", 322 | caller, line, exp[i], i, real[i]); 323 | } 324 | } 325 | } 326 | 327 | void 328 | assert_equal(long exp, 329 | long real, 330 | const char* caller, 331 | int line) 332 | { 333 | if (exp != real) 334 | { 335 | CTEST_ERR("%s:%d expected %ld, got %ld", caller, line, exp, real); 336 | } 337 | } 338 | 339 | void 340 | assert_not_equal(long exp, 341 | long real, 342 | const char* caller, 343 | int line) 344 | { 345 | if ( (exp) == (real) ) 346 | { 347 | CTEST_ERR("%s:%d should not be %ld", caller, line, real); 348 | } 349 | } 350 | 351 | void 352 | assert_null(void* real, 353 | const char* caller, 354 | int line) 355 | { 356 | if ( (real) != NULL ) 357 | { 358 | CTEST_ERR("%s:%d should be NULL", caller, line); 359 | } 360 | } 361 | 362 | void 363 | assert_not_null(const void* real, 364 | const char* caller, 365 | int line) 366 | { 367 | if (real == NULL) 368 | { 369 | CTEST_ERR("%s:%d should not be NULL", caller, line); 370 | } 371 | } 372 | 373 | void 374 | assert_true(int real, 375 | const char* caller, 376 | int line) 377 | { 378 | if ( (real) == 0 ) 379 | { 380 | CTEST_ERR("%s:%d should be true", caller, line); 381 | } 382 | } 383 | 384 | void 385 | assert_false(int real, 386 | const char* caller, 387 | int line) 388 | { 389 | if ( (real) != 0 ) 390 | { 391 | CTEST_ERR("%s:%d should be false", caller, line); 392 | } 393 | } 394 | 395 | void 396 | assert_fail(const char* caller, 397 | int line) 398 | { 399 | CTEST_ERR("%s:%d shouldn't come here", caller, line); 400 | } 401 | 402 | 403 | static int 404 | suite_all(struct ctest* t) 405 | { 406 | UNUSED_PARAM(t); 407 | return 1; 408 | } 409 | 410 | static int 411 | suite_filter(struct ctest* t) 412 | { 413 | return strncmp( suite_name, t->ssname, strlen(suite_name) ) == 0; 414 | } 415 | 416 | static uint64_t 417 | getCurrentTime() 418 | { 419 | struct timeval now; 420 | gettimeofday(&now, NULL); 421 | uint64_t now64 = now.tv_sec; 422 | now64 *= 1000000; 423 | now64 += (now.tv_usec); 424 | return now64; 425 | } 426 | 427 | static void 428 | color_print(const char* color, 429 | const char* text) 430 | { 431 | if (color_output) 432 | { 433 | printf("%s%s"ANSI_NORMAL "\n", color, text); 434 | } 435 | else 436 | { 437 | printf("%s\n", text); 438 | } 439 | } 440 | 441 | #ifdef __APPLE__ 442 | static void* 443 | find_symbol(struct ctest* test, 444 | const char* fname) 445 | { 446 | size_t len = strlen(test->ssname) + 1 + strlen(fname); 447 | char* symbol_name = (char*) malloc(len + 1); 448 | memset(symbol_name, 0, len + 1); 449 | snprintf(symbol_name, len + 1, "%s_%s", test->ssname, fname); 450 | 451 | /* fprintf(stderr, ">>>> dlsym: loading %s\n", symbol_name); */ 452 | void* symbol = dlsym(RTLD_DEFAULT, symbol_name); 453 | if (!symbol) 454 | { 455 | /* fprintf(stderr, ">>>> ERROR: %s\n", dlerror()); */ 456 | } 457 | /* returns NULL on error */ 458 | 459 | free(symbol_name); 460 | return symbol; 461 | } 462 | #endif 463 | 464 | #ifdef CTEST_SEGFAULT 465 | #include 466 | static void 467 | sighandler(int signum) 468 | { 469 | char msg[128]; 470 | sprintf(msg, "[SIGNAL %d: %s]", signum, sys_siglist[signum]); 471 | color_print(ANSI_BRED, msg); 472 | fflush(stdout); 473 | 474 | /* "Unregister" the signal handler and send the signal back to the process 475 | * so it can terminate as expected */ 476 | signal(signum, SIG_DFL); 477 | kill(getpid(), signum); 478 | } 479 | #endif 480 | 481 | int 482 | ctest_main(int argc, 483 | const char* argv[]) 484 | { 485 | static int total = 0; 486 | static int num_ok = 0; 487 | static int num_fail = 0; 488 | static int num_skip = 0; 489 | static int index = 1; 490 | static filter_func filter = suite_all; 491 | 492 | #ifdef CTEST_SEGFAULT 493 | signal(SIGSEGV, sighandler); 494 | #endif 495 | 496 | if (argc == 2) 497 | { 498 | suite_name = argv[1]; 499 | filter = suite_filter; 500 | } 501 | 502 | color_output = isatty(1); 503 | uint64_t t1 = getCurrentTime(); 504 | 505 | struct ctest* ctest_begin = &__TNAME(suite, test); 506 | struct ctest* ctest_end = &__TNAME(suite, test); 507 | /* find begin and end of section by comparing magics */ 508 | while (1) 509 | { 510 | struct ctest* t = ctest_begin - 1; 511 | if (t->magic != __CTEST_MAGIC) 512 | { 513 | break; 514 | } 515 | ctest_begin--; 516 | } 517 | while (1) 518 | { 519 | struct ctest* t = ctest_end + 1; 520 | if (t->magic != __CTEST_MAGIC) 521 | { 522 | break; 523 | } 524 | ctest_end++; 525 | } 526 | ctest_end++; /* end after last one */ 527 | 528 | static struct ctest* test; 529 | for (test = ctest_begin; test != ctest_end; test++) 530 | { 531 | if (test == &__ctest_suite_test) 532 | { 533 | continue; 534 | } 535 | if ( filter(test) ) 536 | { 537 | total++; 538 | } 539 | } 540 | 541 | for (test = ctest_begin; test != ctest_end; test++) 542 | { 543 | if (test == &__ctest_suite_test) 544 | { 545 | continue; 546 | } 547 | if ( filter(test) ) 548 | { 549 | ctest_errorbuffer[0] = 0; 550 | ctest_errorsize = MSG_SIZE - 1; 551 | ctest_errormsg = ctest_errorbuffer; 552 | printf("TEST %d/%d %s:%s ", index, total, test->ssname, test->ttname); 553 | fflush(stdout); 554 | if (test->skip) 555 | { 556 | color_print(ANSI_BYELLOW, "[SKIPPED]"); 557 | num_skip++; 558 | } 559 | else 560 | { 561 | int result = setjmp(ctest_err); 562 | if (result == 0) 563 | { 564 | #ifdef __APPLE__ 565 | if (!test->setup) 566 | { 567 | test->setup = (SetupFunc)find_symbol(test, "setup"); 568 | } 569 | if (!test->teardown) 570 | { 571 | test->teardown = (SetupFunc)find_symbol(test, "teardown"); 572 | } 573 | #endif 574 | 575 | if (test->setup) 576 | { 577 | test->setup(test->data); 578 | } 579 | if (test->data) 580 | { 581 | test->run(test->data); 582 | } 583 | else 584 | { 585 | test->run(); 586 | } 587 | if (test->teardown) 588 | { 589 | test->teardown(test->data); 590 | } 591 | /* if we got here it's ok */ 592 | #ifdef COLOR_OK 593 | color_print(ANSI_BGREEN, "[OK]"); 594 | #else 595 | printf("[OK]\n"); 596 | #endif 597 | num_ok++; 598 | } 599 | else 600 | { 601 | color_print(ANSI_BRED, "[FAIL]"); 602 | num_fail++; 603 | } 604 | if (ctest_errorsize != MSG_SIZE - 1) 605 | { 606 | printf("%s", ctest_errorbuffer); 607 | } 608 | } 609 | index++; 610 | } 611 | } 612 | uint64_t t2 = getCurrentTime(); 613 | 614 | const char* color = (num_fail) ? ANSI_BRED : ANSI_GREEN; 615 | char results[80]; 616 | sprintf(results, 617 | "RESULTS: %d tests (%d ok, %d failed, %d skipped) ran in %" PRIu64 " ms", 618 | total, 619 | num_ok, 620 | num_fail, 621 | num_skip, 622 | (t2 - t1) / 1000); 623 | color_print(color, results); 624 | return num_fail; 625 | } 626 | 627 | #endif 628 | 629 | #endif 630 | -------------------------------------------------------------------------------- /test/icelib_nomination_medialines_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "test_utils.h" 7 | #include "icelib.h" 8 | 9 | 10 | ICELIB_INSTANCE* m_icelib; 11 | static char remoteUfrag[] = "rm0Uf"; 12 | static char remotePasswd[] = "rm0Pa"; 13 | 14 | 15 | typedef struct { 16 | bool gotCB; 17 | const struct sockaddr* destination; 18 | const struct sockaddr* source; 19 | uint32_t userValue1; 20 | uint32_t userValue2; 21 | uint32_t componentId; 22 | bool useRelay; 23 | char ufrag[ ICE_MAX_UFRAG_LENGTH]; 24 | /* const char *pUfrag; */ 25 | const char* pPasswd; 26 | uint32_t peerPriority; 27 | bool useCandidate; 28 | bool iceControlling; 29 | bool iceControlled; 30 | uint64_t tieBreaker; 31 | StunMsgId transactionId; 32 | }m_ConncheckCB; 33 | 34 | 35 | typedef struct { 36 | uint64_t priority; 37 | int32_t proto; 38 | struct sockaddr_storage local; 39 | struct sockaddr_storage remote; 40 | }m_NominationCB; 41 | 42 | m_ConncheckCB m_connChkCB[50]; 43 | uint32_t num_checks = 0; 44 | 45 | m_ConncheckCB m_nomChkCB[50]; 46 | uint32_t num_nom = 0; /* sorry could not resist the name..*/ 47 | 48 | m_NominationCB m_nominationCB[50]; 49 | uint32_t num_pair_nom = 0; 50 | 51 | 52 | ICELIB_Result 53 | Complete(void* pUserData, 54 | unsigned int userval1, 55 | bool controlling, 56 | bool failed) 57 | { 58 | (void) pUserData; 59 | (void) userval1; 60 | (void) controlling; 61 | (void) failed; 62 | 63 | return 0; 64 | } 65 | 66 | ICELIB_Result 67 | Nominated(void* pUserData, 68 | uint32_t userValue1, 69 | uint32_t userValue2, 70 | uint32_t componentId, 71 | uint64_t priority, 72 | int32_t proto, 73 | const struct sockaddr* local, 74 | const struct sockaddr* remote) 75 | { 76 | (void)pUserData; 77 | (void)userValue1; 78 | (void)userValue2; 79 | (void)componentId; 80 | (void)priority; 81 | (void) proto; 82 | (void)local; 83 | (void) remote; 84 | 85 | m_nominationCB[num_pair_nom].priority = priority; 86 | m_nominationCB[num_pair_nom].proto = proto; 87 | sockaddr_copy( (struct sockaddr*)&m_nominationCB[num_pair_nom].local, 88 | local ); 89 | sockaddr_copy( (struct sockaddr*)&m_nominationCB[num_pair_nom].remote, 90 | remote ); 91 | num_pair_nom++; 92 | return 0; 93 | } 94 | 95 | ICELIB_Result 96 | sendConnectivityCheck(void* pUserData, 97 | int proto, 98 | int socket, 99 | const struct sockaddr* destination, 100 | const struct sockaddr* source, 101 | uint32_t userValue1, 102 | uint32_t userValue2, 103 | uint32_t componentId, 104 | bool useRelay, 105 | const char* pUfrag, 106 | const char* pPasswd, 107 | uint32_t peerPriority, 108 | bool useCandidate, 109 | bool iceControlling, 110 | bool iceControlled, 111 | uint64_t tieBreaker, 112 | StunMsgId transactionId) 113 | { 114 | (void)pUserData; 115 | (void) proto; 116 | (void) socket; 117 | if (useCandidate) 118 | { 119 | m_nomChkCB[num_nom].gotCB = true; 120 | m_nomChkCB[num_nom].destination = destination; 121 | m_nomChkCB[num_nom].source = source; 122 | m_nomChkCB[num_nom].userValue1 = userValue1; 123 | m_nomChkCB[num_nom].userValue2 = userValue2; 124 | m_nomChkCB[num_nom].componentId = componentId; 125 | m_nomChkCB[num_nom].useRelay = useRelay; 126 | strncpy(m_nomChkCB[num_nom].ufrag, pUfrag, ICE_MAX_UFRAG_LENGTH); 127 | m_nomChkCB[num_nom].pPasswd = pPasswd; 128 | m_nomChkCB[num_nom].peerPriority = peerPriority; 129 | m_nomChkCB[num_nom].useCandidate = useCandidate; 130 | m_nomChkCB[num_nom].iceControlling = iceControlling; 131 | m_nomChkCB[num_nom].iceControlled = iceControlled; 132 | m_nomChkCB[num_nom].transactionId = transactionId; 133 | m_nomChkCB[num_nom].tieBreaker = tieBreaker; 134 | num_nom++; 135 | } 136 | else 137 | { 138 | m_connChkCB[num_checks].gotCB = true; 139 | m_connChkCB[num_checks].destination = destination; 140 | m_connChkCB[num_checks].source = source; 141 | m_connChkCB[num_checks].userValue1 = userValue1; 142 | m_connChkCB[num_checks].userValue2 = userValue2; 143 | m_connChkCB[num_checks].componentId = componentId; 144 | m_connChkCB[num_checks].useRelay = useRelay; 145 | strncpy(m_connChkCB[num_checks].ufrag, pUfrag, ICE_MAX_UFRAG_LENGTH); 146 | m_connChkCB[num_checks].pPasswd = pPasswd; 147 | m_connChkCB[num_checks].peerPriority = peerPriority; 148 | m_connChkCB[num_checks].useCandidate = useCandidate; 149 | m_connChkCB[num_checks].iceControlling = iceControlling; 150 | m_connChkCB[num_checks].iceControlled = iceControlled; 151 | m_connChkCB[num_checks].transactionId = transactionId; 152 | m_connChkCB[num_checks].tieBreaker = tieBreaker; 153 | 154 | num_checks++; 155 | } 156 | return 0; 157 | } 158 | 159 | void 160 | printLog(void* pUserData, 161 | ICELIB_logLevel logLevel, 162 | const char* str) 163 | { 164 | (void)pUserData; 165 | (void)logLevel; 166 | (void)str; 167 | /* printf("%s\n", str); */ 168 | } 169 | 170 | CTEST_DATA(data) 171 | { 172 | int a; 173 | }; 174 | 175 | 176 | CTEST_SETUP(data) 177 | { 178 | (void)data; 179 | struct sockaddr_storage m0_defaultAddr; 180 | struct sockaddr_storage m0_localHostRtp; 181 | struct sockaddr_storage m1_localHostRtp; 182 | 183 | ICELIB_CONFIGURATION iceConfig; 184 | 185 | uint32_t mediaIdx; 186 | 187 | srand( time(NULL) ); 188 | num_checks = 0; 189 | num_nom = 0; 190 | num_pair_nom = 0; 191 | 192 | m_icelib = (ICELIB_INSTANCE*)malloc( sizeof(ICELIB_INSTANCE) ); 193 | 194 | sockaddr_initFromString( (struct sockaddr*)&m0_localHostRtp, 195 | "192.168.2.10:56780" ); 196 | sockaddr_initFromString( (struct sockaddr*)&m1_localHostRtp, 197 | "192.168.2.10:56788" ); 198 | 199 | 200 | iceConfig.tickIntervalMS = 20; 201 | iceConfig.keepAliveIntervalS = 15; 202 | iceConfig.maxCheckListPairs = ICELIB_MAX_PAIRS; 203 | iceConfig.aggressiveNomination = true; 204 | iceConfig.iceLite = false; 205 | iceConfig.logLevel = ICELIB_logDebug; 206 | /* iceConfig.logLevel = ICELIB_logDisable; */ 207 | 208 | 209 | ICELIB_Constructor(m_icelib, 210 | &iceConfig); 211 | 212 | ICELIB_setCallbackOutgoingBindingRequest(m_icelib, 213 | sendConnectivityCheck, 214 | NULL); 215 | 216 | ICELIB_setCallbackConnecitivityChecksComplete(m_icelib, 217 | Complete, 218 | NULL); 219 | 220 | 221 | ICELIB_setCallbackLog(m_icelib, 222 | printLog, 223 | NULL, 224 | ICELIB_logDebug); 225 | 226 | ICELIB_setCallbackNominated(m_icelib, 227 | Nominated, 228 | NULL); 229 | 230 | /* Local side */ 231 | /* Medialine: 0 */ 232 | mediaIdx = ICELIB_addLocalMediaStream(m_icelib, 42, 42, ICE_CAND_TYPE_HOST); 233 | ICELIB_addLocalCandidate(m_icelib, 234 | mediaIdx, 235 | 1, 236 | 5, 237 | (struct sockaddr*)&m0_localHostRtp, 238 | NULL, 239 | ICE_TRANS_UDP, 240 | ICE_CAND_TYPE_HOST, 241 | 0xffff); 242 | mediaIdx = ICELIB_addLocalMediaStream(m_icelib, 42, 43, ICE_CAND_TYPE_HOST); 243 | ICELIB_addLocalCandidate(m_icelib, 244 | mediaIdx, 245 | 1, 246 | 5, 247 | (struct sockaddr*)&m1_localHostRtp, 248 | NULL, 249 | ICE_TRANS_UDP, 250 | ICE_CAND_TYPE_HOST, 251 | 0xffff); 252 | 253 | /* Remote side */ 254 | /* Medialine: 0 */ 255 | sockaddr_initFromString( (struct sockaddr*)&m0_defaultAddr, 256 | "158.38.48.10:5004" ); 257 | 258 | ICELIB_addRemoteMediaStream(m_icelib, remoteUfrag, remotePasswd, 259 | (struct sockaddr*)&m0_defaultAddr); 260 | ICELIB_addRemoteCandidate(m_icelib, 261 | 0, 262 | "1", 263 | 1, 264 | 1, 265 | 2130706431, 266 | "158.38.48.10", 267 | 5004, 268 | ICE_TRANS_UDP, 269 | ICE_CAND_TYPE_HOST); 270 | 271 | ICELIB_addRemoteCandidate(m_icelib, 272 | 0, 273 | "1", 274 | 1, 275 | 1, 276 | 2130705430, 277 | "158.38.48.10", 278 | 3478, 279 | ICE_TRANS_UDP, 280 | ICE_CAND_TYPE_HOST); 281 | 282 | ICELIB_addRemoteCandidate(m_icelib, 283 | 0, 284 | "1", 285 | 1, 286 | 1, 287 | 2130206431, 288 | "158.38.48.10", 289 | 33434, 290 | ICE_TRANS_UDP, 291 | ICE_CAND_TYPE_HOST); 292 | /* Medialine: 1 */ 293 | sockaddr_initFromString( (struct sockaddr*)&m0_defaultAddr, 294 | "158.38.48.10:5004" ); 295 | 296 | ICELIB_addRemoteMediaStream(m_icelib, remoteUfrag, remotePasswd, 297 | (struct sockaddr*)&m0_defaultAddr); 298 | ICELIB_addRemoteCandidate(m_icelib, 299 | 1, 300 | "1", 301 | 1, 302 | 1, 303 | 2130706431, 304 | "158.38.48.10", 305 | 5004, 306 | ICE_TRANS_UDP, 307 | ICE_CAND_TYPE_HOST); 308 | 309 | ICELIB_addRemoteCandidate(m_icelib, 310 | 1, 311 | "1", 312 | 1, 313 | 1, 314 | 2130705430, 315 | "158.38.48.10", 316 | 3478, 317 | ICE_TRANS_UDP, 318 | ICE_CAND_TYPE_HOST); 319 | 320 | ICELIB_addRemoteCandidate(m_icelib, 321 | 1, 322 | "1", 323 | 1, 324 | 1, 325 | 2130206431, 326 | "158.38.48.10", 327 | 33434, 328 | ICE_TRANS_UDP, 329 | ICE_CAND_TYPE_HOST); 330 | } 331 | 332 | 333 | 334 | 335 | CTEST_TEARDOWN(data) 336 | { 337 | (void) data; 338 | ICELIB_Destructor(m_icelib); 339 | free(m_icelib); 340 | } 341 | 342 | 343 | 344 | CTEST2(data, multiple_host_addr) 345 | { 346 | (void) data; 347 | memset(&m_connChkCB, 0, sizeof(m_ConncheckCB) * 50); 348 | memset(&m_nomChkCB, 0, sizeof(m_ConncheckCB) * 50); 349 | memset(&m_nominationCB, 0, sizeof(m_NominationCB) * 50); 350 | 351 | ASSERT_TRUE( ICELIB_Start(m_icelib, true) ); 352 | 353 | ASSERT_TRUE( ICELIB_isRunning(m_icelib) ); 354 | 355 | ASSERT_FALSE( ICELIB_Mangled(m_icelib) ); 356 | 357 | for (int i = 0; i < 40; i++) 358 | { 359 | ICELIB_Tick(m_icelib); 360 | 361 | } 362 | /* All the chacks are sent.. Lets trigger some responses */ 363 | for (uint32_t i = 0; i < num_checks; i++) 364 | { 365 | ICELIB_incomingBindingResponse(m_icelib, 366 | 200, 367 | m_connChkCB[i].transactionId, 368 | m_connChkCB[i].destination, 369 | m_connChkCB[i].source, 370 | m_connChkCB[i].source); 371 | ICELIB_Tick(m_icelib); 372 | } 373 | 374 | /* Wait for nominations.. */ 375 | for (uint32_t i = 0; i < 30; i++) 376 | { 377 | ICELIB_Tick(m_icelib); 378 | 379 | } 380 | 381 | for (uint32_t i = 0; i < num_nom; i++) 382 | { 383 | ICELIB_incomingBindingResponse(m_icelib, 384 | 200, 385 | m_nomChkCB[i].transactionId, 386 | m_nomChkCB[i].destination, 387 | m_nomChkCB[i].source, 388 | m_nomChkCB[i].source); 389 | 390 | 391 | ICELIB_Tick(m_icelib); 392 | } 393 | ICELIB_Tick(m_icelib); 394 | 395 | ASSERT_TRUE(sockaddr_ipPort( 396 | (const struct sockaddr*)&m_nominationCB[0].local) == 56780); 397 | ASSERT_TRUE(sockaddr_ipPort( 398 | (const struct sockaddr*)&m_nominationCB[0].remote) == 5004); 399 | 400 | ASSERT_TRUE(sockaddr_ipPort( 401 | (const struct sockaddr*)&m_nominationCB[1].local) == 56788); 402 | ASSERT_TRUE(sockaddr_ipPort( 403 | (const struct sockaddr*)&m_nominationCB[1].remote) == 5004); 404 | 405 | 406 | ASSERT_TRUE( ICELIB_isIceComplete(m_icelib) ); 407 | 408 | ASSERT_TRUE( m_icelib->iceState == ICELIB_COMPLETED); 409 | } 410 | 411 | 412 | CTEST2(data, multiple_host_addr_medialine_fail) 413 | { 414 | (void) data; 415 | memset(&m_connChkCB, 0, sizeof(m_ConncheckCB) * 50); 416 | memset(&m_nomChkCB, 0, sizeof(m_ConncheckCB) * 50); 417 | memset(&m_nominationCB, 0, sizeof(m_NominationCB) * 50); 418 | 419 | 420 | ASSERT_TRUE( ICELIB_Start(m_icelib, true) ); 421 | 422 | ASSERT_TRUE( ICELIB_isRunning(m_icelib) ); 423 | 424 | ASSERT_FALSE( ICELIB_Mangled(m_icelib) ); 425 | 426 | for (int i = 0; i < 40; i++) 427 | { 428 | ICELIB_Tick(m_icelib); 429 | 430 | } 431 | /* All the chacks are sent.. Lets trigger some responses */ 432 | for (uint32_t i = 0; i < num_checks; i++) 433 | { 434 | 435 | if (m_connChkCB[i].userValue2 == 43) 436 | { 437 | /* This is medialine 2.. Ignore.. */ 438 | } 439 | else 440 | { 441 | ICELIB_incomingBindingResponse(m_icelib, 442 | 200, 443 | m_connChkCB[i].transactionId, 444 | m_connChkCB[i].destination, 445 | m_connChkCB[i].source, 446 | m_connChkCB[i].source); 447 | ICELIB_Tick(m_icelib); 448 | } 449 | } 450 | 451 | /* Wait for nominations.. */ 452 | for (uint32_t i = 0; i < 30; i++) 453 | { 454 | ICELIB_Tick(m_icelib); 455 | 456 | } 457 | 458 | for (uint32_t i = 0; i < num_nom; i++) 459 | { 460 | ICELIB_incomingBindingResponse(m_icelib, 461 | 200, 462 | m_nomChkCB[i].transactionId, 463 | m_nomChkCB[i].destination, 464 | m_nomChkCB[i].source, 465 | m_nomChkCB[i].source); 466 | 467 | 468 | ICELIB_Tick(m_icelib); 469 | } 470 | ICELIB_Tick(m_icelib); 471 | 472 | for (uint32_t i = 0; i < 2000; i++) 473 | { 474 | ICELIB_Tick(m_icelib); 475 | 476 | } 477 | 478 | ASSERT_TRUE(sockaddr_ipPort( 479 | (const struct sockaddr*)&m_nominationCB[0].local) == 56780); 480 | ASSERT_TRUE(sockaddr_ipPort( 481 | (const struct sockaddr*)&m_nominationCB[0].remote) == 5004); 482 | 483 | ASSERT_FALSE(sockaddr_ipPort( 484 | (const struct sockaddr*)&m_nominationCB[1].local) == 56788); 485 | ASSERT_FALSE(sockaddr_ipPort( 486 | (const struct sockaddr*)&m_nominationCB[1].remote) == 5004); 487 | 488 | 489 | ASSERT_FALSE( ICELIB_isIceComplete(m_icelib) ); 490 | 491 | ASSERT_TRUE(m_icelib->iceState == ICELIB_FAILED); 492 | } 493 | 494 | 495 | #if 0 496 | CTEST2(data, multiple_host_addr_missing) 497 | { 498 | (void) data; 499 | memset( &m_connChkCB, 0, sizeof(m_ConncheckCB) ); 500 | memset( &m_nomChkCB, 0, sizeof(m_ConncheckCB) ); 501 | memset( &m_nominationCB, 0, sizeof(m_NominationCB) ); 502 | 503 | ASSERT_TRUE( ICELIB_Start(m_icelib, true) ); 504 | 505 | ASSERT_TRUE( ICELIB_isRunning(m_icelib) ); 506 | 507 | ASSERT_FALSE( ICELIB_Mangled(m_icelib) ); 508 | 509 | for (int i = 0; i < 15; i++) 510 | { 511 | ICELIB_Tick(m_icelib); 512 | 513 | } 514 | /* All the chacks are sent.. Lets trigger some responses */ 515 | /* Let the lowest pri finish first.. */ 516 | ICELIB_incomingBindingResponse(m_icelib, 517 | 200, 518 | m_connChkCB[2].transactionId, 519 | m_connChkCB[2].destination, 520 | m_connChkCB[2].source, 521 | m_connChkCB[2].source); 522 | ICELIB_Tick(m_icelib); 523 | ICELIB_Tick(m_icelib); 524 | 525 | ICELIB_incomingBindingResponse(m_icelib, 526 | 200, 527 | m_nomChkCB[0].transactionId, 528 | m_nomChkCB[0].destination, 529 | m_nomChkCB[0].source, 530 | m_nomChkCB[0].source); 531 | ICELIB_Tick(m_icelib); 532 | ICELIB_Tick(m_icelib); 533 | 534 | ASSERT_TRUE(sockaddr_ipPort( 535 | (const struct sockaddr*)&m_nominationCB[0].local) == 56780); 536 | ASSERT_TRUE(sockaddr_ipPort( 537 | (const struct sockaddr*)&m_nominationCB[0].remote) == 33434); 538 | 539 | 540 | /* So lets see what happens if a beetr pri pair shows up.. */ 541 | ICELIB_incomingBindingResponse(m_icelib, 542 | 200, 543 | m_connChkCB[1].transactionId, 544 | m_connChkCB[1].destination, 545 | m_connChkCB[1].source, 546 | m_connChkCB[1].source); 547 | 548 | ICELIB_Tick(m_icelib); 549 | ICELIB_Tick(m_icelib); 550 | 551 | ICELIB_incomingBindingResponse(m_icelib, 552 | 200, 553 | m_nomChkCB[1].transactionId, 554 | m_nomChkCB[1].destination, 555 | m_nomChkCB[1].source, 556 | m_nomChkCB[1].source); 557 | ICELIB_Tick(m_icelib); 558 | ICELIB_Tick(m_icelib); 559 | ASSERT_TRUE(sockaddr_ipPort( 560 | (const struct sockaddr*)&m_nominationCB[1].local) == 56780); 561 | ASSERT_TRUE(sockaddr_ipPort( 562 | (const struct sockaddr*)&m_nominationCB[1].remote) == 3478); 563 | 564 | 565 | for (int i = 0; i < 2000; i++) 566 | { 567 | ICELIB_Tick(m_icelib); 568 | 569 | } 570 | 571 | 572 | ASSERT_TRUE( ICELIB_isIceComplete(m_icelib) ); 573 | 574 | ASSERT_TRUE( m_icelib->iceState == ICELIB_COMPLETED); 575 | 576 | } 577 | 578 | CTEST2(data, ice_failure) 579 | { 580 | (void) data; 581 | memset( &m_connChkCB, 0, sizeof(m_ConncheckCB) ); 582 | memset( &m_nomChkCB, 0, sizeof(m_ConncheckCB) ); 583 | memset( &m_nominationCB, 0, sizeof(m_NominationCB) ); 584 | 585 | ASSERT_TRUE( ICELIB_Start(m_icelib, true) ); 586 | 587 | ASSERT_TRUE( ICELIB_isRunning(m_icelib) ); 588 | 589 | ASSERT_FALSE( ICELIB_Mangled(m_icelib) ); 590 | 591 | for (int i = 0; i < 2000; i++) 592 | { 593 | ICELIB_Tick(m_icelib); 594 | 595 | } 596 | 597 | ASSERT_FALSE( ICELIB_isIceComplete(m_icelib) ); 598 | ASSERT_TRUE(m_icelib->iceState == ICELIB_FAILED); 599 | 600 | } 601 | #endif 602 | -------------------------------------------------------------------------------- /test/icelib_nomination_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "test_utils.h" 7 | #include "icelib.h" 8 | 9 | 10 | ICELIB_INSTANCE* m_icelib; 11 | static char remoteUfrag[] = "rm0Uf"; 12 | static char remotePasswd[] = "rm0Pa"; 13 | 14 | 15 | typedef struct { 16 | bool gotCB; 17 | const struct sockaddr* destination; 18 | const struct sockaddr* source; 19 | uint32_t userValue1; 20 | uint32_t userValue2; 21 | uint32_t componentId; 22 | bool useRelay; 23 | char ufrag[ ICE_MAX_UFRAG_LENGTH]; 24 | /* const char *pUfrag; */ 25 | const char* pPasswd; 26 | uint32_t peerPriority; 27 | bool useCandidate; 28 | bool iceControlling; 29 | bool iceControlled; 30 | uint64_t tieBreaker; 31 | StunMsgId transactionId; 32 | }m_ConncheckCB; 33 | 34 | 35 | typedef struct { 36 | uint64_t priority; 37 | int32_t proto; 38 | struct sockaddr_storage local; 39 | struct sockaddr_storage remote; 40 | }m_NominationCB; 41 | 42 | m_ConncheckCB m_connChkCB[50]; 43 | uint32_t num_checks = 0; 44 | 45 | m_ConncheckCB m_nomChkCB[50]; 46 | uint32_t num_nom = 0; /* sorry could not resist the name..*/ 47 | 48 | m_NominationCB m_nominationCB[50]; 49 | uint32_t num_pair_nom = 0; 50 | 51 | 52 | ICELIB_Result 53 | Complete(void* pUserData, 54 | unsigned int userval1, 55 | bool controlling, 56 | bool failed) 57 | { 58 | (void) pUserData; 59 | (void) userval1; 60 | (void) controlling; 61 | (void) failed; 62 | return 0; 63 | } 64 | 65 | ICELIB_Result 66 | Nominated(void* pUserData, 67 | uint32_t userValue1, 68 | uint32_t userValue2, 69 | uint32_t componentId, 70 | uint64_t priority, 71 | int32_t proto, 72 | const struct sockaddr* local, 73 | const struct sockaddr* remote) 74 | { 75 | (void)pUserData; 76 | (void)userValue1; 77 | (void)userValue2; 78 | (void)componentId; 79 | (void)priority; 80 | (void) proto; 81 | (void)local; 82 | (void) remote; 83 | 84 | m_nominationCB[num_pair_nom].priority = priority; 85 | m_nominationCB[num_pair_nom].proto = proto; 86 | sockaddr_copy( (struct sockaddr*)&m_nominationCB[num_pair_nom].local, 87 | local ); 88 | sockaddr_copy( (struct sockaddr*)&m_nominationCB[num_pair_nom].remote, 89 | remote ); 90 | num_pair_nom++; 91 | return 0; 92 | } 93 | 94 | ICELIB_Result 95 | sendConnectivityCheck(void* pUserData, 96 | int proto, 97 | int socket, 98 | const struct sockaddr* destination, 99 | const struct sockaddr* source, 100 | uint32_t userValue1, 101 | uint32_t userValue2, 102 | uint32_t componentId, 103 | bool useRelay, 104 | const char* pUfrag, 105 | const char* pPasswd, 106 | uint32_t peerPriority, 107 | bool useCandidate, 108 | bool iceControlling, 109 | bool iceControlled, 110 | uint64_t tieBreaker, 111 | StunMsgId transactionId) 112 | { 113 | (void)pUserData; 114 | (void) proto; 115 | (void) socket; 116 | if (useCandidate) 117 | { 118 | m_nomChkCB[num_nom].gotCB = true; 119 | m_nomChkCB[num_nom].destination = destination; 120 | m_nomChkCB[num_nom].source = source; 121 | m_nomChkCB[num_nom].userValue1 = userValue1; 122 | m_nomChkCB[num_nom].userValue2 = userValue2; 123 | m_nomChkCB[num_nom].componentId = componentId; 124 | m_nomChkCB[num_nom].useRelay = useRelay; 125 | strncpy(m_nomChkCB[num_nom].ufrag, pUfrag, ICE_MAX_UFRAG_LENGTH); 126 | m_nomChkCB[num_nom].pPasswd = pPasswd; 127 | m_nomChkCB[num_nom].peerPriority = peerPriority; 128 | m_nomChkCB[num_nom].useCandidate = useCandidate; 129 | m_nomChkCB[num_nom].iceControlling = iceControlling; 130 | m_nomChkCB[num_nom].iceControlled = iceControlled; 131 | m_nomChkCB[num_nom].transactionId = transactionId; 132 | m_nomChkCB[num_nom].tieBreaker = tieBreaker; 133 | num_nom++; 134 | } 135 | else 136 | { 137 | m_connChkCB[num_checks].gotCB = true; 138 | m_connChkCB[num_checks].destination = destination; 139 | m_connChkCB[num_checks].source = source; 140 | m_connChkCB[num_checks].userValue1 = userValue1; 141 | m_connChkCB[num_checks].userValue2 = userValue2; 142 | m_connChkCB[num_checks].componentId = componentId; 143 | m_connChkCB[num_checks].useRelay = useRelay; 144 | strncpy(m_connChkCB[num_checks].ufrag, pUfrag, ICE_MAX_UFRAG_LENGTH); 145 | m_connChkCB[num_checks].pPasswd = pPasswd; 146 | m_connChkCB[num_checks].peerPriority = peerPriority; 147 | m_connChkCB[num_checks].useCandidate = useCandidate; 148 | m_connChkCB[num_checks].iceControlling = iceControlling; 149 | m_connChkCB[num_checks].iceControlled = iceControlled; 150 | m_connChkCB[num_checks].transactionId = transactionId; 151 | m_connChkCB[num_checks].tieBreaker = tieBreaker; 152 | 153 | num_checks++; 154 | } 155 | return 0; 156 | } 157 | 158 | void 159 | printLog(void* pUserData, 160 | ICELIB_logLevel logLevel, 161 | const char* str) 162 | { 163 | (void)pUserData; 164 | (void)logLevel; 165 | (void)str; 166 | /* printf("%s\n", str); */ 167 | } 168 | 169 | CTEST_DATA(data) 170 | { 171 | int a; 172 | }; 173 | 174 | 175 | CTEST_SETUP(data) 176 | { 177 | (void)data; 178 | struct sockaddr_storage m0_defaultAddr; 179 | struct sockaddr_storage m0_localHostRtp; 180 | 181 | ICELIB_CONFIGURATION iceConfig; 182 | 183 | uint32_t mediaIdx; 184 | 185 | srand( time(NULL) ); 186 | num_checks = 0; 187 | num_nom = 0; 188 | num_pair_nom = 0; 189 | 190 | m_icelib = (ICELIB_INSTANCE*)malloc( sizeof(ICELIB_INSTANCE) ); 191 | 192 | sockaddr_initFromString( (struct sockaddr*)&m0_localHostRtp, 193 | "192.168.2.10:56780" ); 194 | 195 | 196 | iceConfig.tickIntervalMS = 20; 197 | iceConfig.keepAliveIntervalS = 15; 198 | iceConfig.maxCheckListPairs = ICELIB_MAX_PAIRS; 199 | iceConfig.aggressiveNomination = true; 200 | iceConfig.iceLite = false; 201 | iceConfig.logLevel = ICELIB_logDebug; 202 | /* iceConfig.logLevel = ICELIB_logDisable; */ 203 | 204 | 205 | ICELIB_Constructor(m_icelib, 206 | &iceConfig); 207 | 208 | ICELIB_setCallbackOutgoingBindingRequest(m_icelib, 209 | sendConnectivityCheck, 210 | NULL); 211 | 212 | ICELIB_setCallbackConnecitivityChecksComplete(m_icelib, 213 | Complete, 214 | NULL); 215 | 216 | 217 | ICELIB_setCallbackLog(m_icelib, 218 | printLog, 219 | NULL, 220 | ICELIB_logDebug); 221 | 222 | ICELIB_setCallbackNominated(m_icelib, 223 | Nominated, 224 | NULL); 225 | 226 | /* Local side */ 227 | /* Medialine: 0 */ 228 | mediaIdx = ICELIB_addLocalMediaStream(m_icelib, 42, 42, ICE_CAND_TYPE_HOST); 229 | ICELIB_addLocalCandidate(m_icelib, 230 | mediaIdx, 231 | 1, 232 | 7, 233 | (struct sockaddr*)&m0_localHostRtp, 234 | NULL, 235 | ICE_TRANS_UDP, 236 | ICE_CAND_TYPE_HOST, 237 | 0xffff); 238 | 239 | /* Remote side */ 240 | /* Medialine: 0 */ 241 | sockaddr_initFromString( (struct sockaddr*)&m0_defaultAddr, 242 | "158.38.48.10:5004" ); 243 | 244 | ICELIB_addRemoteMediaStream(m_icelib, remoteUfrag, remotePasswd, 245 | (struct sockaddr*)&m0_defaultAddr); 246 | ICELIB_addRemoteCandidate(m_icelib, 247 | 0, 248 | "1", 249 | 1, 250 | 1, 251 | 2130706431, 252 | "158.38.48.10", 253 | 5004, 254 | ICE_TRANS_UDP, 255 | ICE_CAND_TYPE_HOST); 256 | 257 | ICELIB_addRemoteCandidate(m_icelib, 258 | 0, 259 | "1", 260 | 1, 261 | 1, 262 | 2130705430, 263 | "158.38.48.10", 264 | 3478, 265 | ICE_TRANS_UDP, 266 | ICE_CAND_TYPE_HOST); 267 | 268 | ICELIB_addRemoteCandidate(m_icelib, 269 | 0, 270 | "1", 271 | 1, 272 | 1, 273 | 2130206431, 274 | "158.38.48.10", 275 | 33434, 276 | ICE_TRANS_UDP, 277 | ICE_CAND_TYPE_HOST); 278 | } 279 | 280 | 281 | 282 | 283 | CTEST_TEARDOWN(data) 284 | { 285 | (void) data; 286 | ICELIB_Destructor(m_icelib); 287 | free(m_icelib); 288 | } 289 | 290 | 291 | 292 | CTEST2(data, multiple_host_addr) 293 | { 294 | (void) data; 295 | memset(&m_connChkCB, 0, sizeof(m_ConncheckCB) * 50); 296 | memset(&m_nomChkCB, 0, sizeof(m_ConncheckCB) * 50); 297 | memset(&m_nominationCB, 0, sizeof(m_NominationCB) * 50); 298 | 299 | ASSERT_TRUE( ICELIB_Start(m_icelib, true) ); 300 | 301 | ASSERT_TRUE( ICELIB_isRunning(m_icelib) ); 302 | 303 | ASSERT_FALSE( ICELIB_Mangled(m_icelib) ); 304 | 305 | for (int i = 0; i < 15; i++) 306 | { 307 | ICELIB_Tick(m_icelib); 308 | 309 | } 310 | /* All the chacks are sent.. Lets trigger some responses */ 311 | /* Let the lowest pri finish first.. */ 312 | ICELIB_incomingBindingResponse(m_icelib, 313 | 200, 314 | m_connChkCB[2].transactionId, 315 | m_connChkCB[2].destination, 316 | m_connChkCB[2].source, 317 | m_connChkCB[2].source); 318 | ICELIB_Tick(m_icelib); 319 | ICELIB_Tick(m_icelib); 320 | 321 | ICELIB_incomingBindingResponse(m_icelib, 322 | 200, 323 | m_nomChkCB[0].transactionId, 324 | m_nomChkCB[0].destination, 325 | m_nomChkCB[0].source, 326 | m_nomChkCB[0].source); 327 | ICELIB_Tick(m_icelib); 328 | ICELIB_Tick(m_icelib); 329 | 330 | ASSERT_TRUE(sockaddr_ipPort( 331 | (const struct sockaddr*)&m_nominationCB[0].local) == 56780); 332 | ASSERT_TRUE(sockaddr_ipPort( 333 | (const struct sockaddr*)&m_nominationCB[0].remote) == 33434); 334 | 335 | 336 | /* So lets see what happens if a beetr pri pair shows up.. */ 337 | ICELIB_incomingBindingResponse(m_icelib, 338 | 200, 339 | m_connChkCB[1].transactionId, 340 | m_connChkCB[1].destination, 341 | m_connChkCB[1].source, 342 | m_connChkCB[1].source); 343 | 344 | ICELIB_Tick(m_icelib); 345 | ICELIB_Tick(m_icelib); 346 | 347 | ICELIB_incomingBindingResponse(m_icelib, 348 | 200, 349 | m_nomChkCB[1].transactionId, 350 | m_nomChkCB[1].destination, 351 | m_nomChkCB[1].source, 352 | m_nomChkCB[1].source); 353 | ICELIB_Tick(m_icelib); 354 | ICELIB_Tick(m_icelib); 355 | ASSERT_TRUE(sockaddr_ipPort( 356 | (const struct sockaddr*)&m_nominationCB[1].local) == 56780); 357 | ASSERT_TRUE(sockaddr_ipPort( 358 | (const struct sockaddr*)&m_nominationCB[1].remote) == 3478); 359 | 360 | ICELIB_incomingBindingResponse(m_icelib, 361 | 200, 362 | m_connChkCB[0].transactionId, 363 | m_connChkCB[0].destination, 364 | m_connChkCB[0].source, 365 | m_connChkCB[0].source); 366 | 367 | ICELIB_Tick(m_icelib); 368 | ICELIB_Tick(m_icelib); 369 | ICELIB_incomingBindingResponse(m_icelib, 370 | 200, 371 | m_nomChkCB[2].transactionId, 372 | m_nomChkCB[2].destination, 373 | m_nomChkCB[2].source, 374 | m_nomChkCB[2].source); 375 | 376 | ICELIB_Tick(m_icelib); 377 | ICELIB_Tick(m_icelib); 378 | 379 | ASSERT_TRUE( sockaddr_ipPort( 380 | (const struct sockaddr*)&m_nominationCB[2].local) == 56780); 381 | ASSERT_TRUE( sockaddr_ipPort( 382 | (const struct sockaddr*)&m_nominationCB[2].remote) == 5004); 383 | 384 | ASSERT_TRUE( ICELIB_isIceComplete(m_icelib) ); 385 | 386 | ASSERT_TRUE( m_icelib->iceState == ICELIB_COMPLETED); 387 | } 388 | 389 | CTEST2(data, multiple_host_addr_missing) 390 | { 391 | (void) data; 392 | memset(&m_connChkCB, 0, sizeof(m_ConncheckCB) * 50); 393 | memset(&m_nomChkCB, 0, sizeof(m_ConncheckCB) * 50); 394 | memset(&m_nominationCB, 0, sizeof(m_NominationCB) * 50); 395 | 396 | ASSERT_TRUE( ICELIB_Start(m_icelib, true) ); 397 | 398 | ASSERT_TRUE( ICELIB_isRunning(m_icelib) ); 399 | 400 | ASSERT_FALSE( ICELIB_Mangled(m_icelib) ); 401 | 402 | for (int i = 0; i < 15; i++) 403 | { 404 | ICELIB_Tick(m_icelib); 405 | 406 | } 407 | /* All the chacks are sent.. Lets trigger some responses */ 408 | /* Let the lowest pri finish first.. */ 409 | ICELIB_incomingBindingResponse(m_icelib, 410 | 200, 411 | m_connChkCB[2].transactionId, 412 | m_connChkCB[2].destination, 413 | m_connChkCB[2].source, 414 | m_connChkCB[2].source); 415 | ICELIB_Tick(m_icelib); 416 | ICELIB_Tick(m_icelib); 417 | 418 | ICELIB_incomingBindingResponse(m_icelib, 419 | 200, 420 | m_nomChkCB[0].transactionId, 421 | m_nomChkCB[0].destination, 422 | m_nomChkCB[0].source, 423 | m_nomChkCB[0].source); 424 | ICELIB_Tick(m_icelib); 425 | ICELIB_Tick(m_icelib); 426 | 427 | ASSERT_TRUE(sockaddr_ipPort( 428 | (const struct sockaddr*)&m_nominationCB[0].local) == 56780); 429 | ASSERT_TRUE(sockaddr_ipPort( 430 | (const struct sockaddr*)&m_nominationCB[0].remote) == 33434); 431 | 432 | 433 | /* So lets see what happens if a beetr pri pair shows up.. */ 434 | ICELIB_incomingBindingResponse(m_icelib, 435 | 200, 436 | m_connChkCB[1].transactionId, 437 | m_connChkCB[1].destination, 438 | m_connChkCB[1].source, 439 | m_connChkCB[1].source); 440 | 441 | ICELIB_Tick(m_icelib); 442 | ICELIB_Tick(m_icelib); 443 | 444 | ICELIB_incomingBindingResponse(m_icelib, 445 | 200, 446 | m_nomChkCB[1].transactionId, 447 | m_nomChkCB[1].destination, 448 | m_nomChkCB[1].source, 449 | m_nomChkCB[1].source); 450 | ICELIB_Tick(m_icelib); 451 | ICELIB_Tick(m_icelib); 452 | ASSERT_TRUE(sockaddr_ipPort( 453 | (const struct sockaddr*)&m_nominationCB[1].local) == 56780); 454 | ASSERT_TRUE(sockaddr_ipPort( 455 | (const struct sockaddr*)&m_nominationCB[1].remote) == 3478); 456 | 457 | 458 | for (int i = 0; i < 2000; i++) 459 | { 460 | ICELIB_Tick(m_icelib); 461 | 462 | } 463 | 464 | 465 | ASSERT_TRUE( ICELIB_isIceComplete(m_icelib) ); 466 | 467 | ASSERT_TRUE( m_icelib->iceState == ICELIB_COMPLETED); 468 | 469 | } 470 | 471 | CTEST2(data, ice_failure) 472 | { 473 | (void) data; 474 | memset(&m_connChkCB, 0, sizeof(m_ConncheckCB) * 50); 475 | memset(&m_nomChkCB, 0, sizeof(m_ConncheckCB) * 50); 476 | memset(&m_nominationCB, 0, sizeof(m_NominationCB) * 50); 477 | 478 | ASSERT_TRUE( ICELIB_Start(m_icelib, true) ); 479 | 480 | ASSERT_TRUE( ICELIB_isRunning(m_icelib) ); 481 | 482 | ASSERT_FALSE( ICELIB_Mangled(m_icelib) ); 483 | 484 | for (int i = 0; i < 2000; i++) 485 | { 486 | ICELIB_Tick(m_icelib); 487 | 488 | } 489 | 490 | ASSERT_FALSE( ICELIB_isIceComplete(m_icelib) ); 491 | ASSERT_TRUE(m_icelib->iceState == ICELIB_FAILED); 492 | } 493 | -------------------------------------------------------------------------------- /test/icelibtypes_test.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | #include "test_utils.h" 5 | #include "icelibtypes.h" 6 | 7 | CTEST(icelibtypes, candidate_toString) 8 | { 9 | ASSERT_TRUE( 0 == 10 | strcmp(ICELIBTYPES_ICE_CANDIDATE_TYPE_toString(ICE_CAND_TYPE_NONE), 11 | "none") ); 12 | ASSERT_TRUE( 0 == 13 | strcmp(ICELIBTYPES_ICE_CANDIDATE_TYPE_toString(ICE_CAND_TYPE_HOST), 14 | "host") ); 15 | ASSERT_TRUE( 0 == 16 | strcmp(ICELIBTYPES_ICE_CANDIDATE_TYPE_toString( 17 | ICE_CAND_TYPE_SRFLX), 18 | "srflx") ); 19 | ASSERT_TRUE( 0 == 20 | strcmp(ICELIBTYPES_ICE_CANDIDATE_TYPE_toString( 21 | ICE_CAND_TYPE_RELAY), 22 | "relay") ); 23 | ASSERT_TRUE( 0 == 24 | strcmp(ICELIBTYPES_ICE_CANDIDATE_TYPE_toString( 25 | ICE_CAND_TYPE_PRFLX), 26 | "prflx") ); 27 | ASSERT_TRUE( 0 == 28 | strcmp(ICELIBTYPES_ICE_CANDIDATE_TYPE_toString(24), "unknown") ); 29 | 30 | } 31 | 32 | CTEST(icelibtypes, transport_toString) 33 | { 34 | ASSERT_TRUE( 0 == 35 | strcmp(ICELIBTYPES_ICE_TRANSPORT_PROTO_toString(ICE_TRANS_NONE), 36 | "NONE") ); 37 | ASSERT_TRUE( 0 == 38 | strcmp(ICELIBTYPES_ICE_TRANSPORT_PROTO_toString(ICE_TRANS_UDP), 39 | "UDP") ); 40 | ASSERT_TRUE( 0 == 41 | strcmp(ICELIBTYPES_ICE_TRANSPORT_PROTO_toString(ICE_TRANS_TCPACT), 42 | "TCP") ); 43 | ASSERT_TRUE( 0 == 44 | strcmp(ICELIBTYPES_ICE_TRANSPORT_PROTO_toString(ICE_TRANS_TCPPASS), 45 | "TCP") ); 46 | 47 | ASSERT_TRUE( 0 == 48 | strcmp(ICELIBTYPES_ICE_TRANSPORT_toString(ICE_TRANS_NONE), 49 | "none") ); 50 | ASSERT_TRUE( 0 == 51 | strcmp(ICELIBTYPES_ICE_TRANSPORT_toString(ICE_TRANS_UDP), 52 | "udp") ); 53 | ASSERT_TRUE( 0 == 54 | strcmp(ICELIBTYPES_ICE_TRANSPORT_toString(ICE_TRANS_TCPACT), 55 | "tcpact") ); 56 | ASSERT_TRUE( 0 == 57 | strcmp(ICELIBTYPES_ICE_TRANSPORT_toString(ICE_TRANS_TCPPASS), 58 | "tcppass") ); 59 | } 60 | 61 | 62 | CTEST(icelibtypes, iceMedia_empty) 63 | { 64 | ICE_MEDIA iceMedia; 65 | ICELIBTYPES_ICE_MEDIA_reset(&iceMedia); 66 | 67 | 68 | ASSERT_TRUE( ICELIBTYPES_ICE_MEDIA_isEmpty(&iceMedia) ); 69 | 70 | iceMedia.numberOfICEMediaLines = 2; 71 | 72 | ASSERT_FALSE( ICELIBTYPES_ICE_MEDIA_isEmpty(&iceMedia) ); 73 | 74 | } 75 | 76 | 77 | CTEST(icelibtypes, mediastream_empty){ 78 | ICE_MEDIA_STREAM iceMediaStream; 79 | 80 | ICELIBTYPES_ICE_MEDIA_STREAM_reset(&iceMediaStream); 81 | ASSERT_TRUE( ICELIBTYPES_ICE_MEDIA_STREAM_isEmpty(&iceMediaStream) ); 82 | 83 | iceMediaStream.numberOfCandidates = 3; 84 | 85 | ASSERT_FALSE( ICELIBTYPES_ICE_MEDIA_STREAM_isEmpty(&iceMediaStream) ); 86 | } 87 | -------------------------------------------------------------------------------- /test/test_utils.c: -------------------------------------------------------------------------------- 1 | /** 2 | * \file 3 | * 4 | * Copyright (c) 2015 sockaddrutil authors. See LICENSE file. 5 | */ 6 | 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #define CTEST_MAIN 13 | #include "test_utils.h" 14 | 15 | int 16 | main(int argc, 17 | const char* argv[]) 18 | { 19 | return ctest_main(argc, argv); 20 | } 21 | -------------------------------------------------------------------------------- /test/test_utils.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file 3 | * test_utils.h 4 | * 5 | * Copyright (c) 2015 sockaddrutil authors. See LICENSE file. 6 | */ 7 | 8 | 9 | #pragma once 10 | 11 | #define CTEST_SEGFAULT 12 | #include "ctest.h" 13 | 14 | -------------------------------------------------------------------------------- /uncrustify.cfg: -------------------------------------------------------------------------------- 1 | tok_split_gte=false 2 | utf8_byte=true 3 | utf8_force=false 4 | indent_cmt_with_tabs=false 5 | indent_align_string=true 6 | indent_braces=false 7 | indent_braces_no_func=false 8 | indent_braces_no_class=false 9 | indent_braces_no_struct=false 10 | indent_brace_parent=false 11 | indent_namespace=false 12 | indent_extern=false 13 | indent_class=false 14 | indent_class_colon=false 15 | indent_else_if=false 16 | indent_var_def_cont=false 17 | indent_func_call_param=false 18 | indent_func_def_param=false 19 | indent_func_proto_param=false 20 | indent_func_class_param=false 21 | indent_func_ctor_var_param=false 22 | indent_template_param=false 23 | indent_func_param_double=false 24 | indent_relative_single_line_comments=false 25 | indent_col1_comment=false 26 | indent_access_spec_body=false 27 | indent_paren_nl=false 28 | indent_comma_paren=false 29 | indent_bool_paren=false 30 | indent_first_bool_expr=false 31 | indent_square_nl=false 32 | indent_preserve_sql=false 33 | indent_align_assign=true 34 | sp_balance_nested_parens=true 35 | align_keep_tabs=false 36 | align_with_tabs=false 37 | align_on_tabstop=false 38 | align_number_left=true 39 | align_func_params=true 40 | align_same_func_call_params=true 41 | align_var_def_colon=true 42 | align_var_def_attribute=false 43 | align_var_def_inline=false 44 | align_right_cmt_mix=false 45 | align_on_operator=false 46 | align_mix_var_proto=false 47 | align_single_line_func=false 48 | align_single_line_brace=false 49 | align_nl_cont=false 50 | align_left_shift=true 51 | align_oc_decl_colon=false 52 | nl_collapse_empty_body=false 53 | nl_assign_leave_one_liners=false 54 | nl_class_leave_one_liners=false 55 | nl_enum_leave_one_liners=false 56 | nl_getset_leave_one_liners=false 57 | nl_func_leave_one_liners=false 58 | nl_if_leave_one_liners=false 59 | nl_multi_line_cond=false 60 | nl_multi_line_define=false 61 | nl_before_case=false 62 | nl_after_case=false 63 | nl_after_return=false 64 | nl_after_semicolon=false 65 | nl_after_brace_open=false 66 | nl_after_brace_open_cmt=false 67 | nl_after_vbrace_open=false 68 | nl_after_vbrace_open_empty=false 69 | nl_after_brace_close=false 70 | nl_after_vbrace_close=false 71 | nl_define_macro=false 72 | nl_squeeze_ifdef=false 73 | nl_ds_struct_enum_cmt=false 74 | nl_ds_struct_enum_close_brace=false 75 | nl_create_if_one_liner=false 76 | nl_create_for_one_liner=false 77 | nl_create_while_one_liner=false 78 | ls_for_split_full=true 79 | ls_func_split_full=true 80 | nl_after_multiline_comment=false 81 | eat_blanks_after_open_brace=false 82 | eat_blanks_before_close_brace=false 83 | mod_full_brace_if_chain=false 84 | mod_pawn_semicolon=false 85 | mod_full_paren_if_bool=true 86 | mod_remove_extra_semicolon=true 87 | mod_sort_import=false 88 | mod_sort_using=false 89 | mod_sort_include=false 90 | mod_move_case_break=true 91 | mod_remove_empty_return=true 92 | cmt_indent_multi=true 93 | cmt_c_group=false 94 | cmt_c_nl_start=true 95 | cmt_c_nl_end=true 96 | cmt_cpp_group=false 97 | cmt_cpp_nl_start=false 98 | cmt_cpp_nl_end=false 99 | cmt_cpp_to_c=true 100 | cmt_star_cont=true 101 | cmt_multi_check_last=true 102 | cmt_insert_before_preproc=false 103 | pp_indent_at_level=false 104 | pp_region_indent_code=false 105 | pp_if_indent_code=false 106 | pp_define_at_level=false 107 | indent_columns=2 108 | align_var_def_span=1 109 | align_var_def_star_style=0 110 | align_var_def_amp_style=0 111 | align_assign_span=1 112 | align_enum_equ_span=-1 113 | align_var_struct_span=1 114 | align_typedef_star_style=1 115 | align_right_cmt_span=1 116 | code_width=80 117 | cmt_width=80 118 | cmt_reflow_mode=2 119 | cmt_sp_after_star_cont=1 120 | newlines=lf 121 | indent_with_tabs=0 122 | sp_arith=add 123 | sp_assign=add 124 | sp_assign_default=add 125 | sp_before_assign=add 126 | sp_after_assign=add 127 | sp_enum_assign=ignore 128 | sp_bool=add 129 | sp_compare=add 130 | sp_inside_paren=remove 131 | sp_paren_brace=add 132 | sp_before_ptr_star=remove 133 | sp_before_unnamed_ptr_star=remove 134 | sp_between_ptr_star=remove 135 | sp_after_ptr_star=add 136 | sp_before_sparen=add 137 | sp_inside_sparen=remove 138 | sp_special_semi=remove 139 | sp_before_semi=remove 140 | sp_after_semi=add 141 | sp_inside_fparens=remove 142 | sp_inside_fparen=remove 143 | sp_func_call_paren=remove 144 | nl_end_of_file=ignore 145 | nl_if_brace=add 146 | nl_brace_else=add 147 | nl_elseif_brace=add 148 | nl_else_brace=add 149 | nl_brace_finally=add 150 | nl_finally_brace=add 151 | nl_try_brace=add 152 | nl_for_brace=add 153 | nl_catch_brace=add 154 | nl_brace_catch=add 155 | nl_while_brace=add 156 | nl_brace_brace=add 157 | nl_do_brace=add 158 | nl_brace_while=remove 159 | nl_switch_brace=add 160 | nl_func_type_name=add 161 | nl_func_proto_type_name=add 162 | nl_func_def_paren=remove 163 | nl_func_decl_start=remove 164 | nl_func_decl_args=add 165 | nl_func_def_args=add 166 | nl_func_def_start=remove 167 | nl_fdef_brace=add 168 | mod_full_brace_do=add 169 | mod_full_brace_for=add 170 | mod_full_brace_function=add 171 | mod_full_brace_if=add 172 | mod_full_brace_while=add 173 | --------------------------------------------------------------------------------